/* 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 junit.framework.*; import java.lang.reflect.Method; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; //@SuppressWarnings("unused") public class DirectTest extends TestCase implements Paths, GCWaits { public static void main(java.lang.String[] argList) { junit.textui.TestRunner.run(DirectTest.class); } static class MathLibrary { public static native double cos(double x); static { Native.register(Platform.MATH_LIBRARY_NAME); } } interface MathInterface extends Library { double cos(double x); } static class CLibrary { public static class size_t extends IntegerType { private static final long serialVersionUID = 1L; public size_t() { super(Native.POINTER_SIZE); } public size_t(long value) { super(Native.POINTER_SIZE, value); } } public static native Pointer memset(Pointer p, int v, size_t len); public static native Pointer memset(Pointer p, int v, int len); public static native Pointer memset(Pointer p, int v, long len); public static native long memset(long p, int v, long len); public static native int memset(int p, int v, int len); public static native int strlen(String s1); public static native int strlen(Pointer p); public static native int strlen(byte[] b); static { Native.register(Platform.C_LIBRARY_NAME); } } static interface CInterface extends Library { Pointer memset(Pointer p, int v, int len); int strlen(String s); } static interface TestInterface extends Library { interface Int32Callback extends Callback { int invoke(int arg1, int arg2); } interface NativeLongCallback extends Callback { NativeLong invoke(NativeLong arg1, NativeLong arg2); } int callInt32CallbackRepeatedly(Int32Callback cb, int arg1, int arg2, int count); NativeLong callLongCallbackRepeatedly(NativeLongCallback cb, NativeLong arg1, NativeLong arg2, int count); } static class TestLibrary implements TestInterface { @Override public native int callInt32CallbackRepeatedly(Int32Callback cb, int arg1, int arg2, int count); @Override public native NativeLong callLongCallbackRepeatedly(NativeLongCallback cb, NativeLong arg1, NativeLong arg2, int count); static { Native.register("testlib"); } } private static class TestLoader extends URLClassLoader { public TestLoader() throws MalformedURLException { this(null); } public TestLoader(ClassLoader parent) throws MalformedURLException { super(Platform.isWindowsCE() ? new URL[] { new File("/Storage Card/test.jar").toURI().toURL() } : new URL[] { new File(BUILDDIR + "/classes").toURI().toURL(), new File(BUILDDIR + "/test-classes").toURI().toURL(), }, new CloverLoader(parent)); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String boot = System.getProperty("jna.boot.library.path"); if (boot != null) { System.setProperty("jna.boot.library.path", ""); } Class<?> cls = super.findClass(name); if (boot != null) { System.setProperty("jna.boot.library.path", boot); } return cls; } } public void testRegisterMethods() throws Exception { assertEquals("Math library call failed", 1., MathLibrary.cos(0), .01); assertTrue("Library not registered", Native.registered(MathLibrary.class)); Native.unregister(MathLibrary.class); assertFalse("Registered methods not unregistered", Native.registered(MathLibrary.class)); } private Class<?> returnCallingClass() { return Native.getCallingClass(); } public void testFindCallingClass() { assertEquals("Wrong calling class detected", getClass(), returnCallingClass()); } public void testFindNativeClass() { class UnregisterLibrary { class Inner { public Class<?> findDirectMappedClass() { return findDirectMappedClassInner(); } public Class<?> findDirectMappedClassInner() { return Native.findDirectMappedClass(Native.getCallingClass()); }; } public native double cos(double x); public Class<?> findDirectMappedClass() { return new Inner().findDirectMappedClass(); }; } assertEquals("Wrong native class found", UnregisterLibrary.class, new UnregisterLibrary().findDirectMappedClass()); } public static class DirectMapping { public static class DirectStructure extends Structure { public int field; @Override protected List<String> getFieldOrder() { return Arrays.asList("field"); } } public static interface DirectCallback extends Callback { void invoke(); } public DirectMapping(Map<String, ?> options) { Native.register(getClass(), NativeLibrary.getInstance("testlib", options)); } } public void testGetOptionsForDirectMappingWithMemberInitializer() { Class<?>[] classes = { DirectMapping.class, DirectMapping.DirectStructure.class, DirectMapping.DirectCallback.class, }; final TypeMapper mapper = new DefaultTypeMapper(); final int alignment = Structure.ALIGN_NONE; final String encoding = System.getProperty("file.encoding"); Map<String, Object> options = new HashMap<String, Object>(); options.put(Library.OPTION_TYPE_MAPPER, mapper); options.put(Library.OPTION_STRUCTURE_ALIGNMENT, alignment); options.put(Library.OPTION_STRING_ENCODING, encoding); DirectMapping lib = new DirectMapping(options); for (Class<?> cls : classes) { assertEquals("Wrong type mapper for direct mapping " + cls, mapper, Native.getTypeMapper(cls)); assertEquals("Wrong alignment for direct mapping " + cls, alignment, Native.getStructureAlignment(cls)); assertEquals("Wrong encoding for direct mapping " + cls, encoding, Native.getStringEncoding(cls)); Object last = Native.getLibraryOptions(cls); assertSame("Options not cached", last, Native.getLibraryOptions(cls)); } } public static class DirectMappingStatic { final static TypeMapper TEST_MAPPER = new DefaultTypeMapper(); final static int TEST_ALIGNMENT = Structure.ALIGN_DEFAULT; final static String TEST_ENCODING = System.getProperty("file.encoding"); final static Map<String, Object> TEST_OPTIONS = new HashMap<String, Object>() { private static final long serialVersionUID = 1L; // we're not serializing it { put(Library.OPTION_TYPE_MAPPER, TEST_MAPPER); put(Library.OPTION_STRUCTURE_ALIGNMENT, TEST_ALIGNMENT); put(Library.OPTION_STRING_ENCODING, TEST_ENCODING); } }; static { Native.register(DirectMappingStatic.class, NativeLibrary.getInstance("testlib", TEST_OPTIONS)); } public static class DirectStructure extends Structure { public int field; @Override protected List<String> getFieldOrder() { return Arrays.asList("field"); } } public static interface DirectCallback extends Callback { void invoke(); } } public void testGetOptionsForDirectMappingWithStaticInitializer() { Class<?>[] classes = { DirectMappingStatic.class, DirectMappingStatic.DirectStructure.class, DirectMappingStatic.DirectCallback.class, }; for (Class<?> cls : classes) { assertEquals("Wrong type mapper for direct mapping " + cls, DirectMappingStatic.TEST_MAPPER, Native.getTypeMapper(cls)); assertEquals("Wrong alignment for direct mapping " + cls, DirectMappingStatic.TEST_ALIGNMENT, Native.getStructureAlignment(cls)); assertEquals("Wrong encoding for direct mapping " + cls, DirectMappingStatic.TEST_ENCODING, Native.getStringEncoding(cls)); Object last = Native.getLibraryOptions(cls); assertSame("Options not cached", last, Native.getLibraryOptions(cls)); } } static class RemappedCLibrary { public static native int $$YJP$$strlen(String s); public static native int _prefixed_strlen(String s); } public void testDirectMappingFunctionMapper() { FunctionMapper MAPPER = new FunctionMapper() { @Override public String getFunctionName(NativeLibrary lib, Method method) { String name = method.getName(); if (name.startsWith("_prefixed_")) { return name.substring(10); } return name; } }; try { Native.register(RemappedCLibrary.class, NativeLibrary.getInstance(Platform.C_LIBRARY_NAME, Collections.singletonMap(Library.OPTION_FUNCTION_MAPPER, MAPPER))); final String VALUE = getName(); int len; len = RemappedCLibrary.$$YJP$$strlen(VALUE); assertEquals("Mismatched YJP strlen value", VALUE.length(), len); len = RemappedCLibrary._prefixed_strlen(VALUE); assertEquals("Mismatched prefixed strlen value", VALUE.length(), len); } catch(Exception e) { fail("Native method was not properly mapped: " + e); } } public static class PointerNativeMapped implements NativeMapped { String nativeMethodName; @Override public PointerNativeMapped fromNative(Object nativeValue, FromNativeContext context) { nativeMethodName = ((MethodResultContext)context).getMethod().getName(); return this; } @Override public Object toNative() { return null; } @Override public Class<?> nativeType() { return Pointer.class; } } public static class PointerTypeMapped { String nativeMethodName; } public static class FromNativeTests { static native PointerNativeMapped returnPointerArgument(PointerNativeMapped arg); static native PointerTypeMapped returnPointerArgument(PointerTypeMapped arg); } public void testDirectMappingFromNative() { DefaultTypeMapper mapper = new DefaultTypeMapper(); mapper.addTypeConverter(PointerTypeMapped.class, new TypeConverter() { @Override public PointerTypeMapped fromNative(Object nativeValue, FromNativeContext context) { PointerTypeMapped ret = new PointerTypeMapped(); ret.nativeMethodName = ((MethodResultContext)context).getMethod().getName(); return ret; } @Override public Object toNative(Object value, ToNativeContext context) { return null; } @Override public Class<?> nativeType() { return Pointer.class; } }); NativeLibrary lib = NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_TYPE_MAPPER, mapper)); Native.register(FromNativeTests.class, lib); assertEquals("Failed to access MethodResultContext", "returnPointerArgument", FromNativeTests.returnPointerArgument(new PointerNativeMapped()).nativeMethodName); assertEquals("Failed to access MethodResultContext", "returnPointerArgument", FromNativeTests.returnPointerArgument(new PointerTypeMapped()).nativeMethodName); } }