From c1ad91505523198490504b3363e6b610f60cfe2c Mon Sep 17 00:00:00 2001 From: Dominik Riebeling Date: Tue, 28 Dec 2021 16:43:40 +0100 Subject: cmake: Add QtTest test discovery module. Allow discivery of the QtTest based unit test. Taken from https://github.com/ocroquette/cmake-qtest-discovery Change-Id: I79a54568b2dbc216d35a463b6be36c197203c5b5 --- utils/cmake/QtTest.cmake | 130 +++++++++++++++++++++++++++++++++++++++ utils/cmake/QtTestAddTests.cmake | 102 ++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100755 utils/cmake/QtTest.cmake create mode 100755 utils/cmake/QtTestAddTests.cmake (limited to 'utils') diff --git a/utils/cmake/QtTest.cmake b/utils/cmake/QtTest.cmake new file mode 100755 index 0000000000..d967ffd960 --- /dev/null +++ b/utils/cmake/QtTest.cmake @@ -0,0 +1,130 @@ +# Copyright 2020 Olivier Croquette +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT +# WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# v1.2 +# +# Latest version is available from GitHub: +# https://github.com/ocroquette/cmake-qtest-discovery + +#[=======================================================================[.rst: +QtTest +---------- + +This module defines functions to help use the Qt Test infrastructure. +The main function is :command:`qtest_discover_tests`. + +.. command:: qtest_discover_tests + + Automatically add tests with CTest by querying the compiled test executable + for available tests:: + + qtest_discover_tests(target + [WORKING_DIRECTORY dir] + [TEST_PREFIX prefix] + [TEST_SUFFIX suffix] + [PROPERTIES name1 value1...] + [DISCOVERY_TIMEOUT seconds]) + + ``qtest_discover_tests`` sets up a post-build command on the test executable + that generates the list of tests by parsing the output from running the test + with the ``-datatags`` argument. This ensures that the full list of + tests, including instantiations of parameterized tests, is obtained. Since + test discovery occurs at build time, it is not necessary to re-run CMake when + the list of tests changes. + + The options are: + + ``target`` + Specifies the Google Test executable, which must be a known CMake + executable target. CMake will substitute the location of the built + executable when running the test. + + ``WORKING_DIRECTORY dir`` + Specifies the directory in which to run the discovered test cases. If this + option is not provided, the current binary directory is used. + + ``TEST_PREFIX prefix`` + Specifies a ``prefix`` to be prepended to the name of each discovered test + case. + + ``TEST_SUFFIX suffix`` + Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of + every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may + be specified. + + ``PROPERTIES name1 value1...`` + Specifies additional properties to be set on all tests discovered by this + invocation of ``qtest_discover_tests``. You can specify a timeout for the + test execution by setting the TIMEOUT property here, as supported by ctest. + + ``DISCOVERY_TIMEOUT sec`` + Specifies how long (in seconds) CMake will wait for the test to enumerate + available tests. If the test takes longer than this, discovery (and your + build) will fail. Most test executables will enumerate their tests very + quickly, but under some exceptional circumstances, a test may require a + longer timeout. The default is 5. See also the ``TIMEOUT`` option of + :command:`execute_process`. + +#]=======================================================================] + +function(qtest_discover_tests TARGET) + cmake_parse_arguments( + "" + "" + "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;DISCOVERY_TIMEOUT" + "PROPERTIES" + ${ARGN} + ) + + if(NOT _WORKING_DIRECTORY) + set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() + if(NOT _DISCOVERY_TIMEOUT) + set(_DISCOVERY_TIMEOUT 5) + endif() + + set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}") + set(ctest_include_file "${ctest_file_base}_tests.cmake") + add_custom_command(TARGET ${TARGET} + POST_BUILD + COMMAND "${CMAKE_COMMAND}" + -D "\"TEST_EXECUTABLE:FILEPATH=$\"" + -D "\"CTEST_FILE:FILEPATH=${ctest_include_file}\"" + -D "\"TEST_PROPERTIES=${_PROPERTIES}\"" + -D "\"TEST_DISCOVERY_TIMEOUT=${_DISCOVERY_TIMEOUT}\"" + -D "\"TEST_PREFIX=${_TEST_PREFIX}\"" + -D "\"TEST_SUFFIX=${_TEST_SUFFIX}\"" + -D "\"TEST_WORKING_DIR=${_WORKING_DIRECTORY}\"" + -P "\"${_QTTEST_DISCOVER_TESTS_SCRIPT}\"" + BYPRODUCTS "${ctest_include_file}" + ) + + set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES + "${ctest_include_file}" + ) +endfunction() + + +############################################################################### + +set(_QTTEST_DISCOVER_TESTS_SCRIPT + ${CMAKE_CURRENT_LIST_DIR}/QtTestAddTests.cmake +) diff --git a/utils/cmake/QtTestAddTests.cmake b/utils/cmake/QtTestAddTests.cmake new file mode 100755 index 0000000000..1a8db46783 --- /dev/null +++ b/utils/cmake/QtTestAddTests.cmake @@ -0,0 +1,102 @@ +# Copyright 2020 Olivier Croquette +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT +# WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# This script is run as POST_BUILD step, added by QtTest.cmake. See there +# for more information. +# +# v1.2 +# +# Latest version is available from GitHub: +# https://github.com/ocroquette/cmake-qtest-discovery + +get_filename_component(working_dir ${TEST_EXECUTABLE} DIRECTORY) + +execute_process( + COMMAND "${TEST_EXECUTABLE}" -datatags + WORKING_DIR ${working_dir} + OUTPUT_VARIABLE output_variable + TIMEOUT ${TEST_DISCOVERY_TIMEOUT} + ERROR_VARIABLE error_variable + RESULT_VARIABLE result_variable +) + +if(NOT "${result_variable}" EQUAL 0) + string(REPLACE "\n" "\n " output "${output}") + message(FATAL_ERROR + "Error running test executable.\n" + " Path: '${TEST_EXECUTABLE}'\n" + " Result: ${result_variable}\n" + " Output:\n" + " ${output_variable}\n" + " Error:\n" + " ${error_variable}\n" + ) +endif() + +macro(get_and_escape_parameters) + set(test_class ${CMAKE_MATCH_1}) + set(test_method ${CMAKE_MATCH_2}) + set(test_dataset ${CMAKE_MATCH_3}) + + # Test class and method should be safe, but the dataset name might + # contain problematic characters + set(test_dataset_escaped "${test_dataset}") + string(REPLACE "\\" "\\\\" test_dataset_escaped "${test_dataset_escaped}") + string(REPLACE "\"" "\\\"" test_dataset_escaped "${test_dataset_escaped}") +endmacro() + +set(ctest_script_content) +string(REPLACE "\n" ";" output_lines "${output_variable}") +foreach(line ${output_lines}) + set(generated_name) + if(line MATCHES "^([^ ]*) ([^ ]*) (.*)$") + # Line contains a data set name, like in: + # test_qttestdemo myParameterizedTest data set name 1 + # test_qttestdemo myParameterizedTest data set name 2 + get_and_escape_parameters() + set(generated_name "${TEST_PREFIX}${test_class}.${test_method}:${test_dataset_escaped}${TEST_SUFFIX}") + string(APPEND ctest_script_content "add_test(\"${generated_name}\" \"${TEST_EXECUTABLE}\" \"${test_method}:${test_dataset_escaped}\")\n") + elseif(line MATCHES "^([^ ]*) ([^ ]*)$") + # Line doesn't contain a data set name, like in: + # test_qttestdemo myFirstTest + # test_qttestdemo mySecondTest + get_and_escape_parameters() + set(generated_name "${TEST_PREFIX}${test_class}.${test_method}${TEST_SUFFIX}") + string(APPEND ctest_script_content "add_test(\"${generated_name}\" \"${TEST_EXECUTABLE}\" \"${test_method}\")\n") + endif() + if(generated_name) + # Make ctest aware of tests skipped with QSKIP() + # SKIP : test_qttestdemo::mySkippedTest() Example of skipped test + string(APPEND ctest_script_content + "set_tests_properties(\"${generated_name}\" PROPERTIES SKIP_REGULAR_EXPRESSION \"SKIP : \")\n" + ) + # Set other properties + string(APPEND ctest_script_content + "set_tests_properties(\"${generated_name}\" PROPERTIES WORKING_DIRECTORY \"${TEST_WORKING_DIR}\")\n" + ) + string(REPLACE ";" " " external_properties "${TEST_PROPERTIES}") + string(APPEND ctest_script_content + "set_tests_properties(\"${generated_name}\" PROPERTIES ${external_properties})\n" + ) + endif() +endforeach() + +file(WRITE "${CTEST_FILE}" "${ctest_script_content}") -- cgit v1.2.3