diff options
Diffstat (limited to 'utils')
-rwxr-xr-x | utils/cmake/QtTest.cmake | 130 | ||||
-rwxr-xr-x | utils/cmake/QtTestAddTests.cmake | 102 |
2 files changed, 232 insertions, 0 deletions
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 @@ | |||
1 | # Copyright 2020 Olivier Croquette <ocroquette@free.fr> | ||
2 | # | ||
3 | # Permission is hereby granted, free of charge, to any person obtaining | ||
4 | # a copy of this software and associated documentation files (the | ||
5 | # "Software"), to deal in the Software without restriction, including | ||
6 | # without limitation the rights to use, copy, modify, merge, publish, | ||
7 | # distribute, sublicense, and/or sell copies of the Software, and to | ||
8 | # permit persons to whom the Software is furnished to do so, subject to | ||
9 | # the following conditions: | ||
10 | # | ||
11 | # The above copyright notice and this permission notice shall be | ||
12 | # included in all copies or substantial portions of the Software. | ||
13 | # | ||
14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT | ||
15 | # WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO | ||
16 | # THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
18 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
19 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
20 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
21 | # | ||
22 | # v1.2 | ||
23 | # | ||
24 | # Latest version is available from GitHub: | ||
25 | # https://github.com/ocroquette/cmake-qtest-discovery | ||
26 | |||
27 | #[=======================================================================[.rst: | ||
28 | QtTest | ||
29 | ---------- | ||
30 | |||
31 | This module defines functions to help use the Qt Test infrastructure. | ||
32 | The main function is :command:`qtest_discover_tests`. | ||
33 | |||
34 | .. command:: qtest_discover_tests | ||
35 | |||
36 | Automatically add tests with CTest by querying the compiled test executable | ||
37 | for available tests:: | ||
38 | |||
39 | qtest_discover_tests(target | ||
40 | [WORKING_DIRECTORY dir] | ||
41 | [TEST_PREFIX prefix] | ||
42 | [TEST_SUFFIX suffix] | ||
43 | [PROPERTIES name1 value1...] | ||
44 | [DISCOVERY_TIMEOUT seconds]) | ||
45 | |||
46 | ``qtest_discover_tests`` sets up a post-build command on the test executable | ||
47 | that generates the list of tests by parsing the output from running the test | ||
48 | with the ``-datatags`` argument. This ensures that the full list of | ||
49 | tests, including instantiations of parameterized tests, is obtained. Since | ||
50 | test discovery occurs at build time, it is not necessary to re-run CMake when | ||
51 | the list of tests changes. | ||
52 | |||
53 | The options are: | ||
54 | |||
55 | ``target`` | ||
56 | Specifies the Google Test executable, which must be a known CMake | ||
57 | executable target. CMake will substitute the location of the built | ||
58 | executable when running the test. | ||
59 | |||
60 | ``WORKING_DIRECTORY dir`` | ||
61 | Specifies the directory in which to run the discovered test cases. If this | ||
62 | option is not provided, the current binary directory is used. | ||
63 | |||
64 | ``TEST_PREFIX prefix`` | ||
65 | Specifies a ``prefix`` to be prepended to the name of each discovered test | ||
66 | case. | ||
67 | |||
68 | ``TEST_SUFFIX suffix`` | ||
69 | Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of | ||
70 | every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may | ||
71 | be specified. | ||
72 | |||
73 | ``PROPERTIES name1 value1...`` | ||
74 | Specifies additional properties to be set on all tests discovered by this | ||
75 | invocation of ``qtest_discover_tests``. You can specify a timeout for the | ||
76 | test execution by setting the TIMEOUT property here, as supported by ctest. | ||
77 | |||
78 | ``DISCOVERY_TIMEOUT sec`` | ||
79 | Specifies how long (in seconds) CMake will wait for the test to enumerate | ||
80 | available tests. If the test takes longer than this, discovery (and your | ||
81 | build) will fail. Most test executables will enumerate their tests very | ||
82 | quickly, but under some exceptional circumstances, a test may require a | ||
83 | longer timeout. The default is 5. See also the ``TIMEOUT`` option of | ||
84 | :command:`execute_process`. | ||
85 | |||
86 | #]=======================================================================] | ||
87 | |||
88 | function(qtest_discover_tests TARGET) | ||
89 | cmake_parse_arguments( | ||
90 | "" | ||
91 | "" | ||
92 | "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;DISCOVERY_TIMEOUT" | ||
93 | "PROPERTIES" | ||
94 | ${ARGN} | ||
95 | ) | ||
96 | |||
97 | if(NOT _WORKING_DIRECTORY) | ||
98 | set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") | ||
99 | endif() | ||
100 | if(NOT _DISCOVERY_TIMEOUT) | ||
101 | set(_DISCOVERY_TIMEOUT 5) | ||
102 | endif() | ||
103 | |||
104 | set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}") | ||
105 | set(ctest_include_file "${ctest_file_base}_tests.cmake") | ||
106 | add_custom_command(TARGET ${TARGET} | ||
107 | POST_BUILD | ||
108 | COMMAND "${CMAKE_COMMAND}" | ||
109 | -D "\"TEST_EXECUTABLE:FILEPATH=$<TARGET_FILE:${TARGET}>\"" | ||
110 | -D "\"CTEST_FILE:FILEPATH=${ctest_include_file}\"" | ||
111 | -D "\"TEST_PROPERTIES=${_PROPERTIES}\"" | ||
112 | -D "\"TEST_DISCOVERY_TIMEOUT=${_DISCOVERY_TIMEOUT}\"" | ||
113 | -D "\"TEST_PREFIX=${_TEST_PREFIX}\"" | ||
114 | -D "\"TEST_SUFFIX=${_TEST_SUFFIX}\"" | ||
115 | -D "\"TEST_WORKING_DIR=${_WORKING_DIRECTORY}\"" | ||
116 | -P "\"${_QTTEST_DISCOVER_TESTS_SCRIPT}\"" | ||
117 | BYPRODUCTS "${ctest_include_file}" | ||
118 | ) | ||
119 | |||
120 | set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES | ||
121 | "${ctest_include_file}" | ||
122 | ) | ||
123 | endfunction() | ||
124 | |||
125 | |||
126 | ############################################################################### | ||
127 | |||
128 | set(_QTTEST_DISCOVER_TESTS_SCRIPT | ||
129 | ${CMAKE_CURRENT_LIST_DIR}/QtTestAddTests.cmake | ||
130 | ) | ||
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 @@ | |||
1 | # Copyright 2020 Olivier Croquette <ocroquette@free.fr> | ||
2 | # | ||
3 | # Permission is hereby granted, free of charge, to any person obtaining | ||
4 | # a copy of this software and associated documentation files (the | ||
5 | # "Software"), to deal in the Software without restriction, including | ||
6 | # without limitation the rights to use, copy, modify, merge, publish, | ||
7 | # distribute, sublicense, and/or sell copies of the Software, and to | ||
8 | # permit persons to whom the Software is furnished to do so, subject to | ||
9 | # the following conditions: | ||
10 | # | ||
11 | # The above copyright notice and this permission notice shall be | ||
12 | # included in all copies or substantial portions of the Software. | ||
13 | # | ||
14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT | ||
15 | # WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO | ||
16 | # THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
18 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
19 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
20 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
21 | # | ||
22 | # This script is run as POST_BUILD step, added by QtTest.cmake. See there | ||
23 | # for more information. | ||
24 | # | ||
25 | # v1.2 | ||
26 | # | ||
27 | # Latest version is available from GitHub: | ||
28 | # https://github.com/ocroquette/cmake-qtest-discovery | ||
29 | |||
30 | get_filename_component(working_dir ${TEST_EXECUTABLE} DIRECTORY) | ||
31 | |||
32 | execute_process( | ||
33 | COMMAND "${TEST_EXECUTABLE}" -datatags | ||
34 | WORKING_DIR ${working_dir} | ||
35 | OUTPUT_VARIABLE output_variable | ||
36 | TIMEOUT ${TEST_DISCOVERY_TIMEOUT} | ||
37 | ERROR_VARIABLE error_variable | ||
38 | RESULT_VARIABLE result_variable | ||
39 | ) | ||
40 | |||
41 | if(NOT "${result_variable}" EQUAL 0) | ||
42 | string(REPLACE "\n" "\n " output "${output}") | ||
43 | message(FATAL_ERROR | ||
44 | "Error running test executable.\n" | ||
45 | " Path: '${TEST_EXECUTABLE}'\n" | ||
46 | " Result: ${result_variable}\n" | ||
47 | " Output:\n" | ||
48 | " ${output_variable}\n" | ||
49 | " Error:\n" | ||
50 | " ${error_variable}\n" | ||
51 | ) | ||
52 | endif() | ||
53 | |||
54 | macro(get_and_escape_parameters) | ||
55 | set(test_class ${CMAKE_MATCH_1}) | ||
56 | set(test_method ${CMAKE_MATCH_2}) | ||
57 | set(test_dataset ${CMAKE_MATCH_3}) | ||
58 | |||
59 | # Test class and method should be safe, but the dataset name might | ||
60 | # contain problematic characters | ||
61 | set(test_dataset_escaped "${test_dataset}") | ||
62 | string(REPLACE "\\" "\\\\" test_dataset_escaped "${test_dataset_escaped}") | ||
63 | string(REPLACE "\"" "\\\"" test_dataset_escaped "${test_dataset_escaped}") | ||
64 | endmacro() | ||
65 | |||
66 | set(ctest_script_content) | ||
67 | string(REPLACE "\n" ";" output_lines "${output_variable}") | ||
68 | foreach(line ${output_lines}) | ||
69 | set(generated_name) | ||
70 | if(line MATCHES "^([^ ]*) ([^ ]*) (.*)$") | ||
71 | # Line contains a data set name, like in: | ||
72 | # test_qttestdemo myParameterizedTest data set name 1 | ||
73 | # test_qttestdemo myParameterizedTest data set name 2 | ||
74 | get_and_escape_parameters() | ||
75 | set(generated_name "${TEST_PREFIX}${test_class}.${test_method}:${test_dataset_escaped}${TEST_SUFFIX}") | ||
76 | string(APPEND ctest_script_content "add_test(\"${generated_name}\" \"${TEST_EXECUTABLE}\" \"${test_method}:${test_dataset_escaped}\")\n") | ||
77 | elseif(line MATCHES "^([^ ]*) ([^ ]*)$") | ||
78 | # Line doesn't contain a data set name, like in: | ||
79 | # test_qttestdemo myFirstTest | ||
80 | # test_qttestdemo mySecondTest | ||
81 | get_and_escape_parameters() | ||
82 | set(generated_name "${TEST_PREFIX}${test_class}.${test_method}${TEST_SUFFIX}") | ||
83 | string(APPEND ctest_script_content "add_test(\"${generated_name}\" \"${TEST_EXECUTABLE}\" \"${test_method}\")\n") | ||
84 | endif() | ||
85 | if(generated_name) | ||
86 | # Make ctest aware of tests skipped with QSKIP() | ||
87 | # SKIP : test_qttestdemo::mySkippedTest() Example of skipped test | ||
88 | string(APPEND ctest_script_content | ||
89 | "set_tests_properties(\"${generated_name}\" PROPERTIES SKIP_REGULAR_EXPRESSION \"SKIP : \")\n" | ||
90 | ) | ||
91 | # Set other properties | ||
92 | string(APPEND ctest_script_content | ||
93 | "set_tests_properties(\"${generated_name}\" PROPERTIES WORKING_DIRECTORY \"${TEST_WORKING_DIR}\")\n" | ||
94 | ) | ||
95 | string(REPLACE ";" " " external_properties "${TEST_PROPERTIES}") | ||
96 | string(APPEND ctest_script_content | ||
97 | "set_tests_properties(\"${generated_name}\" PROPERTIES ${external_properties})\n" | ||
98 | ) | ||
99 | endif() | ||
100 | endforeach() | ||
101 | |||
102 | file(WRITE "${CTEST_FILE}" "${ctest_script_content}") | ||