/* Copyright (c) 2007 Wayne Meissner, 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.
* <p/>
* 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.
*/
package com.sun.jna;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.HashMap;
import java.util.Map;
import junit.framework.TestCase;
public class TypeMapperTest extends TestCase {
public static interface TestLibrary extends Library {
int returnInt32Argument(boolean b);
int returnInt32Argument(String s);
int returnInt32Argument(Number n);
}
public void testBooleanToIntArgumentConversion() {
final int MAGIC = 0xABEDCF23;
Map options = new HashMap();
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addToNativeConverter(Boolean.class, new ToNativeConverter() {
public Object toNative(Object arg, ToNativeContext ctx) {
return new Integer(Boolean.TRUE.equals(arg) ? MAGIC : 0);
}
public Class nativeType() {
return Integer.class;
}
});
options.put(Library.OPTION_TYPE_MAPPER, mapper);
TestLibrary lib = (TestLibrary)
Native.loadLibrary("testlib", TestLibrary.class, options);
assertEquals("Failed to convert Boolean argument to Int", MAGIC,
lib.returnInt32Argument(true));
}
public void testStringToIntArgumentConversion() {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addToNativeConverter(String.class, new ToNativeConverter() {
public Object toNative(Object arg, ToNativeContext ctx) {
return Integer.valueOf((String) arg, 16);
}
public Class nativeType() {
return Integer.class;
}
});
Map options = new HashMap();
options.put(Library.OPTION_TYPE_MAPPER, mapper);
final int MAGIC = 0x7BEDCF23;
TestLibrary lib = (TestLibrary)
Native.loadLibrary("testlib", TestLibrary.class, options);
assertEquals("Failed to convert String argument to Int", MAGIC,
lib.returnInt32Argument(Integer.toHexString(MAGIC)));
}
public void testCharSequenceToIntArgumentConversion() {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addToNativeConverter(CharSequence.class, new ToNativeConverter() {
public Object toNative(Object arg, ToNativeContext ctx) {
return Integer.valueOf(((CharSequence)arg).toString(), 16);
}
public Class nativeType() {
return Integer.class;
}
});
Map options = new HashMap();
options.put(Library.OPTION_TYPE_MAPPER, mapper);
final int MAGIC = 0x7BEDCF23;
TestLibrary lib = (TestLibrary)
Native.loadLibrary("testlib", TestLibrary.class, options);
assertEquals("Failed to convert String argument to Int", MAGIC,
lib.returnInt32Argument(Integer.toHexString(MAGIC)));
}
public void testNumberToIntArgumentConversion() {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addToNativeConverter(Double.class, new ToNativeConverter() {
public Object toNative(Object arg, ToNativeContext ctx) {
return new Integer(((Double)arg).intValue());
}
public Class nativeType() {
return Integer.class;
}
});
Map options = new HashMap();
options.put(Library.OPTION_TYPE_MAPPER, mapper);
final int MAGIC = 0x7BEDCF23;
TestLibrary lib = (TestLibrary)
Native.loadLibrary("testlib", TestLibrary.class, options);
assertEquals("Failed to convert Double argument to Int", MAGIC,
lib.returnInt32Argument(new Double(MAGIC)));
}
public static interface BooleanTestLibrary extends Library {
boolean returnInt32Argument(boolean b);
}
public void testIntegerToBooleanResultConversion() throws Exception {
final int MAGIC = 0xABEDCF23;
Map options = new HashMap();
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addToNativeConverter(Boolean.class, new ToNativeConverter() {
public Object toNative(Object value, ToNativeContext ctx) {
return new Integer(Boolean.TRUE.equals(value) ? MAGIC : 0);
}
public Class nativeType() {
return Integer.class;
}
});
mapper.addFromNativeConverter(Boolean.class, new FromNativeConverter() {
public Object fromNative(Object value, FromNativeContext context) {
return Boolean.valueOf(((Integer) value).intValue() == MAGIC);
}
public Class nativeType() {
return Integer.class;
}
});
options.put(Library.OPTION_TYPE_MAPPER, mapper);
BooleanTestLibrary lib = (BooleanTestLibrary)
Native.loadLibrary("testlib", BooleanTestLibrary.class, options);
assertEquals("Failed to convert integer return to boolean TRUE", true,
lib.returnInt32Argument(true));
assertEquals("Failed to convert integer return to boolean FALSE", false,
lib.returnInt32Argument(false));
}
public static interface StructureTestLibrary extends Library {
public static class TestStructure extends Structure {
public TestStructure(TypeMapper mapper) {
setTypeMapper(mapper);
}
public boolean data;
}
}
public void testStructureConversion() throws Exception {
DefaultTypeMapper mapper = new DefaultTypeMapper();
TypeConverter converter = new TypeConverter() {
public Object toNative(Object value, ToNativeContext ctx) {
return new Integer(Boolean.TRUE.equals(value) ? 1 : 0);
}
public Object fromNative(Object value, FromNativeContext context) {
return new Boolean(((Integer)value).intValue() == 1);
}
public Class nativeType() {
return Integer.class;
}
};
mapper.addTypeConverter(Boolean.class, converter);
Map options = new HashMap();
options.put(Library.OPTION_TYPE_MAPPER, mapper);
StructureTestLibrary lib = (StructureTestLibrary)
Native.loadLibrary("testlib", StructureTestLibrary.class, options);
StructureTestLibrary.TestStructure s = new StructureTestLibrary.TestStructure(mapper);
assertEquals("Wrong native size", 4, s.size());
s.data = true;
s.write();
assertEquals("Wrong value written", 1, s.getPointer().getInt(0));
s.getPointer().setInt(0, 0);
s.read();
assertFalse("Wrong value read", s.data);
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface FooBoolean {}
public static interface AnnotationTestLibrary extends Library {
@FooBoolean
boolean returnInt32Argument(boolean b);
}
public void testAnnotationsOnMethods() throws Exception {
final int MAGIC = 0xABEDCF23;
Map options = new HashMap();
final boolean[] hasAnnotation = {false, false};
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addTypeConverter(Boolean.class, new TypeConverter() {
public Object toNative(Object value, ToNativeContext ctx) {
MethodParameterContext mcontext = (MethodParameterContext)ctx;
hasAnnotation[0] = mcontext.getMethod().getAnnotation(FooBoolean.class) != null;
return new Integer(Boolean.TRUE.equals(value) ? MAGIC : 0);
}
public Object fromNative(Object value, FromNativeContext context) {
MethodResultContext mcontext = (MethodResultContext)context;
hasAnnotation[1] = mcontext.getMethod().getAnnotation(FooBoolean.class) != null;
return Boolean.valueOf(((Integer) value).intValue() == MAGIC);
}
public Class nativeType() {
return Integer.class;
}
});
options.put(Library.OPTION_TYPE_MAPPER, mapper);
AnnotationTestLibrary lib = (AnnotationTestLibrary)
Native.loadLibrary("testlib", AnnotationTestLibrary.class, options);
assertEquals("Failed to convert integer return to boolean TRUE", true,
lib.returnInt32Argument(true));
assertTrue("Failed to get annotation from ParameterContext", hasAnnotation[0]);
assertTrue("Failed to get annotation from ResultContext", hasAnnotation[1]);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(TypeMapperTest.class);
}
}