/* Copyright (c) 2009 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.util.Collections;
import junit.framework.TestCase;
public class DirectTypeMapperTest extends TestCase {
private static final String UNICODE = "[\0444]";
/** Converts boolean to int when going to native. */
public static class DirectTestLibraryBoolean {
final static int MAGIC = 0xABEDCF23;
public native int returnInt32Argument(boolean b);
static {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addToNativeConverter(Boolean.class, new ToNativeConverter() {
@Override
public Object toNative(Object arg, ToNativeContext ctx) {
return Integer.valueOf(Boolean.TRUE.equals(arg) ? MAGIC : 0);
}
@Override
public Class<?> nativeType() {
return Integer.class;
}
});
Native.register(NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)));
}
}
/** Converts String to int when going to native. */
public static class DirectTestLibraryString {
public native int returnInt32Argument(String s);
static {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addToNativeConverter(String.class, new ToNativeConverter() {
@Override
public Object toNative(Object arg, ToNativeContext ctx) {
return Integer.valueOf((String) arg, 16);
}
@Override
public Class<?> nativeType() {
return Integer.class;
}
});
Native.register(NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)));
}
}
/** Converts CharSequence to int when going to native. */
public static class DirectTestLibraryCharSequence {
public native int returnInt32Argument(String n);
static {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addToNativeConverter(CharSequence.class, new ToNativeConverter() {
@Override
public Object toNative(Object arg, ToNativeContext ctx) {
return Integer.valueOf(((CharSequence)arg).toString(), 16);
}
@Override
public Class<?> nativeType() {
return Integer.class;
}
});
Native.register(NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)));
}
}
/** Converts Number to int when going to native. */
public static class DirectTestLibraryNumber {
public native int returnInt32Argument(Number n);
static {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addToNativeConverter(Number.class, new ToNativeConverter() {
@Override
public Object toNative(Object arg, ToNativeContext ctx) {
return Integer.valueOf(((Number)arg).intValue());
}
@Override
public Class<?> nativeType() {
return Integer.class;
}
});
Native.register(NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)));
}
}
/** Converts String to WString and back. */
public static class DirectTestLibraryWString {
public native String returnWStringArgument(String s);
static {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addTypeConverter(String.class, new TypeConverter() {
@Override
public Object toNative(Object value, ToNativeContext ctx) {
if (value == null) {
return null;
}
return new WString(value.toString());
}
@Override
public Object fromNative(Object value, FromNativeContext context) {
if (value == null) {
return null;
}
return value.toString();
}
@Override
public Class<?> nativeType() {
return WString.class;
}
});
Native.register(NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)));
}
}
public void testBooleanToIntArgumentConversion() {
DirectTestLibraryBoolean lib = new DirectTestLibraryBoolean();
assertEquals("Failed to convert Boolean argument to Int",
DirectTestLibraryBoolean.MAGIC,
lib.returnInt32Argument(true));
}
public void testStringToIntArgumentConversion() {
final int MAGIC = 0x7BEDCF23;
DirectTestLibraryString lib = new DirectTestLibraryString();
assertEquals("Failed to convert String argument to Int", MAGIC,
lib.returnInt32Argument(Integer.toHexString(MAGIC)));
}
public void testCharSequenceToIntArgumentConversion() {
final int MAGIC = 0x7BEDCF23;
DirectTestLibraryCharSequence lib = new DirectTestLibraryCharSequence();
assertEquals("Failed to convert String argument to Int", MAGIC,
lib.returnInt32Argument(Integer.toHexString(MAGIC)));
}
public void testNumberToIntArgumentConversion() {
final int MAGIC = 0x7BEDCF23;
DirectTestLibraryNumber lib = new DirectTestLibraryNumber();
assertEquals("Failed to convert Double argument to Int", MAGIC,
lib.returnInt32Argument(Double.valueOf(MAGIC)));
}
public void testStringToWStringArgumentConversion() {
final String MAGIC = "magic" + UNICODE;
DirectTestLibraryWString lib = new DirectTestLibraryWString();
assertEquals("Failed to convert String argument to WString", MAGIC,
lib.returnWStringArgument(MAGIC));
}
/** Uses a type mapper to convert boolean->int and int->boolean */
public static class DirectTestLibraryBidirectionalBoolean {
public native boolean returnInt32Argument(boolean b);
static {
final int MAGIC = 0xABEDCF23;
DefaultTypeMapper mapper = new DefaultTypeMapper();
// Use opposite sense of default int<-->boolean conversions
mapper.addToNativeConverter(Boolean.class, new ToNativeConverter() {
@Override
public Object toNative(Object value, ToNativeContext ctx) {
return Integer.valueOf(Boolean.TRUE.equals(value) ? 0 : MAGIC);
}
@Override
public Class<?> nativeType() {
return Integer.class;
}
});
mapper.addFromNativeConverter(Boolean.class, new FromNativeConverter() {
@Override
public Object fromNative(Object value, FromNativeContext context) {
return Boolean.valueOf(((Integer) value).intValue() != MAGIC);
}
@Override
public Class<?> nativeType() {
return Integer.class;
}
});
Native.register(NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)));
}
}
public void testIntegerToBooleanResultConversion() throws Exception {
DirectTestLibraryBidirectionalBoolean lib = new DirectTestLibraryBidirectionalBoolean();
// argument "true" converts to zero; result zero converts to "true"
assertTrue("Failed to convert integer return to boolean TRUE",
lib.returnInt32Argument(true));
// argument "true" converts to MAGIC; result MAGIC converts to "false"
assertFalse("Failed to convert integer return to boolean FALSE",
lib.returnInt32Argument(false));
}
public static class PointTestClass {
public static TypeMapper TYPE_MAPPER;
int x, y;
}
public static class DirectTypeMappedResultTypeTestLibrary {
public native PointTestClass returnPoint(int x, int y);
static {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addTypeConverter(PointTestClass.class, new TypeConverter() {
@Override
public Object fromNative(Object value, FromNativeContext context) {
Pointer p = (Pointer) value;
PointTestClass pc = new PointTestClass();
pc.x = p.getInt(0);
pc.y = p.getInt(4);
Native.free(Pointer.nativeValue(p));
return pc;
}
@Override
public Object toNative(Object value, ToNativeContext context) {
return Pointer.NULL; // dummy implementation (not called)
}
@Override
public Class<?> nativeType() {
return Pointer.class;
}
});
PointTestClass.TYPE_MAPPER = mapper;
Native.register(NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)));
}
}
public void testTypeMapperResultTypeConversion() throws Exception {
DirectTypeMappedResultTypeTestLibrary lib = new DirectTypeMappedResultTypeTestLibrary();
PointTestClass p = lib.returnPoint(1234, 5678);
assertEquals("Failed to convert int* return to java.awt.Point", 1234, p.x);
assertEquals("Failed to convert int* return to java.awt.Point", 5678, p.y);
}
public static class DirectTypeMappedEnumerationTestLibrary {
public static enum Enumeration {
STATUS_0(0), STATUS_1(1), STATUS_ERROR(-1);
private final int code;
Enumeration(int code) { this.code = code; }
public int getCode() { return code; }
public static Enumeration fromCode(int code) {
switch(code) {
case 0: return STATUS_0;
case 1: return STATUS_1;
default: return STATUS_ERROR;
}
}
}
public native Enumeration returnInt32Argument(Enumeration e);
static {
DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addTypeConverter(Enumeration.class, new TypeConverter() {
@Override
public Object toNative(Object arg, ToNativeContext ctx) {
return Integer.valueOf(((Enumeration)arg).getCode());
}
@Override
public Object fromNative(Object value, FromNativeContext context) {
return Enumeration.fromCode(((Integer)value).intValue());
}
@Override
public Class<?> nativeType() {
return Integer.class;
}
});
Native.register(NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)));
}
}
public void testEnumerationConversion() {
DirectTypeMappedEnumerationTestLibrary lib = new DirectTypeMappedEnumerationTestLibrary();
DirectTypeMappedEnumerationTestLibrary.Enumeration e = lib.returnInt32Argument(DirectTypeMappedEnumerationTestLibrary.Enumeration.STATUS_1);
assertEquals("Failed to convert enumeration", DirectTypeMappedEnumerationTestLibrary.Enumeration.STATUS_1, e);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(DirectTypeMapperTest.class);
}
}