on bde717c help sign in
unity8/cmake/modules/QmlTest.cmake
489 lines 19 kB history raw
1# If you need to override the qmlscene or qmltestrunner executables,
2# create the corresponding executable target.
4# These functions respect the global STDOUT_LOGGER and ARTIFACTS_DIR variables.
6# You can use those with cmake_parse_arguments
7# if you need to wrap and mangle arguments.
8set(QMLTEST_OPTIONS ADD_TEST CACHE INTERNAL "")
9set(QMLTEST_SINGLE ITERATIONS ARG_PREFIX CACHE INTERNAL "")
10set(QMLTEST_MULTI ARGS ENVIRONMENT DEPENDS IMPORT_PATHS TARGETS CACHE INTERNAL "")
12# import_executables(name1 [name2 [...]]
13# [OPTIONAL] # continue when not found
14# )
16# This will find the named executables and import them
17# to an imported target of the same name.
19function(import_executables)
20 cmake_parse_arguments(QMLTEST "OPTIONAL" "" "" ${ARGN})
22 foreach(NAME ${QMLTEST_UNPARSED_ARGUMENTS})
23 if(NOT TARGET ${NAME})
24 add_executable(${NAME} IMPORTED GLOBAL)
25 find_program(${NAME}_exe ${NAME})
27 if(NOT QMLTEST_OPTIONAL AND NOT ${NAME}_exe)
28 message(FATAL_ERROR "Could not locate ${NAME}.")
29 elseif(NOT ${NAME}_exe)
30 message(STATUS "Could not locate ${NAME}, skipping.")
31 else()
32 set_target_properties(${NAME} PROPERTIES IMPORTED_LOCATION ${${NAME}_exe})
33 endif()
34 endif()
35 endforeach()
36endfunction()
39# add_qml_test(path component_name
40# [...]
41# )
43# Add test targets for ${component_name} under ${path}. It's assumed
44# that the test file is named ${path}/tst_${component_name}.qml.
46# This function wraps add_manual_qml_test and add_qml_unittest,
47# see below for available arguments.
49function(add_qml_test PATH COMPONENT_NAME)
50 cmake_parse_arguments(QMLTEST "${QMLTEST_OPTIONS}" "${QMLTEST_SINGLE}" "${QMLTEST_MULTI}" ${ARGN})
51 mangle_arguments()
53 add_qml_unittest(${ARGV})
54 add_manual_qml_test(${ARGV})
55endfunction()
58# add_qml_test_data(path component_name
59# [...]
60# )
62# Install file called ${component_name} (or ${component_name}.qml) under
63# ${path}.
65function(add_qml_test_data PATH COMPONENT_NAME)
66 cmake_parse_arguments(TEST "" "DESTINATION" "" ${ARGN})
68 set(filename "${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/${COMPONENT_NAME}")
70 if (IS_DIRECTORY "${filename}")
71 # As a convenience, allow specifying a directory and we will install
72 # all files in the dir. We do it this way rather than passing
73 # DIRECTORY to install() because we want to process any qml files.
74 file(GLOB subfiles RELATIVE "${filename}" "${filename}/*")
75 foreach(subfile ${subfiles})
76 add_qml_test_data("${PATH}/${COMPONENT_NAME}" "${subfile}")
77 endforeach()
78 return()
79 endif()
81 if (NOT EXISTS "${filename}")
82 set(filename "${filename}.qml")
83 set(COMPONENT_NAME "${COMPONENT_NAME}.qml")
84 endif()
86 if ("${filename}" MATCHES "\\.qml$")
87 file(READ "${filename}" contents)
88 string(REGEX REPLACE "(\"[./]*)/qml(/|\")" "\\1\\2" contents "${contents}")
89 # this is for (at least) cardcreatortest which pulls in an architecture-specific
90 # import into the plugins directory (which is a 'qml' once installed).
91 string(REGEX REPLACE "(import \"[./]*)/plugins(/|\")" "\\1/qml\\2" contents "${contents}")
92 set(filename "${CMAKE_CURRENT_BINARY_DIR}/${PATH}/${COMPONENT_NAME}")
93 file(WRITE "${filename}" "${contents}")
94 endif()
96 if (TEST_DESTINATION)
97 set(DESTINATION "${TEST_DESTINATION}")
98 else()
99 file(RELATIVE_PATH relcurpath "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
100 set(DESTINATION "${SHELL_APP_DIR}/${relcurpath}/${PATH}")
101 endif()
103 install(FILES "${filename}" DESTINATION "${DESTINATION}")
104endfunction()
107# add_qml_unittest(path component_name
108# [...]
109# )
111# Add test targets for ${component_name} under ${path}. It's assumed
112# that the test file is named ${path}/tst_${component_name}.qml.
114# This function wraps add_executable_test, see below for available arguments.
116function(add_qml_unittest PATH COMPONENT_NAME)
117 import_executables(qmltestrunner)
119 add_executable_test(${COMPONENT_NAME} qmltestrunner
120 ${ARGN}
121 ARGS -input ${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml ${QMLTEST_ARGS}
122 )
124 if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml")
125 add_qml_test_data("${PATH}" "tst_${COMPONENT_NAME}.qml")
126 endif()
127endfunction()
130# add_manual_qml_test(path component_name
131# [...]
132# )
134# Add manual test targets for ${component_name} under ${path}. It's assumed
135# that the test file is named ${path}/tst_${component_name}.qml.
137# This function wraps add_manual_test, see below for available arguments.
139function(add_manual_qml_test PATH COMPONENT_NAME)
140 import_executables(qmlscene)
141 cmake_parse_arguments(QMLTEST "${QMLTEST_OPTIONS}" "${QMLTEST_SINGLE}" "${QMLTEST_MULTI}" ${ARGN})
143 add_manual_test(${COMPONENT_NAME} qmlscene
144 ${ARGN}
145 ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml ${QMLTEST_ARGS}
146 )
148 if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PATH}/tst_${COMPONENT_NAME}.qml")
149 add_qml_test_data("${PATH}" "tst_${COMPONENT_NAME}.qml")
150 endif()
151endfunction()
154# add_executable_test(target component_name
155# [...] # see doc for add_manual_qml_test for common arguments
156# [ADD_TEST] # whether to add to the "test" target
157# [ARG_PREFIX arg_prefix] # prefix logging arguments with this string
158# [ARGS] arg1 [arg2 [...]] # pass these arguments to the test executable
159# [TARGETS target1 [target2 [...]]] # make the listed targets depend on this test
160# # if a corresponding xvfbtarget1, xvfbtarget2 etc. exists,
161# # this test running under xvfb will be added as a dependency
162# # of those targets
163# [ITERATIONS count] # run this test as a benchmark for ${count} iterations
164# )
166# Logging options in the standard form of "-o filename,format"
167# will be appended to the arguments list, prefixed with ARG_PREFIX.
168# XUnitXML files will be stored in current binary dir.
170# Three targets will be created:
171# - test${component_name} - Runs the test
172# - xvfbtest${component_name} - Runs the test under xvfb
173# - gdbtest${component_name} - Runs the test under gdb
175function(add_executable_test COMPONENT_NAME TARGET)
176 import_executables(gdb xvfb-run OPTIONAL)
178 cmake_parse_arguments(QMLTEST "${QMLTEST_OPTIONS}" "${QMLTEST_SINGLE}" "${QMLTEST_MULTI}" ${ARGN})
179 mangle_arguments()
181 file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
182 set(file_logger -o ${CMAKE_CURRENT_BINARY_DIR}/test${COMPONENT_NAME}.xml,xunitxml)
184 bake_arguments("${QMLTEST_ARG_PREFIX}" args ${iterations} ${file_logger} ${STDOUT_LOGGER})
186 set(qmltest_command
187 $<TARGET_FILE:${TARGET}>
188 ${QMLTEST_ARGS}
189 ${args}
190 )
192 add_qmltest_target(test${COMPONENT_NAME} ${TARGET}
193 COMMAND ${qmltest_command}
194 ${depends}
195 ENVIRONMENT QML2_IMPORT_PATH=${imports} ${QMLTEST_ENVIRONMENT}
196 ${add_test}
197 ${targets}
198 )
200 if(TARGET xvfb-run)
201 add_qmltest_target(xvfbtest${COMPONENT_NAME} ${TARGET}
202 COMMAND $<TARGET_FILE:xvfb-run> --server-args "-screen 0 1024x768x24" --auto-servernum ${qmltest_command}
203 ${depends}
204 ENVIRONMENT QML2_IMPORT_PATH=${imports} ${QMLTEST_ENVIRONMENT} LD_PRELOAD=/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/mesa/libGL.so.1
205 TARGETS ${xvfb_targets}
206 )
207 endif()
209 if(TARGET gdb)
210 add_qmltest_target(gdbtest${COMPONENT_NAME} ${TARGET}
211 COMMAND $<TARGET_FILE:gdb> -ex run -args ${qmltest_command}
212 ${depends}
213 ENVIRONMENT QML2_IMPORT_PATH=${imports} ${QMLTEST_ENVIRONMENT}
214 )
215 endif()
216endfunction()
219# add_manual_test(target component_name
220# [DEPENDS target1 [target2 [...]]] # make this test depend on the specified targets
221# [IMPORT_PATHS import_path1 [import_path2 [...]] # use these QML import paths
222# # (they're searched first to last)
223# [ENVIRONMENT var1=value1 [var2=value2 [...]]] # set these environment variables
224# )
226# Two targets will be created:
227# - try${component_name} - Runs the test for manual interaction
228# - gdbtry${component_name} - Runs the test under gdb
230function(add_manual_test COMPONENT_NAME TARGET)
231 import_executables(gdb OPTIONAL)
233 cmake_parse_arguments(QMLTEST "${QMLTEST_OPTIONS}" "${QMLTEST_SINGLE}" "${QMLTEST_MULTI}" ${ARGN})
234 mangle_arguments()
236 bake_arguments("${QMLTEST_ARG_PREFIX}" args -qmljsdebugger=port:3768,3800)
238 set(qmltry_command
239 $<TARGET_FILE:${TARGET}>
240 ${QMLTEST_ARGS}
241 ${args}
242 )
244 add_qmltest_target(try${COMPONENT_NAME} ${TARGET}
245 COMMAND ${qmltry_command}
246 ${depends}
247 ENVIRONMENT QML2_IMPORT_PATH=${imports} ${QMLTEST_ENVIRONMENT}
248 )
250 if(TARGET gdb)
251 add_qmltest_target(gdbtry${COMPONENT_NAME} ${TARGET}
252 COMMAND $<TARGET_FILE:gdb> -ex run -args ${qmltry_command}
253 ${depends}
254 ENVIRONMENT QML2_IMPORT_PATH=${imports} ${QMLTEST_ENVIRONMENT}
255 )
256 endif()
257endfunction()
260# add_meta_test(target)
262# Adds a test target that will run one of our "meta" test targets, like
263# xvfbuitests. This script will run the specified suite of tests on an
264# installed system.
266function(add_meta_test TARGET_NAME)
267 cmake_parse_arguments(TEST "SERIAL" "" "DEPENDS" ${ARGN})
269 add_custom_target(${TARGET_NAME})
271 set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${TARGET_NAME}.sh")
272 if(TEST_SERIAL)
273 file(WRITE "${filename}" "#!/bin/sh\n\n")
274 else()
275 file(WRITE "${filename}" "#!/usr/bin/parallel --shebang --no-notice\n\n")
276 endif()
278 add_meta_dependencies(${TARGET_NAME} DEPENDS ${TEST_DEPENDS})
279 # else we will write the rest of the script as we add cmake targets
281 install(FILES "${filename}"
282 PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE
283 GROUP_EXECUTE GROUP_READ
284 WORLD_EXECUTE WORLD_READ
285 DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/scripts"
286 )
287endfunction()
290################### INTERNAL ####################
292function(install_test_script TARGET_NAME)
293 cmake_parse_arguments(TEST "" "" "COMMAND;ENVIRONMENT" ${ARGN})
295 # Now write the above test into a shell script that we can run on an
296 # installed system.
297 set(script "#!/bin/sh\n\nset -x\n\n")
298 foreach(ONE_ENV ${TEST_ENVIRONMENT})
299 set(script "${script}export ${ONE_ENV}\n")
300 endforeach()
301 set(script "${script}export UNITY_TESTING_DATADIR=\"${CMAKE_INSTALL_PREFIX}/${SHELL_APP_DIR}\"\n")
302 set(script "${script}export UNITY_TESTING_LIBDIR=\"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}\"\n")
303 set(script "${script}\n")
304 set(script "${script}XML_ARGS=\n")
305 set(script "${script}if [ -n \"\$ARTIFACTS_DIR\" ]; then\n")
306 set(script "${script} XML_ARGS=\"@XML_ARGS@\"\n")
307 set(script "${script} mkdir -p \"@XML_DIR@\"\n")
308 set(script "${script} touch \"@XML_FILE@\"\n")
309 set(script "${script}fi\n")
310 set(script "${script}\n")
311 foreach(ONE_CMD ${TEST_COMMAND})
312 set(script "${script}'${ONE_CMD}' ")
313 endforeach()
314 set(script "${script}\"\$@\"") # Allow passing arguments if desired
316 set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${TARGET_NAME}.sh")
318 # Generate script to file then read it back to resolve any generator
319 # expressions before we try to replace paths.
320 file(GENERATE
321 OUTPUT "${filename}"
322 CONTENT "${script}"
323 )
325 # Do replacement at install time to save needless work and to make sure
326 # we are modifying file after generate step above (which doesn't happen
327 # immediately). We can't use a custom-defined function or macro here...
328 # So instead we use a giant ugly code block.
330 # START OF CODE BLOCK --------------------------------------------------
331 install(CODE "
332 file(READ \"${filename}\" replacestr)
334 # Now some replacements...
335 # tests like to write xml output to our builddir; we don't need that, but we do want them in ARTIFACTS_DIR
336 string(REGEX MATCH \"( '--parameter')? '-o'( '--parameter')? '[^']*,xunitxml' \" xmlargs \"\${replacestr}\")
337 string(REGEX REPLACE \"( '--parameter')? '-o'( '--parameter')? '[^']*,xunitxml' \" \" \\\$XML_ARGS \" replacestr \"\${replacestr}\")
338 string(REGEX REPLACE \"'[^']*/tests/\" \"'\\\$ARTIFACTS_DIR/tests/\" xmlargs \"\${xmlargs}\")
339 string(REGEX REPLACE \".*'([^']*),xunitxml'.*\" \"\\\\1\" xmlfile \"\${xmlargs}\")
340 string(REGEX REPLACE \"(.*)/[^/]*\" \"\\\\1\" xmldir \"\${xmlfile}\")
341 string(REGEX REPLACE \"'\" \"\" xmlargs \"\${xmlargs}\") # strip single quotes
342 string(REGEX REPLACE \"@XML_ARGS@\" \"\${xmlargs}\" replacestr \"\${replacestr}\")
343 string(REGEX REPLACE \"@XML_DIR@\" \"\${xmldir}\" replacestr \"\${replacestr}\")
344 string(REGEX REPLACE \"@XML_FILE@\" \"\${xmlfile}\" replacestr \"\${replacestr}\")
345 # replace build/source roots with their install paths
346 string(REPLACE \"${CMAKE_BINARY_DIR}/libs\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}\" replacestr \"\${replacestr}\")
347 string(REPLACE \"${CMAKE_BINARY_DIR}/plugins\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}\" replacestr \"\${replacestr}\")
348 string(REPLACE \"${CMAKE_BINARY_DIR}/tests/libs\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/libs\" replacestr \"\${replacestr}\")
349 string(REPLACE \"${CMAKE_BINARY_DIR}/tests/mocks\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}/mocks\" replacestr \"\${replacestr}\")
350 string(REPLACE \"${CMAKE_BINARY_DIR}/tests/plugins\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/plugins\" replacestr \"\${replacestr}\")
351 string(REPLACE \"${CMAKE_BINARY_DIR}/tests/qmltests\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/qmltests\" replacestr \"\${replacestr}\")
352 string(REPLACE \"${CMAKE_BINARY_DIR}/tests/uqmlscene\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}\" replacestr \"\${replacestr}\")
353 string(REPLACE \"${CMAKE_BINARY_DIR}/tests/utils/modules\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_INSTALL_QML}/utils\" replacestr \"\${replacestr}\")
354 string(REPLACE \"${CMAKE_SOURCE_DIR}/tests/plugins\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_APP_DIR}/tests/plugins\" replacestr \"\${replacestr}\")
355 string(REPLACE \"${CMAKE_SOURCE_DIR}/tests/qmltests\" \"${CMAKE_INSTALL_PREFIX}/${SHELL_APP_DIR}/tests/qmltests\" replacestr \"\${replacestr}\")
357 file(WRITE \"${filename}\" \"\${replacestr}\")
358 ")
359 # END OF CODE BLOCK --------------------------------------------------
361 install(FILES "${filename}"
362 PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE
363 GROUP_EXECUTE GROUP_READ
364 WORLD_EXECUTE WORLD_READ
365 DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/scripts"
366 )
367endfunction()
369function(add_meta_dependencies UPSTREAM_TARGET)
370 cmake_parse_arguments(TEST "" "" "DEPENDS" ${ARGN})
372 foreach(depend ${TEST_DEPENDS})
373 add_dependencies(${UPSTREAM_TARGET} ${depend})
375 # add depend to the meta test script that we will install on system
376 set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${UPSTREAM_TARGET}.sh")
377 if (EXISTS "${filename}")
378 file(APPEND "${filename}" "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/scripts/${depend}.sh \"\$@\" 2>&1\n")
379 endif()
380 endforeach()
381endfunction()
383# add_qmltest_target(target_name target
384# COMMAND test_exe [arg1 [...]] # execute this test with arguments
385# [...] # see above for available arguments:
386# # ADD_TEST, ENVIRONMENT, DEPENDS and TARGETS
387# )
389function(add_qmltest_target TARGET_NAME TARGET)
390 cmake_parse_arguments(QMLTEST "${QMLTEST_OPTIONS}" "${QMLTEST_SINGLE}" "COMMAND;${QMLTEST_MULTI}" ${ARGN})
391 mangle_arguments()
393 # Additional arguments
394 string(TOLOWER "${CMAKE_GENERATOR}" cmake_generator_lower)
395 if(cmake_generator_lower STREQUAL "unix makefiles")
396 set(function "$(FUNCTION)")
397 endif()
399 add_custom_target(${TARGET_NAME}
400 env ${QMLTEST_ENVIRONMENT}
401 ${QMLTEST_COMMAND} ${function}
402 DEPENDS ${TARGET} ${QMLTEST_DEPENDS}
403 )
405 install_test_script(${TARGET_NAME}
406 ENVIRONMENT ${QMLTEST_ENVIRONMENT}
407 COMMAND ${QMLTEST_COMMAND}
408 )
410 if(QMLTEST_ADD_TEST)
411 add_test(
412 NAME ${TARGET_NAME}
413 COMMAND ${QMLTEST_COMMAND}
414 )
416 foreach(ENV ${QMLTEST_ENVIRONMENT})
417 set_property(TEST ${TARGET_NAME} APPEND PROPERTY ENVIRONMENT ${ENV})
418 endforeach()
420 set_property(TEST ${TARGET_NAME} APPEND PROPERTY DEPENDS ${TARGET})
421 foreach(DEPEND ${DEPENDS})
422 set_property(TEST ${TARGET_NAME} APPEND PROPERTY DEPENDS ${DEPEND})
423 endforeach()
424 endif()
426 foreach(UPSTREAM_TARGET ${QMLTEST_TARGETS})
427 add_meta_dependencies(${UPSTREAM_TARGET} DEPENDS ${TARGET_NAME})
428 endforeach()
429endfunction()
432# mangle_arguments(${ARGN})
434# Verify there were no unparsed arguments and
435# mangle the known ones for further processing.
437macro(mangle_arguments)
438 if(QMLTEST_UNPARSED_ARGUMENTS)
439 message(FATAL_ERROR "Unexpected arguments: ${QMLTEST_UNPARSED_ARGUMENTS}")
440 endif()
442 if(QMLTEST_ADD_TEST)
443 set(add_test ADD_TEST)
444 endif()
446 if(QMLTEST_IMPORT_PATHS)
447 string(REPLACE ";" ":" imports "${QMLTEST_IMPORT_PATHS}")
448 endif()
450 if(QMLTEST_ITERATIONS)
451 set(iterations -iterations ${QMLTEST_ITERATIONS})
452 endif()
454 if(QMLTEST_DEPENDS)
455 set(depends DEPENDS ${QMLTEST_DEPENDS})
456 endif()
458 if(QMLTEST_TARGETS)
459 set(targets TARGETS ${QMLTEST_TARGETS})
460 endif()
462 set(xvfb_targets "")
463 foreach(target ${QMLTEST_TARGETS})
464 if(TARGET xvfb${target})
465 list(APPEND xvfb_targets xvfb${target})
466 endif()
467 endforeach()
468 set(xvfb_targets "${xvfb_targets}" PARENT_SCOPE)
469endmacro()
472# bake_arguments(prefix output
473# arg1 [arg2 [...]]
474# )
476# If set, add the argument prefix before every passed
477# argument and store the result in ${OUTPUT} variable.
479function(bake_arguments PREFIX OUTPUT)
480 set(args "${ARGN}")
481 if(PREFIX)
482 set(args "")
483 foreach(arg ${ARGN})
484 list(APPEND args ${PREFIX})
485 list(APPEND args ${arg})
486 endforeach()
487 endif()
488 set(${OUTPUT} "${args}" PARENT_SCOPE)
489endfunction()