From 4e116ce35c1050ec3e76f08b2e6f69c7c51629c9 Mon Sep 17 00:00:00 2001 From: uniederer Date: Thu, 29 Nov 2012 17:10:26 +0000 Subject: [PATCH] - Reorganization of the build script to make it more portable - Removed the conditional code that decided whether to use JVM for unit tests or not - Changed the unit test code so the test code is now imported by using the DLL function - Introduced mechanisms to concentrate the loading of classes to specific methods instead of putting them into another function git-svn-id: https://svn.code.sf.net/p/libusbjava/code/trunk@301 94ad28fe-ef68-46b1-9651-e7ae4fcf1c4c --- LibusbJava/LibusbJava.cpp | 208 ++++++++++++++--- LibusbJava/build.xml | 350 +++++++++++++++-------------- LibusbJava/test/LibusbJavaTest.cpp | 53 +++-- LibusbJava/version.properties | 2 +- 4 files changed, 399 insertions(+), 214 deletions(-) diff --git a/LibusbJava/LibusbJava.cpp b/LibusbJava/LibusbJava.cpp index fa652a8..9688e8e 100644 --- a/LibusbJava/LibusbJava.cpp +++ b/LibusbJava/LibusbJava.cpp @@ -32,6 +32,8 @@ #ifdef DO_UNIT_TEST # include + +# define TEST_CASE(name) static void name(CuTest *tc) #endif #include @@ -77,6 +79,8 @@ static void LIBUSB_CALL fd_removed_callback(int fd, void *user_data); * Local helper functions * *******************************************************************************************/ +static __inline int ReferencesLoad(JNIEnv *env); +static __inline void ReferencesUnload(JNIEnv *env); static __inline jbyteArray JNICALL to_byteArray(JNIEnv *env, const void *data, size_t len); static __inline void JNICALL ThrowIfUnsuccessful(JNIEnv *env, int libusb_result); static __inline void JNICALL ThrowLibusbError(JNIEnv *env, jint code); @@ -134,16 +138,105 @@ static jfieldID usb_epDescFID_bLength, usb_epDescFID_bDescriptorType, static jfieldID usb_pollfdFID_fd, usb_pollfdFID_events; #ifdef DO_UNIT_TEST - #if TEST_USING_JVM - static struct TestContext - { - JNIEnv *env; - }test_context = { NULL }; + static struct TestContext + { + JNIEnv *env; + }test_context = { NULL }; - # define TEST_CONTEXT() JNIEnv *env = test_context.env - #endif + # define TEST_CONTEXT() JNIEnv *env = test_context.env #endif +/*! \brief Structure holding all the global information needed. */ +static struct { + struct { + int onLoadCalled; + int refs_loaded; + + struct { + struct { + jclass usb_devClazz; + }Usb_Device; + + struct { + jclass usb_devDescClazz; + }Usb_Device_Descriptor; + + struct { + jclass usb_confDescClazz; + }Usb_Config_Descriptor; + }objs; + }jni; +}info = { { 0 } }; + +/******************************************************************************************** + * + * Library Events + * + *******************************************************************************************/ + +/*! \brief The VM calls JNI_OnLoad when the native library is loaded (for example, through + * System.loadLibrary). + * + * \see http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html#JNI_OnLoad + * + * \return The JNI version needed by the native library (use constants as JNI_VERSION_X_Y). + */ +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + JNIEnv* env = NULL; + + info.jni.onLoadCalled = -1; + + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_1) != JNI_OK) { + return -1; + } + + ReferencesLoad(env); + + return JNI_VERSION_1_1; +} + +#if defined(DO_UNIT_TEST) + TEST_CASE(JNI_OnLoad_test) + { + TEST_CONTEXT(); + + CuAssert(tc, "correct initialization", info.jni.onLoadCalled == 0); + info.jni.onLoadCalled=10; + + /* Load the LibusbJava1 class to force the initialization of the library */ + jclass clazz = env->FindClass("ch/ntb/inf/libusbJava/LibusbJava1"); + CuAssert(tc, "ch/ntb/inf/libusbJava/LibusbJava1 loaded", clazz != NULL); + + CuAssert(tc, "JNI_OnLoad was executed", info.jni.onLoadCalled != 0); + env->DeleteLocalRef(clazz); + + /* As garbage collection is not necessarily run after freeing a reference + * and there is no way to force the run of GC, we can't test this here. */ +// CuAssert(tc, "JNI_OnUnload was executed", info.jni.onLoadCalled == 0); + } +#endif + +/*! \brief The VM calls JNI_OnUnload when the class loader containing the native library is + * garbage collected. + * + * This function can be used to perform cleanup operations. Because this function is + * called in an unknown context (such as from a finalizer), the programmer should be + * conservative on using Java VM services, and refrain from arbitrary Java call-backs. + * + * \see http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html#JNI_OnUnload + */ +void JNI_OnUnload(JavaVM *vm, void *reserved) +{ + JNIEnv* env = NULL; + + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_1) == JNI_OK) { + ReferencesUnload(env); + } + + info.jni.onLoadCalled = 0; +} + /******************************************************************************************** * * Methods @@ -182,10 +275,14 @@ JNIEXPORT jlong JNICALL Java_ch_ntb_inf_libusbJava_LibusbJava1_libusb_1init( JNI printf("context = %p\n", &context); #endif - if (!res) { + if (res != 0) + { + ThrowLibusbError(env, res); + return 0; + } + else + { return (jlong) context; - } else { - return (jlong) res; } } @@ -1828,6 +1925,26 @@ JNIEXPORT jstring JNICALL Java_ch_ntb_inf_libusbJava_LibusbJava1_libusb_1strerro return env->NewStringUTF(str); } +/* + * Class: ch_ntb_inf_libusbJava_LibusbJava1 + * Method: setup + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_ch_ntb_inf_libusbJava_LibusbJava1_setup(JNIEnv *env, jclass obj) +{ + return ReferencesLoad(env); +} + +/* + * Class: ch_ntb_inf_libusbJava_LibusbJava1 + * Method: teardown + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_ch_ntb_inf_libusbJava_LibusbJava1_teardown(JNIEnv *env, jclass obj) +{ + ReferencesUnload(env); +} + /* * Class: ch_ntb_inf_libusbJava_LibusbJava1 * Method: libusb_exceptionTest @@ -2001,36 +2118,67 @@ no_class: return; } -#ifdef DO_UNIT_TEST -# if TEST_USING_JVM - static void JVMTest(CuTest *tc) - { - TEST_CONTEXT(); +/*! \brief Loads all class References from the environment. + * + * \param env Pointer to an environment enabling access to the jvm + * + * \return + * - 0 if the references could be loaded successfully + * - <0 if an error occured + */ +static __inline int ReferencesLoad(JNIEnv *env) +{ + int result = -1; - ThrowLibusbError(env, -1); - CuAssert(tc, "LibusbError-Exception occured", env->ExceptionOccurred() != NULL); - env->ExceptionClear(); - } -# endif - - static void FailingTest(CuTest* tc) + if (info.jni.refs_loaded != 0) { - CuAssert(tc, "test should fail", 3 == 1 + 1); + info.jni.refs_loaded = -1; + } + else + { + result = 0; + } + + return result; + + return result; +} + +static __inline void ReferencesUnload(JNIEnv *env) +{ + if (info.jni.refs_loaded == 0) + return; +} + +#ifdef DO_UNIT_TEST + TEST_CASE(JVMTest) + { + TEST_CONTEXT(); + + ThrowLibusbError(env, -1); + jthrowable e = env->ExceptionOccurred(); + CuAssert(tc, "LibusbError-Exception occured", e != NULL); + env->ExceptionClear(); } #endif #ifdef DO_UNIT_TEST + typedef CuSuite* (*tSuiteNew)(void); + + extern "C" JNIEXPORT CuSuite* GetLibusbJavaSuite(tSuiteNew SuiteNew, JNIEnv *env); + /*! \brief Exports the test suite for the libraries helper functions * - * \test */ -CuSuite* CuGetLibusbJavaSuite(JNIEnv *env) + * \param SuiteNew Pointer to an allocator function for a CuTest instance + * \param env JNI Environment for the test + * + * \return A fully setup test suite. */ +JNIEXPORT CuSuite* GetLibusbJavaSuite(tSuiteNew SuiteNew, JNIEnv *env) { - CuSuite* suite = CuSuiteNew(); + CuSuite* suite = SuiteNew(); - SUITE_ADD_TEST(suite, FailingTest); -# if TEST_USING_JVM - SUITE_ADD_TEST(suite, JVMTest); -# endif + SUITE_ADD_TEST(suite, JNI_OnLoad_test); + SUITE_ADD_TEST(suite, JVMTest); test_context.env = env; return suite; diff --git a/LibusbJava/build.xml b/LibusbJava/build.xml index 7ddc2a5..56252f2 100644 --- a/LibusbJava/build.xml +++ b/LibusbJava/build.xml @@ -1,6 +1,6 @@ - - + Build file for libusbJava Shared Library - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LibusbJava/test/LibusbJavaTest.cpp b/LibusbJava/test/LibusbJavaTest.cpp index f8ed282..786bb9a 100644 --- a/LibusbJava/test/LibusbJavaTest.cpp +++ b/LibusbJava/test/LibusbJavaTest.cpp @@ -15,8 +15,6 @@ #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", @@ -66,7 +64,6 @@ int main(void) { int test_fail_count = -1; -#if TEST_USING_JVM jint result = -1; globals.jni.lib = JvmLibraryLoad(); @@ -98,11 +95,8 @@ int main(void) 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()) { @@ -122,27 +116,58 @@ end_no_CreateJavaVM: JvmLibraryFree(); end_no_jvm_lib: -#endif return test_fail_count; } +typedef CuSuite* (*tSuiteNew)(void); +typedef CuSuite* (*tGetDLLtests)(tSuiteNew SuiteNew, JNIEnv *env); + /*! \brief Executes all the tests * * \return Number of tests that failed */ static inline int RunAllTests(void) { - CuSuite *suite = CuGetLibusbJavaSuite(globals.thread_env); - CuString *output = CuStringNew(); + int result = 0; + tGetDLLtests getTestSuite = NULL; + tLibHandle libusb = LoadLibrary("LibusbJava-1_0.dll"); + + if (libusb == NULL) { + printf("Failed to load LibusbJava-1_0.dll: %lu", GetLastError()); + goto no_lib; + } + + getTestSuite = (tGetDLLtests)GetProcAddress(libusb, "GetLibusbJavaSuite"); + if (getTestSuite == NULL) + { + printf("Failed to get unit tests: %lu", GetLastError()); + goto no_suite_new; + } + + /* Run the test procedures */ + { + CuSuite *suite = getTestSuite(&CuSuiteNew, globals.thread_env); + CuString *output = CuStringNew(); - CuSuiteRun(suite); - CuSuiteSummary(suite, output); - CuSuiteDetails(suite, output); + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); - printf("%s\n", output->buffer); + printf("%s\n", output->buffer); - return suite->failCount; + result = suite->failCount; + } + + FreeLibrary(libusb); + + return result; + +no_suite_new: + FreeLibrary(libusb); + +no_lib: + return -1; } /*! \brief Creates a java virtual machine and places all the received handles into diff --git a/LibusbJava/version.properties b/LibusbJava/version.properties index 597ca4d..8d9f590 100644 --- a/LibusbJava/version.properties +++ b/LibusbJava/version.properties @@ -1,4 +1,4 @@ version.major=1 version.minor=0 -version.micro=0 +version.micro=1 version.nano=0 \ No newline at end of file