doctest

FORK: The fastest feature-rich C++11/14/17/20 single-header testing framework
git clone https://git.neptards.moe/neptards/doctest.git
Log | Files | Refs | README

doctest.cmake (7762B)


      1 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
      2 # file Copyright.txt or https://cmake.org/licensing for details.
      3 
      4 #[=======================================================================[.rst:
      5 doctest
      6 -----
      7 
      8 This module defines a function to help use the doctest test framework.
      9 
     10 The :command:`doctest_discover_tests` discovers tests by asking the compiled test
     11 executable to enumerate its tests.  This does not require CMake to be re-run
     12 when tests change.  However, it may not work in a cross-compiling environment,
     13 and setting test properties is less convenient.
     14 
     15 This command is intended to replace use of :command:`add_test` to register
     16 tests, and will create a separate CTest test for each doctest test case.  Note
     17 that this is in some cases less efficient, as common set-up and tear-down logic
     18 cannot be shared by multiple test cases executing in the same instance.
     19 However, it provides more fine-grained pass/fail information to CTest, which is
     20 usually considered as more beneficial.  By default, the CTest test name is the
     21 same as the doctest name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
     22 
     23 .. command:: doctest_discover_tests
     24 
     25   Automatically add tests with CTest by querying the compiled test executable
     26   for available tests::
     27 
     28     doctest_discover_tests(target
     29                          [TEST_SPEC arg1...]
     30                          [EXTRA_ARGS arg1...]
     31                          [WORKING_DIRECTORY dir]
     32                          [TEST_PREFIX prefix]
     33                          [TEST_SUFFIX suffix]
     34                          [PROPERTIES name1 value1...]
     35                          [ADD_LABELS value]
     36                          [TEST_LIST var]
     37                          [JUNIT_OUTPUT_DIR dir]
     38     )
     39 
     40   ``doctest_discover_tests`` sets up a post-build command on the test executable
     41   that generates the list of tests by parsing the output from running the test
     42   with the ``--list-test-cases`` argument.  This ensures that the full
     43   list of tests is obtained.  Since test discovery occurs at build time, it is
     44   not necessary to re-run CMake when the list of tests changes.
     45   However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
     46   in order to function in a cross-compiling environment.
     47 
     48   Additionally, setting properties on tests is somewhat less convenient, since
     49   the tests are not available at CMake time.  Additional test properties may be
     50   assigned to the set of tests as a whole using the ``PROPERTIES`` option.  If
     51   more fine-grained test control is needed, custom content may be provided
     52   through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
     53   directory property.  The set of discovered tests is made accessible to such a
     54   script via the ``<target>_TESTS`` variable.
     55 
     56   The options are:
     57 
     58   ``target``
     59     Specifies the doctest executable, which must be a known CMake executable
     60     target.  CMake will substitute the location of the built executable when
     61     running the test.
     62 
     63   ``TEST_SPEC arg1...``
     64     Specifies test cases, wildcarded test cases, tags and tag expressions to
     65     pass to the doctest executable with the ``--list-test-cases`` argument.
     66 
     67   ``EXTRA_ARGS arg1...``
     68     Any extra arguments to pass on the command line to each test case.
     69 
     70   ``WORKING_DIRECTORY dir``
     71     Specifies the directory in which to run the discovered test cases.  If this
     72     option is not provided, the current binary directory is used.
     73 
     74   ``TEST_PREFIX prefix``
     75     Specifies a ``prefix`` to be prepended to the name of each discovered test
     76     case.  This can be useful when the same test executable is being used in
     77     multiple calls to ``doctest_discover_tests()`` but with different
     78     ``TEST_SPEC`` or ``EXTRA_ARGS``.
     79 
     80   ``TEST_SUFFIX suffix``
     81     Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
     82     every discovered test case.  Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
     83     be specified.
     84 
     85   ``PROPERTIES name1 value1...``
     86     Specifies additional properties to be set on all tests discovered by this
     87     invocation of ``doctest_discover_tests``.
     88 
     89   ``ADD_LABELS value``
     90     Specifies if the test labels should be set automatically.
     91 
     92   ``TEST_LIST var``
     93     Make the list of tests available in the variable ``var``, rather than the
     94     default ``<target>_TESTS``.  This can be useful when the same test
     95     executable is being used in multiple calls to ``doctest_discover_tests()``.
     96     Note that this variable is only available in CTest.
     97 
     98   ``JUNIT_OUTPUT_DIR dir``
     99     If specified, the parameter is passed along with ``--reporters=junit``
    100     and ``--out=`` to the test executable. The actual file name is the same
    101     as the test target, including prefix and suffix. This should be used
    102     instead of EXTRA_ARGS to avoid race conditions writing the XML result
    103     output when using parallel test execution.
    104 
    105 #]=======================================================================]
    106 
    107 #------------------------------------------------------------------------------
    108 function(doctest_discover_tests TARGET)
    109   cmake_parse_arguments(
    110     ""
    111     ""
    112     "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;JUNIT_OUTPUT_DIR"
    113     "TEST_SPEC;EXTRA_ARGS;PROPERTIES;ADD_LABELS"
    114     ${ARGN}
    115   )
    116 
    117   if(NOT _WORKING_DIRECTORY)
    118     set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
    119   endif()
    120   if(NOT _TEST_LIST)
    121     set(_TEST_LIST ${TARGET}_TESTS)
    122   endif()
    123 
    124   ## Generate a unique name based on the extra arguments
    125   string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
    126   string(SUBSTRING ${args_hash} 0 7 args_hash)
    127 
    128   # Define rule to generate test list for aforementioned test executable
    129   set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
    130   set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
    131   get_property(crosscompiling_emulator
    132     TARGET ${TARGET}
    133     PROPERTY CROSSCOMPILING_EMULATOR
    134   )
    135   add_custom_command(
    136     TARGET ${TARGET} POST_BUILD
    137     BYPRODUCTS "${ctest_tests_file}"
    138     COMMAND "${CMAKE_COMMAND}"
    139             -D "TEST_TARGET=${TARGET}"
    140             -D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
    141             -D "TEST_EXECUTOR=${crosscompiling_emulator}"
    142             -D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
    143             -D "TEST_SPEC=${_TEST_SPEC}"
    144             -D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
    145             -D "TEST_PROPERTIES=${_PROPERTIES}"
    146             -D "TEST_ADD_LABELS=${_ADD_LABELS}"
    147             -D "TEST_PREFIX=${_TEST_PREFIX}"
    148             -D "TEST_SUFFIX=${_TEST_SUFFIX}"
    149             -D "TEST_LIST=${_TEST_LIST}"
    150             -D "TEST_JUNIT_OUTPUT_DIR=${_JUNIT_OUTPUT_DIR}"
    151             -D "CTEST_FILE=${ctest_tests_file}"
    152             -P "${_DOCTEST_DISCOVER_TESTS_SCRIPT}"
    153     VERBATIM
    154   )
    155 
    156   file(WRITE "${ctest_include_file}"
    157     "if(EXISTS \"${ctest_tests_file}\")\n"
    158     "  include(\"${ctest_tests_file}\")\n"
    159     "else()\n"
    160     "  add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
    161     "endif()\n"
    162   )
    163 
    164   if(NOT CMAKE_VERSION VERSION_LESS 3.10)
    165     # Add discovered tests to directory TEST_INCLUDE_FILES
    166     set_property(DIRECTORY
    167       APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
    168     )
    169   else()
    170     # Add discovered tests as directory TEST_INCLUDE_FILE if possible
    171     get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
    172     if(NOT ${test_include_file_set})
    173       set_property(DIRECTORY
    174         PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
    175       )
    176     else()
    177       message(FATAL_ERROR
    178         "Cannot set more than one TEST_INCLUDE_FILE"
    179       )
    180     endif()
    181   endif()
    182 
    183 endfunction()
    184 
    185 ###############################################################################
    186 
    187 set(_DOCTEST_DISCOVER_TESTS_SCRIPT
    188   ${CMAKE_CURRENT_LIST_DIR}/doctestAddTests.cmake
    189 )