test.cmake 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. set(_json_test_cmake_list_file ${CMAKE_CURRENT_LIST_FILE})
  2. #############################################################################
  3. # download test data
  4. #############################################################################
  5. include(download_test_data)
  6. # test fixture to download test data
  7. add_test(NAME "download_test_data" COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}
  8. --target download_test_data
  9. )
  10. set_tests_properties(download_test_data PROPERTIES FIXTURES_SETUP TEST_DATA)
  11. if(JSON_Valgrind)
  12. find_program(CMAKE_MEMORYCHECK_COMMAND valgrind)
  13. message(STATUS "Executing test suite with Valgrind (${CMAKE_MEMORYCHECK_COMMAND})")
  14. set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1 --leak-check=full")
  15. separate_arguments(memcheck_command)
  16. endif()
  17. #############################################################################
  18. # detect standard support
  19. #############################################################################
  20. # C++11 is the minimum required
  21. set(compiler_supports_cpp_11 TRUE)
  22. foreach(feature ${CMAKE_CXX_COMPILE_FEATURES})
  23. if (${feature} STREQUAL cxx_std_14)
  24. set(compiler_supports_cpp_14 TRUE)
  25. elseif (${feature} STREQUAL cxx_std_17)
  26. set(compiler_supports_cpp_17 TRUE)
  27. elseif (${feature} STREQUAL cxx_std_20)
  28. set(compiler_supports_cpp_20 TRUE)
  29. elseif (${feature} STREQUAL cxx_std_23)
  30. set(compiler_supports_cpp_23 TRUE)
  31. endif()
  32. endforeach()
  33. #############################################################################
  34. # test functions
  35. #############################################################################
  36. #############################################################################
  37. # json_test_set_test_options(
  38. # all|<tests>
  39. # [CXX_STANDARDS all|<args>...]
  40. # [COMPILE_DEFINITIONS <args>...]
  41. # [COMPILE_FEATURES <args>...]
  42. # [COMPILE_OPTIONS <args>...]
  43. # [LINK_LIBRARIES <args>...]
  44. # [LINK_OPTIONS <args>...]
  45. # [TEST_PROPERTIES <args>...])
  46. #
  47. # Supply test- and standard-specific build settings and/or test properties.
  48. # Specify multiple tests using a list e.g., "test-foo;test-bar".
  49. #
  50. # Must be called BEFORE the test is created.
  51. #############################################################################
  52. function(json_test_set_test_options tests)
  53. cmake_parse_arguments(args "" ""
  54. "CXX_STANDARDS;COMPILE_DEFINITIONS;COMPILE_FEATURES;COMPILE_OPTIONS;LINK_LIBRARIES;LINK_OPTIONS;TEST_PROPERTIES"
  55. ${ARGN})
  56. if(NOT args_CXX_STANDARDS)
  57. set(args_CXX_STANDARDS "all")
  58. endif()
  59. foreach(test ${tests})
  60. if("${test}" STREQUAL "all")
  61. set(test "")
  62. endif()
  63. foreach(cxx_standard ${args_CXX_STANDARDS})
  64. if("${cxx_standard}" STREQUAL "all")
  65. if("${test}" STREQUAL "")
  66. message(FATAL_ERROR "Not supported. Change defaults in: ${_json_test_cmake_list_file}")
  67. endif()
  68. set(test_interface _json_test_interface_${test})
  69. else()
  70. set(test_interface _json_test_interface_${test}_cpp_${cxx_standard})
  71. endif()
  72. if(NOT TARGET ${test_interface})
  73. add_library(${test_interface} INTERFACE)
  74. endif()
  75. target_compile_definitions(${test_interface} INTERFACE ${args_COMPILE_DEFINITIONS})
  76. target_compile_features(${test_interface} INTERFACE ${args_COMPILE_FEATURES})
  77. target_compile_options(${test_interface} INTERFACE ${args_COMPILE_OPTIONS})
  78. target_link_libraries (${test_interface} INTERFACE ${args_LINK_LIBRARIES})
  79. target_link_options(${test_interface} INTERFACE ${args_LINK_OPTIONS})
  80. #set_target_properties(${test_interface} PROPERTIES JSON_TEST_PROPERTIES "${args_TEST_PROPERTIES}")
  81. set_property(DIRECTORY PROPERTY
  82. ${test_interface}_TEST_PROPERTIES "${args_TEST_PROPERTIES}"
  83. )
  84. endforeach()
  85. endforeach()
  86. endfunction()
  87. # for internal use by _json_test_add_test()
  88. function(_json_test_apply_test_properties test_target properties_target)
  89. #get_target_property(test_properties ${properties_target} JSON_TEST_PROPERTIES)
  90. get_property(test_properties DIRECTORY PROPERTY ${properties_target}_TEST_PROPERTIES)
  91. if(test_properties)
  92. set_tests_properties(${test_target} PROPERTIES ${test_properties})
  93. endif()
  94. endfunction()
  95. # for internal use by json_test_add_test_for()
  96. function(_json_test_add_test test_name file main cxx_standard)
  97. set(test_target ${test_name}_cpp${cxx_standard})
  98. if(TARGET ${test_target})
  99. message(FATAL_ERROR "Target ${test_target} has already been added.")
  100. endif()
  101. add_executable(${test_target} ${file})
  102. target_link_libraries(${test_target} PRIVATE ${main})
  103. # set and require C++ standard
  104. set_target_properties(${test_target} PROPERTIES
  105. CXX_STANDARD ${cxx_standard}
  106. CXX_STANDARD_REQUIRED ON
  107. )
  108. # apply standard-specific build settings
  109. if(TARGET _json_test_interface__cpp_${cxx_standard})
  110. target_link_libraries(${test_target} PRIVATE _json_test_interface__cpp_${cxx_standard})
  111. endif()
  112. # apply test-specific build settings
  113. if(TARGET _json_test_interface_${test_name})
  114. target_link_libraries(${test_target} PRIVATE _json_test_interface_${test_name})
  115. endif()
  116. # apply test- and standard-specific build settings
  117. if(TARGET _json_test_interface_${test_name}_cpp_${cxx_standard})
  118. target_link_libraries(${test_target} PRIVATE
  119. _json_test_interface_${test_name}_cpp_${cxx_standard}
  120. )
  121. endif()
  122. if (JSON_FastTests)
  123. add_test(NAME ${test_target}
  124. COMMAND ${test_target} ${DOCTEST_TEST_FILTER}
  125. WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  126. )
  127. else()
  128. add_test(NAME ${test_target}
  129. COMMAND ${test_target} ${DOCTEST_TEST_FILTER} --no-skip
  130. WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  131. )
  132. endif()
  133. set_tests_properties(${test_target} PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA)
  134. # apply standard-specific test properties
  135. if(TARGET _json_test_interface__cpp_${cxx_standard})
  136. _json_test_apply_test_properties(${test_target} _json_test_interface__cpp_${cxx_standard})
  137. endif()
  138. # apply test-specific test properties
  139. if(TARGET _json_test_interface_${test_name})
  140. _json_test_apply_test_properties(${test_target} _json_test_interface_${test_name})
  141. endif()
  142. # apply test- and standard-specific test properties
  143. if(TARGET _json_test_interface_${test_name}_cpp_${cxx_standard})
  144. _json_test_apply_test_properties(${test_target}
  145. _json_test_interface_${test_name}_cpp_${cxx_standard}
  146. )
  147. endif()
  148. if(JSON_Valgrind)
  149. add_test(NAME ${test_target}_valgrind
  150. COMMAND ${memcheck_command} $<TARGET_FILE:${test_target}> ${DOCTEST_TEST_FILTER}
  151. WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  152. )
  153. set_tests_properties(${test_target}_valgrind PROPERTIES
  154. LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA
  155. )
  156. endif()
  157. endfunction()
  158. #############################################################################
  159. # json_test_add_test_for(
  160. # <file>
  161. # [NAME <name>]
  162. # MAIN <main>
  163. # [CXX_STANDARDS <version_number>...] [FORCE])
  164. #
  165. # Given a <file> unit-foo.cpp, produces
  166. #
  167. # test-foo_cpp<version_number>
  168. #
  169. # if C++ standard <version_number> is supported by the compiler and the
  170. # source file contains JSON_HAS_CPP_<version_number>.
  171. # Use NAME <name> to override the filename-derived test name.
  172. # Use FORCE to create the test regardless of the file containing
  173. # JSON_HAS_CPP_<version_number>.
  174. # Test targets are linked against <main>.
  175. # CXX_STANDARDS defaults to "11".
  176. #############################################################################
  177. function(json_test_add_test_for file)
  178. cmake_parse_arguments(args "FORCE" "MAIN;NAME" "CXX_STANDARDS" ${ARGN})
  179. if("${args_MAIN}" STREQUAL "")
  180. message(FATAL_ERROR "Required argument MAIN <main> missing.")
  181. endif()
  182. if("${args_NAME}" STREQUAL "")
  183. get_filename_component(file_basename ${file} NAME_WE)
  184. string(REGEX REPLACE "unit-([^$]+)" "test-\\1" test_name ${file_basename})
  185. else()
  186. set(test_name ${args_NAME})
  187. if(NOT test_name MATCHES "test-[^$]+")
  188. message(FATAL_ERROR "Test name must start with 'test-'.")
  189. endif()
  190. endif()
  191. if("${args_CXX_STANDARDS}" STREQUAL "")
  192. set(args_CXX_STANDARDS 11)
  193. endif()
  194. file(READ ${file} file_content)
  195. foreach(cxx_standard ${args_CXX_STANDARDS})
  196. if(NOT compiler_supports_cpp_${cxx_standard})
  197. continue()
  198. endif()
  199. # add unconditionally if C++11 (default) or forced
  200. if(NOT ("${cxx_standard}" STREQUAL 11 OR args_FORCE))
  201. string(FIND "${file_content}" JSON_HAS_CPP_${cxx_standard} has_cpp_found)
  202. if(${has_cpp_found} EQUAL -1)
  203. continue()
  204. endif()
  205. endif()
  206. _json_test_add_test(${test_name} ${file} ${args_MAIN} ${cxx_standard})
  207. endforeach()
  208. endfunction()
  209. #############################################################################
  210. # json_test_should_build_32bit_test(
  211. # <build_32bit_var> <build_32bit_only_var> <input>)
  212. #
  213. # Check if the 32bit unit test should be built based on the value of <input>
  214. # and store the result in the variables <build_32bit_var> and
  215. # <build_32bit_only_var>.
  216. #############################################################################
  217. function(json_test_should_build_32bit_test build_32bit_var build_32bit_only_var input)
  218. set(${build_32bit_only_var} OFF PARENT_SCOPE)
  219. string(TOUPPER "${input}" ${build_32bit_var})
  220. if("${${build_32bit_var}}" STREQUAL AUTO)
  221. # check if compiler is targeting 32bit by default
  222. include(CheckTypeSize)
  223. check_type_size("size_t" sizeof_size_t LANGUAGE CXX)
  224. if(sizeof_size_t AND ${sizeof_size_t} EQUAL 4)
  225. message(STATUS "Auto-enabling 32bit unit test.")
  226. set(${build_32bit_var} ON)
  227. else()
  228. set(${build_32bit_var} OFF)
  229. endif()
  230. elseif("${${build_32bit_var}}" STREQUAL ONLY)
  231. set(${build_32bit_only_var} ON PARENT_SCOPE)
  232. endif()
  233. set(${build_32bit_var} "${${build_32bit_var}}" PARENT_SCOPE)
  234. endfunction()