diff options
28 files changed, 563 insertions, 41 deletions
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst index e905ef479c..015e36e47f 100644 --- a/Help/manual/cmake-modules.7.rst +++ b/Help/manual/cmake-modules.7.rst @@ -14,6 +14,7 @@ All Modules :maxdepth: 1 /module/AddFileDependencies + /module/AndroidTestUtilities /module/BundleUtilities /module/CheckCCompilerFlag /module/CheckCSourceCompiles diff --git a/Help/module/AndroidTestUtilities.rst b/Help/module/AndroidTestUtilities.rst new file mode 100644 index 0000000000..e7ec864c73 --- /dev/null +++ b/Help/module/AndroidTestUtilities.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/AndroidTestUtilities.cmake diff --git a/Help/release/dev/add-android-test-utilities-module.rst b/Help/release/dev/add-android-test-utilities-module.rst new file mode 100644 index 0000000000..998b3cd40c --- /dev/null +++ b/Help/release/dev/add-android-test-utilities-module.rst @@ -0,0 +1,5 @@ +add-android-test-utilities-module +--------------------------------- + +* A :module:`AndroidTestUtilities` module was added to manage transfer of + test data to an Android device. diff --git a/Modules/AndroidTestUtilities.cmake b/Modules/AndroidTestUtilities.cmake new file mode 100644 index 0000000000..a0a74fa647 --- /dev/null +++ b/Modules/AndroidTestUtilities.cmake @@ -0,0 +1,157 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[======================================================================[.rst: +AndroidTestUtilities +------------------------ + +Create a test that automatically loads specified data onto an Android device. + +Introduction +^^^^^^^^^^^^ + +Use this module to push data needed for testing an Android device behavior +onto a connected Android device. The module will accept files and libraries as +well as separate destinations for each. It will create a test that loads the +files into a device object store and link to them from the specified +destination. The files are only uploaded if they are not already in the object +store. + +For example: + +.. code-block:: cmake + + include(AndroidTestUtilities) + android_add_test_data( + example_setup_test + FILES <files>... + LIBS <libs>... + DEVICE_TEST_DIR "/data/local/tests/example" + DEVICE_OBJECT_STORE "/sdcard/.ExternalData/SHA" + ) + + +At build time a test named "example_setup_test" will be created. Run this test +on the command line with :manual:`ctest(1)` to load the data onto the Android +device. + +Module Functions +^^^^^^^^^^^^^^^^ + +.. command:: android_add_test_data + + :: + + android_add_test_data(<test-name> + [FILES <files>...] [FILES_DEST <device-dir>] + [LIBS <libs>...] [LIBS_DEST <device-dir>] + [DEVICE_OBJECT_STORE <device-dir>] + [DEVICE_TEST_DIR <device-dir>] + [NO_LINK_REGEX <strings>...] + ) + + The ``android_add_test_data`` function is used to copy files and libraries + needed to run project-specific tests. On the host operating system, this is + done at build time. For on-device testing, the files are loaded onto the + device by the manufactured test at run time. + + This function accepts the following named parameters: + + ``FILES <files>...`` + zero or more files needed for testing + ``LIBS <libs>...`` + zero or more libraries needed for testing + ``FILES_DEST <device-dir>`` + absolute path where the data files are expected to be + ``LIBS_DEST <device-dir>`` + absolute path where the libraries are expected to be + ``DEVICE_OBJECT_STORE <device-dir>`` + absolute path to the location where the data is stored on-device + ``DEVICE_TEST_DIR <device-dir>`` + absolute path to the root directory of the on-device test location + ``NO_LINK_REGEX <strings>...`` + list of regex strings matching the names of files that should be + copied from the object store to the testing directory +#]======================================================================] + +include(${CMAKE_CURRENT_LIST_DIR}/ExternalData.cmake) + +set(_AndroidTestUtilities_SELF_DIR "${CMAKE_CURRENT_LIST_DIR}") + +# The parameters to this function should be set to the list of directories, +# files, and libraries that need to be installed prior to testing. +function(android_add_test_data test_name) + # As the names suggest, oneValueArgs lists the arguments that specify a + # single value, while multiValueArgs can contain one or more values. + set(keywordArgs) + set(oneValueArgs FILES_DEST LIBS_DEST DEVICE_OBJECT_STORE DEVICE_TEST_DIR) + set(multiValueArgs FILES LIBS NO_LINK_REGEX) + + # For example, if you called this function with FILES </path/to/file> + # then this path would be stored in the variable AST_FILES. + # The AST prefix stands for the name of this function (android_add_test_data). + cmake_parse_arguments(AST "${keywordArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if(NOT AST_DEVICE_TEST_DIR) + message(FATAL_ERROR "-- You must specify the location of the on device test directory.") + endif() + if(NOT AST_DEVICE_OBJECT_STORE) + message(FATAL_ERROR "-- You must specify the location of the on device object store.") + endif() + if(${AST_DEVICE_TEST_DIR} STREQUAL "/") + message(FATAL_ERROR "-- The device test directory cannot be '/'") + endif() + + # Copy all test data files into the binary directory, where tests are run. + # ExternalData will handle fetching DATA{...} references. + string(REPLACE "|" ";" hash_algs "${_ExternalData_REGEX_EXT}") + # Convert ExternalData placeholder file names to DATA{} syntax. + foreach(alg ${hash_algs}) + string(REGEX REPLACE "([^ ;]+)\\.${alg}" "DATA{\\1}" AST_FILES "${AST_FILES}") + endforeach() + + set(DATA_TARGET_NAME "${test_name}") + ExternalData_Expand_Arguments( + ${DATA_TARGET_NAME} + extern_data_output + ${AST_FILES}) + ExternalData_Add_Target(${DATA_TARGET_NAME}) + + # For regular files on Linux, just copy them directly. + foreach(path ${AST_FILES}) + foreach(output ${extern_data_output}) + if(${output} STREQUAL ${path}) + # Check if a destination was specified. If not, we copy by default + # into this project's binary directory, preserving its relative path. + if(AST_${VAR}_DEST) + set(DEST ${CMAKE_BINARY_DIR}/${parent_dir}/${AST_${VAR}_DEST}) + else() + get_filename_component(parent_dir ${path} DIRECTORY) + set(DEST "${CMAKE_BINARY_DIR}/${parent_dir}") + endif() + get_filename_component(extern_data_source ${output} REALPATH) + get_filename_component(extern_data_basename ${output} NAME) + add_custom_command( + TARGET ${DATA_TARGET_NAME} POST_BUILD + DEPENDS ${extern_data_source} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${extern_data_source} ${DEST}/${extern_data_basename} + ) + endif() + endforeach() + endforeach() + + if(ANDROID) + string(REGEX REPLACE "DATA{([^ ;]+)}" "\\1" processed_FILES "${AST_FILES}") + add_test( + NAME ${test_name} + COMMAND ${CMAKE_COMMAND} + "-Darg_files_dest=${AST_FILES_DEST}" + "-Darg_libs_dest=${AST_LIBS_DEST}" + "-Darg_dev_test_dir=${AST_DEVICE_TEST_DIR}" + "-Darg_dev_obj_store=${AST_DEVICE_OBJECT_STORE}" + "-Darg_no_link_regex=${AST_NO_LINK_REGEX}" + "-Darg_files=${processed_FILES}" + "-Darg_libs=${AST_LIBS}" + "-Darg_src_dir=${CMAKE_CURRENT_SOURCE_DIR}" + -P ${_AndroidTestUtilities_SELF_DIR}/AndroidTestUtilities/PushToAndroidDevice.cmake) + endif() +endfunction() diff --git a/Modules/AndroidTestUtilities/PushToAndroidDevice.cmake b/Modules/AndroidTestUtilities/PushToAndroidDevice.cmake new file mode 100644 index 0000000000..f5f2564cf3 --- /dev/null +++ b/Modules/AndroidTestUtilities/PushToAndroidDevice.cmake @@ -0,0 +1,174 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +# This function handles pushing all of the test files needed to the device. +# It places the data files in the object store and makes links to them from +# the appropriate directories. +# +# This function accepts the following named parameters: +# DIRS : one or more directories needed for testing. +# FILES : one or more files needed for testing. +# LIBS : one or more libraries needed for testing. +# DIRS_DEST : specify where the directories should be installed. +# FILES_DEST : specify where the files should be installed. +# LIBS_DEST : specify where the libraries should be installed. +# DEV_OBJ_STORE : specify where the actual data files should be placed. +# DEV_TEST_DIR : specify the root file for the module test directory. +# The DEV_OBJ_STORE and DEV_TEST_DIR variables are required. + +# The parameters to this function should be set to the list of directories, +# files, and libraries that need to be installed prior to testing. +function(android_push_test_files_to_device) + + # The functions in the module need the adb executable. + find_program(adb_executable adb) + if(NOT adb_executable) + message(FATAL_ERROR "could not find adb") + endif() + + function(execute_adb_command) + execute_process(COMMAND ${adb_executable} ${ARGN} RESULT_VARIABLE res_var OUTPUT_VARIABLE out_var ERROR_VARIABLE err_var) + set(out_var ${out_var} PARENT_SCOPE) + if(res_var) + string(REGEX REPLACE ";" " " com "${ARGN}") + message(FATAL_ERROR "Error occured during adb command: adb ${com}\nError: ${err_var}.") + endif() + endfunction() + + # Checks to make sure that a given file exists on the device. If it does, + # if(file_exists) will return true. + macro(check_device_file_exists device_file file_exists) + set(${file_exists} "") + execute_adb_command(shell ls ${device_file}) + if(NOT out_var) # when a directory exists but is empty the output is empty + set(${file_exists} "YES") + else() + string(FIND ${out_var} "No such file or directory" no_file_exists) + if(${no_file_exists} STREQUAL "-1") # -1 means the file exists + set(${file_exists} "YES") + endif() + endif() + endmacro() + + # Checks to see if a filename matches a regex. + function(filename_regex filename reg_ex) + string(REGEX MATCH ${reg_ex} filename_match ${filename}) + set(filename_match ${filename_match} PARENT_SCOPE) + endfunction() + + # If a file with given name exists in the CMAKE_BINARY_DIR then use that file. + # Otherwise use the file with root in CMAKE_CURRENT_SOURCE_DIR. + macro(set_absolute_path relative_path absolute_path) + set(${absolute_path} ${arg_src_dir}/${relative_path}) + if(EXISTS ${CMAKE_BINARY_DIR}/${relative_path}) + set(${absolute_path} ${CMAKE_BINARY_DIR}/${relative_path}) + endif() + if(NOT EXISTS ${${absolute_path}}) + if(EXISTS ${relative_path}) + set(${absolute_path} ${relative_path}) + else() + message(FATAL_ERROR "Cannot find file for specified path: ${relative_path}") + endif() + endif() + endmacro() + + # This function pushes the data into the device object store and + # creates a link to that data file in a specified location. + # + # This function requires the following un-named parameters: + # data_path : absolute path to data to load into dev obj store. + # dev_object_store : absolute path to the device object store directory. + # link_origin : absolute path to the origin of the link to the dev obj store data file. + function(push_and_link data_path dev_object_store link_origin) + FILE(SHA1 ${data_path} hash_val) + set(obj_store_dst ${dev_object_store}/${hash_val}) + check_device_file_exists(${obj_store_dst} obj_store_file_exists) + # TODO: Verify that the object store file is indeed hashed correctly. Could use md5. + if(NOT obj_store_file_exists) + execute_adb_command(push ${data_path} ${obj_store_dst}) + endif() + check_device_file_exists(${link_origin} link_exists) + if(link_exists) + execute_adb_command(shell rm -f ${link_origin}) + endif() + foreach(ex ${arg_no_link_regex}) + filename_regex(${data_path} ${ex}) + LIST(APPEND match_ex ${filename_match}) + endforeach() + if(match_ex) + execute_adb_command(shell cp ${obj_store_dst} ${link_origin}) + else() + execute_adb_command(shell ln -s ${obj_store_dst} ${link_origin}) + endif() + endfunction() + + #---------------------------------------------------------------------------- + #--------------------Beginning of actual function---------------------------- + #---------------------------------------------------------------------------- + set(oneValueArgs FILES_DEST LIBS_DEST DEV_TEST_DIR DEV_OBJ_STORE) + set(multiValueArgs FILES LIBS) + cmake_parse_arguments(_ptd "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Setup of object store and test dir. + check_device_file_exists(${_ptd_DEV_OBJ_STORE} dev_obj_store_exists) + if(NOT dev_obj_store_exists) + execute_adb_command(shell mkdir -p ${_ptd_DEV_OBJ_STORE}) + endif() + check_device_file_exists(${_ptd_DEV_TEST_DIR} test_dir_exists) + if(test_dir_exists) + # This is protected in the SetupProjectTests module. + execute_adb_command(shell echo rm -r ${_ptd_DEV_TEST_DIR} | su) + endif() + execute_adb_command(shell mkdir -p ${_ptd_DEV_TEST_DIR}) + + # Looping over the various types of test data possible. + foreach(TYPE ${multiValueArgs}) + if(_ptd_${TYPE}) + + # determine if the data type destination has been explicitly specified. + if(_ptd_${TYPE}_DEST) + set(dest ${_ptd_${TYPE}_DEST}) + else() + if(${TYPE} STREQUAL LIBS) + set(dest ${_ptd_DEV_TEST_DIR}/lib) + else() + set(dest ${_ptd_DEV_TEST_DIR}) + endif() + endif() + execute_adb_command(shell mkdir -p ${dest}) + + # Loop over the files passed in + foreach(relative_path ${_ptd_${TYPE}}) + # The absolute path can be through the source directory or the build directory. + # If the file/dir exists in the build directory that version is chosen. + set_absolute_path(${relative_path} absolute_path) + # Need to transfer all data files in the data directories to the device + # except those explicitly ignored. + if(${TYPE} STREQUAL FILES) + get_filename_component(file_dir ${relative_path} DIRECTORY) + # dest was determined earlier, relative_path is a dir, file is path from relative path to a data + set(cur_dest ${dest}/${relative_path}) + set(on_dev_dir ${dest}/${file_dir}) + execute_adb_command(shell mkdir -p ${on_dev_dir}) + if(IS_SYMLINK ${absolute_path}) + get_filename_component(real_data_origin ${absolute_path} REALPATH) + push_and_link(${real_data_origin} ${_ptd_DEV_OBJ_STORE} ${cur_dest}) + else() + push_and_link(${absolute_path} ${_ptd_DEV_OBJ_STORE} ${cur_dest}) + endif() + else() # LIBS + execute_adb_command(push ${absolute_path} ${dest}) + endif() + endforeach() + endif() + endforeach() +endfunction() + +android_push_test_files_to_device( + FILES_DEST ${arg_files_dest} + LIBS_DEST ${arg_libs_dest} + DEV_TEST_DIR ${arg_dev_test_dir} + DEV_OBJ_STORE ${arg_dev_obj_store} + FILES ${arg_files} + LIBS ${arg_libs} + ) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 3c36419e5b..3e27338336 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160930) +set(CMake_VERSION_PATCH 20161001) #set(CMake_VERSION_RC 1) diff --git a/Source/cmAuxSourceDirectoryCommand.cxx b/Source/cmAuxSourceDirectoryCommand.cxx index fed4d5b735..665591185b 100644 --- a/Source/cmAuxSourceDirectoryCommand.cxx +++ b/Source/cmAuxSourceDirectoryCommand.cxx @@ -32,6 +32,8 @@ bool cmAuxSourceDirectoryCommand::InitialPass( sourceListValue = def; } + std::vector<std::string> files; + // Load all the files in the directory cmsys::Directory dir; if (dir.Load(tdir.c_str())) { @@ -55,14 +57,16 @@ bool cmAuxSourceDirectoryCommand::InitialPass( // depends can be done cmSourceFile* sf = this->Makefile->GetOrCreateSource(fullname); sf->SetProperty("ABSTRACT", "0"); - if (!sourceListValue.empty()) { - sourceListValue += ";"; - } - sourceListValue += fullname; + files.push_back(fullname); } } } } + std::sort(files.begin(), files.end()); + if (!sourceListValue.empty()) { + sourceListValue += ";"; + } + sourceListValue += cmJoin(files, ";"); this->Makefile->AddDefinition(args[1], sourceListValue.c_str()); return true; } diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index 71687ac04c..5246a676b9 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -434,13 +434,15 @@ static std::string ReadAll(const std::string& filename) return stream.str(); } -static std::string ListQt5RccInputs(cmSourceFile* sf, - cmGeneratorTarget const* target, - std::vector<std::string>& depends) +/// @brief Reads the resource files list from from a .qrc file - Qt5 version +/// @return True if the .qrc file was successfully parsed +static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target, + std::vector<std::string>& depends) { std::string rccCommand = GetRccExecutable(target); bool hasDashDashList = false; + // Read rcc features { std::vector<std::string> command; command.push_back(rccCommand); @@ -456,15 +458,12 @@ static std::string ListQt5RccInputs(cmSourceFile* sf, hasDashDashList = true; } } - - std::vector<std::string> qrcEntries; - + // Run rcc list command std::vector<std::string> command; command.push_back(rccCommand); command.push_back(hasDashDashList ? "--list" : "-list"); std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - command.push_back(absFile); std::string rccStdOut; @@ -479,17 +478,18 @@ static std::string ListQt5RccInputs(cmSourceFile* sf, << " failed:\n" << rccStdOut << "\n" << rccStdErr << std::endl; - std::cerr << err.str(); - return std::string(); + cmSystemTools::Error(err.str().c_str()); + return false; } + // Parse rcc list output { std::istringstream ostr(rccStdOut); std::string oline; while (std::getline(ostr, oline)) { oline = cmQtAutoGeneratorsStripCR(oline); if (!oline.empty()) { - qrcEntries.push_back(oline); + depends.push_back(oline); } } } @@ -507,30 +507,28 @@ static std::string ListQt5RccInputs(cmSourceFile* sf, std::ostringstream err; err << "AUTOGEN: error: Rcc lists unparsable output " << eline << std::endl; - std::cerr << err.str(); - return std::string(); + cmSystemTools::Error(err.str().c_str()); + return false; } pos += searchString.length(); std::string::size_type sz = eline.size() - pos - 1; - qrcEntries.push_back(eline.substr(pos, sz)); + depends.push_back(eline.substr(pos, sz)); } } } - depends.insert(depends.end(), qrcEntries.begin(), qrcEntries.end()); - return cmJoin(qrcEntries, "@list_sep@"); + return true; } -static std::string ListQt4RccInputs(cmSourceFile* sf, - std::vector<std::string>& depends) +/// @brief Reads the resource files list from from a .qrc file - Qt4 version +/// @return True if the .qrc file was successfully parsed +static bool ListQt4RccInputs(cmSourceFile* sf, + std::vector<std::string>& depends) { const std::string qrcContents = ReadAll(sf->GetFullPath()); cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); - std::string entriesList; - const char* sep = ""; - size_t offset = 0; while (fileMatchRegex.find(qrcContents.c_str() + offset)) { std::string qrcEntry = fileMatchRegex.match(1); @@ -547,12 +545,21 @@ static std::string ListQt4RccInputs(cmSourceFile* sf, qrcEntry = sf->GetLocation().GetDirectory() + "/" + qrcEntry; } - entriesList += sep; - entriesList += qrcEntry; - sep = "@list_sep@"; depends.push_back(qrcEntry); } - return entriesList; + return true; +} + +/// @brief Reads the resource files list from from a .qrc file +/// @return True if the rcc file was successfully parsed +static bool ListQtRccInputs(const std::string& qtMajorVersion, + cmSourceFile* sf, cmGeneratorTarget const* target, + std::vector<std::string>& depends) +{ + if (qtMajorVersion == "5") { + return ListQt5RccInputs(sf, target, depends); + } + return ListQt4RccInputs(sf, depends); } static void SetupAutoRccTarget(cmGeneratorTarget const* target) @@ -615,16 +622,12 @@ static void SetupAutoRccTarget(cmGeneratorTarget const* target) } optionSep = ";"; - std::vector<std::string> depends; - std::string entriesList; if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - if (qtMajorVersion == "5") { - entriesList = ListQt5RccInputs(sf, target, depends); + std::vector<std::string> depends; + if (ListQtRccInputs(qtMajorVersion, sf, target, depends)) { + entriesList = cmJoin(depends, "@list_sep@"); } else { - entriesList = ListQt4RccInputs(sf, depends); - } - if (entriesList.empty()) { return; } } @@ -778,11 +781,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( rcc_output.push_back(rcc_output_file); } if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - if (qtMajorVersion == "5") { - ListQt5RccInputs(sf, target, depends); - } else { - ListQt4RccInputs(sf, depends); - } + ListQtRccInputs(qtMajorVersion, sf, target, depends); #if defined(_WIN32) && !defined(__CYGWIN__) // Cannot use PRE_BUILD because the resource files themselves // may not be sources within the target so VS may not know the diff --git a/Tests/QtAutogen/CMakeLists.txt b/Tests/QtAutogen/CMakeLists.txt index e35e1d1ff1..c713d1c964 100644 --- a/Tests/QtAutogen/CMakeLists.txt +++ b/Tests/QtAutogen/CMakeLists.txt @@ -44,10 +44,16 @@ else() endif() +# -- RCC only add_executable(rcconly rcconly.cpp second_resource.qrc) set_property(TARGET rcconly PROPERTY AUTORCC ON) target_link_libraries(rcconly ${QT_QTCORE_TARGET}) +# -- RCC empty +add_executable(rcc_empty rcc_empty.cpp rcc_empty_resource.qrc) +set_property(TARGET rcc_empty PROPERTY AUTORCC ON) +target_link_libraries(rcc_empty ${QT_QTCORE_TARGET}) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_definitions(-DFOO -DSomeDefine="Barx") diff --git a/Tests/QtAutogen/rcc_empty.cpp b/Tests/QtAutogen/rcc_empty.cpp new file mode 100644 index 0000000000..3f9f9a28d7 --- /dev/null +++ b/Tests/QtAutogen/rcc_empty.cpp @@ -0,0 +1,9 @@ + +extern int qInitResources_rcc_empty_resource(); + +int main(int, char**) +{ + // Fails to link if the symbol is not present. + qInitResources_rcc_empty_resource(); + return 0; +} diff --git a/Tests/QtAutogen/rcc_empty_resource.qrc b/Tests/QtAutogen/rcc_empty_resource.qrc new file mode 100644 index 0000000000..4ca9cd5837 --- /dev/null +++ b/Tests/QtAutogen/rcc_empty_resource.qrc @@ -0,0 +1,4 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> +</qresource> +</RCC> diff --git a/Tests/RunCMake/AndroidTestUtilities/CMakeLists.txt b/Tests/RunCMake/AndroidTestUtilities/CMakeLists.txt new file mode 100644 index 0000000000..dc92486973 --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.6) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/AndroidTestUtilities/RunCMakeTest.cmake b/Tests/RunCMake/AndroidTestUtilities/RunCMakeTest.cmake new file mode 100644 index 0000000000..f0ae24b2fe --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/RunCMakeTest.cmake @@ -0,0 +1,20 @@ +include(RunCMake) + +function(run_ATU case target) + # Use a single build tree for a few tests without cleaning. + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + if(target) + set(build_args --target ${target}) + else() + set(build_args) + endif() + run_cmake(${case}) + run_cmake_command(${case}Build ${CMAKE_COMMAND} --build . --config Debug ${build_args}) +endfunction() + +run_ATU(SetupTest1 "") +run_ATU(SetupTest2 "tests") +run_ATU(SetupTest3 "tests") diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest1.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest1.cmake new file mode 100644 index 0000000000..1c9098b3af --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest1.cmake @@ -0,0 +1,17 @@ +enable_testing() +include(AndroidTestUtilities) + +find_program(adb_executable adb) + +set(ExternalData_URL_TEMPLATES + "https://data.kitware.com/api/v1/file/hashsum/%(algo)/%(hash)/download" + ) + +set(test_files "data/a.txt") + +set(ANDROID 1) + +android_add_test_data(setup_test + FILES ${test_files} + DEVICE_TEST_DIR "/data/local/tests/example1" + DEVICE_OBJECT_STORE "/sdcard/.ExternalData/SHA") diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest1Build-check.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest1Build-check.cmake new file mode 100644 index 0000000000..ef7569d65a --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest1Build-check.cmake @@ -0,0 +1,5 @@ +include(${CMAKE_CURRENT_LIST_DIR}/check.cmake) +compare_build_to_expected(FILES + "data/a.txt" + ) +check_for_setup_test() diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest2.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest2.cmake new file mode 100644 index 0000000000..cf4c764a1d --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest2.cmake @@ -0,0 +1,30 @@ +enable_testing() +include(AndroidTestUtilities) + +add_custom_target(tests) +find_program(adb_executable adb) + +set(ExternalData_URL_TEMPLATES + "https://data.kitware.com/api/v1/file/hashsum/%(algo)/%(hash)/download" + ) +set(test_files + "data/a.txt" + "data/subfolder/b.txt" + "data/subfolder/protobuffer.p" + ) + +set(test_libs "data/subfolder/exampleLib.txt") + +set(ANDROID 1) + +android_add_test_data(setup_test + FILES ${test_files} + LIBS ${test_libs} + DEVICE_TEST_DIR "/data/local/tests/example2" + DEVICE_OBJECT_STORE "/sdcard/.ExternalData/SHA" + NO_LINK_REGEX "\\.p$") + +set_property( + TARGET setup_test + PROPERTY EXCLUDE_FROM_ALL 1) +add_dependencies(tests setup_test) diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest2Build-check.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest2Build-check.cmake new file mode 100644 index 0000000000..6adbd59d77 --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest2Build-check.cmake @@ -0,0 +1,7 @@ +include(${CMAKE_CURRENT_LIST_DIR}/check.cmake) +compare_build_to_expected(FILES + "data/a.txt" + "data/subfolder/b.txt" + "data/subfolder/protobuffer.p" + ) +check_for_setup_test() diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest3.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest3.cmake new file mode 100644 index 0000000000..b32b6b1a8a --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest3.cmake @@ -0,0 +1,33 @@ +enable_testing() +include(AndroidTestUtilities) + +add_custom_target(tests) +find_program(adb_executable adb) + +set(ExternalData_URL_TEMPLATES + "https://data.kitware.com/api/v1/file/hashsum/%(algo)/%(hash)/download" + ) +set(test_dir "/data/local/tests/example3") +set(test_files + "data/a.txt" + "data/subfolder/b.txt" + ) +set(test_libs "libs/exampleLib.txt") +set(files_dest "${test_dir}/storage_folder") +set(libs_dest "${test_dir}/lib/lib/lib") + +set(ANDROID 1) + +android_add_test_data(setup_test + FILES ${test_files} + LIBS ${test_libs} + FILES_DEST ${files_dest} + LIBS_DEST ${libs_dest} + DEVICE_TEST_DIR "/data/local/tests/example3" + DEVICE_OBJECT_STORE "/sdcard/.ExternalData/SHA" + NO_LINK_REGEX "\\.p$") + +set_property( + TARGET setup_test + PROPERTY EXCLUDE_FROM_ALL 1) +add_dependencies(tests setup_test) diff --git a/Tests/RunCMake/AndroidTestUtilities/SetupTest3Build-check.cmake b/Tests/RunCMake/AndroidTestUtilities/SetupTest3Build-check.cmake new file mode 100644 index 0000000000..3062cdc32e --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/SetupTest3Build-check.cmake @@ -0,0 +1,6 @@ +include(${CMAKE_CURRENT_LIST_DIR}/check.cmake) +compare_build_to_expected(FILES + "data/a.txt" + "data/subfolder/b.txt" + ) +check_for_setup_test() diff --git a/Tests/RunCMake/AndroidTestUtilities/check.cmake b/Tests/RunCMake/AndroidTestUtilities/check.cmake new file mode 100644 index 0000000000..ccd4d74dd9 --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/check.cmake @@ -0,0 +1,20 @@ +function(compare_build_to_expected) + cmake_parse_arguments(_comp "" "" "FILES" ${ARGN}) + set(missing) + foreach(file ${_comp_FILES}) + if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${file}") + list(APPEND missing "${file}") + endif() + endforeach() + if(missing) + string(APPEND RunCMake_TEST_FAILED "Missing files:\n ${missing}") + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) + endif() +endfunction() + +function(check_for_setup_test) + file(STRINGS "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" output_var REGEX "add_test\\(setup_test.*") + if(NOT output_var) + set(RunCMake_TEST_FAILED "Could not find the test: setup_test" PARENT_SCOPE) + endif() +endfunction() diff --git a/Tests/RunCMake/AndroidTestUtilities/data/a.txt b/Tests/RunCMake/AndroidTestUtilities/data/a.txt new file mode 100644 index 0000000000..9d454fb87e --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/data/a.txt @@ -0,0 +1 @@ +Here is a file to test. diff --git a/Tests/RunCMake/AndroidTestUtilities/data/proto.proto b/Tests/RunCMake/AndroidTestUtilities/data/proto.proto new file mode 100644 index 0000000000..7402a3a360 --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/data/proto.proto @@ -0,0 +1 @@ +proto.proto diff --git a/Tests/RunCMake/AndroidTestUtilities/data/subfolder/b.txt b/Tests/RunCMake/AndroidTestUtilities/data/subfolder/b.txt new file mode 100644 index 0000000000..c8c6a898bb --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/data/subfolder/b.txt @@ -0,0 +1 @@ +SetupTest2.cmake diff --git a/Tests/RunCMake/AndroidTestUtilities/data/subfolder/protobuffer.p b/Tests/RunCMake/AndroidTestUtilities/data/subfolder/protobuffer.p new file mode 100644 index 0000000000..a5dc7d2315 --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/data/subfolder/protobuffer.p @@ -0,0 +1 @@ +protobuffer.p diff --git a/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.so b/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.so new file mode 100644 index 0000000000..f4cdf826e1 --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.so @@ -0,0 +1 @@ +here is a fake lib. diff --git a/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.txt b/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.txt new file mode 100644 index 0000000000..308921a52f --- /dev/null +++ b/Tests/RunCMake/AndroidTestUtilities/libs/exampleLib.txt @@ -0,0 +1 @@ +here is an example lib! diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 0eafbeff56..9dc540f785 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -131,6 +131,7 @@ if(NOT CMake_TEST_EXTERNAL_CMAKE) ) endif() +add_RunCMake_test(AndroidTestUtilities) add_RunCMake_test(BuildDepends) if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja") add_RunCMake_test(CompilerChange) diff --git a/Tests/Server/server-test.py b/Tests/Server/server-test.py index 72f82ba4c4..14767f4cc1 100644 --- a/Tests/Server/server-test.py +++ b/Tests/Server/server-test.py @@ -102,4 +102,18 @@ for obj in testData: print("Completed") +# Tell the server to exit. +proc.stdin.close() +proc.stdout.close() + +# Wait for the server to exit. +# If this version of python supports it, terminate the server after a timeout. +try: + proc.wait(timeout=5) +except TypeError: + proc.wait() +except: + proc.terminate() + raise + sys.exit(0) |