static NOINLINE const char* _expand_environment( hash_t key, char* var ) { if( key == HASH_EXECUTABLE_NAME ) return environment_executable_name(); else if( key == HASH_EXECUTABLE_DIRECTORY ) return environment_executable_directory(); else if( key == HASH_EXECUTABLE_PATH ) return environment_executable_path(); else if( key == HASH_INITIAL_WORKING_DIRECTORY ) return environment_initial_working_directory(); else if( key == HASH_CURRENT_WORKING_DIRECTORY ) return environment_current_working_directory(); else if( key == HASH_HOME_DIRECTORY ) return environment_home_directory(); else if( key == HASH_TEMPORARY_DIRECTORY ) return environment_temporary_directory(); else if( string_equal_substr( var, "variable[", 9 ) ) //variable[varname] - Environment variable named "varname" { const char* value; unsigned int end_pos = string_find( var, ']', 9 ); if( end_pos != STRING_NPOS ) var[end_pos] = 0; value = environment_variable( var ); if( end_pos != STRING_NPOS ) var[end_pos] = ']'; return value; } return ""; }
int main_run(void* main_arg) { #if !BUILD_MONOLITHIC string_const_t pattern; string_t* exe_paths = 0; size_t iexe, exesize; process_t* process = 0; string_t process_path = { 0, 0 }; unsigned int* exe_flags = 0; #else void* test_result; #endif #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL int remain_counter = 0; #endif #if BUILD_DEBUG const string_const_t build_name = string_const(STRING_CONST("debug")); #elif BUILD_RELEASE const string_const_t build_name = string_const(STRING_CONST("release")); #elif BUILD_PROFILE const string_const_t build_name = string_const(STRING_CONST("profile")); #elif BUILD_DEPLOY const string_const_t build_name = string_const(STRING_CONST("deploy")); #endif #if BUILD_MONOLITHIC const string_const_t build_type = string_const(STRING_CONST(" monolithic")); #else const string_const_t build_type = string_empty(); #endif char* pathbuf; int process_result = 0; thread_t event_thread; FOUNDATION_UNUSED(main_arg); FOUNDATION_UNUSED(build_name); log_set_suppress(HASH_TEST, ERRORLEVEL_DEBUG); log_infof(HASH_TEST, STRING_CONST("Task library v%s built for %s using %s (%.*s%.*s)"), string_from_version_static(task_module_version()).str, FOUNDATION_PLATFORM_DESCRIPTION, FOUNDATION_COMPILER_DESCRIPTION, STRING_FORMAT(build_name), STRING_FORMAT(build_type)); thread_initialize(&event_thread, event_loop, 0, STRING_CONST("event_thread"), THREAD_PRIORITY_NORMAL, 0); thread_start(&event_thread); pathbuf = memory_allocate(HASH_STRING, BUILD_MAX_PATHLEN, 0, MEMORY_PERSISTENT); while (!thread_is_running(&event_thread)) thread_sleep(10); #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL while (!_test_should_start) { #if FOUNDATION_PLATFORM_ANDROID system_process_events(); #endif thread_sleep(100); } #endif fs_remove_directory(STRING_ARGS(environment_temporary_directory())); #if BUILD_MONOLITHIC test_run_fn tests[] = { test_task_run, 0 }; #if FOUNDATION_PLATFORM_ANDROID thread_t test_thread; thread_initialize(&test_thread, test_runner, tests, STRING_CONST("test_runner"), THREAD_PRIORITY_NORMAL, 0); thread_start(&test_thread); log_debug(HASH_TEST, STRING_CONST("Starting test runner thread")); while (!thread_is_running(&test_thread)) { system_process_events(); thread_sleep(10); } while (thread_is_running(&test_thread)) { system_process_events(); thread_sleep(10); } test_result = thread_join(&test_thread); process_result = (int)(intptr_t)test_result; thread_finalize(&test_thread); #else test_result = test_runner(tests); process_result = (int)(intptr_t)test_result; #endif if (process_result != 0) log_warnf(HASH_TEST, WARNING_SUSPICIOUS, STRING_CONST("Tests failed with exit code %d"), process_result); #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL while (!_test_should_terminate && _test_have_focus && (remain_counter < 50)) { system_process_events(); thread_sleep(100); ++remain_counter; } #endif log_debug(HASH_TEST, STRING_CONST("Exiting main loop")); #else // !BUILD_MONOLITHIC //Find all test executables in the current executable directory #if FOUNDATION_PLATFORM_WINDOWS pattern = string_const(STRING_CONST("^test-.*\\.exe$")); #elif FOUNDATION_PLATFORM_MACOSX pattern = string_const(STRING_CONST("^test-.*$")); #elif FOUNDATION_PLATFORM_POSIX pattern = string_const(STRING_CONST("^test-.*$")); #else # error Not implemented #endif exe_paths = fs_matching_files(STRING_ARGS(environment_executable_directory()), STRING_ARGS(pattern), false); array_resize(exe_flags, array_size(exe_paths)); memset(exe_flags, 0, sizeof(unsigned int) * array_size(exe_flags)); #if FOUNDATION_PLATFORM_MACOSX //Also search for test applications string_const_t app_pattern = string_const(STRING_CONST("^test-.*\\.app$")); regex_t* app_regex = regex_compile(app_pattern.str, app_pattern.length); string_t* subdirs = fs_subdirs(STRING_ARGS(environment_executable_directory())); for (size_t idir = 0, dirsize = array_size(subdirs); idir < dirsize; ++idir) { if (regex_match(app_regex, subdirs[idir].str, subdirs[idir].length, 0, 0)) { string_t exe_path = { subdirs[idir].str, subdirs[idir].length - 4 }; array_push(exe_paths, exe_path); array_push(exe_flags, PROCESS_MACOSX_USE_OPENAPPLICATION); } } string_array_deallocate(subdirs); regex_deallocate(app_regex); #endif for (iexe = 0, exesize = array_size(exe_paths); iexe < exesize; ++iexe) { string_const_t* process_args = 0; string_const_t exe_file_name = path_base_file_name(STRING_ARGS(exe_paths[iexe])); if (string_equal(STRING_ARGS(exe_file_name), STRING_ARGS(environment_executable_name()))) continue; //Don't run self process_path = path_concat(pathbuf, BUILD_MAX_PATHLEN, STRING_ARGS(environment_executable_directory()), STRING_ARGS(exe_paths[iexe])); process = process_allocate(); process_set_executable_path(process, STRING_ARGS(process_path)); process_set_working_directory(process, STRING_ARGS(environment_executable_directory())); process_set_flags(process, PROCESS_ATTACHED | exe_flags[iexe]); if (!_test_memory_tracker) array_push(process_args, string_const(STRING_CONST("--no-memory-tracker"))); process_set_arguments(process, process_args, array_size(process_args)); log_infof(HASH_TEST, STRING_CONST("Running test executable: %.*s"), STRING_FORMAT(exe_paths[iexe])); process_result = process_spawn(process); while (process_result == PROCESS_WAIT_INTERRUPTED) { thread_sleep(10); process_result = process_wait(process); } process_deallocate(process); array_deallocate(process_args); if (process_result != 0) { if (process_result >= PROCESS_INVALID_ARGS) log_warnf(HASH_TEST, WARNING_SUSPICIOUS, STRING_CONST("Tests failed, process terminated with error %x"), process_result); else log_warnf(HASH_TEST, WARNING_SUSPICIOUS, STRING_CONST("Tests failed with exit code %d"), process_result); process_set_exit_code(-1); goto exit; } log_infof(HASH_TEST, STRING_CONST("All tests from %.*s passed (%d)"), STRING_FORMAT(exe_paths[iexe]), process_result); } log_info(HASH_TEST, STRING_CONST("All tests passed")); exit: if (exe_paths) string_array_deallocate(exe_paths); array_deallocate(exe_flags); #endif _test_should_terminate = true; thread_signal(&event_thread); thread_finalize(&event_thread); memory_deallocate(pathbuf); log_infof(HASH_TEST, STRING_CONST("Tests exiting: %s (%d)"), process_result ? "FAILED" : "PASSED", process_result); if (process_result) memory_set_tracker(memory_tracker_none()); return process_result; }
int main_run( void* main_arg ) { #if !BUILD_MONOLITHIC const char* pattern = 0; char** exe_paths = 0; unsigned int iexe, exesize; process_t* process = 0; char* process_path = 0; unsigned int* exe_flags = 0; #endif #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL int remain_counter = 0; #endif #if BUILD_DEBUG const char* build_name = "debug"; #elif BUILD_RELEASE const char* build_name = "release"; #elif BUILD_PROFILE const char* build_name = "profile"; #elif BUILD_DEPLOY const char* build_name = "deploy"; #endif int process_result = 0; object_t thread = 0; FOUNDATION_UNUSED( main_arg ); FOUNDATION_UNUSED( build_name ); log_set_suppress( HASH_TEST, ERRORLEVEL_DEBUG ); log_infof( HASH_TEST, "Foundation library v%s built for %s using %s (%s)", string_from_version_static( foundation_version() ), FOUNDATION_PLATFORM_DESCRIPTION, FOUNDATION_COMPILER_DESCRIPTION, build_name ); thread = thread_create( event_thread, "event_thread", THREAD_PRIORITY_NORMAL, 0 ); thread_start( thread, 0 ); while( !thread_is_running( thread ) ) thread_sleep( 10 ); #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID while( !_test_should_start ) { #if FOUNDATION_PLATFORM_ANDROID system_process_events(); #endif thread_sleep( 100 ); } #endif fs_remove_directory( environment_temporary_directory() ); #if BUILD_MONOLITHIC test_run_fn tests[] = { test_app_run, test_array_run, test_atomic_run, test_base64_run, test_bitbuffer_run, test_blowfish_run, test_bufferstream_run, test_config_run, test_crash_run, test_environment_run, test_error_run, test_event_run, test_fs_run, test_hash_run, test_hashmap_run, test_hashtable_run, test_library_run, test_math_run, test_md5_run, test_mutex_run, test_objectmap_run, test_path_run, test_pipe_run, test_process_run, test_profile_run, test_radixsort_run, test_random_run, test_regex_run, test_ringbuffer_run, test_semaphore_run, test_stacktrace_run, test_stream_run, //stream test closes stdin test_string_run, test_system_run, test_time_run, test_uuid_run, 0 }; #if FOUNDATION_PLATFORM_ANDROID object_t test_thread = thread_create( test_runner, "test_runner", THREAD_PRIORITY_NORMAL, 0 ); thread_start( test_thread, tests ); log_debug( HASH_TEST, "Starting test runner thread" ); while( !thread_is_running( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } while( thread_is_running( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } process_result = (int)(intptr_t)thread_result( test_thread ); thread_destroy( test_thread ); while( thread_is_thread( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } #else process_result = (int)(intptr_t)test_runner( 0, tests ); #endif if( process_result != 0 ) log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL while( !_test_should_terminate && _test_have_focus && ( remain_counter < 50 ) ) { system_process_events(); thread_sleep( 100 ); ++remain_counter; } #endif log_debug( HASH_TEST, "Exiting main loop" ); #else // !BUILD_MONOLITHIC //Find all test executables in the current executable directory #if FOUNDATION_PLATFORM_WINDOWS pattern = "^test-.*\\.exe$"; #elif FOUNDATION_PLATFORM_MACOSX pattern = "^test-.*$"; #elif FOUNDATION_PLATFORM_POSIX pattern = "^test-.*$"; #else # error Not implemented #endif exe_paths = fs_matching_files( environment_executable_directory(), pattern, false ); array_resize( exe_flags, array_size( exe_paths ) ); memset( exe_flags, 0, sizeof( unsigned int ) * array_size( exe_flags ) ); #if FOUNDATION_PLATFORM_MACOSX //Also search for test applications const char* app_pattern = "^test-.*\\.app$"; regex_t* app_regex = regex_compile( app_pattern ); char** subdirs = fs_subdirs( environment_executable_directory() ); for( int idir = 0, dirsize = array_size( subdirs ); idir < dirsize; ++idir ) { if( regex_match( app_regex, subdirs[idir], string_length( subdirs[idir] ), 0, 0 ) ) { array_push( exe_paths, string_substr( subdirs[idir], 0, string_length( subdirs[idir] ) - 4 ) ); array_push( exe_flags, PROCESS_MACOSX_USE_OPENAPPLICATION ); } } string_array_deallocate( subdirs ); regex_deallocate( app_regex ); #endif for( iexe = 0, exesize = array_size( exe_paths ); iexe < exesize; ++iexe ) { bool is_self = false; char* exe_file_name = path_base_file_name( exe_paths[iexe] ); if( string_equal( exe_file_name, environment_executable_name() ) ) is_self = true; string_deallocate( exe_file_name ); if( is_self ) continue; //Don't run self process_path = path_merge( environment_executable_directory(), exe_paths[iexe] ); process = process_allocate(); process_set_executable_path( process, process_path ); process_set_working_directory( process, environment_executable_directory() ); process_set_flags( process, PROCESS_ATTACHED | exe_flags[iexe] ); log_infof( HASH_TEST, "Running test executable: %s", exe_paths[iexe] ); process_result = process_spawn( process ); while( process_result == PROCESS_WAIT_INTERRUPTED ) { thread_sleep( 10 ); process_result = process_wait( process ); } process_deallocate( process ); string_deallocate( process_path ); if( process_result != 0 ) { if( process_result >= PROCESS_INVALID_ARGS ) log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed, process terminated with error %x", process_result ); else log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); process_set_exit_code( -1 ); goto exit; } log_infof( HASH_TEST, "All tests from %s passed (%d)", exe_paths[iexe], process_result ); } log_info( HASH_TEST, "All tests passed" ); exit: if( exe_paths ) string_array_deallocate( exe_paths ); array_deallocate( exe_flags ); #endif thread_terminate( thread ); thread_destroy( thread ); while( thread_is_running( thread ) ) thread_sleep( 10 ); while( thread_is_thread( thread ) ) thread_sleep( 10 ); log_infof( HASH_TEST, "Tests exiting: %d", process_result ); return process_result; }
void config_load( const char* name, hash_t filter_section, bool built_in, bool overwrite ) { /*lint --e{838} Safety null assign all pointers for all preprocessor paths */ /*lint --e{750} Unused macros in some paths */ #define NUM_SEARCH_PATHS 10 #define ANDROID_ASSET_PATH_INDEX 5 char* sub_exe_path = 0; char* exe_parent_path = 0; char* exe_processed_path = 0; char* abs_exe_parent_path = 0; char* abs_exe_processed_path = 0; char* bundle_path = 0; char* home_dir = 0; char* cmdline_path = 0; char* cwd_config_path = 0; const char* paths[NUM_SEARCH_PATHS]; #if !FOUNDATION_PLATFORM_FAMILY_MOBILE const char* const* cmd_line; int icl, clsize; #endif int start_path, i, j; const char buildsuffix[4][9] = { "/debug", "/release", "/profile", "/deploy" }; const char platformsuffix[7][14] = { "/win32", "/win64", "/osx", "/ios", "/android", "/raspberrypi", "/unknown" }; const char binsuffix[1][5] = { "/bin" }; FOUNDATION_ASSERT( name ); sub_exe_path = path_merge( environment_executable_directory(), "config" ); exe_parent_path = path_merge( environment_executable_directory(), "../config" ); abs_exe_parent_path = path_make_absolute( exe_parent_path ); exe_processed_path = string_clone( environment_executable_directory() ); for( i = 0; i < 4; ++i ) { if( string_ends_with( exe_processed_path, buildsuffix[i] ) ) { exe_processed_path[ string_length( exe_processed_path ) - string_length( buildsuffix[i] ) ] = 0; break; } } for( i = 0; i < 7; ++i ) { if( string_ends_with( exe_processed_path, platformsuffix[i] ) ) { exe_processed_path[ string_length( exe_processed_path ) - string_length( platformsuffix[i] ) ] = 0; break; } } for( i = 0; i < 1; ++i ) { if( string_ends_with( exe_processed_path, binsuffix[i] ) ) { exe_processed_path[ string_length( exe_processed_path ) - string_length( binsuffix[i] ) ] = 0; break; } } exe_processed_path = path_append( exe_processed_path, "config" ); abs_exe_processed_path = path_make_absolute( exe_processed_path ); paths[0] = environment_executable_directory(); paths[1] = sub_exe_path; paths[2] = abs_exe_parent_path; paths[3] = abs_exe_processed_path; #if FOUNDATION_PLATFORM_FAMILY_DESKTOP && !BUILD_DEPLOY paths[4] = environment_initial_working_directory(); #else paths[4] = 0; #endif #if FOUNDATION_PLATFORM_APPLE bundle_path = path_merge( environment_executable_directory(), "../Resources/config" ); paths[5] = bundle_path; #elif FOUNDATION_PLATFORM_ANDROID paths[5] = "/config"; #else paths[5] = 0; #endif #if FOUNDATION_PLATFORM_FAMILY_DESKTOP paths[6] = environment_current_working_directory(); #else paths[6] = 0; #endif paths[7] = 0; paths[8] = 0; string_deallocate( exe_parent_path ); string_deallocate( exe_processed_path ); #if FOUNDATION_PLATFORM_FAMILY_DESKTOP cwd_config_path = path_merge( environment_current_working_directory(), "config" ); paths[7] = cwd_config_path; cmd_line = environment_command_line(); /*lint -e{850} We modify loop var to skip extra arg */ for( icl = 0, clsize = array_size( cmd_line ); icl < clsize; ++icl ) { /*lint -e{613} array_size( cmd_line ) in loop condition does the null pointer guard */ if( string_equal_substr( cmd_line[icl], "--configdir", 11 ) ) { if( string_equal_substr( cmd_line[icl], "--configdir=", 12 ) ) { paths[8] = cmdline_path = string_substr( cmd_line[icl], 12, STRING_NPOS ); } else if( icl < ( clsize - 1 ) ) { paths[8] = cmdline_path = string_clone( cmd_line[++icl] ); } } } #endif start_path = 0; if( !built_in ) { #if FOUNDATION_PLATFORM_WINDOWS home_dir = path_merge( environment_home_directory(), environment_application()->config_dir ); #elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_MACOSX home_dir = path_prepend( string_concat( ".", environment_application()->config_dir ), environment_home_directory() ); #endif if( home_dir ) paths[9] = home_dir; start_path = 9; } else { paths[9] = 0; } for( i = start_path; i < NUM_SEARCH_PATHS; ++i ) { char* filename; stream_t* istream; bool path_already_searched = false; if( !paths[i] ) continue; for( j = start_path; j < i; ++j ) { if( paths[j] && string_equal( paths[j], paths[i] ) ) { path_already_searched = true; break; } } if( path_already_searched ) continue; //TODO: Support loading configs from virtual file system (i.e in zip/other packages) filename = string_append( path_merge( paths[i], name ), ".ini" ); istream = 0; #if FOUNDATION_PLATFORM_ANDROID if( i == ANDROID_ASSET_PATH_INDEX ) istream = asset_stream_open( filename, STREAM_IN ); else #endif istream = stream_open( filename, STREAM_IN ); if( istream ) { config_parse( istream, filter_section, overwrite ); stream_deallocate( istream ); } string_deallocate( filename ); if( built_in ) { const char* FOUNDATION_PLATFORM_name = #if FOUNDATION_PLATFORM_WINDOWS "windows"; #elif FOUNDATION_PLATFORM_LINUX_RASPBERRYPI "raspberrypi"; #elif FOUNDATION_PLATFORM_LINUX "linux"; #elif FOUNDATION_PLATFORM_MACOSX "osx"; #elif FOUNDATION_PLATFORM_IOS "ios"; #elif FOUNDATION_PLATFORM_ANDROID "android"; #else # error Insert platform name "unknown"; #endif filename = string_append( path_append( path_merge( paths[i], FOUNDATION_PLATFORM_name ), name ), ".ini" ); #if FOUNDATION_PLATFORM_ANDROID if( i == ANDROID_ASSET_PATH_INDEX ) istream = asset_stream_open( filename, STREAM_IN ); else #endif istream = stream_open( filename, STREAM_IN ); if( istream ) { config_parse( istream, filter_section, overwrite ); stream_deallocate( istream ); } string_deallocate( filename ); } } string_deallocate( home_dir ); string_deallocate( cmdline_path ); string_deallocate( sub_exe_path ); string_deallocate( abs_exe_processed_path ); string_deallocate( abs_exe_parent_path ); string_deallocate( bundle_path ); string_deallocate( cwd_config_path ); }
int main_run( void* main_arg ) { const char* pattern = 0; char** exe_paths = 0; unsigned int iexe, exesize; process_t* process = 0; char* process_path = 0; int process_result = 0; object_t thread = 0; thread = thread_create( event_thread, "event_thread", THREAD_PRIORITY_NORMAL, 0 ); thread_start( thread, 0 ); #if FOUNDATION_PLATFORM_ANDROID int test_fn = 0; test_run_fn tests[] = { //test_app_run test_array_run, test_atomic_run, test_base64_run, test_bitbuffer_run, test_blowfish_run, test_bufferstream_run, test_config_run, test_crash_run, test_environment_run, test_error_run, test_event_run, test_fs_run, test_hash_run, test_hashmap_run, test_hashtable_run, test_library_run, test_math_run, test_md5_run, test_mutex_run, test_objectmap_run, test_path_run, test_pipe_run, test_profile_run, test_radixsort_run, test_random_run, test_ringbuffer_run, test_semaphore_run, //test_stacktrace_run, test_string_run, test_uuid_run, 0 }; do { if( process_result >= 0 ) { if( ( process_result = tests[test_fn]() ) >= 0 ) log_infof( HASH_TEST, "All tests passed (%d)", process_result ); } ++test_fn; } while( tests[test_fn] && ( process_result >= 0 ) ); if( process_result != 0 ) { log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); } #else //Find all test executables in the current executable directory #if FOUNDATION_PLATFORM_WINDOWS pattern = "test-*.exe"; #elif FOUNDATION_PLATFORM_MACOSX || FOUNDATION_PLATFORM_IOS pattern = "test-*"; #elif FOUNDATION_PLATFORM_POSIX pattern = "test-*"; #else # error Not implemented #endif exe_paths = fs_matching_files( environment_executable_directory(), pattern, true ); for( iexe = 0, exesize = array_size( exe_paths ); iexe < exesize; ++iexe ) { bool is_self = false; char* exe_file_name = path_base_file_name( exe_paths[iexe] ); if( string_equal( exe_file_name, environment_executable_name() ) ) is_self = true; string_deallocate( exe_file_name ); if( is_self ) continue; //Don't run self process_path = path_merge( environment_executable_directory(), exe_paths[iexe] ); process = process_allocate(); process_set_executable_path( process, process_path ); process_set_working_directory( process, environment_executable_directory() ); process_set_flags( process, PROCESS_ATTACHED ); log_infof( HASH_TEST, "Running test executable: %s", exe_paths[iexe] ); process_result = process_spawn( process ); while( process_result == PROCESS_WAIT_INTERRUPTED ) { thread_sleep( 10 ); process_result = process_wait( process ); } process_deallocate( process ); string_deallocate( process_path ); if( process_result != 0 ) { if( process_result >= PROCESS_INVALID_ARGS ) log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed, process terminated with error %x", process_result ); else log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); process_set_exit_code( -1 ); goto exit; } log_infof( HASH_TEST, "All tests from %s passed (%d)", exe_paths[iexe], process_result ); } log_info( HASH_TEST, "All tests passed" ); exit: if( exe_paths ) string_array_deallocate( exe_paths ); #endif thread_terminate( thread ); thread_destroy( thread ); while( thread_is_running( thread ) ) thread_sleep( 10 ); return process_result; }
object_t library_load( const char* name ) { library_t* library; hash_t namehash; unsigned int i, size; uint64_t id; #if FOUNDATION_PLATFORM_WINDOWS char* dllname; HANDLE dll; #endif //Locate already loaded library library = 0; namehash = string_hash( name ); for( i = 0, size = objectmap_size( _library_map ); i < size; ++i ) { library = objectmap_raw_lookup( _library_map, i ); if( library && ( library->namehash == namehash ) ) { FOUNDATION_ASSERT( string_equal( library->name, name ) ); atomic_incr32( &library->ref ); return library->id; } } error_context_push( "loading library", name ); //Try loading library #if FOUNDATION_PLATFORM_WINDOWS dllname = string_format( "%s.dll", name ); dll = LoadLibraryA( dllname ); if( !dll ) { #if FOUNDATION_PLATFORM_ARCH_X86 string_deallocate( dllname ); dllname = string_format( "%s32.dll", name ); dll = LoadLibraryA( dllname ); #elif FOUNDATION_PLATFORM_ARCH_X86_64 string_deallocate( dllname ); dllname = string_format( "%s64.dll", name ); dll = LoadLibraryA( dllname ); #endif } string_deallocate( dllname ); if( !dll ) { log_warnf( 0, WARNING_SUSPICIOUS, "Unable to load DLL '%s': %s", name, system_error_message( 0 ) ); error_context_pop(); return 0; } #elif FOUNDATION_PLATFORM_POSIX # if FOUNDATION_PLATFORM_APPLE char* libname = string_format( "lib%s.dylib", name ); # else char* libname = string_format( "lib%s.so", name ); # endif void* lib = dlopen( libname, RTLD_LAZY ); string_deallocate( libname ); #if FOUNDATION_PLATFORM_ANDROID if( !lib ) { libname = string_format( "%s/lib%s.so", environment_executable_directory(), name ); lib = dlopen( libname, RTLD_LAZY ); string_deallocate( libname ); } #endif if( !lib ) { log_warnf( 0, WARNING_SUSPICIOUS, "Unable to load dynamic library '%s': %s", name, dlerror() ); error_context_pop(); return 0; } #else log_errorf( 0, ERROR_NOT_IMPLEMENTED, "Dynamic library loading not implemented for this platform: %s", name ); error_context_pop(); return 0; #endif id = objectmap_reserve( _library_map ); if( !id ) { #if FOUNDATION_PLATFORM_WINDOWS FreeLibrary( dll ); #elif FOUNDATION_PLATFORM_POSIX dlclose( lib ); #endif log_errorf( 0, ERROR_OUT_OF_MEMORY, "Unable to allocate new library '%s', map full", name ); error_context_pop(); return 0; } library = memory_allocate_zero( sizeof( library_t ), 0, MEMORY_PERSISTENT ); library->ref = 1; library->id = id; library->namehash = string_hash( name ); string_copy( library->name, name, 32 ); #if FOUNDATION_PLATFORM_WINDOWS library->dll = dll; #elif FOUNDATION_PLATFORM_POSIX library->lib = lib; #endif objectmap_set( _library_map, id, library ); error_context_pop(); return library->id; }
int main_run( void* main_arg ) { #if !FOUNDATION_PLATFORM_IOS && !FOUNDATION_PLATFORM_ANDROID const char* pattern = 0; char** exe_paths = 0; unsigned int iexe, exesize; process_t* process = 0; char* process_path = 0; unsigned int* exe_flags = 0; #endif int process_result = 0; object_t thread = 0; log_set_suppress( HASH_TEST, ERRORLEVEL_DEBUG ); thread = thread_create( event_thread, "event_thread", THREAD_PRIORITY_NORMAL, 0 ); thread_start( thread, 0 ); while( !thread_is_running( thread ) ) thread_sleep( 10 ); #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID while( !_test_should_start ) thread_sleep( 10 ); test_run_fn tests[] = { //test_app_run test_array_run, test_atomic_run, test_base64_run, test_bitbuffer_run, test_blowfish_run, test_bufferstream_run, test_config_run, test_crash_run, test_environment_run, test_error_run, test_event_run, test_fs_run, test_hash_run, test_hashmap_run, test_hashtable_run, test_library_run, test_math_run, test_md5_run, test_mutex_run, test_objectmap_run, test_path_run, test_pipe_run, test_profile_run, test_radixsort_run, test_random_run, test_ringbuffer_run, test_semaphore_run, test_stacktrace_run, test_string_run, test_uuid_run, 0 }; #if FOUNDATION_PLATFORM_ANDROID object_t test_thread = thread_create( test_runner, "test_runner", THREAD_PRIORITY_NORMAL, 0 ); thread_start( test_thread, tests ); while( !thread_is_running( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } while( thread_is_running( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } process_result = (int)(intptr_t)thread_result( test_thread ); thread_destroy( test_thread ); while( thread_is_thread( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } #else process_result = (int)(intptr_t)test_runner( 0, tests ); #endif if( process_result != 0 ) log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); while( !_test_should_terminate ) { system_process_events(); thread_sleep( 100 ); } log_debug( HASH_TEST, "Exiting main loop" ); #else //Find all test executables in the current executable directory #if FOUNDATION_PLATFORM_WINDOWS pattern = "test-*.exe"; #elif FOUNDATION_PLATFORM_MACOSX pattern = "test-*"; #elif FOUNDATION_PLATFORM_POSIX pattern = "test-*"; #else # error Not implemented #endif exe_paths = fs_matching_files( environment_executable_directory(), pattern, false ); array_resize( exe_flags, array_size( exe_paths ) ); memset( exe_flags, 0, sizeof( unsigned int ) * array_size( exe_flags ) ); #if FOUNDATION_PLATFORM_MACOSX //Also search for test-*.app const char* app_pattern = "test-*.app"; char** subdirs = fs_subdirs( environment_executable_directory() ); for( int idir = 0, dirsize = array_size( subdirs ); idir < dirsize; ++idir ) { if( string_match_pattern( subdirs[idir], app_pattern ) ) { array_push( exe_paths, string_substr( subdirs[idir], 0, string_length( subdirs[idir] ) - 4 ) ); array_push( exe_flags, PROCESS_OSX_USE_OPENAPPLICATION ); } } string_array_deallocate( subdirs ); #endif for( iexe = 0, exesize = array_size( exe_paths ); iexe < exesize; ++iexe ) { bool is_self = false; char* exe_file_name = path_base_file_name( exe_paths[iexe] ); if( string_equal( exe_file_name, environment_executable_name() ) ) is_self = true; string_deallocate( exe_file_name ); if( is_self ) continue; //Don't run self process_path = path_merge( environment_executable_directory(), exe_paths[iexe] ); process = process_allocate(); process_set_executable_path( process, process_path ); process_set_working_directory( process, environment_executable_directory() ); process_set_flags( process, PROCESS_ATTACHED | exe_flags[iexe] ); log_infof( HASH_TEST, "Running test executable: %s", exe_paths[iexe] ); process_result = process_spawn( process ); while( process_result == PROCESS_WAIT_INTERRUPTED ) { thread_sleep( 10 ); process_result = process_wait( process ); } process_deallocate( process ); string_deallocate( process_path ); if( process_result != 0 ) { if( process_result >= PROCESS_INVALID_ARGS ) log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed, process terminated with error %x", process_result ); else log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); process_set_exit_code( -1 ); goto exit; } log_infof( HASH_TEST, "All tests from %s passed (%d)", exe_paths[iexe], process_result ); } log_info( HASH_TEST, "All tests passed" ); exit: if( exe_paths ) string_array_deallocate( exe_paths ); array_deallocate( exe_flags ); #endif thread_terminate( thread ); thread_destroy( thread ); while( thread_is_running( thread ) ) thread_sleep( 10 ); while( thread_is_thread( thread ) ) thread_sleep( 10 ); return process_result; }