/* Copyright (c) 2007 Wayne Meissner, 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.Arrays; import java.util.Collections; import java.util.List; import junit.framework.TestCase; //@SuppressWarnings("unused") public class TypeMapperTest extends TestCase { private static final String UNICODE = "[\0444]"; public static interface TestLibrary extends Library { int returnInt32Argument(boolean b); int returnInt32Argument(String s); int returnInt32Argument(Number n); WString returnWStringArgument(String s); String returnWStringArgument(WString s); } public void testBooleanToIntArgumentConversion() { final int MAGIC = 0xABEDCF23; 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; } }); TestLibrary lib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); 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() { @Override public Object toNative(Object arg, ToNativeContext ctx) { return Integer.valueOf((String) arg, 16); } @Override public Class<?> nativeType() { return Integer.class; } }); final int MAGIC = 0x7BEDCF23; TestLibrary lib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); assertEquals("Failed to convert String argument to Int", MAGIC, lib.returnInt32Argument(Integer.toHexString(MAGIC))); } public void testStringToWStringArgumentConversion() { DefaultTypeMapper mapper = new DefaultTypeMapper(); mapper.addToNativeConverter(String.class, new ToNativeConverter() { @Override public Object toNative(Object arg, ToNativeContext ctx) { return new WString(arg.toString()); } @Override public Class<?> nativeType() { return WString.class; } }); final String MAGIC = "magic" + UNICODE; TestLibrary lib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); assertEquals("Failed to convert String argument to WString", new WString(MAGIC), lib.returnWStringArgument(MAGIC)); } public void testCharSequenceToIntArgumentConversion() { 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; } }); final int MAGIC = 0x7BEDCF23; TestLibrary lib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); 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() { @Override public Object toNative(Object arg, ToNativeContext ctx) { return Integer.valueOf(((Double)arg).intValue()); } @Override public Class<?> nativeType() { return Integer.class; } }); final int MAGIC = 0x7BEDCF23; TestLibrary lib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); assertEquals("Failed to convert Double argument to Int", MAGIC, lib.returnInt32Argument(Double.valueOf(MAGIC))); } public void testWStringToStringResultConversion() throws Exception { final String MAGIC = "magic" + UNICODE; DefaultTypeMapper mapper = new DefaultTypeMapper(); mapper.addFromNativeConverter(String.class, new FromNativeConverter() { @Override public Object fromNative(Object value, FromNativeContext ctx) { if (value == null) { return null; } return value.toString(); } @Override public Class<?> nativeType() { return WString.class; } }); TestLibrary lib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); assertEquals("Failed to convert WString result to String", MAGIC, lib.returnWStringArgument(new WString(MAGIC))); } public static interface BooleanTestLibrary extends Library { boolean returnInt32Argument(boolean b); } public void testIntegerToBooleanResultConversion() throws Exception { final int MAGIC = 0xABEDCF23; DefaultTypeMapper mapper = new DefaultTypeMapper(); mapper.addToNativeConverter(Boolean.class, new ToNativeConverter() { @Override public Object toNative(Object value, ToNativeContext ctx) { return Integer.valueOf(Boolean.TRUE.equals(value) ? MAGIC : 0); } @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; } }); BooleanTestLibrary lib = Native.loadLibrary("testlib", BooleanTestLibrary.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); 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) { super(mapper); } public boolean data; @Override protected List<String> getFieldOrder() { return Arrays.asList("data"); } } } public void testStructureConversion() throws Exception { DefaultTypeMapper mapper = new DefaultTypeMapper(); TypeConverter converter = new TypeConverter() { @Override public Object toNative(Object value, ToNativeContext ctx) { return Integer.valueOf(Boolean.TRUE.equals(value) ? 1 : 0); } @Override public Object fromNative(Object value, FromNativeContext context) { return Boolean.valueOf(((Integer)value).intValue() == 1); } @Override public Class<?> nativeType() { return Integer.class; } }; mapper.addTypeConverter(Boolean.class, converter); Native.loadLibrary("testlib", StructureTestLibrary.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); 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); } 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 static interface EnumerationTestLibrary extends Library { Enumeration returnInt32Argument(Enumeration arg); } public void testEnumConversion() throws Exception { DefaultTypeMapper mapper = new DefaultTypeMapper(); TypeConverter converter = new TypeConverter() { @Override public Object toNative(Object value, ToNativeContext ctx) { return Integer.valueOf(((Enumeration)value).getCode()); } @Override public Object fromNative(Object value, FromNativeContext context) { return Enumeration.fromCode(((Integer)value).intValue()); } @Override public Class<?> nativeType() { return Integer.class; } }; mapper.addTypeConverter(Enumeration.class, converter); EnumerationTestLibrary lib = Native.loadLibrary("testlib", EnumerationTestLibrary.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); assertEquals("Enumeration improperly converted", Enumeration.STATUS_1, lib.returnInt32Argument(Enumeration.STATUS_1)); } public static void main(String[] args) { junit.textui.TestRunner.run(TypeMapperTest.class); } }