diff options
Diffstat (limited to 'cmake/test.cmake')
-rw-r--r-- | cmake/test.cmake | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/cmake/test.cmake b/cmake/test.cmake new file mode 100644 index 0000000..bb840c6 --- /dev/null +++ b/cmake/test.cmake @@ -0,0 +1,273 @@ +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) + 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_target_properties(${test_interface} PROPERTIES JSON_TEST_PROPERTIES "${args_TEST_PROPERTIES}") + 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_target_property(test_properties ${properties_target} JSON_TEST_PROPERTIES) + 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} + ) + set_tests_properties(${test_target}_valgrind PROPERTIES + LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA + ) + 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() |