# Adds standard ctest tests for each *.c;*.cpp;*.cxx in # ${PROJECT_NAME}_TESTS for all ${PROJECT_NAME}_targets # # Sets ${PROJECT_NAME}_TEST_TARGETS to the test targets generated if(NOT ${PROJECT_NAME}_IS_DEPENDENCY AND (NOT DEFINED BUILD_TESTING OR BUILD_TESTING)) if(DEFINED ${PROJECT_NAME}_TESTS) enable_testing() function(generate_tests) # Firstly get all non-source files foreach(testsource ${${PROJECT_NAME}_TESTS}) if(NOT testsource MATCHES ".+/(.+)[.](c|cpp|cxx)$") list(APPEND testnonsources ${testsource}) endif() endforeach() function(do_add_test outtargets testsource special nogroup) unset(${outtargets} PARENT_SCOPE) set(target_names) if(testsource MATCHES ".+/(.+)[.](c|cpp|cxx)$") # We'll assume the test name is the source file name set(testname ${CMAKE_MATCH_1}) # Path could however be test/tests//*.cpp if(testsource MATCHES ".+/tests/([^/]+)/(.+)[.](c|cpp|cxx)$") set(testname ${CMAKE_MATCH_1}) endif() set(thistestsources ${testsource}) foreach(testnonsource ${testnonsources}) if(testnonsource MATCHES ${testname}) list(APPEND thistestsources ${testnonsource}) endif() endforeach() foreach(_target ${${PROJECT_NAME}_TARGETS}) set(target ${_target}) if(nogroup) unset(group) elseif(target MATCHES "_hl$") set(group _hl) elseif(target MATCHES "_sl$") set(group _sl) elseif(target MATCHES "_dl$") set(group _dl) else() unset(group) endif() if(special STREQUAL "") set(target_name "${target}--${testname}") else() set(group ${group}-${special}) set(target_name "${target}-${special}-${testname}") if(NOT target MATCHES "_hl$") set(target "${target}-${special}") endif() endif() add_executable(${target_name} ${thistestsources}) set(target_in_disable_list ${PROJECT_NAME}_INTERFACE_DISABLED) foreach(item ${${PROJECT_NAME}_TESTS_DISABLE_PRECOMPILE_HEADERS}) if(target_name MATCHES ${item}) set(target_in_disable_list 1) break() endif() endforeach() if(target_in_disable_list) set_target_properties(${target_name} PROPERTIES DISABLE_PRECOMPILE_HEADERS On) else() if(NOT first_test_target${group}) set(first_test_target${group} ${target_name} PARENT_SCOPE) elseif(COMMAND target_precompile_headers) #message("*** target_precompile_headers(${target_name} REUSE_FROM ${first_test_target${group}})") target_precompile_headers(${target_name} REUSE_FROM ${first_test_target${group}}) endif() endif() set_target_properties(${target_name} PROPERTIES EXCLUDE_FROM_ALL ON ) if(DEFINED group) add_dependencies(${group} ${target_name}) endif() target_link_libraries(${target_name} PRIVATE ${target}) set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" POSITION_INDEPENDENT_CODE ON ) if(WIN32) target_compile_definitions(${target_name} PRIVATE _CRT_NONSTDC_NO_WARNINGS) # Shut up about using POSIX functions endif() if(MSVC) target_compile_options(${target_name} PRIVATE /W4) # Stronger warnings else() target_compile_options(${target_name} PRIVATE -Wall -Wextra) # Stronger warnings endif() list(APPEND target_names "${target_name}") endforeach() if(target_names) set(${outtargets} "${target_names}" PARENT_SCOPE) endif() endif() endfunction() # Deal with normal tests + special builds of them first set(testtargets) foreach(special ${SPECIAL_BUILDS} "") set(first_test_target_hl) set(first_test_target_sl) set(first_test_target_dl) foreach(testsource ${${PROJECT_NAME}_TESTS}) do_add_test(target_names "${testsource}" "${special}" OFF) foreach(target_name ${target_names}) # This is a normal test target run for success list(APPEND testtargets "${target_name}") if(special STREQUAL "") # Output test detail to JUnit XML add_test(NAME ${target_name} CONFIGURATIONS Debug Release RelWithDebInfo MinSizeRel COMMAND $ --reporter junit --out $.junit.xml ) else() add_test(NAME ${target_name} COMMAND $ CONFIGURATIONS ${special}) if(DEFINED ${special}_LINK_FLAGS) _target_link_options(${target_name} PRIVATE ${${special}_LINK_FLAGS}) endif() target_compile_options(${target_name} PRIVATE ${${special}_COMPILE_FLAGS}) string(REGEX MATCH "_(hl|sl|dl)-" out ${target_name}) list(APPEND ${PROJECT_NAME}_${CMAKE_MATCH_1}_${special}_TARGETS ${target_name}) endif() endforeach() endforeach() endforeach() set(${PROJECT_NAME}_TEST_TARGETS ${testtargets} PARENT_SCOPE) foreach(special ${SPECIAL_BUILDS}) if(DEFINED ${PROJECT_NAME}_hl_${special}_TARGETS) set(${PROJECT_NAME}_hl_${special}_TARGETS ${${PROJECT_NAME}_hl_${special}_TARGETS} PARENT_SCOPE) endif() if(DEFINED ${PROJECT_NAME}_sl_${special}_TARGETS) set(${PROJECT_NAME}_sl_${special}_TARGETS ${${PROJECT_NAME}_sl_${special}_TARGETS} PARENT_SCOPE) endif() if(DEFINED ${PROJECT_NAME}_dl_${special}_TARGETS) set(${PROJECT_NAME}_dl_${special}_TARGETS ${${PROJECT_NAME}_dl_${special}_TARGETS} PARENT_SCOPE) endif() endforeach() # Deal with tests which require the compilation to succeed set(testtargets) set(first_test_target_hl) set(first_test_target_sl) set(first_test_target_dl) foreach(testsource ${${PROJECT_NAME}_COMPILE_TESTS}) do_add_test(target_names "${testsource}" "" OFF) list(APPEND testtargets ${target_names}) endforeach() set(${PROJECT_NAME}_COMPILE_TEST_TARGETS ${testtargets} PARENT_SCOPE) # Deal with tests which require the compilation to fail in an exact way set(testtargets) set(first_test_target_hl) set(first_test_target_sl) set(first_test_target_dl) foreach(testsource ${${PROJECT_NAME}_COMPILE_FAIL_TESTS}) do_add_test(target_names "${testsource}" "" ON) foreach(target_name ${target_names}) list(APPEND testtargets "${target_name}") # Do not build these normally, only on request set_target_properties(${target_name} PROPERTIES EXCLUDE_FROM_ALL ON EXCLUDE_FROM_DEFAULT_BUILD ON CXX_CLANG_TIDY "" ) # This test tries to build this test expecting failure add_test(NAME ${target_name} COMMAND ${CMAKE_COMMAND} --build . --target ${target_name} --config $ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" ) # Fetch the regex to detect correct failure file(STRINGS "${testsource}" firstline LIMIT_COUNT 2) list(GET firstline 1 firstline) set_tests_properties(${target_name} PROPERTIES PASS_REGULAR_EXPRESSION "${firstline}") endforeach() endforeach() set(${PROJECT_NAME}_COMPILE_FAIL_TARGETS ${testtargets} PARENT_SCOPE) endfunction() generate_tests() endif() # # For all special builds, create custom "all" target for each of those so one can build "everything with asan" etc # foreach(special ${SPECIAL_BUILDS}) # if(DEFINED ${PROJECT_NAME}_hl_${special}_TARGETS) # indented_message(STATUS "Creating non-default all target for special build ${PROJECT_NAME}_hl-${special}") # indented_message(STATUS "*** ${${PROJECT_NAME}_hl_${special}_TARGETS}") # add_custom_target(${PROJECT_NAME}_hl-${special} DEPENDS ${${PROJECT_NAME}_hl_${special}_TARGETS}) # endif() # endforeach() # We need to now decide on some default build target group. Prefer static libraries # unless this is a header only library set(dont_run_tests) if(TARGET ${PROJECT_NAME}_sl) set_target_properties(_sl PROPERTIES EXCLUDE_FROM_ALL OFF) set(dont_run_tests "_(hl|dl)-") else() set_target_properties(_hl PROPERTIES EXCLUDE_FROM_ALL OFF) set(dont_run_tests "_(sl|dl)-") endif() if(UNIT_TESTS_BUILD_ALL) if(TARGET ${PROJECT_NAME}_hl) set_target_properties(_hl PROPERTIES EXCLUDE_FROM_ALL OFF) endif() if(TARGET ${PROJECT_NAME}_sl) set_target_properties(_sl PROPERTIES EXCLUDE_FROM_ALL OFF) endif() if(TARGET ${PROJECT_NAME}_dl) set_target_properties(_dl PROPERTIES EXCLUDE_FROM_ALL OFF) endif() else() # Don't run the tests which are not built by all foreach(target ${${PROJECT_NAME}_TEST_TARGETS}) if(target MATCHES "${dont_run_tests}") set_tests_properties(${target} PROPERTIES DISABLED ON) endif() endforeach() endif() endif()