| set(_json_test_cmake_list_file ${CMAKE_CURRENT_LIST_FILE}) | |
| ############################################################################# | |
| # download test data | |
| ############################################################################# | |
| include(download_test_data) | |
| # test fixture to download test data | |
| add_test(NAME "download_test_data" COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} | |
| --target download_test_data | |
| ) | |
| set_tests_properties(download_test_data PROPERTIES FIXTURES_SETUP TEST_DATA) | |
| if(JSON_Valgrind) | |
| find_program(CMAKE_MEMORYCHECK_COMMAND valgrind) | |
| message(STATUS "Executing test suite with Valgrind (${CMAKE_MEMORYCHECK_COMMAND})") | |
| set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1 --leak-check=full") | |
| separate_arguments(memcheck_command) | |
| endif() | |
| ############################################################################# | |
| # detect standard support | |
| ############################################################################# | |
| # C++11 is the minimum required | |
| set(compiler_supports_cpp_11 TRUE) | |
| foreach(feature ${CMAKE_CXX_COMPILE_FEATURES}) | |
| if (${feature} STREQUAL cxx_std_14) | |
| set(compiler_supports_cpp_14 TRUE) | |
| elseif (${feature} STREQUAL cxx_std_17) | |
| set(compiler_supports_cpp_17 TRUE) | |
| elseif (${feature} STREQUAL cxx_std_20) | |
| set(compiler_supports_cpp_20 TRUE) | |
| elseif (${feature} STREQUAL cxx_std_23) | |
| set(compiler_supports_cpp_23 TRUE) | |
| elseif (${feature} STREQUAL cxx_std_26) | |
| set(compiler_supports_cpp_26 TRUE) | |
| endif() | |
| endforeach() | |
| ############################################################################# | |
| # test functions | |
| ############################################################################# | |
| ############################################################################# | |
| # json_test_set_test_options( | |
| # all|<tests> | |
| # [CXX_STANDARDS all|<args>...] | |
| # [COMPILE_DEFINITIONS <args>...] | |
| # [COMPILE_FEATURES <args>...] | |
| # [COMPILE_OPTIONS <args>...] | |
| # [LINK_LIBRARIES <args>...] | |
| # [LINK_OPTIONS <args>...] | |
| # [TEST_PROPERTIES <args>...]) | |
| # | |
| # Supply test- and standard-specific build settings and/or test properties. | |
| # Specify multiple tests using a list e.g., "test-foo;test-bar". | |
| # | |
| # Must be called BEFORE the test is created. | |
| ############################################################################# | |
| function(json_test_set_test_options tests) | |
| cmake_parse_arguments(args "" "" | |
| "CXX_STANDARDS;COMPILE_DEFINITIONS;COMPILE_FEATURES;COMPILE_OPTIONS;LINK_LIBRARIES;LINK_OPTIONS;TEST_PROPERTIES" | |
| ${ARGN}) | |
| if(NOT args_CXX_STANDARDS) | |
| set(args_CXX_STANDARDS "all") | |
| endif() | |
| foreach(test ${tests}) | |
| if("${test}" STREQUAL "all") | |
| set(test "") | |
| endif() | |
| foreach(cxx_standard ${args_CXX_STANDARDS}) | |
| if("${cxx_standard}" STREQUAL "all") | |
| if("${test}" STREQUAL "") | |
| message(FATAL_ERROR "Not supported. Change defaults in: ${_json_test_cmake_list_file}") | |
| endif() | |
| set(test_interface _json_test_interface_${test}) | |
| else() | |
| set(test_interface _json_test_interface_${test}_cpp_${cxx_standard}) | |
| endif() | |
| if(NOT TARGET ${test_interface}) | |
| add_library(${test_interface} INTERFACE) | |
| endif() | |
| target_compile_definitions(${test_interface} INTERFACE ${args_COMPILE_DEFINITIONS}) | |
| target_compile_features(${test_interface} INTERFACE ${args_COMPILE_FEATURES}) | |
| target_compile_options(${test_interface} INTERFACE ${args_COMPILE_OPTIONS}) | |
| target_link_libraries (${test_interface} INTERFACE ${args_LINK_LIBRARIES}) | |
| target_link_options(${test_interface} INTERFACE ${args_LINK_OPTIONS}) | |
| set_property(DIRECTORY PROPERTY | |
| ${test_interface}_TEST_PROPERTIES "${args_TEST_PROPERTIES}" | |
| ) | |
| endforeach() | |
| endforeach() | |
| endfunction() | |
| # for internal use by _json_test_add_test() | |
| function(_json_test_apply_test_properties test_target properties_target) | |
| get_property(test_properties DIRECTORY PROPERTY ${properties_target}_TEST_PROPERTIES) | |
| if(test_properties) | |
| set_tests_properties(${test_target} PROPERTIES ${test_properties}) | |
| endif() | |
| endfunction() | |
| # for internal use by json_test_add_test_for() | |
| function(_json_test_add_test test_name file main cxx_standard) | |
| set(test_target ${test_name}_cpp${cxx_standard}) | |
| if(TARGET ${test_target}) | |
| message(FATAL_ERROR "Target ${test_target} has already been added.") | |
| endif() | |
| add_executable(${test_target} ${file}) | |
| target_link_libraries(${test_target} PRIVATE ${main}) | |
| # set and require C++ standard | |
| set_target_properties(${test_target} PROPERTIES | |
| CXX_STANDARD ${cxx_standard} | |
| CXX_STANDARD_REQUIRED ON | |
| ) | |
| # apply standard-specific build settings | |
| if(TARGET _json_test_interface__cpp_${cxx_standard}) | |
| target_link_libraries(${test_target} PRIVATE _json_test_interface__cpp_${cxx_standard}) | |
| endif() | |
| # apply test-specific build settings | |
| if(TARGET _json_test_interface_${test_name}) | |
| target_link_libraries(${test_target} PRIVATE _json_test_interface_${test_name}) | |
| endif() | |
| # apply test- and standard-specific build settings | |
| if(TARGET _json_test_interface_${test_name}_cpp_${cxx_standard}) | |
| target_link_libraries(${test_target} PRIVATE | |
| _json_test_interface_${test_name}_cpp_${cxx_standard} | |
| ) | |
| endif() | |
| if (JSON_FastTests) | |
| add_test(NAME ${test_target} | |
| COMMAND ${test_target} ${DOCTEST_TEST_FILTER} | |
| WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | |
| ) | |
| else() | |
| add_test(NAME ${test_target} | |
| COMMAND ${test_target} ${DOCTEST_TEST_FILTER} --no-skip | |
| WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | |
| ) | |
| endif() | |
| set_tests_properties(${test_target} PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA) | |
| # apply standard-specific test properties | |
| if(TARGET _json_test_interface__cpp_${cxx_standard}) | |
| _json_test_apply_test_properties(${test_target} _json_test_interface__cpp_${cxx_standard}) | |
| endif() | |
| # apply test-specific test properties | |
| if(TARGET _json_test_interface_${test_name}) | |
| _json_test_apply_test_properties(${test_target} _json_test_interface_${test_name}) | |
| endif() | |
| # apply test- and standard-specific test properties | |
| if(TARGET _json_test_interface_${test_name}_cpp_${cxx_standard}) | |
| _json_test_apply_test_properties(${test_target} | |
| _json_test_interface_${test_name}_cpp_${cxx_standard} | |
| ) | |
| endif() | |
| if(JSON_Valgrind) | |
| add_test(NAME ${test_target}_valgrind | |
| COMMAND ${memcheck_command} $<TARGET_FILE:${test_target}> ${DOCTEST_TEST_FILTER} | |
| WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | |
| ) | |
| # under Valgrind the slowest tests take close to 25 minutes, so ctest's | |
| # default timeout of 1500 seconds leaves no headroom | |
| set_tests_properties(${test_target}_valgrind PROPERTIES | |
| LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA TIMEOUT 3600 | |
| ) | |
| endif() | |
| endfunction() | |
| ############################################################################# | |
| # json_test_add_test_for( | |
| # <file> | |
| # [NAME <name>] | |
| # MAIN <main> | |
| # [CXX_STANDARDS <version_number>...] [FORCE]) | |
| # | |
| # Given a <file> unit-foo.cpp, produces | |
| # | |
| # test-foo_cpp<version_number> | |
| # | |
| # if C++ standard <version_number> is supported by the compiler and the | |
| # source file contains JSON_HAS_CPP_<version_number>. | |
| # Use NAME <name> to override the filename-derived test name. | |
| # Use FORCE to create the test regardless of the file containing | |
| # JSON_HAS_CPP_<version_number>. | |
| # Test targets are linked against <main>. | |
| # CXX_STANDARDS defaults to "11". | |
| ############################################################################# | |
| function(json_test_add_test_for file) | |
| cmake_parse_arguments(args "FORCE" "MAIN;NAME" "CXX_STANDARDS" ${ARGN}) | |
| if("${args_MAIN}" STREQUAL "") | |
| message(FATAL_ERROR "Required argument MAIN <main> missing.") | |
| endif() | |
| if("${args_NAME}" STREQUAL "") | |
| get_filename_component(file_basename ${file} NAME_WE) | |
| string(REGEX REPLACE "unit-(.+)" "test-\\1" test_name ${file_basename}) | |
| else() | |
| set(test_name ${args_NAME}) | |
| if(NOT test_name MATCHES "test-.+") | |
| message(FATAL_ERROR "Test name must start with 'test-'.") | |
| endif() | |
| endif() | |
| if("${args_CXX_STANDARDS}" STREQUAL "") | |
| set(args_CXX_STANDARDS 11) | |
| endif() | |
| file(READ ${file} file_content) | |
| foreach(cxx_standard ${args_CXX_STANDARDS}) | |
| if(NOT compiler_supports_cpp_${cxx_standard}) | |
| continue() | |
| endif() | |
| # add unconditionally if C++11 (default) or forced | |
| if(NOT ("${cxx_standard}" STREQUAL 11 OR args_FORCE)) | |
| string(FIND "${file_content}" JSON_HAS_CPP_${cxx_standard} has_cpp_found) | |
| if(${has_cpp_found} EQUAL -1) | |
| continue() | |
| endif() | |
| endif() | |
| _json_test_add_test(${test_name} ${file} ${args_MAIN} ${cxx_standard}) | |
| endforeach() | |
| endfunction() | |
| ############################################################################# | |
| # json_test_should_build_32bit_test( | |
| # <build_32bit_var> <build_32bit_only_var> <input>) | |
| # | |
| # Check if the 32bit unit test should be built based on the value of <input> | |
| # and store the result in the variables <build_32bit_var> and | |
| # <build_32bit_only_var>. | |
| ############################################################################# | |
| function(json_test_should_build_32bit_test build_32bit_var build_32bit_only_var input) | |
| set(${build_32bit_only_var} OFF PARENT_SCOPE) | |
| string(TOUPPER "${input}" ${build_32bit_var}) | |
| if("${${build_32bit_var}}" STREQUAL AUTO) | |
| # check if compiler is targeting 32bit by default | |
| include(CheckTypeSize) | |
| check_type_size("size_t" sizeof_size_t LANGUAGE CXX) | |
| if(${sizeof_size_t} AND ${sizeof_size_t} EQUAL 4) | |
| message(STATUS "Auto-enabling 32bit unit test.") | |
| set(${build_32bit_var} ON) | |
| else() | |
| set(${build_32bit_var} OFF) | |
| endif() | |
| elseif("${${build_32bit_var}}" STREQUAL ONLY) | |
| set(${build_32bit_only_var} ON PARENT_SCOPE) | |
| endif() | |
| set(${build_32bit_var} "${${build_32bit_var}}" PARENT_SCOPE) | |
| endfunction() |