diff --git a/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake index b19976ce66..29f90f53f1 100644 --- a/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake +++ b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake @@ -1,52 +1,63 @@ function(usFunctionEmbedResources src_var) - MACRO_PARSE_ARGUMENTS(US_RESOURCE "LIBRARY_NAME;ROOT_DIR;FILES" "" ${ARGN}) + MACRO_PARSE_ARGUMENTS(US_RESOURCE "LIBRARY_NAME;EXECUTABLE_NAME;ROOT_DIR;FILES" "" ${ARGN}) if(NOT src_var) message(SEND_ERROR "Output variable name not specified.") endif() - if(NOT US_RESOURCE_LIBRARY_NAME) - message(SEND_ERROR "LIBRARY_NAME argument not specified.") + if(US_RESOURCE_EXECUTABLE_NAME AND US_RESOURCE_LIBRARY_NAME) + message(SEND_ERROR "Only one of LIBRARY_NAME or EXECUTABLE_NAME can be specified.") + endif() + + if(NOT US_RESOURCE_LIBRARY_NAME AND NOT US_RESOURCE_EXECUTABLE_NAME) + message(SEND_ERROR "LIBRARY_NAME or EXECUTABLE_NAME argument not specified.") endif() if(NOT US_RESOURCE_FILES) message(WARNING "No FILES argument given. Skipping resource processing.") return() endif() if(NOT US_RESOURCE_ROOT_DIR) set(US_RESOURCE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) endif() if(NOT IS_ABSOLUTE ${US_RESOURCE_ROOT_DIR}) set(US_RESOURCE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${US_RESOURCE_ROOT_DIR}") endif() if(NOT IS_DIRECTORY ${US_RESOURCE_ROOT_DIR}) message(SEND_ERROR "The ROOT_DIR argument is not a directory: ${US_RESOURCE_ROOT_DIR}") endif() set(absolute_res_files) foreach(res_file ${US_RESOURCE_FILES}) set(res_file "${US_RESOURCE_ROOT_DIR}/${res_file}") if(IS_DIRECTORY ${res_file}) message(SEND_ERROR "A resource cannot be a directory: ${res_file}") endif() if(NOT EXISTS ${res_file}) message(SEND_ERROR "Resource does not exists: ${res_file}") endif() file(TO_NATIVE_PATH "${res_file}" res_file) list(APPEND absolute_res_files ${res_file}) endforeach() - set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_LIBRARY_NAME}_resources.cpp") + if(US_RESOURCE_LIBRARY_NAME) + set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_LIBRARY_NAME}_resources.cpp") + set(us_lib_name ${US_RESOURCE_LIBRARY_NAME}) + else() + set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_EXECUTABLE_NAME}_resources.cpp") + set(us_lib_name "\"\"") + endif() + add_custom_command( OUTPUT ${us_cpp_resource_file} - COMMAND ${US_RCC_EXECUTABLE_NAME} ${US_RESOURCE_LIBRARY_NAME} ${us_cpp_resource_file} ${absolute_res_files} + COMMAND ${US_RCC_EXECUTABLE_NAME} "${us_lib_name}" ${us_cpp_resource_file} ${absolute_res_files} WORKING_DIRECTORY ${US_RESOURCE_ROOT_DIR} DEPENDS ${absolute_res_files} COMMENT "Generating embedded resource file ${us_cpp_resource_name}" ) set(${src_var} "${${src_var}};${us_cpp_resource_file}" PARENT_SCOPE) endfunction() diff --git a/Core/Code/CppMicroServices/test/CMakeLists.txt b/Core/Code/CppMicroServices/test/CMakeLists.txt index 3442dc7eff..489f435e70 100644 --- a/Core/Code/CppMicroServices/test/CMakeLists.txt +++ b/Core/Code/CppMicroServices/test/CMakeLists.txt @@ -1,99 +1,101 @@ #----------------------------------------------------------------------------- # Configure files, include dirs, etc. #----------------------------------------------------------------------------- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/usTestingConfig.h.in" "${PROJECT_BINARY_DIR}/include/usTestingConfig.h") include_directories(${US_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}) if(NOT US_ENABLE_SERVICE_FACTORY_SUPPORT) include_directories(${US_BASECLASS_INCLUDE_DIRS}) endif() link_directories(${US_LINK_DIRS}) if(NOT US_ENABLE_SERVICE_FACTORY_SUPPORT) link_directories(${US_BASECLASS_LIBRARY_DIRS}) endif() #----------------------------------------------------------------------------- # Create test modules #----------------------------------------------------------------------------- include(usFunctionCreateTestModule) set(_us_test_module_libs "" CACHE INTERNAL "" FORCE) add_subdirectory(modules) #----------------------------------------------------------------------------- # Add unit tests #----------------------------------------------------------------------------- set(_tests usDebugOutputTest usLDAPFilterTest usModuleTest usModuleResourceTest usServiceRegistryTest usServiceTrackerTest usStaticModuleTest ) if(US_BUILD_SHARED_LIBS) list(APPEND _tests usServiceListenerTest) if(US_ENABLE_AUTOLOADING_SUPPORT) list(APPEND _tests usModuleAutoLoadTest) endif() endif() set(_additional_srcs usTestManager.cpp usTestUtilModuleListener.cpp usTestUtilSharedLibrary.cpp ) set(_test_driver ${PROJECT_NAME}TestDriver) set(_test_sourcelist_extra_args ) create_test_sourcelist(_srcs ${_test_driver}.cpp ${_tests} ${_test_sourcelist_extra_args}) +usFunctionEmbedResources(_srcs EXECUTABLE_NAME ${_test_driver} FILES usTestResource.txt) + # Generate a custom "module init" file for the test driver executable set(MODULE_DEPENDS_STR ) foreach(_dep ${US_LINK_LIBRARIES}) set(MODULE_DEPENDS_STR "${MODULE_DEPENDS_STR} ${_dep}") endforeach() if(US_BUILD_SHARED_LIBS) usFunctionGenerateModuleInit(_srcs NAME ${_test_driver} DEPENDS "${MODULE_DEPENDS_STR}" VERSION "0.1.0" EXECUTABLE ) endif() add_executable(${_test_driver} ${_srcs} ${_additional_srcs}) if(NOT US_BUILD_SHARED_LIBS) target_link_libraries(${_test_driver} ${_us_test_module_libs}) endif() target_link_libraries(${_test_driver} ${US_LINK_LIBRARIES}) if(NOT US_ENABLE_SERVICE_FACTORY_SUPPORT) target_link_libraries(${_test_driver} ${US_BASECLASS_LIBRARIES}) endif() # Register tests foreach(_test ${_tests}) add_test(NAME ${_test} COMMAND ${_test_driver} ${_test}) endforeach() if(US_TEST_LABELS) set_tests_properties(${_tests} PROPERTIES LABELS "${US_TEST_LABELS}") endif() #----------------------------------------------------------------------------- # Add dependencies for shared libraries #----------------------------------------------------------------------------- if(US_BUILD_SHARED_LIBS) foreach(_test_module ${_us_test_module_libs}) add_dependencies(${_test_driver} ${_test_module}) endforeach() endif() diff --git a/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp b/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp index e5da6561e1..5b85d221df 100644 --- a/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp +++ b/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp @@ -1,347 +1,360 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include #include #include "usTestUtilSharedLibrary.h" #include "usTestingMacros.h" #include #include US_USE_NAMESPACE namespace { void checkResourceInfo(const ModuleResource& res, const std::string& path, const std::string& baseName, const std::string& completeBaseName, const std::string& suffix, int size, bool children = false) { US_TEST_CONDITION_REQUIRED(res.IsValid(), "Valid resource") US_TEST_CONDITION(res.GetBaseName() == baseName, "GetBaseName()") US_TEST_CONDITION(res.GetChildren().empty() == !children, "No children") US_TEST_CONDITION(res.GetCompleteBaseName() == completeBaseName, "GetCompleteBaseName()") US_TEST_CONDITION(res.GetFileName() == completeBaseName + "." + suffix, "GetFileName()") US_TEST_CONDITION(res.GetFilePath() == path + completeBaseName + "." + suffix, "GetFilePath()") US_TEST_CONDITION(res.GetPath() == path, "GetPath()") US_TEST_CONDITION(res.GetSize() == size, "Data size") US_TEST_CONDITION(res.GetSuffix() == suffix, "Suffix") } void testTextResource(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", 16, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", 13, false); const std::streampos ssize(12); const std::string fileData = "foo and\nbar\n"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, rs.gcount()); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); rs.clear(); rs.seekg(0); US_TEST_CONDITION_REQUIRED(rs.tellg() == std::streampos(0), "Move to start") US_TEST_CONDITION_REQUIRED(rs.good(), "Start re-reading"); std::vector lines; std::string line; while (std::getline(rs, line)) { lines.push_back(line); } US_TEST_CONDITION_REQUIRED(lines.size() > 1, "Number of lines") US_TEST_CONDITION(lines[0] == "foo and", "Check first line") US_TEST_CONDITION(lines[1] == "bar", "Check second line") } void testTextResourceAsBinary(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", 16, false); const std::streampos ssize(16); const std::string fileData = "foo and\r\nbar\r\n\r\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", 13, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #endif ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, rs.gcount()); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } void testSpecialCharacters(Module* module) { ModuleResource res = module->GetResource("special_chars.dummy.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", 56, false); const std::streampos ssize(54); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)\n"; #else checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", 54, false); const std::streampos ssize(53); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios_base::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios_base::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } content.append(buffer, rs.gcount()); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } void testBinaryResource(Module* module) { ModuleResource res = module->GetResource("/icons/cppmicroservices.png"); checkResourceInfo(res, "/icons/", "cppmicroservices", "cppmicroservices", "png", 2424, false); ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios_base::end); std::streampos resLength = rs.tellg(); rs.seekg(0); std::ifstream png(CppMicroServices_SOURCE_DIR "/test/modules/libRWithResources/resources/icons/cppmicroservices.png", std::ifstream::in | std::ifstream::binary); US_TEST_CONDITION_REQUIRED(png.is_open(), "Open reference file") png.seekg(0, std::ios_base::end); std::streampos pngLength = png.tellg(); png.seekg(0); US_TEST_CONDITION(resLength = res.GetSize(), "Check resource size") US_TEST_CONDITION_REQUIRED(resLength == pngLength, "Compare sizes") char c1 = 0; char c2 = 0; bool isEqual = true; int count = 0; while (png.get(c1) && rs.get(c2)) { ++count; if (c1 != c2) { isEqual = false; break; } } US_TEST_CONDITION_REQUIRED(count == pngLength, "Check if everything was read"); US_TEST_CONDITION_REQUIRED(isEqual, "Equal binary contents"); US_TEST_CONDITION(png.eof(), "EOF check"); } void testResourceTree(Module* module) { ModuleResource res = module->GetResource(""); US_TEST_CONDITION(res.GetFilePath() == "/", "Check root file path") US_TEST_CONDITION(res.IsDir() == true, "Check type") std::vector children = res.GetChildren(); std::sort(children.begin(), children.end()); US_TEST_CONDITION_REQUIRED(children.size() == 4, "Check child count") US_TEST_CONDITION(children[0] == "foo.txt", "Check child name") US_TEST_CONDITION(children[1] == "icons", "Check child name") US_TEST_CONDITION(children[2] == "special_chars.dummy.txt", "Check child name") US_TEST_CONDITION(children[3] == "test.xml", "Check child name") ModuleResource readme = module->GetResource("/icons/readme.txt"); US_TEST_CONDITION(readme.IsFile() && readme.GetChildren().empty(), "Check file resource") ModuleResource icons = module->GetResource("icons"); US_TEST_CONDITION(icons.IsDir() && !icons.IsFile() && !icons.GetChildren().empty(), "Check directory resource") children = icons.GetChildren(); US_TEST_CONDITION_REQUIRED(children.size() == 2, "Check icons child count") std::sort(children.begin(), children.end()); US_TEST_CONDITION(children[0] == "cppmicroservices.png", "Check child name") US_TEST_CONDITION(children[1] == "readme.txt", "Check child name") // find all .txt files std::vector nodes = module->FindResources("", "*.txt", false); std::sort(nodes.begin(), nodes.end()); US_TEST_CONDITION_REQUIRED(nodes.size() == 2, "Found child count") US_TEST_CONDITION(nodes[0] == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1] == "/special_chars.dummy.txt", "Check child name") nodes = module->FindResources("", "*.txt", true); std::sort(nodes.begin(), nodes.end()); US_TEST_CONDITION_REQUIRED(nodes.size() == 3, "Found child count") US_TEST_CONDITION(nodes[0] == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1] == "/icons/readme.txt", "Check child name") US_TEST_CONDITION(nodes[2] == "/special_chars.dummy.txt", "Check child name") // find all resources nodes = module->FindResources("", "", true); US_TEST_CONDITION(nodes.size() == 5, "Total resource number") nodes = module->FindResources("", "**", true); US_TEST_CONDITION(nodes.size() == 5, "Total resource number") // test pattern matching nodes.clear(); nodes = module->FindResources("/icons", "*micro*.png", false); US_TEST_CONDITION(nodes.size() == 1 && nodes[0] == "/icons/cppmicroservices.png", "Check file pattern matches") nodes.clear(); nodes = module->FindResources("", "*.txt", true); US_TEST_CONDITION(nodes.size() == 3, "Check recursive pattern matches") } void testResourceOperators(Module* module) { ModuleResource invalid = module->GetResource("invalid"); ModuleResource foo = module->GetResource("foo.txt"); US_TEST_CONDITION_REQUIRED(foo.IsValid() && foo, "Check valid resource") ModuleResource foo2(foo); US_TEST_CONDITION(foo == foo2, "Check copy constructor and equality operator") US_TEST_CONDITION(foo != invalid, "Check inequality with invalid resource") ModuleResource xml = module->GetResource("/test.xml"); US_TEST_CONDITION_REQUIRED(xml.IsValid() && xml, "Check valid resource") US_TEST_CONDITION(foo != xml, "Check inequality") US_TEST_CONDITION(foo < xml, "Check operator<") // check operator< by using a set std::set resources; resources.insert(foo); resources.insert(foo); resources.insert(xml); US_TEST_CONDITION(resources.size() == 2, "Check operator< with set") // check hash function specialization US_UNORDERED_SET_TYPE resources2; resources2.insert(foo); resources2.insert(foo); resources2.insert(xml); US_TEST_CONDITION(resources2.size() == 2, "Check operator< with unordered set") // check operator<< std::ostringstream oss; oss << foo; US_TEST_CONDITION(oss.str() == foo.GetFilePath(), "Check operator<<") } +void testResourceFromExecutable(Module* module) +{ + ModuleResource resource = module->GetResource("usTestResource.txt"); + US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid executable resource") + + std::string line; + ModuleResourceStream rs(resource); + std::getline(rs, line); + US_TEST_CONDITION(line == "meant to be compiled into the test driver", "Check executable resource content") +} + } // end unnamed namespace int usModuleResourceTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleResourceTest"); ModuleContext* mc = GetModuleContext(); assert(mc); SharedLibraryHandle libR("TestModuleR"); try { libR.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } Module* moduleR = ModuleRegistry::GetModule("TestModuleR Module"); US_TEST_CONDITION_REQUIRED(moduleR != NULL, "Test for existing module TestModuleR") US_TEST_CONDITION(moduleR->GetName() == "TestModuleR Module", "Test module name") testResourceTree(moduleR); testResourceOperators(moduleR); testTextResource(moduleR); testTextResourceAsBinary(moduleR); testSpecialCharacters(moduleR); testBinaryResource(moduleR); ModuleResource foo = moduleR->GetResource("foo.txt"); US_TEST_CONDITION(foo.IsValid() == true, "Valid resource") libR.Unload(); US_TEST_CONDITION(foo.IsValid() == false, "Invalidated resource") US_TEST_CONDITION(foo.GetData() == NULL, "NULL data") + testResourceFromExecutable(mc->GetModule()); + US_TEST_END() } diff --git a/Core/Code/CppMicroServices/test/usTestResource.txt b/Core/Code/CppMicroServices/test/usTestResource.txt new file mode 100644 index 0000000000..b5125a157a --- /dev/null +++ b/Core/Code/CppMicroServices/test/usTestResource.txt @@ -0,0 +1 @@ +meant to be compiled into the test driver