/* 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.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import junit.framework.TestCase;
//@SuppressWarnings("unused")
public class LastErrorTest extends TestCase {
private static final Map<String, ?> OPTIONS =
Collections.singletonMap(Library.OPTION_FUNCTION_MAPPER, new FunctionMapper() {
@Override
public String getFunctionName(NativeLibrary library, Method m) {
if (m.getName().equals("noThrowLastError")
|| m.getName().equals("throwLastError")) {
return "setLastError";
}
return m.getName();
}
});
public interface TestLibrary extends Library {
void setLastError(int code);
void noThrowLastError(int code);
void throwLastError(int code) throws LastErrorException;
}
public static class DirectTestLibrary implements TestLibrary {
@Override
public native void setLastError(int code);
@Override
public native void noThrowLastError(int code);
@Override
public native void throwLastError(int code) throws LastErrorException;
static {
Native.register(NativeLibrary.getInstance("testlib", OPTIONS));
}
}
public void testLastErrorPerThreadStorage() throws Exception {
final TestLibrary lib = Native.loadLibrary("testlib", TestLibrary.class);
final int NTHREADS = 100;
final int[] errors = new int[NTHREADS];
List<Thread> threads = new ArrayList<Thread>(NTHREADS);
for (int i=0;i < NTHREADS;i++) {
final int idx = i;
Thread t = new Thread("tLastErrorSetter-" + i) {
@Override
public void run() {
lib.setLastError(-idx-1);
errors[idx] = Native.getLastError();
}
};
t.setDaemon(true); // so we can stop the main thread if necessary
threads.add(t);
}
int EXPECTED = 42;
lib.setLastError(EXPECTED);
assertEquals("Wrong error on main thread (immediate)", EXPECTED, Native.getLastError());
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
t.join(TimeUnit.SECONDS.toMillis(7L));
assertFalse("Thread " + t.getName() + " still alive", t.isAlive());
}
assertEquals("Wrong error on main thread", EXPECTED, Native.getLastError());
for (int i=0;i < threads.size();i++) {
assertEquals("Wrong error on thread " + i, -i-1, errors[i]);
}
}
private final int ERROR = Platform.isWindows() ? 1 : -1;
public void testThrowLastError() {
TestLibrary lib = Native.loadLibrary("testlib", TestLibrary.class, OPTIONS);
lib.noThrowLastError(ERROR);
assertEquals("Last error not preserved", ERROR, Native.getLastError());
try {
lib.throwLastError(ERROR);
fail("Method should throw LastErrorException");
} catch(LastErrorException e) {
assertEquals("Exception should contain error code", ERROR, e.getErrorCode());
assertTrue("Exception should include error message: '" + e.getMessage() + "'", e.getMessage().length() > 0);
}
}
public void testThrowLastErrorDirect() {
TestLibrary lib = new DirectTestLibrary();
lib.noThrowLastError(ERROR);
assertEquals("Last error not preserved", ERROR, Native.getLastError());
try {
lib.throwLastError(ERROR);
fail("Method should throw LastErrorException");
} catch(LastErrorException e) {
assertEquals("Exception should contain error code", ERROR, e.getErrorCode());
assertTrue("Exception should include error message: " + e.getMessage(), e.getMessage().length() > 0);
}
}
public static void main(String[] args) {
junit.textui.TestRunner.run(LastErrorTest.class);
}
}