1 /* Copyright (c) 2007-2009 Timothy Wall, All Rights Reserved
2  *
3  * The contents of this file is dual-licensed under 2
4  * alternative Open Source/Free licenses: LGPL 2.1 or later and
5  * Apache License 2.0. (starting with JNA version 4.0.0).
6  *
7  * You can freely decide which license you want to apply to
8  * the project.
9  *
10  * You may obtain a copy of the LGPL License at:
11  *
12  * http://www.gnu.org/licenses/licenses.html
13  *
14  * A copy is also included in the downloadable source code package
15  * containing JNA, in file "LGPL2.1".
16  *
17  * You may obtain a copy of the Apache License at:
18  *
19  * http://www.apache.org/licenses/
20  *
21  * A copy is also included in the downloadable source code package
22  * containing JNA, in file "AL2.0".
23  */
24 package com.sun.jna;
25 
26 import java.nio.charset.Charset;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.concurrent.atomic.AtomicReference;
33 
34 import com.sun.jna.Structure.FieldOrder;
35 import com.sun.jna.Structure.StructureSet;
36 import com.sun.jna.ptr.ByteByReference;
37 import com.sun.jna.ptr.IntByReference;
38 import com.sun.jna.ptr.LongByReference;
39 
40 import junit.framework.TestCase;
41 
42 /** TODO: need more alignment tests, especially platform-specific behavior
43  * @author twall@users.sf.net
44  */
45 //@SuppressWarnings("unused")
46 public class StructureTest extends TestCase {
47 
48     private static final String UNICODE = "[\u0444]";
49 
main(java.lang.String[] argList)50     public static void main(java.lang.String[] argList) {
51         junit.textui.TestRunner.run(StructureTest.class);
52     }
53 
testSimpleSize()54     public void testSimpleSize() throws Exception {
55         class TestStructure extends Structure {
56             public int field;
57             @Override
58             protected List<String> getFieldOrder() {
59                 return Arrays.asList("field");
60             }
61         }
62         Structure s = new TestStructure();
63         assertEquals("Wrong size", 4, s.size());
64     }
65 
testInitializeFromPointer()66     public void testInitializeFromPointer() {
67         class TestStructureX extends Structure {
68             public int field1, field2;
69             @Override
70             protected List<String> getFieldOrder() {
71                 return Arrays.asList("field1", "field2");
72             }
73             public TestStructureX() {
74             }
75             public TestStructureX(Pointer p) {
76                 super(p);
77             }
78         }
79         Structure s = new TestStructureX();
80         Pointer p = s.getPointer();
81         Structure s1 = new TestStructureX(p);
82         Pointer p1 = s1.getPointer();
83 
84         assertEquals("Constructor address not used", p, p1);
85         assertFalse("Pointer should not be auto-allocated", p.getClass().equals(p1.getClass()));
86         assertNotSame("Initial pointer should not be used directly: " + p, p, p1);
87     }
88 
testInitializeWithTypeMapper()89     public void testInitializeWithTypeMapper() {
90         class TestStructure extends Structure {
91             public int field;
92             @Override
93             protected List<String> getFieldOrder() {
94                 return Arrays.asList("field");
95             }
96             public TestStructure(TypeMapper m) {
97                 super(ALIGN_DEFAULT, m);
98             }
99         }
100         TypeMapper m = new DefaultTypeMapper();
101         TestStructure s = new TestStructure(m);
102         assertEquals("Type mapper not installed", m, s.getTypeMapper());
103     }
104 
105     // must be public to populate array
106     public static class TestAllocStructure extends Structure {
107         public static final List<String> FIELDS = createFieldsOrder("f0", "f1", "f2", "f3");
108         public int f0;
109         public int f1;
110         public int f2;
111         public int f3;
112 
113         @Override
getFieldOrder()114         protected List<String> getFieldOrder() {
115             return FIELDS;
116         }
117     }
118 
testFieldsAllocated()119     public void testFieldsAllocated() {
120         class TestStructure extends Structure {
121             public TestStructure() { }
122             public TestStructure(Pointer p) { super(p); }
123             public int field;
124             @Override
125             protected List<String> getFieldOrder() {
126                 return Arrays.asList("field");
127             }
128             public int fieldCount() { ensureAllocated(); return fields().size(); }
129         }
130         TestStructure s = new TestStructure();
131         assertEquals("Wrong number of fields (default)", 1, s.fieldCount());
132 
133         s = new TestStructure(new Memory(4));
134         assertEquals("Wrong number of fields (preallocated)", 1, s.fieldCount());
135     }
136 
testProvidedMemoryTooSmall()137     public void testProvidedMemoryTooSmall() {
138         class TestStructure extends Structure {
139             public TestStructure(Pointer p) { super(p); }
140             public int field;
141             @Override
142             protected List<String> getFieldOrder() {
143                 return Arrays.asList("field");
144             }
145         }
146         try {
147             new TestStructure(new Memory(2));
148             fail("Expect exception if provided memory is insufficient");
149         }
150         catch(IllegalArgumentException e) {
151         }
152     }
153 
testClearOnAllocate()154     public void testClearOnAllocate() {
155         TestAllocStructure s = new TestAllocStructure();
156         s.read();
157         assertEquals("Memory not cleared on structure init", 0, s.f0);
158         assertEquals("Memory not cleared on structure init", 0, s.f1);
159         assertEquals("Memory not cleared on structure init", 0, s.f2);
160         assertEquals("Memory not cleared on structure init", 0, s.f3);
161 
162         s = (TestAllocStructure)s.toArray(2)[1];
163         assertEquals("Memory not cleared on array init", 0, s.f0);
164         assertEquals("Memory not cleared on array init", 0, s.f1);
165         assertEquals("Memory not cleared on array init", 0, s.f2);
166         assertEquals("Memory not cleared on array init", 0, s.f3);
167     }
168 
169     // cross-platform smoke test
testGNUCAlignment()170     public void testGNUCAlignment() {
171         class TestStructure extends Structure {
172             public byte b;
173             public short s;
174             public int i;
175             public long l;
176             public float f;
177             public double d;
178             @Override
179             protected List<String> getFieldOrder() {
180                 return Arrays.asList("b", "s", "i", "l", "f", "d");
181             }
182         }
183         Structure s = new TestStructure();
184         s.setAlignType(Structure.ALIGN_GNUC);
185         final int SIZE = Native.MAX_ALIGNMENT == 8 ? 32 : 28;
186         assertEquals("Wrong structure size", SIZE, s.size());
187     }
188 
189     // cross-platform smoke test
testMSVCAlignment()190     public void testMSVCAlignment() {
191         class TestStructure extends Structure {
192             public byte b;
193             public short s;
194             public int i;
195             public long l;
196             public float f;
197             public double d;
198             @Override
199             protected List<String> getFieldOrder() {
200                 return Arrays.asList("b", "s", "i", "l", "f", "d");
201             }
202         }
203         Structure s = new TestStructure();
204         s.setAlignType(Structure.ALIGN_MSVC);
205         assertEquals("Wrong structure size", 32, s.size());
206     }
207 
208     public static abstract class FilledStructure extends Structure {
209         private boolean initialized;
210         @Override
ensureAllocated()211         protected void ensureAllocated() {
212             super.ensureAllocated();
213             if (!initialized) {
214                 initialized = true;
215                 for (int i=0;i < size();i++) {
216                     getPointer().setByte(i, (byte)0xFF);
217                 }
218             }
219         }
220     }
221     // Do NOT change the order of naming w/o changing testlib.c as well
222     public static class TestStructure0 extends FilledStructure {
223         public static final List<String> FIELDS = createFieldsOrder("field0", "field1");
224         public byte field0 = 0x01;
225         public short field1 = 0x0202;
226         @Override
getFieldOrder()227         protected List<String> getFieldOrder() {
228             return FIELDS;
229         }
230     }
231     @FieldOrder({ "field0", "field1" })
232     public static class AnnotatedTestStructure0 extends FilledStructure {
233         public byte field0 = 0x01;
234         public short field1 = 0x0202;
235     }
236     public static class TestStructure1 extends FilledStructure {
237         public static final List<String> FIELDS = createFieldsOrder("field0", "field1");
238         public byte field0 = 0x01;
239         public int field1 = 0x02020202;
240         @Override
getFieldOrder()241         protected List<String> getFieldOrder() {
242             return FIELDS;
243         }
244     }
245     @FieldOrder({ "field0", "field1" })
246     public static class AnnotatedTestStructure1 extends FilledStructure {
247         public byte field0 = 0x01;
248         public int field1 = 0x02020202;
249     }
250     public static class TestStructure2 extends FilledStructure {
251         public static final List<String> FIELDS = createFieldsOrder("field0", "field1");
252         public short field0 = 0x0101;
253         public int field1 = 0x02020202;
254         @Override
getFieldOrder()255         protected List<String> getFieldOrder() {
256             return FIELDS;
257         }
258     }
259     @FieldOrder({ "field0", "field1" })
260     public static class AnnotatedTestStructure2 extends FilledStructure {
261         public short field0 = 0x0101;
262         public int field1 = 0x02020202;
263     }
264     public static class TestStructure3 extends FilledStructure {
265         public static final List<String> FIELDS = createFieldsOrder("field0", "field1", "field2");
266         public int field0 = 0x01010101;
267         public short field1 = 0x0202;
268         public int field2 = 0x03030303;
269         @Override
getFieldOrder()270         protected List<String> getFieldOrder() {
271             return FIELDS;
272         }
273     }
274     @FieldOrder({ "field0", "field1", "field2" })
275     public static class AnnotatedTestStructure3 extends FilledStructure {
276         public int field0 = 0x01010101;
277         public short field1 = 0x0202;
278         public int field2 = 0x03030303;
279     }
280     public static class TestStructure4 extends FilledStructure {
281         public static final List<String> FIELDS = createFieldsOrder("field0", "field1", "field2", "field3");
282         public int field0 = 0x01010101;
283         public long field1 = 0x0202020202020202L;
284         public int field2 = 0x03030303;
285         public long field3 = 0x0404040404040404L;
286         @Override
getFieldOrder()287         protected List<String> getFieldOrder() {
288             return FIELDS;
289         }
290     }
291     @FieldOrder({ "field0", "field1", "field2", "field3" })
292     public static class AnnotatedTestStructure4 extends FilledStructure {
293         public int field0 = 0x01010101;
294         public long field1 = 0x0202020202020202L;
295         public int field2 = 0x03030303;
296         public long field3 = 0x0404040404040404L;
297     }
298     @FieldOrder({ "field0", "field1" })
299     public static class _InheritanceTestStructure4Parent extends FilledStructure {
300         public int field0 = 0x01010101;
301         public long field1 = 0x0202020202020202L;
302     }
303     @FieldOrder({ "field2", "field3" })
304     public static class InheritanceTestStructure4 extends _InheritanceTestStructure4Parent {
305         public int field2 = 0x03030303;
306         public long field3 = 0x0404040404040404L;
307     }
308     public static class TestStructure5 extends FilledStructure {
309         public static final List<String> FIELDS = createFieldsOrder("field0", "field1");
310         public long field0 = 0x0101010101010101L;
311         public byte field1 = 0x02;
312         @Override
getFieldOrder()313         protected List<String> getFieldOrder() {
314             return FIELDS;
315         }
316     }
317     @FieldOrder({ "field0", "field1" })
318     public static class AnnotatedTestStructure5 extends FilledStructure {
319         public long field0 = 0x0101010101010101L;
320         public byte field1 = 0x02;
321     }
322     public interface SizeTest extends Library {
getStructureSize(int type)323         int getStructureSize(int type);
324     }
testStructureSize(int index)325     private void testStructureSize(int index) {
326         testStructureSize("", index);
327     }
testStructureSize(String prefix, int index)328     private void testStructureSize(String prefix, int index) {
329         try {
330             SizeTest lib = Native.load("testlib", SizeTest.class);
331             Class<? extends Structure> cls = (Class<? extends Structure>) Class.forName(getClass().getName() + "$" + prefix + "TestStructure" + index);
332             Structure s = Structure.newInstance(cls);
333             assertEquals("Incorrect size for structure " + index + "=>" + s.toString(true), lib.getStructureSize(index), s.size());
334         }
335         catch(Exception e) {
336             throw new Error(e);
337         }
338     }
testStructureSize0()339     public void testStructureSize0() {
340         testStructureSize(0);
341     }
annotatedTestStructureSize0()342     public void annotatedTestStructureSize0() {
343         testStructureSize("Eazy", 0);
344     }
testStructureSize1()345     public void testStructureSize1() {
346         testStructureSize(1);
347     }
annotatedTestStructureSize1()348     public void annotatedTestStructureSize1() {
349         testStructureSize("Eazy", 1);
350     }
testStructureSize2()351     public void testStructureSize2() {
352         testStructureSize(2);
353     }
annotatedTestStructureSize2()354     public void annotatedTestStructureSize2() {
355         testStructureSize("Eazy", 2);
356     }
testStructureSize3()357     public void testStructureSize3() {
358         testStructureSize(3);
359     }
annotatedTestStructureSize3()360     public void annotatedTestStructureSize3() {
361         testStructureSize("Eazy", 3);
362     }
testStructureSize4()363     public void testStructureSize4() {
364         testStructureSize(4);
365     }
annotatedTestStructureSize4()366     public void annotatedTestStructureSize4() {
367         testStructureSize("Eazy", 4);
368     }
inheritanceTestStructureSize4()369     public void inheritanceTestStructureSize4() {
370         testStructureSize("Inheritance", 4);
371     }
testStructureSize5()372     public void testStructureSize5() {
373         testStructureSize(5);
374     }
annotatedTestStructureSize5()375     public void annotatedTestStructureSize5() {
376         testStructureSize("Eazy", 5);
377     }
378 
379     public interface AlignmentTest extends Library {
testStructureAlignment(Structure s, int type, IntByReference offsetp, LongByReference valuep)380         int testStructureAlignment(Structure s, int type,
381                                    IntByReference offsetp, LongByReference valuep);
382     }
383 
testAlignStruct(int index)384     private void testAlignStruct(int index) {
385         testAlignStruct("", index);
386     }
testAlignStruct(String prefix,int index)387     private void testAlignStruct(String prefix,int index) {
388         AlignmentTest lib = Native.load("testlib", AlignmentTest.class);
389         try {
390             IntByReference offset = new IntByReference();
391             LongByReference value = new LongByReference();
392             Class<?> cls = Class.forName(getClass().getName() + "$" + prefix + "TestStructure" + index);
393             Structure s = Structure.newInstance((Class<? extends Structure>) cls);
394             int result = lib.testStructureAlignment(s, index, offset, value);
395             assertEquals("Wrong native value at field " + result
396                          + "=0x" + Long.toHexString(value.getValue())
397                          + " (actual native field offset=" + offset.getValue()
398                          + ") in " + s, -2, result);
399         }
400         catch(Exception e) {
401             throw new Error(e);
402         }
403     }
testAlignStruct0()404     public void testAlignStruct0() {
405         testAlignStruct(0);
406     }
annotatedTestAlignStruct0()407     public void annotatedTestAlignStruct0() {
408         testAlignStruct("Annotated", 0);
409     }
testAlignStruct1()410     public void testAlignStruct1() {
411         testAlignStruct(1);
412     }
annotatedTestAlignStruct1()413     public void annotatedTestAlignStruct1() {
414         testAlignStruct("Annotated", 1);
415     }
testAlignStruct2()416     public void testAlignStruct2() {
417         testAlignStruct(2);
418     }
annotatedTestAlignStruct2()419     public void annotatedTestAlignStruct2() {
420         testAlignStruct("Annotated", 2);
421     }
testAlignStruct3()422     public void testAlignStruct3() {
423         testAlignStruct(3);
424     }
annotatedTestAlignStruct3()425     public void annotatedTestAlignStruct3() {
426         testAlignStruct("Annotated", 3);
427     }
testAlignStruct4()428     public void testAlignStruct4() {
429         testAlignStruct(4);
430     }
annotatedTestAlignStruct4()431     public void annotatedTestAlignStruct4() {
432         testAlignStruct("Annotated", 4);
433     }
inheritanceTestAlignStruct4()434     public void inheritanceTestAlignStruct4() {
435         testAlignStruct("Inheritance", 4);
436     }
testAlignStruct5()437     public void testAlignStruct5() {
438         testAlignStruct(5);
439     }
annotatedTestAlignStruct5()440     public void annotatedTestAlignStruct5() {
441         testAlignStruct("Annotated", 5);
442     }
443 
testInheritanceFieldOrder()444     public void testInheritanceFieldOrder() {
445         @FieldOrder({ "a", "b" })
446         class Parent extends Structure {
447             public int a;
448             public int b;
449         }
450         @FieldOrder({ "c", "d" })
451         class Son extends Parent {
452             public int c;
453             public int d;
454         }
455 
456         Son test = new Son();
457         assertEquals("Wrong field order", Arrays.asList("a", "b", "c", "d"), test.getFieldOrder());
458     }
459 
testStructureWithNoFields()460     public void testStructureWithNoFields() {
461         class TestStructure extends Structure {
462             @Override
463             protected List<String> getFieldOrder() {
464                 return Collections.emptyList();
465             }
466         }
467         try {
468             new TestStructure();
469             fail("Structure should not be instantiable if it has no public member fields");
470         }
471         catch(IllegalArgumentException e) {
472             // expected - ignored
473         }
474     }
475 
testAnnotatedStructureWithNoFields()476     public void testAnnotatedStructureWithNoFields() {
477         class TestStructure extends Structure {
478         }
479         try {
480             new TestStructure();
481             fail("Structure should not be instantiable if it has no public member fields");
482         }
483         catch(IllegalArgumentException e) {
484             // expected - ignored
485         }
486     }
487 
testAnnotatedStructureWithNoFieldsWithAnnot()488     public void testAnnotatedStructureWithNoFieldsWithAnnot() {
489         @FieldOrder({ })
490         class TestStructure extends Structure {
491         }
492         try {
493             new TestStructure();
494             fail("Structure should not be instantiable if it has no public member fields");
495         }
496         catch(IllegalArgumentException e) {
497             // expected - ignored
498         }
499     }
500 
testStructureWithOnlyNonPublicMemberFields()501     public void testStructureWithOnlyNonPublicMemberFields() {
502         class TestStructure extends Structure {
503             int field;
504             @Override
505             protected List<String> getFieldOrder() {
506                 return Arrays.asList("field");
507             }
508         }
509         try {
510             new TestStructure();
511             fail("Structure should not be instantiable if it has no public member fields");
512         }
513         catch(Error e) {
514             // expected - ignored
515         }
516     }
517 
518     // must be publicly accessible in order to create array elements
519     public static class PublicTestStructure extends Structure {
520         public static class ByValue extends PublicTestStructure implements Structure.ByValue {
ByValue()521             public ByValue() { }
ByValue(Pointer p)522             public ByValue(Pointer p) { super(p); }
523         }
524         public static class ByReference extends PublicTestStructure implements Structure.ByReference {
ByReference()525             public ByReference() { }
ByReference(Pointer p)526             public ByReference(Pointer p) { super(p); }
527         }
528 
529         public static final List<String> FIELDS = createFieldsOrder("x", "y");
530         public int x = 1, y = 2;
PublicTestStructure()531         public PublicTestStructure() { }
PublicTestStructure(Pointer p)532         public PublicTestStructure(Pointer p) { super(p); read(); }
533         public static int allocations = 0;
534         @Override
allocateMemory(int size)535         protected void allocateMemory(int size) {
536             super.allocateMemory(size);
537             ++allocations;
538         }
539         @Override
getFieldOrder()540         protected List<String> getFieldOrder() {
541             return FIELDS;
542         }
543     }
testStructureField()544     public void testStructureField() {
545         class TestStructure extends Structure {
546             public PublicTestStructure s1, s2;
547             public int after;
548             @Override
549             protected List<String> getFieldOrder() {
550                 return Arrays.asList("s1", "s2", "after");
551             }
552         }
553         TestStructure s = new TestStructure();
554         TestStructure s2 = new TestStructure();
555         assertNotNull("Inner structure should be initialized", s.s1);
556         assertNotNull("Inner structure should be initialized (cached)", s2.s1);
557         assertEquals("Wrong aggregate size",
558                      s.s1.size() + s.s2.size() + 4, s.size());
559         s.write();
560         assertEquals("Wrong memory for structure field 1 after write",
561                      s.getPointer(), s.s1.getPointer());
562         assertEquals("Wrong memory for structure field 2 after write",
563                      s.getPointer().share(s.s1.size()),
564                      s.s2.getPointer());
565 
566         s.read();
567         assertEquals("Wrong memory for structure field 1 after read",
568                      s.getPointer(), s.s1.getPointer());
569         assertEquals("Wrong memory for structure field 2 after read",
570                      s.getPointer().share(s.s1.size()),
571                      s.s2.getPointer());
572     }
573 
testStructureByValueField()574     public void testStructureByValueField() {
575         class TestStructure extends Structure {
576             public PublicTestStructure.ByValue s1, s2;
577             public int after;
578             @Override
579             protected List<String> getFieldOrder() {
580                 return Arrays.asList("s1", "s2", "after");
581             }
582         }
583         TestStructure s = new TestStructure();
584         TestStructure s2 = new TestStructure();
585         assertNotNull("Inner structure should be initialized", s.s1);
586         assertNotNull("Inner structure should be initialized (cached)", s2.s1);
587         assertEquals("Wrong aggregate size",
588                      s.s1.size() + s.s2.size() + 4, s.size());
589         s.write();
590         assertEquals("Wrong memory for structure field 1 after write",
591                      s.getPointer(), s.s1.getPointer());
592         assertEquals("Wrong memory for structure field 2 after write",
593                      s.getPointer().share(s.s1.size()),
594                      s.s2.getPointer());
595 
596         s.read();
597         assertEquals("Wrong memory for structure field 1 after read",
598                      s.getPointer(), s.s1.getPointer());
599         assertEquals("Wrong memory for structure field 2 after read",
600                      s.getPointer().share(s.s1.size()),
601                      s.s2.getPointer());
602     }
603 
604     public static class TestUnion extends Union {
605         public int u_int;
606         public float u_float;
607         public double u_double;
608     }
testUnionField()609     public void testUnionField() {
610         class TestStructure extends Structure {
611             public long s_long;
612             public TestUnion s_union;
613             public int s_int;
614             @Override
615             protected List<String> getFieldOrder() {
616                 return Arrays.asList("s_long", "s_union", "s_int");
617             }
618         }
619         TestStructure s = new TestStructure();
620         assertEquals("Wrong structure size", Native.MAX_PADDING == 4 ? 20 : 24, s.size());
621         assertEquals("Wrong union size", 8, s.s_union.size());
622     }
623 
624     public static class NonAllocatingTestStructure extends PublicTestStructure {
NonAllocatingTestStructure()625         public NonAllocatingTestStructure() { }
NonAllocatingTestStructure(Pointer p)626         public NonAllocatingTestStructure(Pointer p) { super(p); read(); }
627         @Override
allocateMemory(int size)628         protected void allocateMemory(int size) {
629             throw new Error("Memory unexpectedly allocated");
630         }
631     }
632 
633     // TODO: add'l newInstance(Pointer) tests:
634     // NOTE: ensure structure-by-value respected (no more flag on newjavastructure)
635     // native call (direct mode)
636     // getNativeAlignment
testStructureFieldAvoidsSeparateMemoryAllocation()637     public void testStructureFieldAvoidsSeparateMemoryAllocation() {
638         class TestStructure extends Structure {
639             public NonAllocatingTestStructure s1;
640             public TestStructure() { }
641             @Override
642             protected List<String> getFieldOrder() {
643                 return Arrays.asList("s1");
644             }
645         }
646         TestStructure ts = new TestStructure();
647         assertNotNull("Inner structure should be initialized", ts.s1);
648     }
649 
testPrimitiveArrayField()650     public void testPrimitiveArrayField() {
651         class TestStructure extends Structure {
652             public byte[] buffer = new byte[1024];
653             @Override
654             protected List<String> getFieldOrder() {
655                 return Arrays.asList("buffer");
656             }
657         }
658         TestStructure s = new TestStructure();
659         TestStructure s2 = new TestStructure();
660         assertEquals("Wrong size for structure with nested array", 1024, s.size());
661         assertEquals("Wrong size for structure with nested array (cached)", 1024, s2.size());
662         assertNotNull("Array should be initialized", s.buffer);
663         assertNotNull("Array should be initialized (cached)", s2.buffer);
664         s.write();
665         s.read();
666     }
667 
testStructureArrayField()668     public void testStructureArrayField() {
669         class TestStructure extends Structure {
670             // uninitialized array elements
671             public PublicTestStructure[] inner = new PublicTestStructure[2];
672             // initialized array elements
673             public PublicTestStructure[] inner2 = (PublicTestStructure[])
674                 new PublicTestStructure().toArray(2);
675             @Override
676             protected List<String> getFieldOrder() {
677                 return Arrays.asList("inner", "inner2");
678             }
679         }
680         TestStructure s = new TestStructure();
681         int innerSize = new PublicTestStructure().size();
682         assertEquals("Wrong size for structure with nested array of struct",
683                      s.inner.length * innerSize + s.inner2.length * innerSize,
684                      s.size());
685         Structure s0 = s.inner2[0];
686         Structure s1 = s.inner2[1];
687 
688         s.write();
689         assertNotNull("Inner array elements should auto-initialize after write", s.inner[0]);
690         assertSame("Inner array (2) element 0 reference should not be changed after write", s0, s.inner2[0]);
691         assertSame("Inner array (2) element 1 reference should not be changed after write", s1, s.inner2[1]);
692 
693         s.inner[0].x = s.inner[1].x = -1;
694         s.inner2[0].x = s.inner2[1].x = -1;
695         s.read();
696         assertEquals("Inner structure array element 0 not properly read",
697                      0, s.inner[0].x);
698         assertEquals("Inner structure array element 1 not properly read",
699                      0, s.inner[1].x);
700         // First element (after toArray()) should preserve values from field initializers
701         assertEquals("Inner structure array (2) element 0 not properly read",
702                      1, s.inner2[0].x);
703         // Subsequent elements from toArray() are initialized from first's
704         // memory, which is zeroed
705         assertEquals("Inner structure array (2) element 1 not properly read",
706                      0, s.inner2[1].x);
707 
708         assertEquals("Wrong memory for uninitialized nested array",
709                      s.getPointer(), s.inner[0].getPointer());
710         assertEquals("Wrong memory for initialized nested array",
711                      s.getPointer().share(innerSize * s.inner.length),
712                      s.inner2[0].getPointer());
713     }
714 
715     public static class ToArrayTestStructure extends Structure {
716         public static final List<String> FIELDS = createFieldsOrder("inner");
717         public PublicTestStructure[] inner =
718             (PublicTestStructure[])new PublicTestStructure().toArray(2);
719 
720         @Override
getFieldOrder()721         protected List<String> getFieldOrder() {
722             return FIELDS;
723         }
724     }
testToArrayWithStructureArrayField()725     public void testToArrayWithStructureArrayField() {
726         ToArrayTestStructure[] array =
727             (ToArrayTestStructure[])new ToArrayTestStructure().toArray(2);
728         assertEquals("Wrong address for top-level array element",
729                      array[0].getPointer().share(array[0].size()),
730                      array[1].getPointer());
731         assertEquals("Wrong address for nested array element",
732                      array[1].inner[0].getPointer().share(array[1].inner[0].size()),
733                      array[1].inner[1].getPointer());
734     }
735 
testUninitializedNestedArrayFails()736     public void testUninitializedNestedArrayFails() {
737         class TestStructure extends Structure {
738             public Pointer[] buffer;
739             @Override
740             protected List<String> getFieldOrder() {
741                 return Arrays.asList("buffer");
742             }
743         }
744         Structure s = new TestStructure();
745         try {
746             s.size();
747             fail("Size can't be calculated unless array fields are initialized");
748         }
749         catch(IllegalStateException e) {
750         }
751     }
752 
testReadWriteStructure()753     public void testReadWriteStructure() {
754         class TestStructure extends Structure {
755             public TestStructure() {
756                 // Have to do this due to inline primitive arrays
757                 allocateMemory();
758             }
759             public boolean z;       // native int
760             public byte b;          // native char
761             public char c;          // native wchar_t
762             public short s;         // native short
763             public int i;           // native int
764             public long l;          // native long long
765             public float f;         // native float
766             public double d;        // native double
767             public byte[] ba = new byte[3];
768             public char[] ca = new char[3];
769             public short[] sa = new short[3];
770             public int[] ia = new int[3];
771             public long[] la = new long[3];
772             public float[] fa = new float[3];
773             public double[] da = new double[3];
774             public PublicTestStructure nested;
775             @Override
776             protected List<String> getFieldOrder() {
777                 return Arrays.asList("z", "b", "c", "s", "i", "l", "f", "d", "ba", "ca", "sa", "ia", "la", "fa", "da", "nested");
778             }
779         }
780         TestStructure s = new TestStructure();
781         // set content of the structure
782         s.z = true;
783         s.b = 1;
784         s.c = 2;
785         s.s = 3;
786         s.i = 4;
787         s.l = 5;
788         s.f = 6.0f;
789         s.d = 7.0;
790         s.nested.x = 1;
791         s.nested.y = 2;
792         for (int i = 0; i < 3; i++) {
793             s.ba[i] = (byte) (8 + i);
794             s.ca[i] = (char) (11 + i);
795             s.sa[i] = (short) (14 + i);
796             s.ia[i] = 17 + i;
797             s.la[i] = 23 + i;
798             s.fa[i] = (float) 26 + i;
799             s.da[i] = (double) 29 + i;
800         }
801         // write content to memory
802         s.write();
803         Pointer p = s.getPointer();
804         s = new TestStructure();
805         s.useMemory(p);
806         // read content from memory and compare field values
807         s.read();
808         assertEquals("Wrong boolean field value after write/read", s.z, true);
809         assertEquals("Wrong byte field value after write/read", s.b, 1);
810         assertEquals("Wrong char field value after write/read", s.c, 2);
811         assertEquals("Wrong short field value after write/read", s.s, 3);
812         assertEquals("Wrong int field value after write/read", s.i, 4);
813         assertEquals("Wrong long field value after write/read", s.l, 5);
814         assertEquals("Wrong float field value after write/read", s.f, 6.0f, 0f);
815         assertEquals("Wrong double field value after write/read", s.d, 7.0, 0d);
816         assertEquals("Wrong nested struct field value after write/read (x)", s.nested.x, 1);
817         assertEquals("Wrong nested struct field value after write/read (y)", s.nested.y, 2);
818         for (int i = 0; i < 3; i++) {
819             assertEquals("Wrong byte array field value after write/read", s.ba[i], (byte) (8 + i));
820             assertEquals("Wrong char array field value after write/read", s.ca[i], (char) (11 + i));
821             assertEquals("Wrong short array field value after write/read", s.sa[i], (short) (14 + i));
822             assertEquals("Wrong int array field value after write/read", s.ia[i], 17 + i);
823             assertEquals("Wrong long array field value after write/read", s.la[i], 23 + i);
824             assertEquals("Wrong float array field value after write/read", s.fa[i], (float) 26 + i, 0f);
825             assertEquals("Wrong double array field value after write/read", s.da[i], (double) 29 + i, 0d);
826         }
827         // test constancy of references after read
828         int[] ia = s.ia;
829         s.read();
830         assertTrue("Array field reference should be unchanged", ia == s.ia);
831     }
832 
testNativeLongSize()833     public void testNativeLongSize() throws Exception {
834         class TestStructure extends Structure {
835             public NativeLong l;
836             @Override
837             protected List<String> getFieldOrder() {
838                 return Arrays.asList("l");
839             }
840         }
841         Structure s = new TestStructure();
842         assertEquals("Wrong size", NativeLong.SIZE, s.size());
843     }
844 
testNativeLongRead()845     public void testNativeLongRead() throws Exception {
846         class TestStructure extends Structure {
847             public int i;
848             public NativeLong l;
849             @Override
850             protected List<String> getFieldOrder() {
851                 return Arrays.asList("i", "l");
852             }
853         }
854         TestStructure s = new TestStructure();
855         if (NativeLong.SIZE == 8) {
856             final long MAGIC = 0x1234567887654321L;
857             s.getPointer().setLong(8, MAGIC);
858             s.read();
859             assertEquals("NativeLong field mismatch", MAGIC, s.l.longValue());
860         }
861         else {
862             final int MAGIC = 0xABEDCF23;
863             s.getPointer().setInt(4, MAGIC);
864             s.read();
865             assertEquals("NativeLong field mismatch", MAGIC, s.l.intValue());
866         }
867     }
868 
testNativeLongWrite()869     public void testNativeLongWrite() throws Exception {
870         class TestStructure extends Structure {
871             public int i;
872             public NativeLong l;
873             @Override
874             protected List<String> getFieldOrder() {
875                 return Arrays.asList("i", "l");
876             }
877         }
878         TestStructure s = new TestStructure();
879         if (NativeLong.SIZE == 8) {
880             final long MAGIC = 0x1234567887654321L;
881             s.l = new NativeLong(MAGIC);
882             s.write();
883             long l = s.getPointer().getLong(8);
884             assertEquals("NativeLong field mismatch", MAGIC, l);
885         }
886         else {
887             final int MAGIC = 0xABEDCF23;
888             s.l = new NativeLong(MAGIC);
889             s.write();
890             int i = s.getPointer().getInt(4);
891             assertEquals("NativeLong field mismatch", MAGIC, i);
892         }
893     }
894 
testMemoryField()895     public void testMemoryField() {
896         class MemoryFieldStructure extends Structure {
897             public Memory m;
898             @Override
899             protected List<String> getFieldOrder() {
900                 return Arrays.asList("m");
901             }
902         }
903         new MemoryFieldStructure().size();
904     }
905 
testDisallowFunctionPointerAsField()906     public void testDisallowFunctionPointerAsField() {
907         class DisallowFunctionPointer extends Structure {
908             public Function cb;
909             @Override
910             protected List<String> getFieldOrder() {
911                 return Arrays.asList("cb");
912             }
913         }
914         try {
915             new DisallowFunctionPointer().size();
916             fail("Function fields should not be allowed");
917         }
918         catch(IllegalArgumentException e) {
919             // expected - ignored
920         }
921     }
922 
923     public static class BadFieldStructure extends Structure {
924         public static final List<String> FIELDS = createFieldsOrder("badField");
925         public Object badField;
926         @Override
getFieldOrder()927         protected List<String> getFieldOrder() {
928             return FIELDS;
929         }
930     }
testUnsupportedField()931     public void testUnsupportedField() {
932         class BadNestedStructure extends Structure {
933             public BadFieldStructure badStruct = new BadFieldStructure();
934             @Override
935             protected List<String> getFieldOrder() {
936                 return Arrays.asList("badStruct");
937             }
938         }
939         try {
940             new BadFieldStructure();
941             fail("Should throw IllegalArgumentException on bad field");
942         }
943         catch(IllegalArgumentException e) {
944             assertTrue("Exception should include field name: " + e.getMessage(), e.getMessage().indexOf("badField") != -1);
945         }
946         try {
947             new BadNestedStructure();
948             fail("Should throw IllegalArgumentException on bad field");
949         }
950         catch(IllegalArgumentException e) {
951             assertTrue("Exception should include enclosing type: " + e,
952                        e.getMessage().indexOf(BadNestedStructure.class.getName()) != -1);
953             assertTrue("Exception should include nested field name: " + e,
954                        e.getMessage().indexOf("badStruct") != -1);
955             assertTrue("Exception should include field name: " + e,
956                        e.getMessage().indexOf("badField") != -1);
957         }
958     }
959 
testToArray()960     public void testToArray() {
961         final int allocated[] = { 0 };
962         PublicTestStructure.allocations = 0;
963         PublicTestStructure s = new PublicTestStructure();
964         PublicTestStructure[] array = (PublicTestStructure[])s.toArray(1);
965         assertEquals("Array should consist of a single element",
966                      1, array.length);
967         assertEquals("First element should be original", s, array[0]);
968 
969         array = (PublicTestStructure[])s.toArray(2);
970         assertEquals("Structure memory should be expanded", 2, array.length);
971         assertEquals("No memory should be allocated for new element", 1, PublicTestStructure.allocations);
972         assertEquals("Structure.read called on New element", 0, array[1].x);
973     }
974 
testByReferenceArraySync()975     public void testByReferenceArraySync() {
976         PublicTestStructure.ByReference s = new PublicTestStructure.ByReference();
977         PublicTestStructure.ByReference[] array =
978             (PublicTestStructure.ByReference[])s.toArray(2);
979         class TestStructure extends Structure {
980             public PublicTestStructure.ByReference ref;
981             @Override
982             protected List<String> getFieldOrder() {
983                 return Arrays.asList("ref");
984             }
985         }
986         TestStructure ts = new TestStructure();
987         ts.ref = s;
988         final int VALUE = 42;
989         array[0].x = VALUE;
990         array[1].x = VALUE;
991         ts.write();
992 
993         assertEquals("Array element not written: " + array[0],
994                      VALUE, array[0].getPointer().getInt(0));
995         assertEquals("Array element not written: " + array[1],
996                      VALUE, array[1].getPointer().getInt(0));
997 
998         array[0].getPointer().setInt(4, VALUE);
999         array[1].getPointer().setInt(4, VALUE);
1000         ts.read();
1001 
1002         assertEquals("Array element not read: " + array[0], VALUE, array[0].y);
1003         assertEquals("Array element not read: " + array[1], VALUE, array[1].y);
1004     }
1005 
1006     public static class CbStruct extends Structure {
1007         public static final List<String> FIELDS = createFieldsOrder("cb");
1008         public Callback cb;
1009         @Override
getFieldOrder()1010         protected List<String> getFieldOrder() {
1011             return FIELDS;
1012         }
1013     }
testCallbackWrite()1014     public void testCallbackWrite() {
1015         final CbStruct s = new CbStruct();
1016         s.cb = new Callback() {
1017             public void callback() {
1018             }
1019         };
1020         s.write();
1021         Pointer func = s.getPointer().getPointer(0);
1022         assertNotNull("Callback trampoline not set", func);
1023         Map<Callback, CallbackReference> refs = CallbackReference.callbackMap;
1024         assertTrue("Callback not cached", refs.containsKey(s.cb));
1025         CallbackReference ref = refs.get(s.cb);
1026         assertEquals("Wrong trampoline", ref.getTrampoline(), func);
1027     }
1028 
testUninitializedArrayField()1029     public void testUninitializedArrayField() {
1030         class UninitializedArrayFieldStructure extends Structure {
1031             public byte[] array;
1032             @Override
1033             protected List<String> getFieldOrder() {
1034                 return Arrays.asList("array");
1035             }
1036         }
1037         try {
1038             Structure s = new UninitializedArrayFieldStructure();
1039             assertTrue("Invalid size: " + s.size(), s.size() > 0);
1040             fail("Uninitialized array field should cause write failure");
1041         } catch(IllegalStateException e) {
1042             // expected
1043         }
1044     }
1045 
1046     public static class StructureWithArrayOfStructureField extends Structure {
1047         public static final List<String> FIELDS = createFieldsOrder("array");
1048         public Structure[] array;
1049         @Override
getFieldOrder()1050         protected List<String> getFieldOrder() {
1051             return FIELDS;
1052         }
1053     }
testPlainStructureArrayField()1054     public void testPlainStructureArrayField() {
1055         try {
1056             new StructureWithArrayOfStructureField();
1057             fail("Structure[] should not be allowed as a field of Structure");
1058         }
1059         catch(IllegalArgumentException e) {
1060             // expected - ignored
1061         }
1062         catch(Exception e) {
1063             fail("Wrong exception thrown when Structure[] field encountered in a Structure: " + e);
1064         }
1065     }
1066 
1067     public static class ArrayOfPointerStructure extends Structure {
1068         public static final List<String> FIELDS = createFieldsOrder("array");
1069         final static int SIZE = 10;
1070         public Pointer[] array = new Pointer[SIZE];
1071 
1072         @Override
getFieldOrder()1073         protected List<String> getFieldOrder() {
1074             return FIELDS;
1075         }
1076     }
1077 
testPointerArrayField()1078     public void testPointerArrayField() {
1079         ArrayOfPointerStructure s = new ArrayOfPointerStructure();
1080         int size = s.size();
1081         assertEquals("Wrong size", ArrayOfPointerStructure.SIZE * Native.POINTER_SIZE, size);
1082         s.array[0] = s.getPointer();
1083         s.write();
1084         s.array[0] = null;
1085         s.read();
1086         assertEquals("Wrong first element", s.getPointer(), s.array[0]);
1087     }
1088 
1089     public static class VolatileStructure extends Structure {
1090         public static final List<String> FIELDS = createFieldsOrder("counter", "value");
1091         public volatile int counter;
1092         public int value;
1093 
1094         @Override
getFieldOrder()1095         protected List<String> getFieldOrder() {
1096             return FIELDS;
1097         }
1098     }
1099 
testVolatileStructureField()1100     public void testVolatileStructureField() {
1101         VolatileStructure s = new VolatileStructure();
1102         s.counter = 1;
1103         s.value = 1;
1104         s.write();
1105         assertEquals("Volatile field should not be written", 0, s.getPointer().getInt(0));
1106         assertEquals("Non-volatile field should be written", 1, s.getPointer().getInt(4));
1107         s.writeField("counter");
1108         assertEquals("Explicit volatile field write failed", 1, s.getPointer().getInt(0));
1109 
1110         s.equals(s);
1111         assertEquals("Structure equals should leave volatile field unchanged", 1, s.getPointer().getInt(0));
1112 
1113         s.hashCode();
1114         assertEquals("Structure equals should leave volatile field unchanged", 1, s.getPointer().getInt(0));
1115     }
1116 
1117     public static class StructureWithPointers extends Structure {
1118         public static final List<String> FIELDS = createFieldsOrder("s1", "s2");
1119         public PublicTestStructure.ByReference s1;
1120         public PublicTestStructure.ByReference s2;
1121         @Override
getFieldOrder()1122         protected List<String> getFieldOrder() {
1123             return FIELDS;
1124         }
1125     }
testStructureByReferenceField()1126     public void testStructureByReferenceField() {
1127         StructureWithPointers s = new StructureWithPointers();
1128         assertEquals("Wrong size for structure with structure references", Native.POINTER_SIZE * 2, s.size());
1129         assertNull("Initial refs should be null", s.s1);
1130     }
1131 
testRegenerateStructureByReferenceField()1132     public void testRegenerateStructureByReferenceField() {
1133         StructureWithPointers s = new StructureWithPointers();
1134         PublicTestStructure.ByReference inner = new PublicTestStructure.ByReference();
1135         PublicTestStructure.allocations = 0;
1136         s.s1 = inner;
1137         s.write();
1138         s.s1 = null;
1139         s.read();
1140         assertEquals("Inner structure not regenerated on read", inner, s.s1);
1141         assertEquals("Inner structure should not allocate memory", 0, PublicTestStructure.allocations);
1142     }
1143 
testPreserveStructureByReferenceWithUnchangedPointerOnRead()1144     public void testPreserveStructureByReferenceWithUnchangedPointerOnRead() {
1145         StructureWithPointers s = new StructureWithPointers();
1146         PublicTestStructure.ByReference inner =
1147             new PublicTestStructure.ByReference();
1148 
1149         s.s1 = inner;
1150         s.write();
1151         s.read();
1152         assertSame("Read should preserve structure object", inner, s.s1);
1153         assertTrue("Read should preserve structure memory",
1154                    inner.getPointer() instanceof Memory);
1155     }
1156 
1157     public static class TestPointer extends PointerType { }
testPreservePointerFields()1158     public void testPreservePointerFields() {
1159         class TestStructure extends Structure {
1160             public Pointer p = new Memory(256);
1161             public TestPointer p2 = new TestPointer() {
1162                 { setPointer(new Memory(256)); }
1163             };
1164             @Override
1165             protected List<String> getFieldOrder() {
1166                 return Arrays.asList("p", "p2");
1167             }
1168         }
1169         TestStructure s = new TestStructure();
1170         final Pointer p = s.p;
1171         final TestPointer p2 = s.p2;
1172         s.write();
1173         s.read();
1174         assertSame("Should preserve Pointer references if peer unchanged", p, s.p);
1175         assertSame("Should preserve PointerType references if peer unchanged", p2, s.p2);
1176     }
1177 
testPreserveStringFields()1178     public void testPreserveStringFields() {
1179         final String VALUE = getName();
1180         final WString WVALUE = new WString(getName() + UNICODE);
1181         class TestStructure extends Structure {
1182             public String s;
1183             public WString ws;
1184             @Override
1185             protected List<String> getFieldOrder() {
1186                 return Arrays.asList("s", "ws");
1187             }
1188         }
1189         TestStructure s = new TestStructure();
1190         Memory m = new Memory(VALUE.length()+1);
1191         m.setString(0, VALUE);
1192         Memory m2 = new Memory((WVALUE.length()+1)*Native.WCHAR_SIZE);
1193         m2.setString(0, WVALUE);
1194 
1195         s.getPointer().setPointer(0, m);
1196         s.getPointer().setPointer(Native.POINTER_SIZE, m2);
1197         s.read();
1198         assertEquals("Wrong String field value", VALUE, s.s);
1199         assertEquals("Wrong WString field value", WVALUE, s.ws);
1200 
1201         s.write();
1202         assertEquals("String field should not be overwritten: " + s, m, s.getPointer().getPointer(0));
1203         assertEquals("WString field should not be overwritten: " + s, m2, s.getPointer().getPointer(Native.POINTER_SIZE));
1204     }
1205 
1206     // Ensure string cacheing doesn't interfere with wrapped structure writes.
1207     public static class StructureFromPointer extends Structure {
1208         public static final List<String> FIELDS = createFieldsOrder("s", "ws");
1209         public String s;
1210         public WString ws;
StructureFromPointer(Pointer p)1211         public StructureFromPointer(Pointer p) {
1212             super(p);
1213             read();
1214         }
StructureFromPointer()1215         public StructureFromPointer() {
1216             super();
1217         }
1218         @Override
getFieldOrder()1219         protected List<String> getFieldOrder() {
1220             return FIELDS;
1221         }
1222     }
1223 
testInitializeStructureFieldWithStrings()1224     public void testInitializeStructureFieldWithStrings() {
1225         class ContainingStructure extends Structure {
1226             public StructureFromPointer inner;
1227             @Override
1228             protected List<String> getFieldOrder() {
1229                 return Arrays.asList("inner");
1230             }
1231         }
1232         StructureFromPointer o = new StructureFromPointer();
1233         Charset charset = Charset.forName(o.getStringEncoding());
1234         final String VALUE = getName() + charset.decode(charset.encode(UNICODE));
1235         final WString WVALUE = new WString(VALUE);
1236         o.s = VALUE;
1237         o.ws = WVALUE;
1238         o.write();
1239         StructureFromPointer t = new StructureFromPointer(o.getPointer());
1240         assertEquals("String field not initialized", VALUE, t.s);
1241         assertEquals("WString field not initialized", WVALUE, t.ws);
1242 
1243         ContainingStructure outer = new ContainingStructure();
1244         outer.inner = t;
1245         outer.write();
1246         assertEquals("Inner String field corrupted", VALUE, outer.inner.s);
1247         assertEquals("Inner WString field corrupted", WVALUE, outer.inner.ws);
1248         outer.inner.read();
1249         assertEquals("Native memory behind Inner String field not updated", VALUE, outer.inner.s);
1250         assertEquals("Native memory behind Inner WString field not updated", WVALUE, outer.inner.ws);
1251     }
1252 
testOverwriteStructureByReferenceFieldOnRead()1253     public void testOverwriteStructureByReferenceFieldOnRead() {
1254         StructureWithPointers s = new StructureWithPointers();
1255         PublicTestStructure.ByReference inner =
1256             new PublicTestStructure.ByReference();
1257         PublicTestStructure.ByReference inner2 =
1258             new PublicTestStructure.ByReference();
1259         s.s1 = inner2;
1260         s.write();
1261         s.s1 = inner;
1262         s.read();
1263         assertNotSame("Read should overwrite structure reference", inner, s.s1);
1264     }
1265 
testAutoWriteStructureByReferenceField()1266     public void testAutoWriteStructureByReferenceField() {
1267         StructureWithPointers s = new StructureWithPointers();
1268         s.s1 = new StructureTest.PublicTestStructure.ByReference();
1269         s.s1.x = -1;
1270         s.write();
1271         assertEquals("Structure.ByReference field not written automatically",
1272                      -1, s.s1.getPointer().getInt(0));
1273     }
1274 
testStructureByReferenceArrayField()1275     public void testStructureByReferenceArrayField() {
1276         class TestStructure extends Structure {
1277             public PublicTestStructure.ByReference[] array = new PublicTestStructure.ByReference[2];
1278             @Override
1279             protected List<String> getFieldOrder() {
1280                 return Arrays.asList("array");
1281             }
1282         }
1283         TestStructure s = new TestStructure();
1284         assertEquals("Wrong structure size", 2*Native.POINTER_SIZE, s.size());
1285 
1286         PublicTestStructure.ByReference ref = new PublicTestStructure.ByReference();
1287         ref.x = 42;
1288         Object aref = s.array;
1289         s.array[0] = ref;
1290         s.array[1] = new PublicTestStructure.ByReference();
1291 
1292         s.write();
1293         s.read();
1294 
1295         assertSame("Array reference should not change", aref, s.array);
1296         assertSame("Elements should not be overwritten when unchanged",
1297                    ref, s.array[0]);
1298 
1299         s.array[0] = null;
1300         s.read();
1301         assertNotSame("Null should be overwritten with a new ref", ref, s.array[0]);
1302         assertNotNull("New ref should not be null", s.array[0]);
1303         assertEquals("New ref should be equivalent", ref, s.array[0]);
1304     }
1305 
testAutoReadWriteStructureByReferenceArrayField()1306     public void testAutoReadWriteStructureByReferenceArrayField() {
1307         class TestStructure extends Structure {
1308             public PublicTestStructure.ByReference field;
1309             @Override
1310             protected List<String> getFieldOrder() {
1311                 return Arrays.asList("field");
1312             }
1313         }
1314         TestStructure s = new TestStructure();
1315         s.field = new PublicTestStructure.ByReference();
1316         PublicTestStructure.ByReference[] array =
1317             (PublicTestStructure.ByReference[])s.field.toArray(2);
1318         final int VALUE = -1;
1319         array[1].x = VALUE;
1320         s.write();
1321         assertEquals("ByReference array member not auto-written",
1322                      VALUE, array[1].getPointer().getInt(0));
1323 
1324         array[1].getPointer().setInt(0, VALUE*2);
1325         s.read();
1326         assertEquals("ByReference array member not auto-read",
1327                      VALUE*2, array[1].x);
1328     }
1329 
1330     public static class NestedTypeInfoStructure extends Structure {
1331         public static final List<String> FIELDS = createFieldsOrder("inner", "dummy");
1332         public static class Inner extends Structure {
1333             public static final List<String> FIELDS = createFieldsOrder("dummy");
1334             public int dummy;
1335             @Override
getFieldOrder()1336             protected List<String> getFieldOrder() {
1337                 return FIELDS;
1338             }
1339         }
1340         public Inner inner;
1341         public int dummy;
1342         @Override
getFieldOrder()1343         protected List<String> getFieldOrder() {
1344             return FIELDS;
1345         }
1346     }
1347     public static class size_t extends IntegerType {
1348         private static final long serialVersionUID = 1L;
size_t()1349         public size_t() { this(0); }
size_t(long value)1350         public size_t(long value) { super(Native.POINTER_SIZE, value); }
1351     }
1352     /** Same structure as the internal representation, to be initialized from
1353      * the internal FFIType native data.
1354      */
1355     public static class TestFFIType extends Structure {
1356         public static final List<String> FIELDS = createFieldsOrder("size", "alignment", "type", "elements");
1357         // NOTE: this field is not normally initialized by libffi
1358         // We force initialize by calling initialize_ffi_type
1359         public size_t size;
1360         public short alignment;
1361         public short type;
1362         public Pointer elements;
1363 
TestFFIType(Pointer p)1364         public TestFFIType(Pointer p) {
1365             super(p);
1366             read();
1367             assertTrue("Test FFIType type not initialized: " + this, this.type != 0);
1368 
1369             // Force libffi to explicitly calculate the size field of
1370             // this FFIType object
1371             int size = Native.initialize_ffi_type(p.peer);
1372             read();
1373             assertEquals("Test FFIType size improperly initialized: " + TestFFIType.this, size, TestFFIType.this.size.intValue());
1374         }
1375         @Override
getFieldOrder()1376         protected List<String> getFieldOrder() {
1377             return FIELDS;
1378         }
1379     }
testNestedStructureTypeInfo()1380     public void testNestedStructureTypeInfo() {
1381         NestedTypeInfoStructure s = new NestedTypeInfoStructure();
1382         Pointer p = s.getTypeInfo();
1383         assertNotNull("Type info should not be null", p);
1384         TestFFIType ffi_type = new TestFFIType(p);
1385         assertEquals("FFIType size mismatch: " + ffi_type, s.size(), ffi_type.size.intValue());
1386         Pointer els = ffi_type.elements;
1387         Pointer inner = s.inner.getTypeInfo();
1388         assertEquals("Wrong type information for 'inner' field",
1389                      inner, els.getPointer(0));
1390         assertEquals("Wrong type information for integer field",
1391                      Structure.getTypeInfo(0).getPointer(),
1392                      els.getPointer(Native.POINTER_SIZE));
1393         assertNull("Type element list should be null-terminated",
1394                    els.getPointer(Native.POINTER_SIZE*2));
1395     }
1396 
testInnerArrayTypeInfo()1397     public void testInnerArrayTypeInfo() {
1398         class TestStructure extends Structure {
1399             public int[] inner = new int[5];
1400             @Override
1401             protected List<String> getFieldOrder() {
1402                 return Arrays.asList("inner");
1403             }
1404         }
1405         Structure s = new TestStructure();
1406         Pointer p = s.getTypeInfo();
1407         assertNotNull("Type info should not be null", p);
1408         TestFFIType ffi_type = new TestFFIType(p);
1409         assertEquals("Wrong structure size", 20, s.size());
1410         assertEquals("FFIType info size mismatch", s.size(), ffi_type.size.intValue());
1411     }
1412 
testTypeInfoForNull()1413     public void testTypeInfoForNull() {
1414         assertEquals("Wrong type information for 'null'",
1415                      Structure.getTypeInfo(new Pointer(0)),
1416                      Structure.getTypeInfo(null));
1417     }
1418 
testToString()1419     public void testToString() {
1420         // wce missing String.matches() and regex support
1421         if (Platform.isWindowsCE()) return;
1422 
1423         class TestStructure extends Structure {
1424             public int intField;
1425             public PublicTestStructure inner;
1426             @Override
1427             protected List<String> getFieldOrder() {
1428                 return Arrays.asList("intField", "inner");
1429             }
1430         }
1431         TestStructure s = new TestStructure();
1432         final String LS = System.getProperty("line.separator");
1433         System.setProperty("jna.dump_memory", "true");
1434         final String EXPECTED = "(?m).*" + s.size() + " bytes.*\\{" + LS
1435             + "  int intField@0x0=0x0000" + LS
1436             + "  .* inner@0x4=.*\\{" + LS
1437             + "    int x@0x0=.*" + LS
1438             + "    int y@0x4=.*" + LS
1439             + "  \\}" + LS
1440             + "\\}" + LS
1441             + "memory dump" + LS
1442             + "\\[[0-9a-f]+\\]" + LS
1443             + "\\[[0-9a-f]+\\]" + LS
1444             + "\\[[0-9a-f]+\\]";
1445         String actual = s.toString();
1446         assertTrue("Improperly formatted toString(): expected "
1447                    + EXPECTED + "\n" + actual,
1448                    actual.matches(EXPECTED));
1449 
1450         System.setProperty("jna.dump_memory", "false");
1451         assertFalse("Doesn't dump memory when jna.dump_memory is false",
1452                    s.toString().contains("memory dump"));
1453     }
1454 
testNativeMappedWrite()1455     public void testNativeMappedWrite() {
1456         class TestStructure extends Structure {
1457             public ByteByReference ref;
1458             @Override
1459             protected List<String> getFieldOrder() {
1460                 return Arrays.asList("ref");
1461             }
1462         }
1463         TestStructure s = new TestStructure();
1464         ByteByReference ref = s.ref = new ByteByReference();
1465         s.write();
1466         assertEquals("Value not properly written", ref.getPointer(), s.getPointer().getPointer(0));
1467 
1468         s.ref = null;
1469         s.write();
1470         assertNull("Non-null value was written: " + s.getPointer().getPointer(0), s.getPointer().getPointer(0));
1471     }
1472 
testNativeMappedRead()1473     public void testNativeMappedRead() {
1474         class TestStructure extends Structure {
1475             public ByteByReference ref;
1476             @Override
1477             protected List<String> getFieldOrder() {
1478                 return Arrays.asList("ref");
1479             }
1480         }
1481         TestStructure s = new TestStructure();
1482         s.read();
1483         assertNull("Should read null for initial field value", s.ref);
1484 
1485         ByteByReference ref = new ByteByReference();
1486         s.getPointer().setPointer(0, ref.getPointer());
1487         s.read();
1488         assertEquals("Field incorrectly read", ref, s.ref);
1489 
1490         s.getPointer().setPointer(0, null);
1491         s.read();
1492         assertNull("Null field incorrectly read", s.ref);
1493     }
1494 
1495     public static class ROStructure extends Structure {
1496         public static final List<String> FIELDS = createFieldsOrder("field");
1497         public final int field;
1498         @Override
getFieldOrder()1499         protected List<String> getFieldOrder() {
1500             return FIELDS;
1501         }
1502         {
1503             // Initialize in ctor to avoid compiler replacing
1504             // field references with a constant everywhere
1505             field = 0;
1506         }
1507     }
avoidConstantFieldOptimization(ROStructure s)1508     private ROStructure avoidConstantFieldOptimization(ROStructure s) {
1509         return s;
1510     }
1511 
testReadOnlyField()1512     public void testReadOnlyField() {
1513         if (!Platform.RO_FIELDS) {
1514             try {
1515                 new ROStructure();
1516                 fail("Creation of a Structure with final fields should fail");
1517             }
1518             catch(Exception e) {
1519             }
1520             return;
1521         }
1522 
1523         ROStructure s = new ROStructure();
1524         s.getPointer().setInt(0, 42);
1525         s.read();
1526         s = avoidConstantFieldOptimization(s);
1527         assertEquals("Field value should be set from native", 42, s.field);
1528 
1529         s.getPointer().setInt(0, 0);
1530         s.read();
1531         s = avoidConstantFieldOptimization(s);
1532         assertEquals("Field value not synched after native change", 0, s.field);
1533 
1534         // Read-only fields  should not be copied to native memory
1535         s.getPointer().setInt(0, 42);
1536         try { s.write(); } catch(UnsupportedOperationException e) { }
1537         assertEquals("Field should not be written", 42, s.getPointer().getInt(0));
1538 
1539         // Native changes should propagate to read-only fields
1540         s.read();
1541         s = avoidConstantFieldOptimization(s);
1542         assertEquals("Field value not synched after native change (2)", 42, s.field);
1543 
1544     }
testNativeMappedArrayField()1545     public void testNativeMappedArrayField() {
1546         final int SIZE = 24;
1547         class TestStructure extends Structure {
1548             public NativeLong[] longs = new NativeLong[SIZE];
1549             @Override
1550             protected List<String> getFieldOrder() {
1551                 return Arrays.asList("longs");
1552             }
1553         }
1554         TestStructure s = new TestStructure();
1555         assertEquals("Wrong structure size", Native.LONG_SIZE * SIZE, s.size());
1556 
1557         NativeLong[] aref = s.longs;
1558         for (int i=0;i < s.longs.length;i++) {
1559             s.longs[i] = new NativeLong(i);
1560         }
1561         s.write();
1562         for (int i=0;i < s.longs.length;i++) {
1563             assertEquals("Value not written to memory at index " + i,
1564                          i, s.getPointer().getNativeLong(i * NativeLong.SIZE).intValue());
1565         }
1566         s.read();
1567         assertEquals("Array reference should remain unchanged on read",
1568                      aref, s.longs);
1569 
1570         for (int i=0;i < s.longs.length;i++) {
1571             assertEquals("Wrong value after read at index " + i,
1572                          i, s.longs[i].intValue());
1573         }
1574     }
1575 
1576 
testInitializeNativeMappedField()1577     public void testInitializeNativeMappedField() {
1578         final long VALUE = 20;
1579         final NativeLong INITIAL = new NativeLong(VALUE);
1580         class TestStructure extends Structure {
1581             // field overwritten, wrong value before write
1582             // NL bug, wrong value written
1583             { setAlignType(ALIGN_NONE); }
1584             public NativeLong nl = INITIAL;
1585             public NativeLong uninitialized;
1586             @Override
1587             protected List<String> getFieldOrder() {
1588                 return Arrays.asList("nl", "uninitialized");
1589             }
1590         }
1591         TestStructure ts = new TestStructure();
1592         TestStructure ts2 = new TestStructure();
1593         assertEquals("Wrong value in field", VALUE, ts.nl.longValue());
1594         assertSame("Initial value overwritten", INITIAL, ts.nl);
1595         assertEquals("Wrong field value before write", VALUE, ts.nl.longValue());
1596         assertNotNull("Uninitialized field should be initialized", ts.uninitialized);
1597         assertNotNull("Uninitialized field should be initialized (cached)", ts2.uninitialized);
1598         assertEquals("Wrong initialized value", 0, ts.uninitialized.longValue());
1599         ts.write();
1600         assertEquals("Wrong field value written", VALUE, ts.getPointer().getNativeLong(0).longValue());
1601         assertEquals("Wrong field value written (2)", 0, ts.getPointer().getNativeLong(NativeLong.SIZE).longValue());
1602         ts.read();
1603         assertEquals("Wrong field value", VALUE, ts.nl.longValue());
1604         assertEquals("Wrong field value (2)", 0, ts.uninitialized.longValue());
1605     }
1606 
testThrowErrorOnMissingFieldOrderOnDerivedStructure()1607     public void testThrowErrorOnMissingFieldOrderOnDerivedStructure() {
1608         class TestStructure extends Structure {
1609             public int f1, f2;
1610             @Override
1611             protected List<String> getFieldOrder() {
1612                 return Arrays.asList("f1", "f2");
1613             }
1614         }
1615         class NoFieldOrder extends TestStructure {
1616             public int f3;
1617         }
1618         try {
1619             new NoFieldOrder();
1620             fail("Expected an error when structure fails to provide field order");
1621         }
1622         catch(Error e) {
1623         }
1624     }
1625 
testThrowErrorOnIncorrectFieldOrderNameMismatch()1626     public void testThrowErrorOnIncorrectFieldOrderNameMismatch() {
1627         class TestStructure extends Structure {
1628             public int f1, f2;
1629             @Override
1630             protected List<String> getFieldOrder() {
1631                 return Arrays.asList("F1", "F2");
1632             }
1633         }
1634         try {
1635             new TestStructure();
1636             fail("Expected an error when creating a structure without mismatched field names");
1637         }
1638         catch(Error e) {
1639         }
1640     }
1641 
testThrowErrorOnIncorrectFieldOrderCount()1642     public void testThrowErrorOnIncorrectFieldOrderCount() {
1643         class TestStructure extends Structure {
1644             public int f1, f2;
1645             @Override
1646             protected List<String> getFieldOrder() {
1647                 return Arrays.asList("f1", "f2", "f3");
1648             }
1649         }
1650         try {
1651             new TestStructure();
1652             fail("Expected an error when creating a structure with wrong number of fiels in getFieldOrder()");
1653         }
1654         catch(Error e) {
1655             // expected - ignored
1656         }
1657     }
1658 
1659     public static class XTestStructure extends Structure {
1660         public static final List<String> FIELDS = createFieldsOrder("first");
1661         public int first = 1;
1662         @Override
getFieldOrder()1663         protected List<String> getFieldOrder() {
1664             return FIELDS;
1665         }
1666     }
1667 
1668     public static class XTestStructureSub extends XTestStructure {
1669         public static final List<String> EXTRA_FIELDS = createFieldsOrder("second");
1670         private static final AtomicReference<List<String>> fieldsHolder = new AtomicReference<List<String>>(null);
resolveEffectiveFields(List<String> baseFields)1671         private static List<String> resolveEffectiveFields(List<String> baseFields) {
1672             List<String> fields;
1673             synchronized (fieldsHolder) {
1674                 fields = fieldsHolder.get();
1675                 if (fields == null) {
1676                     fields = createFieldsOrder(baseFields, EXTRA_FIELDS);
1677                     fieldsHolder.set(fields);
1678                 }
1679             }
1680 
1681             return fields;
1682         }
1683         public int second = 2;
1684 
1685         @Override
getFieldOrder()1686         protected List<String> getFieldOrder() {
1687             return resolveEffectiveFields(super.getFieldOrder());
1688         }
1689     }
1690 
testInheritedStructureFieldOrder()1691     public void testInheritedStructureFieldOrder() {
1692         XTestStructureSub s = new XTestStructureSub();
1693         assertEquals("Wrong size", 8, s.size());
1694         s.write();
1695         assertEquals("Wrong first field: " + s, s.first, s.getPointer().getInt(0));
1696         assertEquals("Wrong second field: " + s, s.second, s.getPointer().getInt(4));
1697     }
1698 
testVariedStructureFieldOrder()1699     public void testVariedStructureFieldOrder() {
1700         final String[] ORDER = new String[] { "one", "two", "three" };
1701         final String[] ORDER2 = new String[] { "one", "two", "three", "four", "five" };
1702         class TestStructure extends Structure {
1703             public int one = 1;
1704             public int three = 3;
1705             public int two = 2;
1706             @Override
1707             protected List<String> getFieldOrder() {
1708                 return Arrays.asList(ORDER);
1709             }
1710         }
1711         class DerivedTestStructure extends TestStructure {
1712             public int five = 5;
1713             public int four = 4;
1714             @Override
1715             protected List<String> getFieldOrder() {
1716                 List<String> list = new ArrayList<String>(super.getFieldOrder());
1717                 list.addAll(Arrays.asList("four", "five"));
1718                 return list;
1719             }
1720         }
1721 
1722         TestStructure s = new TestStructure();
1723         assertEquals("Wrong field order", Arrays.asList(ORDER), s.getFieldOrder());
1724         s.write();
1725         assertEquals("Wrong first field: " + s, s.one, s.getPointer().getInt(0));
1726         assertEquals("Wrong second field: " + s, s.two, s.getPointer().getInt(4));
1727         assertEquals("Wrong third field: " + s, s.three, s.getPointer().getInt(8));
1728 
1729         DerivedTestStructure s2 = new DerivedTestStructure();
1730         assertEquals("Wrong field order", Arrays.asList(ORDER2), s2.getFieldOrder());
1731         s2.write();
1732         assertEquals("Wrong first field: " + s2, s2.one, s2.getPointer().getInt(0));
1733         assertEquals("Wrong second field: " + s2, s2.two, s2.getPointer().getInt(4));
1734         assertEquals("Wrong third field: " + s2, s2.three, s2.getPointer().getInt(8));
1735         assertEquals("Wrong derived field (1): " + s2, s2.four, s2.getPointer().getInt(12));
1736         assertEquals("Wrong derived field (2): " + s2, s2.five, s2.getPointer().getInt(16));
1737     }
1738 
testCustomTypeMapper()1739     public void testCustomTypeMapper() {
1740         class TestField { }
1741         final DefaultTypeMapper mapper = new DefaultTypeMapper() {
1742             {
1743                 addTypeConverter(TestField.class, new TypeConverter() {
1744                     @Override
1745                     public Object fromNative(Object value, FromNativeContext context) {
1746                         return new TestField();
1747                     }
1748                     @Override
1749                     public Class<?> nativeType() {
1750                         return String.class;
1751                     }
1752                     @Override
1753                     public Object toNative(Object value, ToNativeContext ctx) {
1754                         return value == null ? null : value.toString();
1755                     }
1756                 });
1757             }
1758         };
1759         class TestStructure extends Structure {
1760             public TestField field;
1761             public TestStructure() {
1762                 super(mapper);
1763             }
1764             @Override
1765             protected List<String> getFieldOrder() {
1766                 return Arrays.asList("field");
1767             }
1768         }
1769         Structure s = new TestStructure();
1770         assertEquals("Wrong type mapper: " + s, mapper, s.getTypeMapper());
1771     }
1772 
testWriteWithNullBoxedPrimitives()1773     public void testWriteWithNullBoxedPrimitives() {
1774         class TestStructure extends Structure {
1775             public Boolean zfield;
1776             public Integer field;
1777             @Override
1778             protected List<String> getFieldOrder() {
1779                 return Arrays.asList("zfield", "field");
1780             }
1781         }
1782         TestStructure s = new TestStructure();
1783         s.write();
1784         s.read();
1785         assertNotNull("Field should not be null after read", s.field);
1786     }
1787 
1788     @SuppressWarnings("unlikely-arg-type")
testStructureEquals()1789     public void testStructureEquals() {
1790         class OtherStructure extends Structure {
1791             public int first;
1792             public int[] second = new int[4];
1793             public Pointer[] third = new Pointer[4];
1794             @Override
1795             protected List<String> getFieldOrder() {
1796                 return Arrays.asList("first", "second", "third");
1797             }
1798         }
1799         class TestStructure extends Structure {
1800             public int first;
1801             public int[] second = new int[4];
1802             public Pointer[] third = new Pointer[4];
1803             @Override
1804             protected List<String> getFieldOrder() {
1805                 return Arrays.asList("first", "second", "third");
1806             }
1807             public TestStructure() { }
1808             public TestStructure(Pointer p) { super(p); }
1809         }
1810         OtherStructure s0 = new OtherStructure();
1811         TestStructure s1 = new TestStructure();
1812         TestStructure s2 = new TestStructure(s1.getPointer());
1813         TestStructure s3 = new TestStructure(s2.getPointer());
1814         TestStructure s4 = new TestStructure();
1815 
1816         assertFalse("Structures of different classes with same fields are not equal", s1.equals(s0));
1817         assertFalse("Structures of different classes with same fields are not equal (reflexive)", s0.equals(s1));
1818 
1819         assertFalse("Compare to null failed", s1.equals(null));
1820         assertTrue("Equals is not reflexive", s1.equals(s1));
1821         assertTrue("Equals failed on structures with same pointer", s1.equals(s2));
1822         assertTrue("Equals is not symmetric", s2.equals(s1));
1823         assertTrue("Equals is not transitive", s1.equals(s2) && s2.equals(s3) && s1.equals(s3));
1824         assertFalse("Compare to different structure failed", s1.equals(s4));
1825     }
1826 
testStructureHashCodeMatchesWhenEqual()1827     public void testStructureHashCodeMatchesWhenEqual() {
1828         class TestStructure extends Structure {
1829             public int first;
1830             @Override
1831             protected List<String> getFieldOrder() {
1832                 return Arrays.asList("first");
1833             }
1834         }
1835         TestStructure s1 = new TestStructure();
1836         TestStructure s2 = new TestStructure();
1837         assertFalse("hashCode should be different for two different structures", s1.hashCode() == s2.hashCode());
1838 
1839         s2.useMemory(s1.getPointer());
1840         assertEquals("hashCode should match when structures have same pointer", s1.hashCode(), s2.hashCode());
1841 
1842         s2.useMemory(s1.getPointer());
1843         assertEquals("hashCode should match when structures have same pointer", s1.hashCode(), s2.hashCode());
1844     }
1845 
testRecursiveWrite()1846     public void testRecursiveWrite() {
1847         class TestStructureByRef extends Structure implements Structure.ByReference{
1848             public TestStructureByRef(Pointer p) { super(p); }
1849             public TestStructureByRef() { }
1850             public int unique;
1851             public TestStructureByRef s;
1852             @Override
1853             protected List<String> getFieldOrder() {
1854                 return Arrays.asList("unique", "s");
1855             }
1856         }
1857         TestStructureByRef s = new TestStructureByRef();
1858         s.s = new TestStructureByRef();
1859         s.unique = 1;
1860         s.s.s = s;
1861         s.s.unique = 2;
1862 
1863         s.write();
1864         assertEquals("Structure field contents not written", 1, s.getPointer().getInt(0));
1865         assertEquals("ByReference structure field contents not written", 2, s.s.getPointer().getInt(0));
1866 
1867         s.s.unique = 0;
1868         Structure value = s.s;
1869         s.read();
1870         assertEquals("ByReference structure field not preserved", value, s.s);
1871         assertEquals("ByReference structure field contents not read", 2, s.s.unique);
1872         assertTrue("Temporary storage should be cleared", Structure.busy().isEmpty());
1873     }
1874 
1875     public static class CyclicTestStructure extends Structure {
1876         public static class ByReference extends CyclicTestStructure implements Structure.ByReference {}
1877         public static final List<String> FIELDS = createFieldsOrder("next");
CyclicTestStructure(Pointer p)1878         public CyclicTestStructure(Pointer p) { super(p); }
CyclicTestStructure()1879         public CyclicTestStructure() { }
1880         public CyclicTestStructure.ByReference next;
1881         @Override
getFieldOrder()1882         protected List<String> getFieldOrder() {
1883             return FIELDS;
1884         }
1885     }
testCyclicRead()1886     public void testCyclicRead() {
1887         CyclicTestStructure s = new CyclicTestStructure();
1888         s.next = new CyclicTestStructure.ByReference();
1889 
1890         Structure value = s.next;
1891         s.next.next = s.next;
1892         s.write();
1893         s.read();
1894         assertEquals("ByReference structure field not preserved", value, s.next);
1895 
1896         value = s.next;
1897         s.next.next = null;
1898         s.read();
1899         assertSame("ByReference structure field should reuse existing value", value, s.next);
1900         assertSame("Nested ByReference structure field should reuse existing value", value, s.next.next);
1901     }
1902 
testAvoidMemoryAllocationInPointerCTOR()1903     public void testAvoidMemoryAllocationInPointerCTOR() {
1904         class TestStructure extends Structure {
1905             public int field;
1906             @Override
1907             protected List<String> getFieldOrder() {
1908                 return Arrays.asList("field");
1909             }
1910             public TestStructure(Pointer p) {
1911                 super(p);
1912             }
1913             @Override
1914             protected Memory autoAllocate(int size) {
1915                 fail("Memory should not be auto-allocated");
1916                 return null;
1917             }
1918         }
1919         Memory p = new Memory(4);
1920         Structure s = new TestStructure(p);
1921     }
1922 
testPointerCTORWithInitializedFields()1923     public void testPointerCTORWithInitializedFields() {
1924         class TestStructure extends Structure {
1925             public int intField;
1926             public byte[] arrayField = new byte[256];
1927             @Override
1928             protected List<String> getFieldOrder() {
1929                 return Arrays.asList("intField", "arrayField");
1930             }
1931             public TestStructure(Pointer p) {
1932                 super(p);
1933                 read(); // Important!
1934             }
1935         }
1936         Memory p = new Memory(260);
1937         p.setInt(0, 1);
1938         p.setByte(4, (byte)2);
1939         p.setByte(5, (byte)3);
1940         p.setByte(6, (byte)4);
1941         p.setByte(7, (byte)5);
1942         TestStructure s = new TestStructure(p);
1943 
1944         assertEquals("Structure primitive field not initialized",
1945                      (byte)1, s.intField);
1946         assertEquals("Structure primitive array field not initialized",
1947                      (byte)2, s.arrayField[0]);
1948         assertEquals("Structure primitive array field not initialized",
1949                      (byte)3, s.arrayField[1]);
1950         assertEquals("Structure primitive array field not initialized",
1951                      (byte)4, s.arrayField[2]);
1952         assertEquals("Structure primitive array field not initialized",
1953                      (byte)5, s.arrayField[3]);
1954         assertEquals("Wrong structure size", p.size(), s.size());
1955     }
1956 
1957 
1958     public static class TestByReferenceArrayField extends Structure {
1959         public static final List<String> FIELDS = createFieldsOrder("value1", "array", "value2");
TestByReferenceArrayField()1960         public TestByReferenceArrayField() { }
TestByReferenceArrayField(Pointer m)1961         public TestByReferenceArrayField(Pointer m) {
1962             super(m);
1963             read(); // Important!
1964         }
1965         public int value1;
1966         public ByReference[] array = new ByReference[13];
1967         public int value2;
1968         @Override
getFieldOrder()1969         protected List<String> getFieldOrder() {
1970             return FIELDS;
1971         }
1972 
1973         public static class ByReference extends TestByReferenceArrayField implements Structure.ByReference { }
1974     }
1975 
testByReferenceArrayField()1976     public static void testByReferenceArrayField() {
1977         TestByReferenceArrayField.ByReference s = new TestByReferenceArrayField.ByReference();
1978         s.value1 = 22;
1979         s.array[0] = s;
1980         s.value2 = 42;
1981         s.write();
1982 
1983         TestByReferenceArrayField s2 =
1984             new TestByReferenceArrayField(s.getPointer());
1985         assertEquals("value1 not properly read from Pointer", s.value1, s2.value1);
1986         assertNotNull("Structure.ByReference array field was not initialized", s2.array);
1987         assertEquals("Structure.ByReference array field initialized to incorrect length", 13, s2.array.length);
1988         assertNotNull("Structure.ByReference array field element was not initialized", s2.array[0]);
1989         assertEquals("Incorrect value for Structure.ByReference array field element", s.array[0].getPointer(), s2.array[0].getPointer());
1990         assertEquals("Field 'value2' not properly read from Pointer", s.value2, s2.value2);
1991     }
1992 
testEquals()1993     public void testEquals() {
1994         class TestStructure extends Structure {
1995             public int field;
1996             @Override
1997             protected List<String> getFieldOrder() {
1998                 return Arrays.asList("field");
1999             }
2000             public TestStructure() { }
2001             public TestStructure(Pointer p) { super(p); read(); }
2002         }
2003         Structure s = new TestStructure();
2004         assertTrue("Should match self", s.equals(s));
2005         assertFalse("Not equal null", s.equals(null));
2006         assertFalse("Not equal some other object", s.equals(new Object()));
2007         Structure s1 = new TestStructure(s.getPointer());
2008         assertEquals("Same base address/type should be equal", s, s1);
2009     }
2010 
testStructureLayoutCacheing()2011     public void testStructureLayoutCacheing() {
2012         class TestStructure extends Structure {
2013             public int field;
2014             @Override
2015             protected List<String> getFieldOrder() {
2016                 return Arrays.asList("field");
2017             }
2018         }
2019         Structure ts = new TestStructure(); ts.ensureAllocated();
2020         Structure ts2 = new TestStructure(); ts2.ensureAllocated();
2021 
2022         assertSame("Structure layout not cached", ts.fields(), ts2.fields());
2023     }
2024 
testStructureLayoutVariableNoCache()2025     public void testStructureLayoutVariableNoCache() {
2026         class TestStructure extends Structure {
2027             public byte[] variable;
2028             @Override
2029             protected List<String> getFieldOrder() {
2030                 return Arrays.asList("variable");
2031             }
2032             public TestStructure(int size) {
2033                 this.variable = new byte[size];
2034             }
2035         }
2036         Structure ts = new TestStructure(8);
2037         Structure ts2 = new TestStructure(16);
2038 
2039         // Ensure allocated; primitive array prevents initial layout calculation
2040         ts.ensureAllocated(); ts2.ensureAllocated();
2041         assertNotSame("Structure layout should not be cached", ts.fields(), ts2.fields());
2042     }
2043 
testStructureLayoutCacheingWithTypeMapper()2044     public void testStructureLayoutCacheingWithTypeMapper() {
2045         class TestTypeMapper extends DefaultTypeMapper {
2046             {
2047                 TypeConverter tc = new TypeConverter() {
2048                     @Override
2049                     public Class<?> nativeType() { return int.class; }
2050                     @Override
2051                     public Object fromNative(Object nativeValue, FromNativeContext c) {
2052                         return Boolean.valueOf(nativeValue.equals(Integer.valueOf(0)));
2053                     }
2054                     @Override
2055                     public Object toNative(Object value, ToNativeContext c) {
2056                         return Integer.valueOf(Boolean.TRUE.equals(value) ? -1 : 0);
2057                     }
2058                 };
2059                 addTypeConverter(boolean.class, tc);
2060                 addTypeConverter(Boolean.class, tc);
2061             }
2062         }
2063         final TestTypeMapper m = new TestTypeMapper();
2064         class TestStructure extends Structure {
2065             public boolean field;
2066             @Override
2067             protected List<String> getFieldOrder() {
2068                 return Arrays.asList("field");
2069             }
2070             public TestStructure() {
2071                 super(m);
2072             }
2073             public TestStructure(TypeMapper m) {
2074                 super(m);
2075             }
2076         }
2077         Structure ts = new TestStructure();
2078         Structure ts2 = new TestStructure();
2079         Structure ts3 = new TestStructure(m);
2080         assertSame("Structure layout should be cached with custom type mapper", ts.fields(), ts2.fields());
2081         assertSame("Structure layout should be cached with custom type mapper, regardless of constructor type", ts.fields(), ts3.fields());
2082     }
2083 
testStructureLayoutCacheingWithAlignment()2084     public void testStructureLayoutCacheingWithAlignment() {
2085         class TestStructure extends Structure {
2086             public byte first;
2087             public int second;
2088             @Override
2089             protected List<String> getFieldOrder() {
2090                 return Arrays.asList("first", "second");
2091             }
2092             public TestStructure() {
2093                 setAlignType(ALIGN_NONE);
2094             }
2095             public TestStructure(int alignType) {
2096                 super(alignType);
2097             }
2098         }
2099         Structure ts = new TestStructure();
2100         Structure ts2 = new TestStructure();
2101         Structure ts3 = new TestStructure(Structure.ALIGN_NONE);
2102 
2103         assertSame("Structure layout should be cached with custom alignment", ts.fields(), ts2.fields());
2104         assertSame("Structure layout should be cached with custom alignment, regardless of how set", ts.fields(), ts3.fields());
2105     }
2106 
testStructureSetIterator()2107     public void testStructureSetIterator() {
2108         assertNotNull("Indirect test of StructureSet.Iterator",
2109                       Structure.busy().toString());
2110     }
2111 
testFFITypeCalculationWithTypeMappedFields()2112     public void testFFITypeCalculationWithTypeMappedFields() {
2113         final TypeMapper mapper = new TypeMapper() {
2114             @Override
2115             public FromNativeConverter getFromNativeConverter(Class<?> cls) {
2116                 if (Boolean.class.equals(cls)
2117                     || boolean.class.equals(cls)) {
2118                     return new FromNativeConverter() {
2119                         @Override
2120                         public Class<?> nativeType() {
2121                             return byte.class;
2122                         }
2123                         @Override
2124                         public Object fromNative(Object nativeValue, FromNativeContext context) {
2125                             return nativeValue.equals(Byte.valueOf((byte)0))
2126                                 ? Boolean.FALSE : Boolean.TRUE;
2127                         }
2128                     };
2129                 }
2130                 return null;
2131             }
2132             @Override
2133             public ToNativeConverter getToNativeConverter(Class<?> javaType) {
2134                 if (Boolean.class.equals(javaType)
2135                     || boolean.class.equals(javaType)) {
2136                     return new ToNativeConverter() {
2137                         @Override
2138                         public Object toNative(Object value, ToNativeContext context) {
2139                             return Byte.valueOf(Boolean.TRUE.equals(value) ? (byte)1 : (byte)0);
2140                         }
2141                         @Override
2142                         public Class<?> nativeType() {
2143                             return byte.class;
2144                         }
2145                     };
2146                 }
2147                 return null;
2148             }
2149         };
2150         class TestStructure extends Structure {
2151             public boolean b;
2152             public short s;
2153             // Ensure we're not stuffed into a register
2154             public int p0,p1,p2,p3,p4,p5,p6,p7;
2155             public TestStructure() {
2156                 super(mapper);
2157             }
2158             @Override
2159             protected List<String> getFieldOrder() {
2160                 return Arrays.asList("b", "s", "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7");
2161             }
2162         }
2163         Structure s = new TestStructure();
2164         assertEquals("Wrong type mapper for structure", mapper, s.getTypeMapper());
2165 
2166         TestFFIType ffi_type = new TestFFIType(Structure.getTypeInfo(s).getPointer());
2167         assertEquals("Java Structure size does not match FFIType size",
2168                      s.size(), ffi_type.size.intValue());
2169     }
2170 
testDefaultStringEncoding()2171     public void testDefaultStringEncoding() {
2172         class TestStructure extends Structure {
2173             public String field;
2174             @Override
2175             protected List<String> getFieldOrder() {
2176                 return Arrays.asList("field");
2177             }
2178         }
2179         TestStructure s = new TestStructure();
2180         assertEquals("Wrong default structure encoding",
2181                      Native.getDefaultStringEncoding(),
2182                      s.getStringEncoding());
2183     }
2184 
testStringFieldEncoding()2185     public void testStringFieldEncoding() throws Exception {
2186         class TestStructure extends Structure {
2187             public String field;
2188             @Override
2189             protected List<String> getFieldOrder() {
2190                 return Arrays.asList("field");
2191             }
2192         }
2193         TestStructure s = new TestStructure();
2194         final String ENCODING = "utf8";
2195         s.setStringEncoding(ENCODING);
2196         assertEquals("Manual customization of string encoding failed", ENCODING, s.getStringEncoding());
2197 
2198         final String VALUE = "\u0444\u043b\u0441\u0432\u0443";
2199         s.field = VALUE;
2200         s.write();
2201         byte[] expected = VALUE.getBytes("utf8");
2202         byte[] actual = s.getPointer().getPointer(0).getByteArray(0, expected.length);
2203         for (int i=0;i < Math.min(expected.length, actual.length);i++) {
2204             assertEquals("Improperly encoded (" + ENCODING
2205                          + ") on structure write at " + i,
2206                          expected[i], actual[i]);
2207         }
2208         assertEquals("Encoding length mismatch", expected.length, actual.length);
2209 
2210         s.field = null;
2211         s.read();
2212         assertEquals("String not decoded properly on read", VALUE, s.field);
2213     }
2214 
testThreadLocalSetReleasesReferences()2215     public void testThreadLocalSetReleasesReferences() {
2216         class TestStructure extends Structure {
2217             public String field;
2218             @Override
2219             protected List<String> getFieldOrder() {
2220                 return Arrays.asList("field");
2221             }
2222         }
2223 
2224         TestStructure ts1 = new TestStructure();
2225         TestStructure ts2 = new TestStructure();
2226 
2227         StructureSet structureSet = (StructureSet) Structure.busy();
2228         structureSet.add(ts1);
2229         structureSet.add(ts2);
2230         structureSet.remove(ts1);
2231         assertNotNull(structureSet.elements[0]);
2232         structureSet.remove(ts2);
2233         assertNull(structureSet.elements[0]);
2234     }
2235 }
2236