201 lines
7.4 KiB
CMake
201 lines
7.4 KiB
CMake
# cc_testing.cmake — Test target helpers.
|
|
#
|
|
# Provides: cc_test()
|
|
# Requires: cc_targets.cmake (for cc_executable).
|
|
#
|
|
# Note: dependency acquisition is NOT performed here.
|
|
# T13/T14 own dependency replacement; this module assumes
|
|
# GTest/GMock targets are already available when cc_test() is called.
|
|
|
|
# cc_test(name [NO_MAIN] [SRCS src...] [HDRS hdr...]
|
|
# [INCS [PUBLIC|PRIVATE dirs...]...]
|
|
# [DEPS [PUBLIC|PRIVATE deps...]...]
|
|
# [DEFINES [PUBLIC|PRIVATE defs...]...]
|
|
# [OPTIONS opts...] [FEATURES features...]
|
|
# [ARGS args...])
|
|
#
|
|
# Create a test executable linked against GTest and register it with CTest.
|
|
#
|
|
# Required:
|
|
# SRCS — source files (must be non-empty).
|
|
#
|
|
# Optional:
|
|
# HDRS — header files for IDE source grouping.
|
|
# NO_MAIN — do not default-link GTest::gtest_main.
|
|
# INCS — include directories grouped by visibility.
|
|
# INTERFACE is not valid for test executables.
|
|
# DEPS — dependencies grouped by visibility.
|
|
# INTERFACE is not valid for test executables.
|
|
# DEFINES — compile definitions grouped by visibility.
|
|
# INTERFACE is not valid for test executables.
|
|
# OPTIONS — compile options applied PRIVATE to the target.
|
|
# FEATURES — compile features (e.g. cxx_std_14) applied PRIVATE.
|
|
# ARGS — arguments passed to the CTest command.
|
|
#
|
|
# GTest/GMock behavior:
|
|
# - Without NO_MAIN: links GTest::gtest_main (which implies GTest::gtest).
|
|
# - With NO_MAIN: links GTest::gtest only.
|
|
# - GTest::gmock may appear in DEPS with or without NO_MAIN.
|
|
# - GTest::gmock_main requires NO_MAIN (enforced at configure time).
|
|
#
|
|
# CTest registration:
|
|
# - add_test(NAME <target> COMMAND <target> [<ARGS>...]).
|
|
# - If target run_tests exists, adds dependency from run_tests.
|
|
# - If CC_ENABLE_TESTING is OFF, skips target creation entirely.
|
|
#
|
|
function(cc_test TARGET_NAME)
|
|
# --- Check testing gate ---
|
|
if(DEFINED CC_ENABLE_TESTING AND NOT CC_ENABLE_TESTING)
|
|
message(STATUS "cc_test(${TARGET_NAME}): skipped (CC_ENABLE_TESTING is OFF)")
|
|
return()
|
|
endif()
|
|
|
|
# --- Check GTest availability ---
|
|
if(NOT TARGET GTest::gtest)
|
|
message(WARNING
|
|
"cc_test(${TARGET_NAME}): GTest::gtest target not available. "
|
|
"Skipping test target creation. Ensure GTest is configured before "
|
|
"calling cc_test().")
|
|
return()
|
|
endif()
|
|
|
|
# --- Parse top-level keyword arguments ---
|
|
set(_cc_test_options "NO_MAIN")
|
|
set(_cc_test_oneValueArgs "")
|
|
set(_cc_test_multiValueArgs
|
|
"SRCS" "HDRS" "INCS" "DEPS" "DEFINES" "OPTIONS" "FEATURES" "ARGS")
|
|
|
|
cmake_parse_arguments(
|
|
_cc_test
|
|
"${_cc_test_options}"
|
|
"${_cc_test_oneValueArgs}"
|
|
"${_cc_test_multiValueArgs}"
|
|
${ARGN})
|
|
|
|
# --- SRCS is required and non-empty ---
|
|
if(NOT DEFINED _cc_test_SRCS OR _cc_test_SRCS STREQUAL "")
|
|
message(FATAL_ERROR
|
|
"cc_test(${TARGET_NAME}): SRCS is required and must be non-empty. "
|
|
"Example: cc_test(my_test SRCS test_main.cc)")
|
|
endif()
|
|
|
|
# --- Parse visibility-grouped arguments ---
|
|
set(_inc_public "")
|
|
set(_inc_private "")
|
|
set(_inc_interface "")
|
|
set(_inc_all "")
|
|
set(_dep_public "")
|
|
set(_dep_private "")
|
|
set(_dep_interface "")
|
|
set(_dep_all "")
|
|
set(_def_public "")
|
|
set(_def_private "")
|
|
set(_def_interface "")
|
|
set(_def_all "")
|
|
|
|
if(DEFINED _cc_test_INCS)
|
|
_cc_parse_visibility_group(_inc ARGV ${_cc_test_INCS})
|
|
endif()
|
|
|
|
if(DEFINED _cc_test_DEPS)
|
|
_cc_parse_visibility_group(_dep ARGV ${_cc_test_DEPS})
|
|
endif()
|
|
|
|
if(DEFINED _cc_test_DEFINES)
|
|
_cc_parse_visibility_group(_def ARGV ${_cc_test_DEFINES})
|
|
endif()
|
|
|
|
# --- Test executables reject INTERFACE visibility ---
|
|
if(DEFINED _inc_interface AND NOT _inc_interface STREQUAL "")
|
|
message(FATAL_ERROR
|
|
"cc_test(${TARGET_NAME}): INTERFACE include directories are not valid for "
|
|
"test targets. Test executables are not consumed by other targets. "
|
|
"Use PUBLIC or PRIVATE visibility.")
|
|
endif()
|
|
if(DEFINED _dep_interface AND NOT _dep_interface STREQUAL "")
|
|
message(FATAL_ERROR
|
|
"cc_test(${TARGET_NAME}): INTERFACE dependencies are not valid for "
|
|
"test targets. Test executables are not consumed by other targets. "
|
|
"Use PUBLIC or PRIVATE visibility.")
|
|
endif()
|
|
if(DEFINED _def_interface AND NOT _def_interface STREQUAL "")
|
|
message(FATAL_ERROR
|
|
"cc_test(${TARGET_NAME}): INTERFACE definitions are not valid for "
|
|
"test targets. Test executables are not consumed by other targets. "
|
|
"Use PUBLIC or PRIVATE visibility.")
|
|
endif()
|
|
|
|
# --- Validate GTest::gmock_main requires NO_MAIN ---
|
|
set(_all_deps ${_dep_public} ${_dep_private})
|
|
foreach(_dep ${_all_deps})
|
|
if(_dep STREQUAL "GTest::gmock_main")
|
|
if(NOT _cc_test_NO_MAIN)
|
|
message(FATAL_ERROR
|
|
"cc_test(${TARGET_NAME}): GTest::gmock_main requires NO_MAIN. "
|
|
"GTest::gmock_main provides its own main() which conflicts with "
|
|
"the default GTest::gtest_main. Add NO_MAIN to use GTest::gmock_main.")
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
# --- Create executable target ---
|
|
add_executable(${TARGET_NAME} ${_cc_test_SRCS})
|
|
|
|
# --- Apply header files for IDE source grouping ---
|
|
if(DEFINED _cc_test_HDRS AND NOT _cc_test_HDRS STREQUAL "")
|
|
target_sources(${TARGET_NAME} PRIVATE ${_cc_test_HDRS})
|
|
endif()
|
|
|
|
# --- Apply include directories ---
|
|
if(DEFINED _inc_public AND NOT _inc_public STREQUAL "")
|
|
target_include_directories(${TARGET_NAME} PUBLIC ${_inc_public})
|
|
endif()
|
|
if(DEFINED _inc_private AND NOT _inc_private STREQUAL "")
|
|
target_include_directories(${TARGET_NAME} PRIVATE ${_inc_private})
|
|
endif()
|
|
|
|
# --- Apply dependencies ---
|
|
if(DEFINED _dep_public AND NOT _dep_public STREQUAL "")
|
|
target_link_libraries(${TARGET_NAME} PUBLIC ${_dep_public})
|
|
endif()
|
|
if(DEFINED _dep_private AND NOT _dep_private STREQUAL "")
|
|
target_link_libraries(${TARGET_NAME} PRIVATE ${_dep_private})
|
|
endif()
|
|
|
|
# --- Apply compile definitions ---
|
|
if(DEFINED _def_public AND NOT _def_public STREQUAL "")
|
|
target_compile_definitions(${TARGET_NAME} PUBLIC ${_def_public})
|
|
endif()
|
|
if(DEFINED _def_private AND NOT _def_private STREQUAL "")
|
|
target_compile_definitions(${TARGET_NAME} PRIVATE ${_def_private})
|
|
endif()
|
|
|
|
# --- Apply compile options (PRIVATE) ---
|
|
if(DEFINED _cc_test_OPTIONS AND NOT _cc_test_OPTIONS STREQUAL "")
|
|
target_compile_options(${TARGET_NAME} PRIVATE ${_cc_test_OPTIONS})
|
|
endif()
|
|
|
|
# --- Apply compile features (PRIVATE) ---
|
|
if(DEFINED _cc_test_FEATURES AND NOT _cc_test_FEATURES STREQUAL "")
|
|
target_compile_features(${TARGET_NAME} PRIVATE ${_cc_test_FEATURES})
|
|
endif()
|
|
|
|
# --- Link GTest/GMock ---
|
|
if(_cc_test_NO_MAIN)
|
|
target_link_libraries(${TARGET_NAME} PRIVATE GTest::gtest)
|
|
else()
|
|
target_link_libraries(${TARGET_NAME} PRIVATE GTest::gtest_main)
|
|
endif()
|
|
|
|
# --- Apply platform link flags ---
|
|
comm_link(${TARGET_NAME})
|
|
|
|
# --- Register with CTest ---
|
|
add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME} ${_cc_test_ARGS})
|
|
|
|
# --- Add to aggregate run_tests target ---
|
|
if(TARGET run_tests)
|
|
add_dependencies(run_tests ${TARGET_NAME})
|
|
endif()
|
|
endfunction()
|