diff --git a/LibusbJava/.cproject b/LibusbJava/.cproject
index be2bb51..4c46a1f 100644
--- a/LibusbJava/.cproject
+++ b/LibusbJava/.cproject
@@ -42,6 +42,7 @@
@@ -54,7 +55,7 @@
-
@@ -111,7 +112,7 @@
-
@@ -134,7 +135,7 @@
-
diff --git a/LibusbJava/LibusbJava.cpp b/LibusbJava/LibusbJava.cpp
index 9dbab72..fa652a8 100644
--- a/LibusbJava/LibusbJava.cpp
+++ b/LibusbJava/LibusbJava.cpp
@@ -15,7 +15,8 @@
* (java.nio). As this class is made to store the start pointer to native buffers
* we could create a "ByteBuffer" of length 0 where the start address represents
* e.g. the handle. This can be done using the following JNI Call:
- * env->NewDirectByteBuffer(myPointer, 0); // size = 0, you don't want anyone to change it
+ * env->NewDirectByteBuffer(myPointer, 0); // size = 0, you don't want anyone to
+ * // change the data you are pointing to...
*/
/********************************************************************************************
@@ -29,6 +30,10 @@
#include
#include
+#ifdef DO_UNIT_TEST
+# include
+#endif
+
#include
#include "libusb.h"
@@ -128,6 +133,17 @@ static jfieldID usb_epDescFID_bLength, usb_epDescFID_bDescriptorType,
/*Libusb_pollfd*/
static jfieldID usb_pollfdFID_fd, usb_pollfdFID_events;
+#ifdef DO_UNIT_TEST
+ #if TEST_USING_JVM
+ static struct TestContext
+ {
+ JNIEnv *env;
+ }test_context = { NULL };
+
+ # define TEST_CONTEXT() JNIEnv *env = test_context.env
+ #endif
+#endif
+
/********************************************************************************************
*
* Methods
@@ -208,7 +224,8 @@ JNIEXPORT jobject JNICALL Java_ch_ntb_inf_libusbJava_LibusbJava1_libusb_1get_1de
/*usb_device*/
jobject devClazz = env->FindClass("ch/ntb/inf/libusbJava/Usb_Device");//returns a local reference
- usb_devClazz = (jclass)env->NewGlobalRef(devClazz);//make it global
+ usb_devClazz = (jclass)env->NewGlobalRef(devClazz); // make it global to avoid class unloading and therefore
+ // invalidating the references obtained.
if (usb_devClazz == NULL) {
return NULL; /* exception thrown */
}
@@ -1657,7 +1674,7 @@ JNIEXPORT jint JNICALL Java_ch_ntb_inf_libusbJava_LibusbJava1_libusb_1get_1next_
timeval tv;
/*! \todo Is this code working correctly if we use it in a 64-Bit environment? Actually
- * it's unlikely to have a timeout of more than 2^(31)-1 seconds. But it is a
+ * it's unlikely to have a timeout of more than 2^(31)-1 seconds. But still it is a
* possible value. */
res = libusb_get_next_timeout((libusb_context*) (unsigned long) ctx, &tv);
@@ -1983,3 +2000,39 @@ no_class:
return;
}
+
+#ifdef DO_UNIT_TEST
+# if TEST_USING_JVM
+ static void JVMTest(CuTest *tc)
+ {
+ TEST_CONTEXT();
+
+ ThrowLibusbError(env, -1);
+ CuAssert(tc, "LibusbError-Exception occured", env->ExceptionOccurred() != NULL);
+ env->ExceptionClear();
+ }
+# endif
+
+ static void FailingTest(CuTest* tc)
+ {
+ CuAssert(tc, "test should fail", 3 == 1 + 1);
+ }
+#endif
+
+#ifdef DO_UNIT_TEST
+/*! \brief Exports the test suite for the libraries helper functions
+ *
+ * \test */
+CuSuite* CuGetLibusbJavaSuite(JNIEnv *env)
+{
+ CuSuite* suite = CuSuiteNew();
+
+ SUITE_ADD_TEST(suite, FailingTest);
+# if TEST_USING_JVM
+ SUITE_ADD_TEST(suite, JVMTest);
+# endif
+
+ test_context.env = env;
+ return suite;
+}
+#endif
diff --git a/LibusbJava/build.xml b/LibusbJava/build.xml
index af2045a..7ddc2a5 100644
--- a/LibusbJava/build.xml
+++ b/LibusbJava/build.xml
@@ -16,12 +16,15 @@
-
+
+
-
+
+
+
@@ -33,9 +36,9 @@
-
+
-
+
@@ -43,14 +46,14 @@
-
+
-
+
-
+
@@ -63,15 +66,15 @@
-
+
-
+
-
+
@@ -84,15 +87,15 @@
-
+
-
+
-
+
@@ -108,14 +111,50 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -135,7 +174,7 @@
-
+
diff --git a/LibusbJava/test/CuTest.c b/LibusbJava/test/CuTest.c
new file mode 100644
index 0000000..8f61199
--- /dev/null
+++ b/LibusbJava/test/CuTest.c
@@ -0,0 +1,339 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "CuTest.h"
+
+/*-------------------------------------------------------------------------*
+ * CuStr
+ *-------------------------------------------------------------------------*/
+
+char* CuStrAlloc(int size)
+{
+ char* newStr = (char*) malloc( sizeof(char) * (size) );
+ return newStr;
+}
+
+char* CuStrCopy(const char* old)
+{
+ int len = strlen(old);
+ char* newStr = CuStrAlloc(len + 1);
+ strcpy(newStr, old);
+ return newStr;
+}
+
+/*-------------------------------------------------------------------------*
+ * CuString
+ *-------------------------------------------------------------------------*/
+
+void CuStringInit(CuString* str)
+{
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*) malloc(sizeof(char) * str->size);
+ str->buffer[0] = '\0';
+}
+
+CuString* CuStringNew(void)
+{
+ CuString* str = (CuString*) malloc(sizeof(CuString));
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*) malloc(sizeof(char) * str->size);
+ str->buffer[0] = '\0';
+ return str;
+}
+
+void CuStringDelete(CuString *str)
+{
+ if (!str) return;
+ free(str->buffer);
+ free(str);
+}
+
+void CuStringResize(CuString* str, int newSize)
+{
+ str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
+ str->size = newSize;
+}
+
+void CuStringAppend(CuString* str, const char* text)
+{
+ int length;
+
+ if (text == NULL) {
+ text = "NULL";
+ }
+
+ length = strlen(text);
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ str->length += length;
+ strcat(str->buffer, text);
+}
+
+void CuStringAppendChar(CuString* str, char ch)
+{
+ char text[2];
+ text[0] = ch;
+ text[1] = '\0';
+ CuStringAppend(str, text);
+}
+
+void CuStringAppendFormat(CuString* str, const char* format, ...)
+{
+ va_list argp;
+ char buf[HUGE_STRING_LEN];
+ va_start(argp, format);
+ vsprintf(buf, format, argp);
+ va_end(argp);
+ CuStringAppend(str, buf);
+}
+
+void CuStringInsert(CuString* str, const char* text, int pos)
+{
+ int length = strlen(text);
+ if (pos > str->length)
+ pos = str->length;
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
+ str->length += length;
+ memcpy(str->buffer + pos, text, length);
+}
+
+/*-------------------------------------------------------------------------*
+ * CuTest
+ *-------------------------------------------------------------------------*/
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function)
+{
+ t->name = CuStrCopy(name);
+ t->failed = 0;
+ t->ran = 0;
+ t->message = NULL;
+ t->function = function;
+ t->jumpBuf = NULL;
+}
+
+CuTest* CuTestNew(const char* name, TestFunction function)
+{
+ CuTest* tc = CU_ALLOC(CuTest);
+ CuTestInit(tc, name, function);
+ return tc;
+}
+
+void CuTestDelete(CuTest *t)
+{
+ if (!t) return;
+ free(t->name);
+ free(t);
+}
+
+void CuTestRun(CuTest* tc)
+{
+ jmp_buf buf;
+ tc->jumpBuf = &buf;
+ if (setjmp(buf) == 0)
+ {
+ tc->ran = 1;
+ (tc->function)(tc);
+ }
+ tc->jumpBuf = 0;
+}
+
+static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
+{
+ char buf[HUGE_STRING_LEN];
+
+ sprintf(buf, "%s:%d: ", file, line);
+ CuStringInsert(string, buf, 0);
+
+ tc->failed = 1;
+ tc->message = string->buffer;
+ if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
+}
+
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
+{
+ CuString string;
+
+ CuStringInit(&string);
+ if (message2 != NULL)
+ {
+ CuStringAppend(&string, message2);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, message);
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
+{
+ if (condition) return;
+ CuFail_Line(tc, file, line, NULL, message);
+}
+
+void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ const char* expected, const char* actual)
+{
+ CuString string;
+ if ((expected == NULL && actual == NULL) ||
+ (expected != NULL && actual != NULL &&
+ strcmp(expected, actual) == 0))
+ {
+ return;
+ }
+
+ CuStringInit(&string);
+ if (message != NULL)
+ {
+ CuStringAppend(&string, message);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, "expected <");
+ CuStringAppend(&string, expected);
+ CuStringAppend(&string, "> but was <");
+ CuStringAppend(&string, actual);
+ CuStringAppend(&string, ">");
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ int expected, int actual)
+{
+ char buf[STRING_MAX];
+ if (expected == actual) return;
+ sprintf(buf, "expected <%d> but was <%d>", expected, actual);
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ double expected, double actual, double delta)
+{
+ char buf[STRING_MAX];
+ if (fabs(expected - actual) <= delta) return;
+ sprintf(buf, "expected <%f> but was <%f>", expected, actual);
+
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ void* expected, void* actual)
+{
+ char buf[STRING_MAX];
+ if (expected == actual) return;
+ sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+
+/*-------------------------------------------------------------------------*
+ * CuSuite
+ *-------------------------------------------------------------------------*/
+
+void CuSuiteInit(CuSuite* testSuite)
+{
+ testSuite->count = 0;
+ testSuite->failCount = 0;
+ memset(testSuite->list, 0, sizeof(testSuite->list));
+}
+
+CuSuite* CuSuiteNew(void)
+{
+ CuSuite* testSuite = CU_ALLOC(CuSuite);
+ CuSuiteInit(testSuite);
+ return testSuite;
+}
+
+void CuSuiteDelete(CuSuite *testSuite)
+{
+ unsigned int n;
+ for (n=0; n < MAX_TEST_CASES; n++)
+ {
+ if (testSuite->list[n])
+ {
+ CuTestDelete(testSuite->list[n]);
+ }
+ }
+ free(testSuite);
+
+}
+
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
+{
+ assert(testSuite->count < MAX_TEST_CASES);
+ testSuite->list[testSuite->count] = testCase;
+ testSuite->count++;
+}
+
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
+{
+ int i;
+ for (i = 0 ; i < testSuite2->count ; ++i)
+ {
+ CuTest* testCase = testSuite2->list[i];
+ CuSuiteAdd(testSuite, testCase);
+ }
+}
+
+void CuSuiteRun(CuSuite* testSuite)
+{
+ int i;
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ CuTestRun(testCase);
+ if (testCase->failed) { testSuite->failCount += 1; }
+ }
+}
+
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary)
+{
+ int i;
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ CuStringAppend(summary, testCase->failed ? "F" : ".");
+ }
+ CuStringAppend(summary, "\n\n");
+}
+
+void CuSuiteDetails(CuSuite* testSuite, CuString* details)
+{
+ int i;
+ int failCount = 0;
+
+ if (testSuite->failCount == 0)
+ {
+ int passCount = testSuite->count - testSuite->failCount;
+ const char* testWord = passCount == 1 ? "test" : "tests";
+ CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
+ }
+ else
+ {
+ if (testSuite->failCount == 1)
+ CuStringAppend(details, "There was 1 failure:\n");
+ else
+ CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
+
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ if (testCase->failed)
+ {
+ failCount++;
+ CuStringAppendFormat(details, "%d) %s: %s\n",
+ failCount, testCase->name, testCase->message);
+ }
+ }
+ CuStringAppend(details, "\n!!!FAILURES!!!\n");
+
+ CuStringAppendFormat(details, "Runs: %d ", testSuite->count);
+ CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
+ CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount);
+ }
+}
diff --git a/LibusbJava/test/CuTest.h b/LibusbJava/test/CuTest.h
new file mode 100644
index 0000000..8b32773
--- /dev/null
+++ b/LibusbJava/test/CuTest.h
@@ -0,0 +1,116 @@
+#ifndef CU_TEST_H
+#define CU_TEST_H
+
+#include
+#include
+
+#define CUTEST_VERSION "CuTest 1.5"
+
+/* CuString */
+
+char* CuStrAlloc(int size);
+char* CuStrCopy(const char* old);
+
+#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE)))
+
+#define HUGE_STRING_LEN 8192
+#define STRING_MAX 256
+#define STRING_INC 256
+
+typedef struct
+{
+ int length;
+ int size;
+ char* buffer;
+} CuString;
+
+void CuStringInit(CuString* str);
+CuString* CuStringNew(void);
+void CuStringRead(CuString* str, const char* path);
+void CuStringAppend(CuString* str, const char* text);
+void CuStringAppendChar(CuString* str, char ch);
+void CuStringAppendFormat(CuString* str, const char* format, ...);
+void CuStringInsert(CuString* str, const char* text, int pos);
+void CuStringResize(CuString* str, int newSize);
+void CuStringDelete(CuString* str);
+
+/* CuTest */
+
+typedef struct CuTest CuTest;
+
+typedef void (*TestFunction)(CuTest *);
+
+struct CuTest
+{
+ char* name;
+ TestFunction function;
+ int failed;
+ int ran;
+ const char* message;
+ jmp_buf *jumpBuf;
+};
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function);
+CuTest* CuTestNew(const char* name, TestFunction function);
+void CuTestRun(CuTest* tc);
+void CuTestDelete(CuTest *t);
+
+/* Internal versions of assert functions -- use the public versions */
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message);
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition);
+void CuAssertStrEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ const char* expected, const char* actual);
+void CuAssertIntEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ int expected, int actual);
+void CuAssertDblEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ double expected, double actual, double delta);
+void CuAssertPtrEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ void* expected, void* actual);
+
+/* public assert functions */
+
+#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms))
+#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond))
+#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond))
+
+#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl))
+#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl))
+#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+
+#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL))
+#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL))
+
+/* CuSuite */
+
+#define MAX_TEST_CASES 1024
+
+#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST))
+
+typedef struct
+{
+ int count;
+ CuTest* list[MAX_TEST_CASES];
+ int failCount;
+
+} CuSuite;
+
+
+void CuSuiteInit(CuSuite* testSuite);
+CuSuite* CuSuiteNew(void);
+void CuSuiteDelete(CuSuite *testSuite);
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase);
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2);
+void CuSuiteRun(CuSuite* testSuite);
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary);
+void CuSuiteDetails(CuSuite* testSuite, CuString* details);
+
+#endif /* CU_TEST_H */
diff --git a/LibusbJava/test/LibusbJavaTest.cpp b/LibusbJava/test/LibusbJavaTest.cpp
new file mode 100644
index 0000000..4caaa4b
--- /dev/null
+++ b/LibusbJava/test/LibusbJavaTest.cpp
@@ -0,0 +1,234 @@
+#include
+#include
+
+#if defined(_WIN32) || defined(_WIN64)
+# include
+
+ typedef HINSTANCE tLibHandle;
+ typedef FARPROC tCallbackPtr;
+#else
+# error "Unit-Tests are not available on this platform"
+#endif
+
+#include "CuTest.h"
+
+#define PATH_SEPARATOR ';' /* define it to be ':' on Solaris */
+#define USER_CLASSPATH "../java/bin" /* where Prog.class is */
+
+extern CuSuite* CuGetLibusbJavaSuite(JNIEnv *env);
+
+const char *lib_paths[] = {
+#if defined(_WIN32) || defined(_WIN64)
+ "server\\jvm.dll",
+ "client\\jvm.dll",
+ "..\\jre\\bin\\server\\jvm.dll",
+ "..\\jre\\bin\\client\\jvm.dll",
+#else
+# error "Library names are unknown for this platform"
+#endif
+ NULL
+};
+
+/*! \brief Signature of the JNI call for creating a new VM */
+typedef jint (CALLBACK *tJavaVMcreate)(JavaVM** jvm, void** env, JavaVMInitArgs* args);
+
+/*! \brief Structure holding the data for the created JVM */
+typedef struct JVM {
+ JavaVM *jvm; /*!< Pointer to the JVM the tests run in */
+ JNIEnv *env; /*!< Pointer to the environment received while creating the
+ JVM */
+}tJVM;
+
+/*! \brief Contains Environment data for the test program */
+static struct
+{
+ struct {
+ tLibHandle lib; /*!< Contains the handle for the loaded JVM-Library */
+ tJavaVMcreate VMcreate; /*!< Holds the pointer to the call for creating a JVM
+ instance. */
+ }jni;
+
+ tJVM jvm; /*!< Contains the data for the created JVM used
+ for tests. */
+
+ JNIEnv* thread_env; /*!< Holds the pointer to the environment that can be
+ used for the tests. (after the thread has been
+ attached) */
+}globals = { { NULL, NULL }, { NULL, NULL }, NULL };
+
+static inline int CreateVM(tJVM *vmdata);
+static inline tCallbackPtr JvmLibraryFunctionGet(const char *name);
+static inline void JvmLibraryFree(void);
+static inline tLibHandle JvmLibraryLoad(void);
+static inline long int JvmLibraryLastErrorGet(void);
+static inline int RunAllTests(void);
+
+int main(void)
+{
+ int test_fail_count = -1;
+
+#if TEST_USING_JVM
+ jint result = -1;
+
+ globals.jni.lib = JvmLibraryLoad();
+ if (globals.jni.lib == NULL)
+ {
+ fprintf(stderr, "Error loading library (%ld)\n", JvmLibraryLastErrorGet());
+ goto end_no_jvm_lib;
+ }
+
+ // get the address of the JNI call to create the VM from the loaded library.
+ globals.jni.VMcreate = (tJavaVMcreate)JvmLibraryFunctionGet("JNI_CreateJavaVM");
+ if (globals.jni.VMcreate == NULL)
+ {
+ fprintf(stderr, "Error getting JNI_CreateJavaVM (%ld)", JvmLibraryLastErrorGet());
+ goto end_no_CreateJavaVM;
+ }
+
+ // Create the VM the tests should be done within
+ result = CreateVM(&globals.jvm);
+ if (result < 0) {
+ fprintf(stderr, "Can't create Java VM (%ld)\n", result);
+ goto end_no_java_vm;
+ }
+
+ // In order to be able to interact with the VM we have to attach our thread to the VM
+ result = globals.jvm.jvm->AttachCurrentThread((void**)&globals.thread_env, NULL);
+ if (result < 0) {
+ fprintf(stderr, "Can't attach thread to Java VM (%ld)\n", result);
+ goto end_no_attach;
+ }
+
+#endif
+
+ test_fail_count = RunAllTests();
+
+#if TEST_USING_JVM
+ /* Check if there is still a pending exception. Usually all the tests should clear the
+ * exceptions if any have been expected. If this is not the case something went wrong... */
+ if (globals.jvm.env->ExceptionOccurred()) {
+ globals.jvm.env->ExceptionDescribe();
+ test_fail_count++;
+ }
+
+ /* After cleaning up the java environment we can safely detach our thread from the JVM */
+ globals.jvm.jvm->DetachCurrentThread();
+
+end_no_attach:
+ globals.jvm.jvm->DestroyJavaVM();
+
+end_no_java_vm:
+end_no_CreateJavaVM:
+ /* Unload the JNI Library */
+ JvmLibraryFree();
+
+end_no_jvm_lib:
+#endif
+ return test_fail_count;
+
+}
+
+/*! \brief Executes all the tests and returns the number of failed tests */
+static int RunAllTests(void)
+{
+ CuSuite *suite = CuGetLibusbJavaSuite(globals.thread_env);
+ CuString *output = CuStringNew();
+
+
+ CuSuiteRun(suite);
+ CuSuiteSummary(suite, output);
+ CuSuiteDetails(suite, output);
+
+ printf("%s\n", output->buffer);
+
+ return suite->failCount;
+}
+
+/*! \brief Creates a java virtual machine and places all the received handles into
+ * the given structure
+ *
+ * \param vmdata Pointer to the structure that should hold all the handles
+ * of the VM created.
+ *
+ * \return
+ * - JNI_OK on success
+ * - <0 on failure (see jni.h)
+ */
+static inline int CreateVM(tJVM *vmdata)
+{
+ JavaVMInitArgs vm_args;
+ JavaVMOption options[1];
+
+ options[0].optionString = "-Djava.class.path=" USER_CLASSPATH;
+ vm_args.version = JNI_VERSION_1_2;
+ vm_args.options = options;
+ vm_args.nOptions = 1;
+ vm_args.ignoreUnrecognized = JNI_TRUE;
+
+ /* Create the Java VM for unit tests */
+ return globals.jni.VMcreate(&vmdata->jvm, (void**) &vmdata->env, &vm_args);
+}
+
+/*! \brief Searches and tries to load the JVM library
+ *
+ * As there are some issues to find the appropriate library in the given path
+ * this function searches a several options for loading a library.
+ *
+ * \return
+ * - Handle for the loaded library
+ * - NULL if the library could not be loaded. Use GetLastError() to determine
+ * the reason.
+ */
+static tLibHandle JvmLibraryLoad(void)
+{
+ unsigned int pos = 0;
+ tLibHandle result = NULL;
+
+ while ((result == NULL) && (lib_paths[pos] != NULL))
+ {
+#if defined(_WIN32) || defined(_WIN64)
+ result = LoadLibrary(lib_paths[pos++]);
+#else
+# error "Unable to load the jvm library for this platform"
+#endif
+ }
+
+ return result;
+}
+
+/*! \brief Wrapper for freeing a loaded JVM library */
+static void JvmLibraryFree(void)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ FreeLibrary(globals.jni.lib);
+#else
+# error "Unable to unload the jvm library for this platform"
+#endif
+}
+
+/*! \brief Wrapper for getting a specific function pointer from the loaded JVM library
+ *
+ * \param name Name of the function to be retrieved.
+ *
+ * \return Function pointer to the given function or NULL if the function could not be found
+ */
+static tCallbackPtr JvmLibraryFunctionGet(const char *name)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ return GetProcAddress(globals.jni.lib, name);
+#else
+# error "Unable to get library function pointer for this platform"
+#endif
+}
+
+/*! \brief Wrapper for getting the reason why the last JvmLibrary*-Call failed
+ *
+ * \return Errorcode describing the error that happened. */
+static inline long int JvmLibraryLastErrorGet(void)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ return GetLastError();
+#else
+# error "Unable to determine last error for this platform"
+#endif
+}