/* Copyright (c) 2007 Timothy Wall, 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.
*
* 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.io.File;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.List;
import junit.framework.TestCase;
public class NativeLibraryTest extends TestCase {
public static interface TestLibrary extends Library {
int callCount();
}
public void testGCNativeLibrary() throws Exception {
NativeLibrary lib = NativeLibrary.getInstance("testlib");
WeakReference ref = new WeakReference(lib);
lib = null;
System.gc();
long start = System.currentTimeMillis();
while (ref.get() != null) {
Thread.sleep(10);
if (System.currentTimeMillis() - start > 5000)
break;
}
assertNull("Library not GC'd", ref.get());
}
public void testAvoidDuplicateLoads() {
TestLibrary lib = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class);
assertEquals("Library should be loaded exactly once",
1, lib.callCount());
assertEquals("Library should not be reloaded",
2, lib.callCount());
}
public void testUseSingleLibraryInstance() {
TestLibrary lib = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class);
int count = lib.callCount();
TestLibrary lib2 = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class);
int count2 = lib2.callCount();
assertEquals("Interfaces should share a library instance",
count + 1, count2);
}
public void testAliasLibraryFilename() {
TestLibrary lib = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class);
int count = lib.callCount();
NativeLibrary nl = NativeLibrary.getInstance("testlib");
TestLibrary lib2 = (TestLibrary)Native.loadLibrary(nl.getFile().getName(), TestLibrary.class);
int count2 = lib2.callCount();
assertEquals("Simple filename load not aliased", count + 1, count2);
}
public void testAliasLibraryFullPath() {
TestLibrary lib = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class);
int count = lib.callCount();
NativeLibrary nl = NativeLibrary.getInstance("testlib");
TestLibrary lib2 = (TestLibrary)Native.loadLibrary(nl.getFile().getAbsolutePath(), TestLibrary.class);
int count2 = lib2.callCount();
assertEquals("Full pathname load not aliased", count + 1, count2);
}
public void testAliasSimpleLibraryName() throws Exception {
NativeLibrary nl = NativeLibrary.getInstance("testlib");
File file = nl.getFile();
WeakReference ref = new WeakReference(nl);
nl = null;
System.gc();
long start = System.currentTimeMillis();
while (ref.get() != null) {
Thread.sleep(10);
if (System.currentTimeMillis() - start > 5000)
fail("Timed out waiting for library to be GC'd");
}
TestLibrary lib = (TestLibrary)Native.loadLibrary(file.getAbsolutePath(), TestLibrary.class);
int count = lib.callCount();
TestLibrary lib2 = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class);
int count2 = lib2.callCount();
assertEquals("Simple library name not aliased", count + 1, count2);
}
public void testFunctionHoldsLibraryReference() throws Exception {
NativeLibrary lib = NativeLibrary.getInstance("testlib");
WeakReference ref = new WeakReference(lib);
Function f = lib.getFunction("callCount");
lib = null;
System.gc();
long start = System.currentTimeMillis();
while (ref.get() != null && System.currentTimeMillis() - start < 2000) {
Thread.sleep(10);
}
assertNotNull("Library GC'd when it should not be", ref.get());
f.invokeInt(new Object[0]);
f = null;
System.gc();
while (ref.get() != null && System.currentTimeMillis() - start < 5000) {
Thread.sleep(10);
}
assertNull("Library not GC'd", ref.get());
}
public void testLoadFrameworkLibrary() {
if (Platform.isMac()) {
try {
NativeLibrary lib = NativeLibrary.getInstance("CoreServices");
assertNotNull("CoreServices not found", lib);
}
catch(UnsatisfiedLinkError e) {
fail("Should search /System/Library/Frameworks");
}
}
}
public void testLookupGlobalVariable() {
NativeLibrary lib = NativeLibrary.getInstance("testlib");
Pointer global = lib.getGlobalVariableAddress("test_global");
assertNotNull("Test variable not found", global);
final int MAGIC = 0x12345678;
assertEquals("Wrong value for library global variable", MAGIC, global.getInt(0));
global.setInt(0, MAGIC+1);
assertEquals("Library global variable not updated", MAGIC+1, global.getInt(0));
}
public void testMatchUnversionedToVersioned() throws Exception {
File lib0 = File.createTempFile("lib", ".so.0");
File dir = lib0.getParentFile();
String name = lib0.getName();
name = name.substring(3, name.indexOf(".so"));
lib0.deleteOnExit();
File lib1 = new File(dir, "lib" + name + ".so.1.0");
lib1.createNewFile();
lib1.deleteOnExit();
File lib1_1 = new File(dir, "lib" + name + ".so.1.1");
lib1_1.createNewFile();
lib1_1.deleteOnExit();
List path = Arrays.asList(new String[] { dir.getAbsolutePath() });
assertEquals("Latest versioned library not found when unversioned requested",
lib1_1.getAbsolutePath(),
NativeLibrary.matchLibrary(name, path));
}
public void testAvoidFalseMatch() throws Exception {
File lib0 = File.createTempFile("lib", ".so.1");
File dir = lib0.getParentFile();
lib0.deleteOnExit();
String name = lib0.getName();
name = name.substring(3, name.indexOf(".so"));
File lib1 = new File(dir, "lib" + name + "-client.so.2");
lib1.createNewFile();
lib1.deleteOnExit();
List path = Arrays.asList(new String[] { dir.getAbsolutePath() });
assertEquals("Library with similar prefix should be ignored",
lib0.getAbsolutePath(),
NativeLibrary.matchLibrary(name, path));
}
public void testParseVersion() throws Exception {
String[] VERSIONS = {
"1",
"1.2",
"1.2.3",
"1.2.3.4",
};
double[] EXPECTED = {
1, 1.02, 1.0203, 1.020304,
};
for (int i=0;i < VERSIONS.length;i++) {
assertEquals("Badly parsed version", EXPECTED[i], NativeLibrary.parseVersion(VERSIONS[i]), 0.0000001);
}
}
public void testGetProcess() {
NativeLibrary process = NativeLibrary.getProcess();
// Access a common C library function
process.getFunction("printf");
}
public static void main(String[] args) {
junit.textui.TestRunner.run(NativeLibraryTest.class);
}
}