From 38b796a516440339936b96c907666b8e4a506a9c Mon Sep 17 00:00:00 2001 From: Timothy Wall Date: Wed, 1 May 2013 00:11:19 -0400 Subject: [PATCH] fix #223, union sizing/layout issue --- CHANGES.md | 1 + src/com/sun/jna/Structure.java | 48 +++++++--- src/com/sun/jna/Union.java | 75 ++++------------ test/com/sun/jna/StructureTest.java | 131 ++++++++++++++++------------ test/com/sun/jna/UnionTest.java | 51 ++++++----- 5 files changed, 160 insertions(+), 146 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 93ca4ce036..0a57637a1c 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,7 @@ Bug Fixes * [#215](https://github.com/twall/jna/issues/215): Force use of XSI `strerror_r` on linux - [LionelCons](https://github.com/LionelCons). * [#214](https://github.com/twall/jna/issues/214): Don't map library names when an absolute path is provided - [@twall](https://github.com/twall). * [#218](https://github.com/twall/jna/issues/218): Explicitly handle broken Android SecurityManager implementation - [@twall](https://github.com/twall). +* [#223](https://github.com/twall/jna/issues/223): Fix layout/size derivation for unions - [@twall](https://github.com/twall). Release 3.5.2 ============= diff --git a/src/com/sun/jna/Structure.java b/src/com/sun/jna/Structure.java index 68742f13e1..8431799c17 100644 --- a/src/com/sun/jna/Structure.java +++ b/src/com/sun/jna/Structure.java @@ -114,7 +114,7 @@ public interface ByReference { } String arch = System.getProperty("os.arch").toLowerCase(); isPPC = "ppc".equals(arch) || "powerpc".equals(arch); isSPARC = "sparc".equals(arch); - isARM = arch.startsWith("arm"); + isARM = arch.startsWith("arm"); } /** Use the platform default alignment. */ @@ -216,7 +216,7 @@ TypeMapper getTypeMapper() { return typeMapper; } - /** Initialize the type mapper for this structure. + /** Initialize the type mapper for this structure. * If null, the default mapper for the * defining class will be used. */ @@ -871,7 +871,7 @@ private List sort(Collection c) { return list; } - /** Returns all field names (sorted) provided so far by + /** Returns all field names (sorted) provided so far by {@link #getFieldOrder} @param force set if results are required immediately @return null if not yet able to provide fields, and force is false. @@ -899,7 +899,7 @@ protected List getFields(boolean force) { Set orderedNames = new HashSet(fieldOrder); if (!orderedNames.equals(names)) { - throw new Error("Structure.getFieldOrder() on " + getClass() + throw new Error("Structure.getFieldOrder() on " + getClass() + " returns names (" + sort(fieldOrder) + ") which do not match declared field names (" @@ -991,6 +991,8 @@ private static class LayoutInfo { private int alignType = ALIGN_DEFAULT; private TypeMapper typeMapper; private boolean variable; + // For unions only, field on which the union FFI type info is based + private StructField typeInfoField; } private void validateField(String name, Class type) { @@ -1029,7 +1031,6 @@ private void validateFields() { members. */ private LayoutInfo deriveLayout(boolean force, boolean avoidFFIType) { - int calculatedSize = 0; List fields = getFields(force); if (fields == null) { @@ -1139,11 +1140,24 @@ else if (writeConverter != null || readConverter != null) { if ((calculatedSize % fieldAlignment) != 0) { calculatedSize += fieldAlignment - (calculatedSize % fieldAlignment); } - structField.offset = calculatedSize; - calculatedSize += structField.size; + if (this instanceof Union) { + structField.offset = 0; + calculatedSize = Math.max(calculatedSize, structField.size); + } + else { + structField.offset = calculatedSize; + calculatedSize += structField.size; + } // Save the field in our list info.fields.put(structField.name, structField); + + if (info.typeInfoField == null + || info.typeInfoField.size < structField.size + || (info.typeInfoField.size == structField.size + && Structure.class.isAssignableFrom(structField.type))) { + info.typeInfoField = structField; + } } if (calculatedSize > 0) { @@ -1504,7 +1518,7 @@ Pointer getTypeInfo() { This is typically most effective when a native call populates a large structure and you only need a few fields out of it. After the native call you can call {@link #readField(String)} on only the fields of - interest. + interest. */ public void setAutoSynch(boolean auto) { setAutoRead(auto); @@ -1544,7 +1558,7 @@ static Pointer getTypeInfo(Object obj) { return FFIType.get(obj); } - /** Called from native code only; same as {@link + /** Called from native code only; same as {@link * #newInstance(Class,Pointer)}, except that it additionally performs * {@link #conditionalAutoRead()}. */ @@ -1619,6 +1633,20 @@ public static Structure newInstance(Class type) throws IllegalArgumentException } } + /** Keep track of the largest aggregate field of the union to use for + * FFI type information. + */ + StructField typeInfoField() { + LayoutInfo info; + synchronized(layoutInfo) { + info = (LayoutInfo)layoutInfo.get(getClass()); + } + if (info != null) { + return info.typeInfoField; + } + return null; + } + static class StructField extends Object { public String name; public Class type; @@ -1704,7 +1732,7 @@ private FFIType(Structure ref) { ref.ensureAllocated(true); if (ref instanceof Union) { - StructField sf = ((Union)ref).biggestField; + StructField sf = ((Union)ref).typeInfoField(); els = new Pointer[] { get(ref.getFieldValue(sf.field), sf.type), null, diff --git a/src/com/sun/jna/Union.java b/src/com/sun/jna/Union.java index d899e81ba2..d08b50d482 100644 --- a/src/com/sun/jna/Union.java +++ b/src/com/sun/jna/Union.java @@ -1,14 +1,14 @@ /* Copyright (c) 2007-2012 Timothy Wall, All Rights Reserved - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * Lesser General Public License for more details. */ package com.sun.jna; @@ -20,18 +20,17 @@ /** Represents a native union. When writing to native memory, the field * corresponding to the type passed to {@link #setType} will be written * to native memory. Upon reading from native memory, Structure, String, - * or WString fields will not be initialized unless they are + * or WString fields will not be initialized unless they are * the current field as identified by a call to {@link #setType}. The current * field is always unset by default to avoid accidentally attempting to read - * a field that is not valid. In the case of a String, for instance, an + * a field that is not valid. In the case of a String, for instance, an * invalid pointer may result in a memory fault when attempting to initialize - * the String. + * the String. */ public abstract class Union extends Structure { private StructField activeField; - StructField biggestField; - - /** Create a Union whose size and alignment will be calculated + + /** Create a Union whose size and alignment will be calculated * automatically. */ protected Union() { } @@ -65,10 +64,10 @@ protected List getFieldOrder() { return list; } - /** Indicates by type which field will be used to write to native memory. + /** Indicates by type which field will be used to write to native memory. * If there are multiple fields of the same type, use {@link * #setType(String)} instead with the field name. - * @throws IllegalArgumentException if the type does not correspond to + * @throws IllegalArgumentException if the type does not correspond to * any declared union field. */ public void setType(Class type) { @@ -82,7 +81,7 @@ public void setType(Class type) { } throw new IllegalArgumentException("No field of type " + type + " in " + this); } - + /** * Indicates which field will be used to write to native memory. * @throws IllegalArgumentException if the name does not correspond to @@ -199,11 +198,11 @@ void writeField(StructField field) { } /** Avoid reading pointer-based fields and structures unless explicitly - * selected. Structures may contain pointer-based fields which can + * selected. Structures may contain pointer-based fields which can * crash the VM if not properly initialized. */ Object readField(StructField field) { - if (field == activeField + if (field == activeField || (!Structure.class.isAssignableFrom(field.type) && !String.class.isAssignableFrom(field.type) && !WString.class.isAssignableFrom(field.type))) { @@ -211,56 +210,12 @@ Object readField(StructField field) { } // Field not accessible // TODO: read structure, to the extent possible; need a "recursive" - // flag to "read" + // flag to "read" to indicate we want to avoid pointer-based fields return null; } - - /** Adjust the size to be the size of the largest element, and ensure - * all fields begin at offset zero. - */ - int calculateSize(boolean force, boolean avoidFFIType) { - int size = super.calculateSize(force, avoidFFIType); - if (size != CALCULATE_SIZE) { - int fsize = 0; - for (Iterator i=fields().values().iterator();i.hasNext();) { - StructField f = (StructField)i.next(); - f.offset = 0; - if (f.size > fsize - // Prefer aggregate types to simple types, since they - // will have more complex packing rules (some platforms - // have specific methods for packing small structs into - // registers, which may not match the packing of bytes - // for a primitive type). - || (f.size == fsize - && Structure.class.isAssignableFrom(f.type))) { - fsize = f.size; - biggestField = f; - } - } - size = calculateAlignedSize(fsize); - if (size > 0) { - // Update native FFI type information, if needed - if (this instanceof ByValue && !avoidFFIType) { - getTypeInfo(); - } - } - } - return size; - } + /** All fields are considered the "first" element. */ protected int getNativeAlignment(Class type, Object value, boolean isFirstElement) { return super.getNativeAlignment(type, value, true); } - - /** Avoid calculating type information until we know our biggest field. - * Return type information for the largest field to ensure all available - * bits are used. - */ - Pointer getTypeInfo() { - if (biggestField == null) { - // Not calculated yet - return null; - } - return super.getTypeInfo(); - } } diff --git a/test/com/sun/jna/StructureTest.java b/test/com/sun/jna/StructureTest.java index 2c4f21c1dc..482e06955d 100644 --- a/test/com/sun/jna/StructureTest.java +++ b/test/com/sun/jna/StructureTest.java @@ -88,7 +88,7 @@ public static class TestAllocStructure extends Structure { public int f2; public int f3; protected List getFieldOrder() { - return Arrays.asList(new String[] { "f0", "f1", "f2", "f3" }); + return Arrays.asList(new String[] { "f0", "f1", "f2", "f3" }); } } @@ -151,7 +151,7 @@ class TestStructure extends Structure { public float f; public double d; protected List getFieldOrder() { - return Arrays.asList(new String[] { "b", "s", "i", "l", "f", "d" }); + return Arrays.asList(new String[] { "b", "s", "i", "l", "f", "d" }); } } Structure s = new TestStructure(); @@ -170,7 +170,7 @@ class TestStructure extends Structure { public float f; public double d; protected List getFieldOrder() { - return Arrays.asList(new String[] { "b", "s", "i", "l", "f", "d" }); + return Arrays.asList(new String[] { "b", "s", "i", "l", "f", "d" }); } } Structure s = new TestStructure(); @@ -195,21 +195,21 @@ public static class TestStructure0 extends FilledStructure { public byte field0 = 0x01; public short field1 = 0x0202; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field0", "field1" }); + return Arrays.asList(new String[] { "field0", "field1" }); } } public static class TestStructure1 extends FilledStructure { public byte field0 = 0x01; public int field1 = 0x02020202; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field0", "field1" }); + return Arrays.asList(new String[] { "field0", "field1" }); } } public static class TestStructure2 extends FilledStructure { public short field0 = 0x0101; public int field1 = 0x02020202; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field0", "field1" }); + return Arrays.asList(new String[] { "field0", "field1" }); } } public static class TestStructure3 extends FilledStructure { @@ -217,7 +217,7 @@ public static class TestStructure3 extends FilledStructure { public short field1 = 0x0202; public int field2 = 0x03030303; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field0", "field1", "field2" }); + return Arrays.asList(new String[] { "field0", "field1", "field2" }); } } public static class TestStructure4 extends FilledStructure { @@ -226,14 +226,14 @@ public static class TestStructure4 extends FilledStructure { public int field2 = 0x03030303; public long field3 = 0x0404040404040404L; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field0", "field1", "field2", "field3" }); + return Arrays.asList(new String[] { "field0", "field1", "field2", "field3" }); } } public static class TestStructure5 extends FilledStructure { public long field0 = 0x0101010101010101L; public byte field1 = 0x02; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field0", "field1" }); + return Arrays.asList(new String[] { "field0", "field1" }); } } public interface SizeTest extends Library { @@ -354,7 +354,7 @@ protected void allocateMemory(int size) { ++allocations; } protected List getFieldOrder() { - return Arrays.asList(new String[] { "x", "y" }); + return Arrays.asList(new String[] { "x", "y" }); } } public void testStructureField() { @@ -362,7 +362,7 @@ class TestStructure extends Structure { public PublicTestStructure s1, s2; public int after; protected List getFieldOrder() { - return Arrays.asList(new String[] { "s1", "s2", "after" }); + return Arrays.asList(new String[] { "s1", "s2", "after" }); } } TestStructure s = new TestStructure(); @@ -386,6 +386,25 @@ protected List getFieldOrder() { s.s2.getPointer()); } + static class TestUnion extends Union { + public int u_int; + public float u_float; + public double u_double; + } + public void testUnionField() { + class TestStructure extends Structure { + public long s_long; + public TestUnion s_union; + public int s_int; + protected List getFieldOrder() { + return Arrays.asList(new String[] { "s_long", "s_union", "s_int" }); + } + } + TestStructure s = new TestStructure(); + assertEquals("Wrong structure size", 24, s.size()); + assertEquals("Wrong union size", 8, s.s_union.size()); + } + public static class NonAllocatingTestStructure extends PublicTestStructure { public NonAllocatingTestStructure() { } public NonAllocatingTestStructure(Pointer p) { super(p); read(); } @@ -394,16 +413,16 @@ protected void allocateMemory(int size) { } } - // TODO: add'l newInstance(Pointer) tests: + // TODO: add'l newInstance(Pointer) tests: // NOTE: ensure structure-by-value respected (no more flag on newjavastructure) - // native call (direct mode) + // native call (direct mode) // getNativeAlignment public void testStructureFieldAvoidsSeparateMemoryAllocation() { class TestStructure extends Structure { public NonAllocatingTestStructure s1; public TestStructure() { } protected List getFieldOrder() { - return Arrays.asList(new String[] { "s1" }); + return Arrays.asList(new String[] { "s1" }); } } TestStructure ts = new TestStructure(); @@ -434,8 +453,8 @@ class TestStructure extends Structure { // initialized array elements public PublicTestStructure[] inner2 = (PublicTestStructure[]) new PublicTestStructure().toArray(2); - protected List getFieldOrder() { - return Arrays.asList(new String[] { "inner", "inner2" }); + protected List getFieldOrder() { + return Arrays.asList(new String[] { "inner", "inner2" }); } } TestStructure s = new TestStructure(); @@ -530,7 +549,7 @@ public TestStructure() { public double[] da = new double[3]; public PublicTestStructure nested; protected List getFieldOrder() { - return Arrays.asList(new String[] { "z", "b", "c", "s", "i", "l", "f", "d", "ba", "ca", "sa", "ia", "la", "fa", "da", "nested" }); + return Arrays.asList(new String[] { "z", "b", "c", "s", "i", "l", "f", "d", "ba", "ca", "sa", "ia", "la", "fa", "da", "nested" }); } } TestStructure s = new TestStructure(); @@ -624,8 +643,8 @@ public void testNativeLongWrite() throws Exception { class TestStructure extends Structure { public int i; public NativeLong l; - protected List getFieldOrder() { - return Arrays.asList(new String[] { "i", "l" }); + protected List getFieldOrder() { + return Arrays.asList(new String[] { "i", "l" }); } } TestStructure s = new TestStructure(); @@ -672,14 +691,14 @@ protected List getFieldOrder() { public static class BadFieldStructure extends Structure { public Object badField; - protected List getFieldOrder() { + protected List getFieldOrder() { return Arrays.asList(new String[] { "badField" }); } } public void testUnsupportedField() { class BadNestedStructure extends Structure { public BadFieldStructure badStruct = new BadFieldStructure(); - protected List getFieldOrder() { + protected List getFieldOrder() { return Arrays.asList(new String[] { "badStruct" }); } } @@ -881,7 +900,7 @@ public void testPreserveStructureByReferenceWithUnchangedPointerOnRead() { assertTrue("Read should preserve structure memory", inner.getPointer() instanceof Memory); } - + public static class TestPointer extends PointerType { } public void testPreservePointerFields() { class TestStructure extends Structure { @@ -925,7 +944,7 @@ protected List getFieldOrder() { assertEquals("String field should not be overwritten", m2, s.getPointer().getPointer(Pointer.SIZE)); } - // Ensure string cacheing doesn't interfere with wrapped structure writes. + // Ensure string cacheing doesn't interfere with wrapped structure writes. public static class StructureFromNative extends Structure { public String s; protected List getFieldOrder() { @@ -938,7 +957,7 @@ public StructureFromNative(Pointer p) { public StructureFromNative() { } } - + public void testInitializeStructureFieldWithStrings() { class ContainingStructure extends Structure { public StructureFromNative inner; @@ -1021,7 +1040,7 @@ protected List getFieldOrder() { } TestStructure s = new TestStructure(); s.field = new PublicTestStructure.ByReference(); - PublicTestStructure.ByReference[] array = + PublicTestStructure.ByReference[] array = (PublicTestStructure.ByReference[])s.field.toArray(2); final int VALUE = -1; array[1].x = VALUE; @@ -1066,13 +1085,13 @@ protected List getFieldOrder() { return Arrays.asList(new String[] { "size", "alignment", "type", "elements" }); } public TestFFIType(Pointer p) { - super(p); + super(p); read(); assertTrue("Test FFIType type not initialized: " + this, this.type != 0); // Force libffi to explicitly calculate the size field of // this FFIType object - int size = Native.initialize_ffi_type(p.peer); + int size = Native.initialize_ffi_type(p.peer); read(); assertEquals("Test FFIType size improperly initialized: " + TestFFIType.this, size, TestFFIType.this.size.intValue()); } @@ -1123,7 +1142,7 @@ class TestStructure extends Structure { public int intField; public PublicTestStructure inner; protected List getFieldOrder() { - return Arrays.asList(new String[] { "intField", "inner" }); + return Arrays.asList(new String[] { "intField", "inner" }); } } TestStructure s = new TestStructure(); @@ -1154,7 +1173,7 @@ public void testNativeMappedWrite() { class TestStructure extends Structure { public ByteByReference ref; protected List getFieldOrder() { - return Arrays.asList(new String[] { "ref" }); + return Arrays.asList(new String[] { "ref" }); } } TestStructure s = new TestStructure(); @@ -1171,7 +1190,7 @@ public void testNativeMappedRead() { class TestStructure extends Structure { public ByteByReference ref; protected List getFieldOrder() { - return Arrays.asList(new String[] { "ref" }); + return Arrays.asList(new String[] { "ref" }); } } TestStructure s = new TestStructure(); @@ -1191,7 +1210,7 @@ protected List getFieldOrder() { public static class ROStructure extends Structure { public final int field; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field" }); + return Arrays.asList(new String[] { "field" }); } { // Initialize in ctor to avoid compiler replacing @@ -1241,7 +1260,7 @@ public void testNativeMappedArrayField() { class TestStructure extends Structure { public NativeLong[] longs = new NativeLong[SIZE]; protected List getFieldOrder() { - return Arrays.asList(new String[] { "longs" }); + return Arrays.asList(new String[] { "longs" }); } } TestStructure s = new TestStructure(); @@ -1277,7 +1296,7 @@ class TestStructure extends Structure { public NativeLong nl = INITIAL; public NativeLong uninitialized; protected List getFieldOrder() { - return Arrays.asList(new String[] { "nl", "uninitialized" }); + return Arrays.asList(new String[] { "nl", "uninitialized" }); } } TestStructure ts = new TestStructure(); @@ -1300,7 +1319,7 @@ public void testThrowErrorOnMissingFieldOrderOnDerivedStructure() { class TestStructure extends Structure { public int f1, f2; protected List getFieldOrder() { - return Arrays.asList(new String[] { "f1", "f2" }); + return Arrays.asList(new String[] { "f1", "f2" }); } } class TestStructure2 extends TestStructure { @@ -1333,7 +1352,7 @@ public void testThrowErrorOnIncorrectFieldOrderCount() { class TestStructure extends Structure { public int f1, f2; protected List getFieldOrder() { - return Arrays.asList(new String[] { "f1", "f2", "f3" }); + return Arrays.asList(new String[] { "f1", "f2", "f3" }); } } try { @@ -1387,7 +1406,7 @@ protected List getFieldOrder() { return list; } } - + TestStructure s = new TestStructure(); assertEquals("Wrong field order", Arrays.asList(ORDER), s.getFieldOrder()); @@ -1444,13 +1463,13 @@ protected List getFieldOrder() { Structure s = new TestStructure(); assertEquals("Wrong type mapper: " + s, mapper, s.getTypeMapper()); } - + public void testWriteWithNullBoxedPrimitives() { class TestStructure extends Structure { public Boolean zfield; public Integer field; protected List getFieldOrder() { - return Arrays.asList(new String[] { "zfield", "field" }); + return Arrays.asList(new String[] { "zfield", "field" }); } } TestStructure s = new TestStructure(); @@ -1465,7 +1484,7 @@ class OtherStructure extends Structure { public int[] second = new int[4]; public Pointer[] third = new Pointer[4]; protected List getFieldOrder() { - return Arrays.asList(new String[] { "first", "second", "third" }); + return Arrays.asList(new String[] { "first", "second", "third" }); } } class TestStructure extends Structure { @@ -1492,7 +1511,7 @@ protected List getFieldOrder() { assertTrue("Equals is not symmetric", s2.equals(s1)); assertTrue("Equals is not transitive", s1.equals(s2) && s2.equals(s3) && s1.equals(s3)); - + } public void testStructureEqualsByValueByReference() { @@ -1501,7 +1520,7 @@ class TestStructure extends Structure { public int[] second = new int[4]; public Pointer[] third = new Pointer[4]; protected List getFieldOrder() { - return Arrays.asList(new String[] { "first", "second", "third" }); + return Arrays.asList(new String[] { "first", "second", "third" }); } } class ByReference extends TestStructure implements Structure.ByReference { } @@ -1518,14 +1537,14 @@ class ByValue extends TestStructure implements Structure.ByValue { } assertTrue("Equals is not symmetric (ByValue)", s3.equals(s1)); assertTrue("Equals is not transitive (ByReference/ByValue)", s1.equals(s2) && s2.equals(s3) && s1.equals(s3)); - + } public void testStructureHashCodeMatchesEqualsTrue() { class TestStructure extends Structure { public int first; protected List getFieldOrder() { - return Arrays.asList(new String[] { "first" }); + return Arrays.asList(new String[] { "first" }); } } TestStructure s1 = new TestStructure(); @@ -1540,7 +1559,7 @@ class TestStructure extends Structure { public byte first; public int second; protected List getFieldOrder() { - return Arrays.asList(new String[] { "first", "second" }); + return Arrays.asList(new String[] { "first", "second" }); } } TestStructure s1 = new TestStructure(); @@ -1559,7 +1578,7 @@ public TestStructureByRef() { } public int unique; public TestStructureByRef s; protected List getFieldOrder() { - return Arrays.asList(new String[] { "unique", "s" }); + return Arrays.asList(new String[] { "unique", "s" }); } } TestStructureByRef s = new TestStructureByRef(); @@ -1592,7 +1611,7 @@ public static class ByReference extends CyclicTestStructure implements Structure public CyclicTestStructure() { } public CyclicTestStructure.ByReference next; protected List getFieldOrder() { - return Arrays.asList(new String[] { "next" }); + return Arrays.asList(new String[] { "next" }); } } public void testCyclicRead() { @@ -1618,7 +1637,7 @@ public void testAvoidMemoryAllocationInPointerCTOR() { class TestStructure extends Structure { public int field; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field" }); + return Arrays.asList(new String[] { "field" }); } public TestStructure(Pointer p) { super(p); @@ -1637,7 +1656,7 @@ class TestStructure extends Structure { public int intField; public byte[] arrayField = new byte[256]; protected List getFieldOrder() { - return Arrays.asList(new String[] { "intField", "arrayField" }); + return Arrays.asList(new String[] { "intField", "arrayField" }); } public TestStructure(Pointer p) { super(p); @@ -1676,7 +1695,7 @@ public TestByReferenceArrayField(Pointer m) { public ByReference[] array = new ByReference[13]; public int value2; protected List getFieldOrder() { - return Arrays.asList(new String[] { "value1", "array", "value2" }); + return Arrays.asList(new String[] { "value1", "array", "value2" }); } public static class ByReference extends TestByReferenceArrayField implements Structure.ByReference { } @@ -1703,7 +1722,7 @@ public void testEquals() { class TestStructure extends Structure { public int field; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field" }); + return Arrays.asList(new String[] { "field" }); } public TestStructure() { } public TestStructure(Pointer p) { super(p); read(); } @@ -1720,7 +1739,7 @@ public void testStructureLayoutCacheing() { class TestStructure extends Structure { public int field; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field" }); + return Arrays.asList(new String[] { "field" }); } } Structure ts = new TestStructure(); ts.ensureAllocated(); @@ -1728,12 +1747,12 @@ protected List getFieldOrder() { assertSame("Structure layout not cached", ts.fields(), ts2.fields()); } - + public void testStructureLayoutVariableNoCache() { class TestStructure extends Structure { public byte[] variable; protected List getFieldOrder() { - return Arrays.asList(new String[] { "variable" }); + return Arrays.asList(new String[] { "variable" }); } public TestStructure(int size) { this.variable = new byte[size]; @@ -1767,7 +1786,7 @@ public Object toNative(Object value, ToNativeContext c) { class TestStructure extends Structure { public boolean field; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field" }); + return Arrays.asList(new String[] { "field" }); } public TestStructure() { super(m); @@ -1788,7 +1807,7 @@ class TestStructure extends Structure { public byte first; public int second; protected List getFieldOrder() { - return Arrays.asList(new String[] { "first", "second" }); + return Arrays.asList(new String[] { "first", "second" }); } public TestStructure() { setAlignType(ALIGN_NONE); @@ -1851,7 +1870,7 @@ public TestStructure() { super(mapper); } protected List getFieldOrder() { - return Arrays.asList(new String[] { "b", "s", "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7" }); + return Arrays.asList(new String[] { "b", "s", "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7" }); } } Structure s = new TestStructure(); diff --git a/test/com/sun/jna/UnionTest.java b/test/com/sun/jna/UnionTest.java index 579c26c646..6f2d0d0c70 100644 --- a/test/com/sun/jna/UnionTest.java +++ b/test/com/sun/jna/UnionTest.java @@ -1,14 +1,14 @@ /* Copyright (c) 2007 Timothy Wall, All Rights Reserved - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * Lesser General Public License for more details. */ package com.sun.jna; @@ -23,22 +23,22 @@ public class UnionTest extends TestCase { public static class TestStructure extends Structure { public String value; protected List getFieldOrder() { - return Arrays.asList(new String[] { "value" }); + return Arrays.asList(new String[] { "value" }); } } - + public static class BigTestStructure extends Structure { public long field1; public long field2; protected List getFieldOrder() { - return Arrays.asList(new String[] { "field1", "field2" }); + return Arrays.asList(new String[] { "field1", "field2" }); } } - + public static class IntStructure extends Structure { public int value; protected List getFieldOrder() { - return Arrays.asList(new String[] { "value" }); + return Arrays.asList(new String[] { "value" }); } } @@ -59,7 +59,7 @@ public static class SizedUnion extends Union { public WString wstring; public Pointer pointer; } - + public static class StructUnion extends Union { public int intField; public TestStructure testStruct; @@ -69,31 +69,33 @@ public static class StructUnion extends Union { public void testCalculateSize() { Union u = new SizedUnion(); + assertEquals("Wrong union size: " + u, 16, u.size()); assertEquals("Union should be size of largest field", new BigTestStructure().size(), u.size()); } public void testFieldOffsets() { StructUnion u = new StructUnion(); + assertEquals("Wrong union size: " + u, Pointer.SIZE, u.size()); u.setType(u.testStruct.getClass()); u.write(); - assertEquals("Wrong struct member base address", + assertEquals("Wrong struct member base address", u.getPointer(), u.testStruct.getPointer()); u.setType(u.intStruct.getClass()); u.write(); - assertEquals("Wrong struct member base address (2)", + assertEquals("Wrong struct member base address (2)", u.getPointer(), u.intStruct.getPointer()); } public void testWriteUnion() { SizedUnion u = new SizedUnion(); - final int VALUE = 0x12345678; + final int VALUE = 0x12345678; u.intField = VALUE; u.setType(int.class); u.write(); assertEquals("Wrong value written", VALUE, u.getPointer().getInt(0)); } - + public void testReadUnion() { SizedUnion u = new SizedUnion(); final int VALUE = 0x12345678; @@ -109,11 +111,12 @@ public void testReadUnion() { assertNull("Unselected String should be null", u.string); assertNull("Unselected WString should be null", u.wstring); } - + public void testWriteTypedUnion() { final int VALUE = 0x12345678; // write an instance of a direct union class to memory StructUnion u = new StructUnion(); + assertEquals("Wrong union size: " + u, Pointer.SIZE, u.size()); IntStructure intStruct = new IntStructure(); intStruct.value = VALUE; u.setTypedValue(intStruct); @@ -138,6 +141,7 @@ public void callback() { public void testReadTypedUnion() { StructUnion u = new StructUnion(); + assertEquals("Wrong union size: " + u, Pointer.SIZE, u.size()); final int VALUE = 0x12345678; u.getPointer().setInt(0, VALUE); assertEquals("int structure not read properly", VALUE, ((IntStructure) u.getTypedValue(IntStructure.class)).value); @@ -145,29 +149,34 @@ public void testReadTypedUnion() { public void testReadTypeInfo() { SizedUnion u = new SizedUnion(); + assertEquals("Wrong union size: " + u, 16, u.size()); + assertNotNull("Type information is missing for union field of type " + BigTestStructure.class, Structure.getTypeInfo(BigTestStructure.class)); + assertNotNull("Type information is missing for union instance", u.getTypeInfo()); if (Native.POINTER_SIZE == 4) { - assertEquals("Type size should be that of longest field if no field active", + assertEquals("Type size should be that of largest field if no field is active", Structure.getTypeInfo(BigTestStructure.class).getInt(0), u.getTypeInfo().getInt(0)); } else { - assertEquals("Type size should be that of longest field if no field active", + assertEquals("Type size should be that of largest field if no field is active", Structure.getTypeInfo(BigTestStructure.class).getLong(0), u.getTypeInfo().getLong(0)); } u.setType(int.class); + assertNotNull("Type information is missing for union field of type " + BigTestStructure.class, Structure.getTypeInfo(BigTestStructure.class)); + assertNotNull("Type information is missing for union instance after type set", u.getTypeInfo()); if (Native.POINTER_SIZE == 4) { - assertEquals("Type size should be that of longest field if field active", + assertEquals("Type size should be that of largest field if any field is active", Structure.getTypeInfo(BigTestStructure.class).getInt(0), u.getTypeInfo().getInt(0)); } else { - assertEquals("Type size should be that of longest field if field active", + assertEquals("Type size should be that of largest field if any field is active", Structure.getTypeInfo(BigTestStructure.class).getLong(0), u.getTypeInfo().getLong(0)); } } - + public void testArraysInUnion() { class TestUnion extends Union { public byte[] bytes = new byte[16]; @@ -175,6 +184,7 @@ class TestUnion extends Union { public int[] ints = new int[4]; } Union u = new TestUnion(); + assertEquals("Wrong union size: " + u, 16, u.size()); u.setType(byte[].class); u.setType(short[].class); u.setType(int[].class); @@ -183,9 +193,10 @@ class TestUnion extends Union { public void testDuplicateFieldTypes() { class TestUnion extends Union { public int field1; - public int field2; + public int field2; } TestUnion u = new TestUnion(); + assertEquals("Wrong union size: " + u, 4, u.size()); u.setType("field1"); u.field1 = 42; u.write();