BasisTest.cmake
Go to the documentation of this file.
1 # ============================================================================
2 # Copyright (c) 2011-2012 University of Pennsylvania
3 # Copyright (c) 2013-2016 Andreas Schuh
4 # All rights reserved.
5 #
6 # See COPYING file for license information or visit
7 # https://cmake-basis.github.io/download.html#license
8 # ============================================================================
9 
10 ##############################################################################
11 # @file BasisTest.cmake
12 # @brief CTest configuration. Include this module instead of CTest.
13 #
14 # @note This module is included by basis_project_initialize().
15 #
16 # @ingroup CMakeAPI
17 ##############################################################################
18 
19 # ============================================================================
20 # configuration
21 # ============================================================================
22 
23 ## @brief Request build of tests.
24 option (BUILD_TESTING "Request build of tests." OFF)
25 
26 # include CTest module which enables testing, but prevent it from generating
27 # any configuration file or adding targets yet as we want to adjust the
28 # default CTest settings--in particular the site name--before
30 include (CTest)
31 
32 # mark timeout option as advanced
33 mark_as_advanced (DART_TESTING_TIMEOUT)
34 
36 include (CTestTargets)
38 
39 # custom CTest configuration
40 if (EXISTS "${PROJECT_CONFIG_DIR}/CTestCustom.cmake.in")
41  configure_file (
42  "${PROJECT_CONFIG_DIR}/CTestCustom.cmake.in"
43  "${PROJECT_BINARY_DIR}/CTestCustom.cmake"
44  @ONLY
45  )
46 elseif (EXISTS "${PROJECT_CONFIG_DIR}/CTestCustom.cmake")
47  configure_file (
48  "${PROJECT_CONFIG_DIR}/CTestCustom.cmake"
49  "${PROJECT_BINARY_DIR}/CTestCustom.cmake"
50  COPYONLY
51  )
52 else ()
53  basis_get_relative_path (CONFIG_DIR "${PROJECT_SOURCE_DIR}" "${PROJECT_CONFIG_DIR}")
54  if (EXISTS "${BASIS_TEMPLATE_DIR}/${CONFIG_DIR}/CTestCustom.cmake.in")
55  # to avoid a Doxygen warning, we need to replace certain patterns used by
56  # the basisproject tool to replace them with project related information
57  #
58  # Note: Do this only on the first pass, otherwise configure_file() will
59  # retrigger CMake every time b/c the modification timestamp of the
60  # source file is newer than the previously configured file.
61  # The use of the "cmake -E copy_if_different" command could be used
62  # here instead, but as we do not expect the CTestCustom.cmake.in
63  # file of the BASIS project template to change, it is sufficient
64  # to only check if we copied the template file already.
65  if (NOT EXISTS "${PROJECT_BINARY_DIR}/CTestCustom.cmake.in")
66  file (READ "${BASIS_TEMPLATE_DIR}/${CONFIG_DIR}/CTestCustom.cmake.in" _TEMPLATE)
67  string (REGEX REPLACE "<year>" "" _TEMPLATE "${_TEMPLATE}")
68  file (WRITE "${PROJECT_BINARY_DIR}/CTestCustom.cmake.in" "${_TEMPLATE}")
69  unset (_TEMPLATE)
70  endif ()
71  # configure the modified template file
72  configure_file (
73  "${PROJECT_BINARY_DIR}/CTestCustom.cmake.in"
74  "${PROJECT_BINARY_DIR}/CTestCustom.cmake"
75  @ONLY
76  )
77  endif ()
78 endif ()
79 
80 # ============================================================================
81 # constants
82 # ============================================================================
83 
84 ## @brief Names of recognized properties on tests.
85 #
86 # Unfortunately, the @c ARGV and @c ARGN arguments of a CMake function()
87 # or macro() does not preserve values which themselves are lists. Therefore,
88 # it is not possible to distinguish between property names and their values
89 # in the arguments passed to basis_set_tests_properties().
90 # To overcome this problem, this list specifies all the possible property names.
91 # Everything else is considered to be a property value except the first argument
92 # follwing right after the @c PROPERTIES keyword. Alternatively,
93 # basis_set_property() can be used as here no disambiguity exists.
94 #
95 # @note Placeholders such as &lt;CONFIG&gt; are allowed. These are treated
96 # as the regular expression "[^ ]+". See basis_list_to_regex().
97 #
98 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#section_PropertiesonTests
99 set (BASIS_PROPERTIES_ON_TESTS
100  ATTACHED_FILES
101  ATTACHED_FILES_ON_FAIL
102  COST
103  DEPENDS
104  ENVIRONMENT
105  FAIL_REGULAR_EXPRESSION
106  LABELS
107  MEASUREMENT
108  PASS_REGULAR_EXPRESSION
109  PROCESSORS
110  REQUIRED_FILES
111  RESOURCE_LOCK
112  RUN_SERIAL
113  TIMEOUT
114  WILL_FAIL
115  WORKING_DIRECTORY
116 )
117 
118 # convert list into regular expression
119 basis_list_to_regex (BASIS_PROPERTIES_ON_TESTS_RE ${BASIS_PROPERTIES_ON_TESTS})
120 
121 # ============================================================================
122 # utilities
123 # ============================================================================
124 
125 ## @addtogroup CMakeUtilities
126 # @{
127 
128 
129 # ----------------------------------------------------------------------------
130 ## @brief Disable testing if project does not implement any tests.
131 #
132 # This function checks if there are test/ subdirectories in the project and
133 # disables and hides the BUILD_TESTING option if none are found.
134 function (basis_disable_testing_if_no_tests)
135  if (IS_DIRECTORY "${PROJECT_TESTING_DIR}")
136  set (DISABLE_TESTING FALSE)
137  else ()
138  set (DISABLE_TESTING TRUE)
139  endif ()
140  if (DISABLE_TESTING)
141  basis_get_relative_path (TESTING_DIR "${PROJECT_SOURCE_DIR}" "${PROJECT_TESTING_DIR}")
142  foreach (M IN LISTS PROJECT_MODULES_ENABLED)
143  if (IS_DIRECTORY "${MODULE_${M}_SOURCE_DIR}/${TESTING_DIR}")
144  set (DISABLE_TESTING FALSE)
145  break ()
146  endif ()
147  endforeach ()
148  endif ()
149  if (DISABLE_TESTING)
150  set_property (CACHE BUILD_TESTING PROPERTY VALUE OFF)
151  set_property (CACHE BUILD_TESTING PROPERTY TYPE INTERNAL)
152  else ()
153  set_property (CACHE BUILD_TESTING PROPERTY TYPE BOOL)
154  endif ()
155 endfunction ()
156 
157 # ----------------------------------------------------------------------------
158 ## @brief Set a property of the tests.
159 #
160 # This function replaces CMake's
161 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_tests_properties">
162 # set_tests_properties()</a> command.
163 #
164 # @note Due to a bug in CMake (http://www.cmake.org/Bug/view.php?id=12303),
165 # except of the first property given directly after the @c PROPERTIES keyword,
166 # only properties listed in @c BASIS_PROPERTIES_ON_TESTS can be set.
167 #
168 # @param [in] ARGN List of arguments for
169 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_tests_properties">
170 # set_tests_properties()</a>.
171 #
172 # @returns Sets the given properties of the specified test.
173 #
174 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_tests_properties
175 #
176 # @ingroup CMakeAPI
178  # convert test names to UIDs
179  set (TEST_UIDS)
180  list (GET ARGN 0 ARG)
181  while (ARG AND NOT ARG MATCHES "^PROPERTIES$")
182  basis_get_test_uid (TEST_UID "${ARG}")
183  list (APPEND TEST_UIDS "${TEST_UID}")
184  list (REMOVE_AT ARGN 0)
185  list (GET ARGN 0 ARG)
186  endwhile ()
187  if (NOT ARG MATCHES "^PROPERTIES$")
188  message (FATAL_ERROR "Missing PROPERTIES argument!")
189  elseif (NOT TEST_UIDS)
190  message (FATAL_ERROR "No test specified!")
191  endif ()
192  # remove PROPERTIES keyword
193  list (REMOVE_AT ARGN 0)
194  # set tests properties
195  #
196  # Note: By iterating over the properties, the empty property values
197  # are correctly passed on to CMake's set_tests_properties()
198  # command, while
199  # set_tests_properties(${TEST_UIDS} PROPERTIES ${ARGN})
200  # (erroneously) discards the empty elements in ARGN.
201  if (BASIS_DEBUG)
202  message ("** basis_set_tests_properties:")
203  message ("** Test(s) : ${TEST_UIDS}")
204  message ("** Properties: [${ARGN}]")
205  endif ()
206  list (LENGTH ARGN N)
207  while (N GREATER 1)
208  list (GET ARGN 0 PROPERTY)
209  list (GET ARGN 1 VALUE)
210  list (REMOVE_AT ARGN 0 1)
211  list (LENGTH ARGN N)
212  # The following loop is only required b/c CMake's ARGV and ARGN
213  # lists do not support arguments which are themselves lists.
214  # Therefore, we need a way to decide when the list of values for a
215  # property is terminated. Hence, we only allow known properties
216  # to be set, except for the first property where the name follows
217  # directly after the PROPERTIES keyword.
218  while (N GREATER 0)
219  list (GET ARGN 0 ARG)
220  if (ARG MATCHES "${BASIS_PROPERTIES_ON_TESTS_RE}")
221  break ()
222  endif ()
223  list (APPEND VALUE "${ARG}")
224  list (REMOVE_AT ARGN 0)
225  list (LENGTH ARGN N)
226  endwhile ()
227  # check property name
228  if ("${PROPERTY}" STREQUAL "")
229  message (FATAL_ERROR "Empty property name given!")
230  endif ()
231  # map test names to test UIDs
232  if (PROPERTY MATCHES "^DEPENDS$")
233  set (UIDS)
234  foreach (V IN LISTS VALUE)
235  basis_get_test_uid (UID "${V}")
236  list (APPEND UIDS "${UID}")
237  endforeach ()
238  set (VALUE ${UIDS})
239  endif ()
240  # set target property
241  if (BASIS_DEBUG)
242  message ("** -> ${PROPERTY} = [${VALUE}]")
243  endif ()
244  set_tests_properties (${TEST_UIDS} PROPERTIES ${PROPERTY} "${VALUE}")
245  endwhile ()
246  # make sure that every property had a corresponding value
247  if (NOT N EQUAL 0)
248  message (FATAL_ERROR "No value given for test property ${ARGN}")
249  endif ()
250 endfunction ()
251 
252 # ----------------------------------------------------------------------------
253 ## @brief Get a property of the test.
254 #
255 # This function replaces CMake's
256 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_test_property">
257 # get_test_property()</a> command.
258 #
259 # @param [out] VAR Property value.
260 # @param [in] TEST_NAME Name of test.
261 # @param [in] ARGN Remaining arguments of
262 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_test_property">
263 # get_test_property()</a>.
264 #
265 # @returns Sets @p VAR to the value of the requested property.
266 #
267 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:get_test_property
268 #
269 # @ingroup CMakeAPI
270 function (basis_get_test_property VAR TEST_NAME)
271  basis_get_test_uid (TEST_UID "${TEST_NAME}")
272  get_test_property (VALUE "${TEST_UID}" ${ARGN})
273  set (${VAR} "${VALUE}" PARENT_SCOPE)
274 endfunction ()
275 
276 # ----------------------------------------------------------------------------
277 ## @brief Create and add a test driver executable.
278 #
279 # @param [in] TESTDRIVER_NAME Name of the test driver.
280 # @param [in] ARGN List of source files implementing tests.
281 #
282 # @ingroup CMakeAPI
283 function (basis_add_test_driver TESTDRIVER_NAME)
284  # parse arguments
285  CMAKE_PARSE_ARGUMENTS (
286  ARGN
287  ""
288  "EXTRA_INCLUDE;FUNCTION"
289  ""
290  ${ARGN}
291  )
292  if (ARGN_EXTRA_INCLUDE OR ARGN_FUNCTION)
293  message (FATAL_ERROR "Invalid argument EXTRA_INCLUDE or FUNCTION! "
294  "Use create_test_sourcelist() if you want to create "
295  "a custom test driver.")
296  endif ()
297  # choose test driver implementation depending on which packages are available
298  set (TESTDRIVER_INCLUDE "basis/testdriver.h")
299  set (TESTDRIVER_LINK_DEPENDS basis.basis)
300  if (ITK_FOUND)
301  basis_include_directories (BEFORE ${ITK_INCLUDE_DIRS})
302  list (APPEND TESTDRIVER_LINK_DEPENDS ${ITK_LIBRARIES})
303  endif ()
304  if (WIN32)
305  list (APPEND TESTDRIVER_LINK_DEPENDS Ws2_32)
306  endif ()
307  # create test driver source code
308  set (TESTDRIVER_SOURCE "${TESTDRIVER_NAME}")
309  if (NOT TESTDRIVER_SOURCE MATCHES "\\.cxx")
310  set (TESTDRIVER_SOURCE "${TESTDRIVER_SOURCE}.cxx")
311  endif ()
312  set (CMAKE_TESTDRIVER_BEFORE_TESTMAIN " #include <basis/testdriver-before-test.inc>")
313  set (CMAKE_TESTDRIVER_AFTER_TESTMAIN " #include <basis/testdriver-after-test.inc>")
314  create_test_sourcelist (
315  TESTDRIVER_SOURCES
316  ${TESTDRIVER_SOURCE} ${ARGN_UNPARSED_ARGUMENTS}
317  EXTRA_INCLUDE "${TESTDRIVER_INCLUDE}"
318  FUNCTION testdriversetup
319  )
320  # add test driver executable
321  basis_add_executable (${TESTDRIVER_NAME} ${TESTDRIVER_SOURCES})
322  basis_target_link_libraries (${TESTDRIVER_NAME} ${TESTDRIVER_LINK_DEPENDS})
323  if (ITK_FOUND)
325  ${TESTDRIVER_NAME}
326  PROPERTIES
327  COMPILE_DEFINITIONS
328  TESTDRIVER_NAME=\"${TESTDRIVER_NAME}\"
329  ITK_VERSION=\"${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}.${ITK_VERSION_PATCH}\"
330  ITK_VERSION_MAJOR=${ITK_VERSION_MAJOR}
331  )
332  else ()
333  basis_set_target_properties (
334  ${TESTDRIVER_NAME}
335  PROPERTIES
336  COMPILE_DEFINITIONS
337  TESTDRIVER_NAME=\"${TESTDRIVER_NAME}\"
338  )
339  endif ()
340 endfunction ()
341 
342 # ----------------------------------------------------------------------------
343 ## @brief Add test.
344 #
345 # This command is used similar to CMake's
346 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_test">
347 # add_test()</a> command. It adds a test to the
348 # <a href="http://www.cmake.org/cmake/help/ctest-2-8-docs.html">CTest</a>-based
349 # testing system. Unlike CMake's
350 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_test">
351 # add_test()</a>, this command can, for convenience, implicitly add
352 # the necessary executable build target to the build system. Therefore,
353 # instead of the name of the executable command, specify the sources of the
354 # test implementation. An executable build target is then added by this
355 # function using basis_add_executable(), and the built executable is used
356 # as test command. If the @p UNITTEST option is given, the necessary unit
357 # testing libraries which are part of the BASIS installation are added as
358 # link dependencies as well as the default implementation of the main()
359 # function if none of the specified source files has the suffix
360 # <tt>-main</tt> or <tt>_main</tt> in the file name.
361 #
362 # Generator expressions as supported by CMake's
363 # <a href="http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_test">
364 # add_test()</a> command are also supported by basis_add_test() as arguments of
365 # the test command. For the argument specifying the test command itself, however,
366 # only the generator expression $<TARGET_FILE:tgt> is allowed. Alternatively,
367 # for this special argument, the name of the executable target can be supplied
368 # directly without the use of the $<TARGET_FILE:tgt> generator expression.
369 # See documentation of basis_process_generator_expressions() for details on
370 # the supported generator expressions.
371 #
372 # Example:
373 # @code
374 # basis_add_test (COMMAND $<TARGET_FILE:basis.testdriver> $<TARGET_FILE:myexe> ...)
375 # basis_add_test (COMMAND basis.testdriver $<TARGET_FILE:myexe> ...)
376 # @endcode
377 #
378 # @param [in] TEST_NAME Name of the test. If a source file is given
379 # as first argument, the test name is derived
380 # from the name of this source file and the source
381 # file is added to the list of sources which implement
382 # the test command.
383 # @param [in] ARGN The following parameters are parsed:
384 # @par
385 # <table border="0">
386 # <tr>
387 # @tp @b COMMAND cmd [arg1 [arg2 ...]] @endtp
388 # <td>The command to execute and optionally its arguments. The command
389 # can be the name of an executable target (including imported targets),
390 # or the name or path of an executable. Alternatively,
391 # a test can be build from sources and the build executable
392 # used as command. In this case, specify the sources using the
393 # @p SOURCES argument. The command name @c cmd if given is used as
394 # output name of the built executable. If you do not want to
395 # specify the name of the output executable explicitly, but have
396 # it derived from the @p TEST_NAME, do not specify the @p COMMAND
397 # option and use the @p ARGS option instead to only specify the
398 # arguments of the test command.</td>
399 # </tr>
400 # <tr>
401 # @tp @b ARGS arg1 [arg2 ...] @endtp
402 # <td>Arguments of the test command. If this option is given, the
403 # specified arguments are appended to the arguments specified
404 # already as part of the @p COMMAND option, if any.</td>
405 # </tr>
406 # <tr>
407 # @tp @b WORKING_DIRECTORY dir @endtp
408 # <td>The working directory of the test command. The generator expression
409 # $<TARGET_FILE_DIR:tgt> can be used to specify a working directory
410 # which corresponds to the output directory of a given target file.
411 # Default: @c TESTING_OUTPUT_DIR / @p TEST_NAME. </td>
412 # </tr>
413 # <tr>
414 # @tp @b CONFIGURATIONS @endtp
415 # <td>If a CONFIGURATIONS option is given then the test will be executed
416 # only when testing under one of the named configurations.</td>
417 # </tr>
418 # <tr>
419 # @tp @b SOURCES file1 [file2 ...] @endtp
420 # <td>The source files of the test. Use the @p UNITTEST option to specify
421 # that the sources are an implementation of a unit test. In this case,
422 # the default implementation of the main() function is added to the
423 # build of the test executable. However, if this list contains a
424 # file with the suffix <tt>-main</tt> or <tt>_main</tt> in the name,
425 # the default implementation of the main() function is not used.
426 # See the documentation of the @p UNITTEST option for further details.</td>
427 # </tr>
428 # <tr>
429 # @tp @b LINK_DEPENDS file1|target1 [file2|target2 ...] @endtp
430 # <td>Link dependencies of test executable build from sources.</td>
431 # </tr>
432 # <tr>
433 # @tp @b NO_DEFAULT_MAIN @endtp
434 # <td>Force that the implementation of the default main() function
435 # is not added to unit tests even if neither of the given source
436 # files has the suffix <tt>-main</tt> or <tt>_main</tt> in the
437 # file name.</td>
438 # </tr>
439 # <tr>
440 # @tp @b UNITTEST @endtp
441 # <td>Specifies that the test is a unit test. In this case, the test
442 # implementation is linked to the default unit testing framework
443 # for the used programming language which is part of the BASIS
444 # installation.</td>
445 # </tr>
446 # <tr>
447 # @tp @b WITH_EXT @endtp
448 # <td>Do not strip extension if test name is derived from source file name.</td>
449 # </tr>
450 # <tr>
451 # @tp @b ARGN @endtp
452 # <td>All other arguments are passed on to basis_add_executable() if
453 # an executable target for the test is added.</td>
454 # </tr>
455 # </table>
456 #
457 # @returns Adds build target for test executable if test source files
458 # are given and/or adds a CTest test which executes the given
459 # test command.
460 #
461 # @sa basis_process_generator_expressions()
462 # @sa http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_test
463 #
464 # @todo Make use of ExternalData module to fetch remote test data.
465 #
466 # @ingroup CMakeAPI
467 function (basis_add_test TEST_NAME)
468  basis_sanitize_for_regex (R "${PROJECT_TESTING_DIR}")
469  if (NOT CMAKE_CURRENT_SOURCE_DIR MATCHES "^${R}")
470  message (FATAL_ERROR "Tests can only be added inside ${PROJECT_TESTING_DIR}!")
471  endif ()
472 
473  # --------------------------------------------------------------------------
474  # parse arguments
475  CMAKE_PARSE_ARGUMENTS (
476  ARGN
477  "UNITTEST;NO_DEFAULT_MAIN;WITH_EXT;CLEAN_WORKING_DIRECTORY_BEFORE_TEST;CLEAN_WORKING_DIRECTORY_AFTER_TEST"
478  "WORKING_DIRECTORY"
479  "CONFIGURATIONS;SOURCES;LINK_DEPENDS;COMMAND;ARGS"
480  ${ARGN}
481  )
482 
483  if (BASIS_DEBUG AND BASIS_VERBOSE)
484  message ("** basis_add_test():")
485  message ("** Test: ${TEST_NAME}")
486  message ("** Command: ${ARGN_COMMAND}")
487  message ("** Arguments: ${ARGN_ARGS}")
488  endif ()
489 
490  list (LENGTH ARGN_COMMAND N)
491  if (N GREATER 1)
492  list (GET ARGN_COMMAND 0 CMD)
493  list (REMOVE_AT ARGN_COMMAND 0)
494  list (APPEND ARGN_ARGS ${ARGN_COMMAND})
495  set (ARGN_COMMAND "${CMD}")
496  endif ()
497 
498  # --------------------------------------------------------------------------
499  # test name
500  if (NOT ARGN_COMMAND AND NOT ARGN_SOURCES)
501  get_filename_component (ARGN_SOURCES "${TEST_NAME}" ABSOLUTE)
502  if (ARGN_WITH_EXT)
503  basis_get_source_target_name (TEST_NAME "${TEST_NAME}" NAME)
504  list (APPEND ARGN_UNPARSED_ARGUMENTS WITH_EXT) # pass on to basis_add_executable()
505  else ()
506  basis_get_source_target_name (TEST_NAME "${TEST_NAME}" NAME_WE)
507  endif ()
508  endif ()
509 
510  basis_check_test_name ("${TEST_NAME}")
511  basis_make_test_uid (TEST_UID "${TEST_NAME}")
512 
513  if (BASIS_DEBUG)
514  message ("** basis_add_test():")
515  message ("** Name: ${TEST_NAME}")
516  message ("** Command: ${ARGN_COMMAND}")
517  message ("** Arguments: ${ARGN_ARGS}")
518  message ("** Sources: ${ARGN_SOURCES}")
519  endif ()
520 
521  # --------------------------------------------------------------------------
522  # build test executable
523  set (LANGUAGE)
524  if (ARGN_SOURCES)
525  if (ARGN_UNITTEST)
526  basis_get_source_language (LANGUAGE ${ARGN_SOURCES})
527  if (NOT ARGN_NO_DEFAULT_MAIN)
528  foreach (SOURCE ${ARGN_SOURCES})
529  if (SOURCE MATCHES "-main\\.|_main\\.")
530  set (ARGN_NO_DEFAULT_MAIN 1)
531  break ()
532  endif ()
533  endforeach ()
534  endif ()
535  if (LANGUAGE MATCHES "CXX")
536  if (NOT ARGN_NO_DEFAULT_MAIN)
538  list (APPEND ARGN_LINK_DEPENDS "${BASIS_TEST_MAIN_LIBRARY}")
539  else ()
540  message (FATAL_ERROR "Test ${TEST_NAME} added as UNITTEST without NO_DEFAULT_MAIN option,"
541  " but BASIS_TEST_MAIN_LIBRARY not set. This library is part of the"
542  " CMake BASIS installation. When you are using the CMake BASIS Modules"
543  " without CMake BASIS installation, add GTest to TEST_DEPENDS and"
544  " set BASIS_TEST_MAIN_LIBRARY to the value of GTEST_MAIN_LIBRARY"
545  " before using the basis_add_test command.")
546  endif ()
547  endif ()
548  if (BASIS_TEST_LIBRARY)
549  list (APPEND ARGN_LINK_DEPENDS "${BASIS_TEST_LIBRARY}")
550  else ()
551  message (FATAL_ERROR "Test ${TEST_NAME} added as UNITTEST, but BASIS_TEST_LIBRARY not set."
552  " This library is part of the CMake BASIS installation. When you are"
553  " using the CMake BASIS Modules without CMake BASIS installation,"
554  " add GTest to TEST_DEPENDS and set BASIS_TEST_LIBRARY to the value"
555  " of GTEST_LIBRARY before using the basis_add_test command.")
556  endif ()
557  endif ()
558  endif ()
559 
560  basis_add_executable (${TEST_NAME} ${ARGN_SOURCES} ${ARGN_UNPARSED_ARGUMENTS})
561  if (ARGN_LINK_DEPENDS)
562  basis_target_link_libraries (${TEST_NAME} ${ARGN_LINK_DEPENDS})
563  endif ()
564 
565  if (ARGN_COMMAND)
566  basis_set_target_properties (${TEST_NAME} PROPERTIES OUTPUT_NAME ${CMD})
567  endif ()
568  set (ARGN_COMMAND ${TEST_NAME})
569 
570  if (BASIS_DEBUG)
571  message ("** Added test executable ${TEST_UID} (${TEST_NAME})")
572  message ("** Sources: ${ARGN_SOURCES}")
573  message ("** Link dependencies: ${ARGN_LINK_DEPENDS}")
574  message ("** Options: ${ARGN_UNPARSED_ARGUMENTS}")
575  endif ()
576  endif ()
577 
578  # --------------------------------------------------------------------------
579  # add test
580  message (STATUS "Adding test ${TEST_UID}...")
581 
582  if (NOT ARGN_WORKING_DIRECTORY)
583  set (ARGN_WORKING_DIRECTORY "${TESTING_OUTPUT_DIR}/${TEST_NAME}")
584  endif ()
585  if (ARGN_WORKING_DIRECTORY MATCHES "^\\$<(.*):(.*)>$")
586  if (NOT "${CMAKE_MATCH_1}" STREQUAL "TARGET_FILE_DIR")
587  message (FATAL_ERROR "Invalid generator expression used for working directory."
588  " Only $<TARGET_FILE_DIR:tgt> can be used as argument"
589  " of the WORKING_DIRECTORY option.")
590  endif ()
591  basis_get_target_location (ARGN_WORKING_DIRECTORY "${CMAKE_MATCH_2}" PATH)
592  else ()
593  if (NOT IS_DIRECTORY "${ARGN_WORKING_DIRECTORY}")
594  file (MAKE_DIRECTORY "${ARGN_WORKING_DIRECTORY}")
595  endif ()
596  endif ()
597  set (OPTS "WORKING_DIRECTORY" "${ARGN_WORKING_DIRECTORY}")
598  if (ARGN_CONFIGURATIONS)
599  list (APPEND OPTS "CONFIGURATIONS")
600  foreach (CONFIG ${ARGN_CONFIGURATIONS})
601  list (APPEND OPTS "${CONFIG}")
602  endforeach ()
603  endif ()
604 
605  if (ARGN_COMMAND MATCHES "^\\$<(.*):(.*)>$")
606  if (NOT "${CMAKE_MATCH_1}" STREQUAL "TARGET_FILE")
607  message (FATAL_ERROR "Invalid generator expression used for test command."
608  " Only $<TARGET_FILE:tgt> can be used as first"
609  " argument of the COMMAND option.")
610  endif ()
611  basis_get_target_location (ARGN_COMMAND "${CMAKE_MATCH_2}" ABSOLUTE)
612  else ()
613  basis_get_target_uid (COMMAND_UID "${ARGN_COMMAND}")
614  if (TARGET "${COMMAND_UID}")
615  basis_get_target_location (ARGN_COMMAND "${COMMAND_UID}" ABSOLUTE)
616  endif ()
617  endif ()
618 
619  basis_process_generator_expressions (ARGN_ARGS ${ARGN_ARGS})
620 
621  if (BASIS_DEBUG)
622  message ("** Add test ${TEST_UID}")
623  message ("** Command: ${ARGN_COMMAND}")
624  message ("** Arguments: ${ARGN_ARGS}")
625  message ("** Working in: ${ARGN_WORKING_DIRECTORY}")
626  endif ()
627 
628  add_test (NAME ${TEST_UID} COMMAND ${ARGN_COMMAND} ${ARGN_ARGS} ${OPTS})
629 
630  # especially in case of C++ unit tests, if the linkage of the tests is done
631  # incorrectly, no tests are actually run and the unit test passes
632  # therefore, add this fail regular expression to identify such issues
633  set_tests_properties (${TEST_UID} PROPERTIES FAIL_REGULAR_EXPRESSION "(\\[ *PASSED *\\]|Ran) 0 tests|No tests were found!!!")
634 
635  message (STATUS "Adding test ${TEST_UID}... - done")
636 endfunction ()
637 
638 # ----------------------------------------------------------------------------
639 ## @brief Add tests of default options for given executable.
640 #
641 # @par Default options:
642 # <table border="0">
643 # <tr>
644 # @tp <b>--helpshort</b> @endtp
645 # <td>Short help. The output has to match the regular expression
646 # "[Uu]sage:\n\s*\<executable name\>", where \<executable name\>
647 # is the name of the tested executable.</td>
648 # </tr>
649 # <tr>
650 # @tp <b>--help, -h</b> @endtp
651 # <td>Help screen. Simply tests if the option is accepted.</td>
652 # </tr>
653 # <tr>
654 # @tp <b>--version</b> @endtp
655 # <td>Version information. Output has to include the project version string.</td>
656 # </tr>
657 # <tr>
658 # @tp <b>--verbose, -v</b> @endtp
659 # <td>Increase verbosity of output messages. Simply tests if the option is accepted.</td>
660 # </tr>
661 # </table>
662 #
663 # @param [in] TARGET_NAME Name of executable or script target.
664 #
665 # @returns Adds tests for the default options of the specified executable.
666 function (basis_add_tests_of_default_options TARGET_NAME)
667  basis_get_target_uid (TARGET_UID "${TARGET_NAME}")
668 
669  message (STATUS "Adding tests of default options for ${TARGET_UID}...")
670 
671  if (NOT TARGET "${TARGET_UID}")
672  message (FATAL_ERROR "Unknown target ${TARGET_UID}.")
673  endif ()
674 
675  # get executable name
676  get_target_property (PREFIX ${TARGET_UID} "PREFIX")
677  get_target_property (OUTPUT_NAME ${TARGET_UID} "OUTPUT_NAME")
678  get_target_property (SUFFIX ${TARGET_UID} "SUFFIX")
679 
680  if (NOT OUTPUT_NAME)
681  set (EXEC_NAME "${TARGET_UID}")
682  endif ()
683  if (PREFIX)
684  set (EXEC_NAME "${PREFIX}${EXEC_NAME}")
685  endif ()
686  if (SUFFIX)
687  set (EXEC_NAME "${EXEC_NAME}${SUFFIX}")
688  endif ()
689 
690  # get absolute path to executable
691  get_target_property (EXEC_DIR ${TARGET_UID} "RUNTIME_OUTPUT_DIRECTORY")
692 
693  # executable command
694  set (EXEC_CMD "${EXEC_DIR}/${EXEC_NAME}")
695 
696  # test option: -v
697  basis_add_test (${EXEC}VersionS "${EXEC_CMD}" "-v")
698 
699  set_tests_properties (
700  ${EXEC}VersionS
701  PROPERTIES
702  PASS_REGULAR_EXPRESSION "${EXEC} ${PROJECT_VERSION}"
703  )
704 
705  # test option: --version
706  basis_add_test (${EXEC}VersionL "${EXEC_CMD}" "--version")
707 
708  set_tests_properties (
709  ${EXEC}VersionL
710  PROPERTIES
711  PASS_REGULAR_EXPRESSION "${EXEC} ${PROJECT_VERSION}"
712  )
713 
714  # test option: -h
715  basis_add_test (${EXEC}HelpS "${EXEC_CMD}" "-h")
716 
717  # test option: --help
718  basis_add_test (${EXEC}HelpL "${EXEC_CMD}" "--help")
719 
720  # test option: --helpshort
721  basis_add_test (${EXEC}UsageL "${EXEC_CMD}" "--helpshort")
722 
723  set_tests_properties (
724  ${EXEC}UsageL
725  PROPERTIES
726  PASS_REGULAR_EXPRESSION "[Uu]sage:(\n)( )*${EXEC_NAME}"
727  )
728 
729  message (STATUS "Adding tests of default options for ${EXEC}... - done")
730 endfunction ()
731 
732 
733 ## @}
734 # end of Doxygen group
function basis_get_test_uid(out TEST_UID, in TEST_NAME)
Get "global" test name, i.e., actual CTest test name.
function basis_get_source_target_name(out TARGET_NAME, in SOURCE_FILE, in ARGN)
Derive target name from source file name.
function basis_get_target_uid(out TARGET_UID, in TARGET_NAME)
Get "global" target name, i.e., actual CMake target name.
cmake RUN_FROM_CTEST_OR_DART
Definition: BasisTest.cmake:35
function basis_make_test_uid(out TEST_UID, in TEST_NAME)
Make test UID from given test name.
function basis_target_link_libraries(in TARGET_NAME, in ARGN)
Add link dependencies to build target.
cmake CMD
function is(in result, in expected, in name)
Test whether a given result is equal to the expected result.
function basis_process_generator_expressions(out ARGS, in ARGN)
Process generator expressions in arguments.
function basis_check_test_name(in TEST_NAME)
Checks whether a given name is a valid test name.
option BUILD_TESTING
Request build of tests.
Definition: BasisTest.cmake:24
macro basis_sanitize_for_regex(out OUT, in STR)
Sanitize string variable for use in regular expression.
function basis_get_source_language(out LANGUAGE, in ARGN)
Detect programming language of given source code files.
Definition: basis.h:34
cmake NAME
function basis_add_tests_of_default_options(in TARGET_NAME)
Add tests of default options for given executable.
cmake BASIS_TEST_MAIN_LIBRARY
Definition: Settings.cmake:150
cmake PROJECT_CONFIG_DIR
Absolute path to directory of BASIS project configuration in source tree.
void testdriversetup(int *argc, char **argv[])
Parse command-line arguments and initialize test driver.
Definition: testdriver.hxx:42
function basis_add_test_driver(in TESTDRIVER_NAME, in ARGN)
Create and add a test driver executable.
cmake COMMAND
cmake BASIS_TEST_LIBRARY
Definition: Settings.cmake:149
cmake PROJECT_TESTING_DIR
Absolute path to directory of testing tree in source tree.
option BASIS_DEBUG
Request debugging messages from BASIS functions.
cmake VALUE
function basis_set_tests_properties(in ARGN)
Set a property of the tests.
option BASIS_VERBOSE
Default Sphinx theme options.
cmake LANGUAGE
Detected scripting language or UNKNOWN.
cmake RUN_FROM_DART
Definition: BasisTest.cmake:29
function basis_set_target_properties(in ARGN)
Set properties on a target.
function basis_get_test_property(out VAR, in TEST_NAME, in ARGN)
Get a property of the test.
function basis_add_executable(in TARGET_NAME, in ARGN)
Add executable target.
function basis_add_test(in TEST_NAME, in ARGN)
Add test.
function basis_include_directories(in ARGN)
Add directories to search path for include files.
function get_filename_component(inout ARGN)
Fixes CMake&#39;s get_filename_component() command.
function fail()
Fail in any case and print reason.
function basis_get_target_location(out VAR, in TARGET_NAME, in PART)
Get location of build target output file(s).