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