From 537d6901c3860cd5c51862db6412b8bf1d1b5b68 Mon Sep 17 00:00:00 2001 From: uniederer Date: Wed, 9 May 2012 06:35:49 +0000 Subject: [PATCH] - Added unit test facilities for the dll git-svn-id: https://svn.code.sf.net/p/libusbjava/code/trunk@298 94ad28fe-ef68-46b1-9651-e7ae4fcf1c4c --- LibusbJava/.cproject | 7 +- LibusbJava/LibusbJava.cpp | 59 ++++- LibusbJava/build.xml | 71 ++++-- LibusbJava/test/CuTest.c | 339 +++++++++++++++++++++++++++++ LibusbJava/test/CuTest.h | 116 ++++++++++ LibusbJava/test/LibusbJavaTest.cpp | 234 ++++++++++++++++++++ 6 files changed, 804 insertions(+), 22 deletions(-) create mode 100644 LibusbJava/test/CuTest.c create mode 100644 LibusbJava/test/CuTest.h create mode 100644 LibusbJava/test/LibusbJavaTest.cpp 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 +}