/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
import com.sun.jna.ReturnTypesTest.TestLibrary.SimpleStructure;
import com.sun.jna.ReturnTypesTest.TestLibrary.TestSmallStructure;
import com.sun.jna.ReturnTypesTest.TestLibrary.TestStructure;
/** Exercise a range of native methods.
*
* @author twall@users.sf.net
*/
public class ReturnTypesTest extends TestCase {
private static final String UNICODE = "[\u0444]";
private static final double DOUBLE_MAGIC = -118.625d;
private static final float FLOAT_MAGIC = -118.625f;
public static interface TestLibrary extends Library {
public static class SimpleStructure extends Structure {
public static final List<String> FIELDS = createFieldsOrder("value");
public double value;
public static int allocations = 0;
public SimpleStructure() { }
public SimpleStructure(Pointer p) { super(p); read(); }
@Override
protected void allocateMemory(int size) {
super.allocateMemory(size);
++allocations;
}
@Override
protected List<String> getFieldOrder() {
return FIELDS;
}
}
public static class TestSmallStructure extends Structure {
public static class ByValue extends TestSmallStructure implements Structure.ByValue { }
public static final List<String> FIELDS = createFieldsOrder("c1", "c2", "s");
public byte c1;
public byte c2;
public short s;
@Override
protected List<String> getFieldOrder() {
return FIELDS;
}
}
public static class TestStructure extends Structure {
public static class ByValue extends TestStructure implements Structure.ByValue { }
public static final List<String> FIELDS = createFieldsOrder("c", "s", "i", "j", "inner");
public byte c;
public short s;
public int i;
public long j;
public SimpleStructure inner;
@Override
protected List<String> getFieldOrder() {
return FIELDS;
}
}
public static class CheckFieldAlignment extends Structure {
public static final List<String> FIELDS = createFieldsOrder("int32Field", "int64Field", "floatField", "doubleField");
public int int32Field = 1;
public long int64Field = 2;
public float floatField = 3f;
public double doubleField = 4d;
@Override
protected List<String> getFieldOrder() {
return FIELDS;
}
}
class TestObject { }
Object returnObjectArgument(Object s);
TestObject returnObjectArgument(TestObject s);
boolean returnFalse();
boolean returnTrue();
int returnInt32Zero();
int returnInt32Magic();
long returnInt64Zero();
long returnInt64Magic();
NativeLong returnLongZero();
NativeLong returnLongMagic();
float returnFloatZero();
float returnFloatMagic();
double returnDoubleZero();
double returnDoubleMagic();
String returnStringMagic();
WString returnWStringMagic();
SimpleStructure returnStaticTestStructure();
SimpleStructure returnNullTestStructure();
TestSmallStructure.ByValue returnSmallStructureByValue();
TestStructure.ByValue returnStructureByValue();
Pointer[] returnPointerArgument(Pointer[] arg);
String[] returnPointerArgument(String[] arg);
WString[] returnPointerArgument(WString[] arg);
}
TestLibrary lib;
@Override
protected void setUp() {
lib = Native.loadLibrary("testlib", TestLibrary.class);
}
@Override
protected void tearDown() {
lib = null;
}
public void testReturnObject() throws Exception {
lib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE));
assertNull("null value not returned", lib.returnObjectArgument(null));
final Object VALUE = new Object() {
@Override
public String toString() {
return getName();
}
};
assertEquals("Wrong object returned", VALUE, lib.returnObjectArgument(VALUE));
}
public void testReturnObjectUnsupported() throws Exception {
try {
lib.returnObjectArgument(new TestLibrary.TestObject());
fail("Java Object return is not supported, should throw IllegalArgumentException");
}
catch(IllegalArgumentException e) {
assertTrue("Exception should include return object type: " + e,
e.getMessage().indexOf(TestLibrary.TestObject.class.getName()) != -1);
}
catch(Throwable e) {
fail("Method declared with Java Object return should throw IllegalArgumentException, not " + e);
}
}
public void testInvokeBoolean() {
assertFalse("Expect false", lib.returnFalse());
assertTrue("Expect true", lib.returnTrue());
}
public void testInvokeInt() {
assertEquals("Expect 32-bit zero", 0, lib.returnInt32Zero());
assertEquals("Expect 32-bit magic",
"12345678",
Integer.toHexString(lib.returnInt32Magic()));
}
public void testInvokeLong() {
assertEquals("Expect 64-bit zero", 0L, lib.returnInt64Zero());
assertEquals("Expect 64-bit magic",
"123456789abcdef0",
Long.toHexString(lib.returnInt64Magic()));
}
public void testInvokeNativeLong() {
if (NativeLong.SIZE == 4) {
assertEquals("Expect 32-bit zero", new NativeLong(0), lib.returnLongZero());
assertEquals("Expect 32-bit magic",
"12345678",
Integer.toHexString(lib.returnLongMagic().intValue()));
} else {
assertEquals("Expect 64-bit zero", new NativeLong(0L),
lib.returnLongZero());
assertEquals("Expect 64-bit magic",
"123456789abcdef0",
Long.toHexString(lib.returnLongMagic().longValue()));
}
}
public interface NativeMappedLibrary extends Library {
Custom returnInt32Argument(int arg);
size_t returnInt32Magic();
size_t returnInt64Magic();
}
public static class size_t extends IntegerType {
private static final long serialVersionUID = 1L;
public size_t() {
this(0);
}
public size_t(long value) {
super(Native.SIZE_T_SIZE, true);
setValue(value);
}
}
public static class Custom implements NativeMapped {
private int value;
public Custom() { }
public Custom(int value) {
this.value = value;
}
@Override
public Object fromNative(Object nativeValue, FromNativeContext context) {
return new Custom(((Integer)nativeValue).intValue());
}
@Override
public Class<?> nativeType() {
return Integer.class;
}
@Override
public Object toNative() {
return Integer.valueOf(value);
}
@Override
public boolean equals(Object o) {
return o instanceof Custom && ((Custom)o).value == value;
}
}
protected NativeMappedLibrary loadNativeMappedLibrary() {
return Native.loadLibrary("testlib", NativeMappedLibrary.class);
}
public void testInvokeNativeMapped() {
NativeMappedLibrary lib = loadNativeMappedLibrary();
final int MAGIC = 0x12345678;
final long MAGIC64 = 0x123456789ABCDEF0L;
final Custom EXPECTED = new Custom(MAGIC);
assertEquals("NativeMapped 'Custom' result not mapped", EXPECTED, lib.returnInt32Argument(MAGIC));
assertEquals("NativeMapped IntegerType result not mapped (32)",
new size_t(MAGIC), lib.returnInt32Magic());
if (Native.SIZE_T_SIZE == 8) {
assertEquals("NativeMapped IntegerType result not mapped (64)",
new size_t(MAGIC64), lib.returnInt64Magic());
}
}
public void testInvokeFloat() {
assertEquals("Expect float zero", 0f, lib.returnFloatZero(), 0d);
assertEquals("Expect float magic",
FLOAT_MAGIC, lib.returnFloatMagic(), 0d);
}
public void testInvokeDouble() {
assertEquals("Expect double zero", 0d, lib.returnDoubleZero(), 0d);
assertEquals("Expect double magic",
DOUBLE_MAGIC, lib.returnDoubleMagic(), 0d);
}
static final String MAGIC = "magic";
public void testInvokeString() {
assertEquals("Expect String magic", MAGIC, lib.returnStringMagic());
}
public void testInvokeWString() {
WString s = lib.returnWStringMagic();
assertEquals("Wrong length", MAGIC.length(), s.toString().length());
assertEquals("Expect WString magic", new WString(MAGIC), s);
}
public void testInvokeStructure() {
SimpleStructure.allocations = 0;
SimpleStructure s = lib.returnStaticTestStructure();
assertEquals("Expect test structure magic", DOUBLE_MAGIC, s.value, 0d);
// Optimized structure allocation
assertEquals("Returned Structure should allocate no memory", 0, SimpleStructure.allocations);
}
public void testInvokeNullStructure() {
SimpleStructure s = lib.returnNullTestStructure();
assertNull("Expect null structure return", s);
}
public void testReturnSmallStructureByValue() {
TestSmallStructure s = lib.returnSmallStructureByValue();
assertNotNull("Returned structure must not be null", s);
assertEquals("Wrong char field value (1)", 1, s.c1);
assertEquals("Wrong char field value (2)", 2, s.c2);
assertEquals("Wrong short field value", 3, s.s);
}
public void testReturnStructureByValue() {
TestStructure s = lib.returnStructureByValue();
assertNotNull("Returned structure must not be null", s);
assertEquals("Wrong char field value", 1, s.c);
assertEquals("Wrong short field value", 2, s.s);
assertEquals("Wrong int field value", 3, s.i);
assertEquals("Wrong long field value", 4, s.j);
assertNotNull("Structure not initialized", s.inner);
assertEquals("Wrong inner structure value", 5, s.inner.value, 0);
}
public void testReturnPointerArray() {
Pointer value = new Memory(10);
Pointer[] input = {
value, null,
};
Pointer[] result = lib.returnPointerArgument(input);
assertEquals("Wrong array length", input.length-1, result.length);
assertEquals("Wrong array element value", value, result[0]);
assertNull("NULL should result in null return value", lib.returnPointerArgument((Pointer[])null));
}
public void testReturnStringArray() {
Charset charset = Charset.forName(Native.getDefaultStringEncoding());
final String VALUE = getName() + charset.decode(charset.encode(UNICODE));
String[] input = {
VALUE, null,
};
String[] result = lib.returnPointerArgument(input);
assertEquals("Wrong array length", input.length-1, result.length);
assertEquals("Wrong array element value", VALUE, result[0]);
assertNull("NULL should result in null return value", lib.returnPointerArgument((String[])null));
}
public void testReturnWStringArray() {
final WString VALUE = new WString(getName() + UNICODE);
WString[] input = {
VALUE, null,
};
WString[] result = lib.returnPointerArgument(input);
assertEquals("Wrong array length", input.length-1, result.length);
assertEquals("Wrong array element value", VALUE, result[0]);
assertNull("NULL should result in null return value", lib.returnPointerArgument((WString[])null));
}
public static void main(java.lang.String[] argList) {
junit.textui.TestRunner.run(ReturnTypesTest.class);
}
}