1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-05-07 23:33:52 +00:00
CLI11/tests/CMakeLists.txt
Philip Top 0f5bf21e91
add some reduction methods to the options on the fuzz tests (#930)
This adds a round trip test for config file generation to the fuzzer. 

(the next step after this PR will be a fuzzer that verifies that the
round trip actually matches the results.
This change ended up requiring quite a few minor changes to fix the
ambiguities between the config file generation and config file reader.

1). There was a number of potential conflicts between positional names
and regular option names that could be triggered in config files, this
required a number of additional checks on the positional naming to
ensure no conflicts.
2). flag options with disable flag override can produce output results
that are not valid by themselves, resolving this required flag input to
be able to handle an array and output the original value set of results.
3). strings with non-printable characters could cause all sorts of chaos
in the config files. This was resolved by generating a binary string
conversion format and handling multiline comments and characters, and
handling escaped characters. Note; I think a better solution is to move
to fully supporting string formatting and escaping along with the binary
strings from TOML now that TOML 1.0 is finalized. That will not be this
PR though, maybe the next one.
4). Lot of ambiguities and edge cases in the string splitter, this was
reworked
5). handling of comments was not done well, especially comment characters in the
name of the option which is allowed.
6). non printable characters in the option naming. This would be weird
in practice but it also cause some big holes in the config file
generation, so the restricted character set for option naming was
expanded. (don't allow spaces or control characters).

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-12-18 05:21:32 -08:00

357 lines
12 KiB
CMake

if(CLI11_SANITIZERS AND ${CMAKE_VERSION} VERSION_GREATER "3.13.0")
message(STATUS "Using arsenm/sanitizers-cmake")
FetchContent_Declare(
sanitizers
GIT_REPOSITORY https://github.com/arsenm/sanitizers-cmake.git
GIT_SHALLOW 1
GIT_TAG 3f0542e)
FetchContent_GetProperties(sanitizers)
if(NOT sanitizers_POPULATED)
FetchContent_Populate(sanitizers)
endif()
list(APPEND CMAKE_MODULE_PATH "${sanitizers_SOURCE_DIR}/cmake")
find_package(Sanitizers)
if(SANITIZE_ADDRESS)
message(STATUS "You might want to use \"${ASan_WRAPPER}\" to run your program")
endif()
else()
macro(add_sanitizers)
endmacro()
endif()
# Add boost to test boost::optional (currently explicitly requested)"
option(CLI11_BOOST "Turn on boost test (currently may fail with Boost 1.70)" OFF)
if(CLI11_BOOST)
find_package(Boost 1.61 REQUIRED)
endif()
set(boost-optional-def $<$<BOOL:${Boost_FOUND}>:CLI11_BOOST_OPTIONAL>)
set(CLI11_TESTS
HelpersTest
ConfigFileTest
OptionTypeTest
SimpleTest
AppTest
SetTest
TransformTest
CreationTest
SubcommandTest
HelpTest
FormatterTest
NewParseTest
OptionalTest
DeprecatedTest
StringParseTest
ComplexTypeTest
TrueFalseTest
OptionGroupTest
EncodingTest)
if(WIN32)
list(APPEND CLI11_TESTS WindowsTest)
endif()
if(CMAKE_CXX_STANDARD GREATER 16)
list(APPEND CLI11_TESTS FuzzFailTest)
endif()
if(Boost_FOUND)
list(APPEND CLI11_TESTS BoostOptionTypeTest)
endif()
set(CLI11_MULTIONLY_TESTS TimerTest)
find_package(Catch2 CONFIG)
if(Catch2_FOUND)
if(NOT TARGET Catch2::Catch2)
message(FATAL_ERROR "Found Catch2 at ${Catch2_DIR} but targets are missing.")
endif()
message(STATUS "Found Catch2 ${Catch2_VERSION}")
if(Catch2_VERSION VERSION_LESS 3)
add_library(catch_main main.cpp catch.hpp)
target_include_directories(catch_main PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(catch_main PUBLIC Catch2::Catch2)
else()
add_library(catch_main ALIAS Catch2::Catch2WithMain)
target_compile_definitions(Catch2::Catch2WithMain INTERFACE -DCLI11_CATCH3)
endif()
else()
message(STATUS "Downloading Catch2")
# FetchContent would be better, but requires newer CMake.
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/catch2")
set(url https://github.com/philsquared/Catch/releases/download/v2.13.10/catch.hpp)
file(
DOWNLOAD ${url} "${CMAKE_CURRENT_BINARY_DIR}/catch2/catch.hpp"
STATUS status
EXPECTED_HASH SHA256=3725c0f0a75f376a5005dde31ead0feb8f7da7507644c201b814443de8355170)
list(GET status 0 error)
if(error)
message(FATAL_ERROR "Could not download ${url}, and Catch2 not found on your system.")
endif()
add_library(catch_main main.cpp catch.hpp)
target_include_directories(catch_main PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}")
endif()
# Add special target that copies the data directory for tests
file(
GLOB_RECURSE DATA_FILES
LIST_DIRECTORIES false
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/data/*")
foreach(DATA_FILE IN LISTS DATA_FILES)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${DATA_FILE}"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${DATA_FILE}"
"${CMAKE_CURRENT_BINARY_DIR}/${DATA_FILE}"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/${DATA_FILE}"
VERBATIM)
endforeach()
add_custom_target(cli11_test_data DEPENDS ${DATA_FILES})
# Build dependent applications which are launched from test code
set(CLI11_DEPENDENT_APPLICATIONS system_args ensure_utf8 ensure_utf8_twice)
foreach(APP IN LISTS CLI11_DEPENDENT_APPLICATIONS)
add_executable(${APP} applications/${APP}.cpp)
target_include_directories(${APP} PRIVATE ${CMAKE_SOURCE_DIR}/include)
endforeach()
function(add_dependent_application_definitions TARGET)
foreach(APP IN LISTS CLI11_DEPENDENT_APPLICATIONS)
string(TOUPPER ${APP} APP_UPPERCASE)
target_compile_definitions(${TARGET}
PRIVATE CLI11_${APP_UPPERCASE}_EXE="$<TARGET_FILE:${APP}>")
endforeach()
endfunction()
# Target must already exist
macro(add_catch_test TESTNAME)
target_link_libraries(${TESTNAME} PUBLIC catch_main)
add_dependencies(${TESTNAME} cli11_test_data)
add_test(${TESTNAME} ${TESTNAME})
set_target_properties(${TESTNAME} PROPERTIES FOLDER "Tests")
if(CLI11_FORCE_LIBCXX)
set_property(
TARGET ${T}
APPEND_STRING
PROPERTY LINK_FLAGS -stdlib=libc++)
endif()
endmacro()
foreach(T IN LISTS CLI11_TESTS)
if(CLI11_CUDA_TESTS)
set_property(SOURCE ${T}.cpp PROPERTY LANGUAGE CUDA)
endif()
add_executable(${T} ${T}.cpp)
add_dependent_application_definitions(${T})
add_sanitizers(${T})
if(NOT CLI11_CUDA_TESTS)
target_link_libraries(${T} PRIVATE CLI11_warnings)
endif()
target_link_libraries(${T} PRIVATE CLI11)
add_catch_test(${T})
if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
add_executable(${T}_Single ${T}.cpp)
add_dependent_application_definitions(${T}_Single)
target_link_libraries(${T}_Single PRIVATE CLI11_SINGLE)
add_catch_test(${T}_Single)
set_property(TARGET ${T}_Single PROPERTY FOLDER "Tests Single File")
endif()
endforeach()
foreach(T IN LISTS CLI11_MULTIONLY_TESTS)
add_executable(${T} ${T}.cpp)
add_dependent_application_definitions(${T})
add_sanitizers(${T})
target_link_libraries(${T} PUBLIC CLI11)
add_catch_test(${T})
endforeach()
if(CMAKE_CXX_STANDARD GREATER 16)
set(TEST_FILE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(FuzzFailTest PUBLIC -DTEST_FILE_FOLDER="${TEST_FILE_FOLDER}")
target_sources(FuzzFailTest PUBLIC ${PROJECT_SOURCE_DIR}/fuzz/fuzzApp.cpp)
if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
target_compile_definitions(FuzzFailTest_Single PUBLIC -DTEST_FILE_FOLDER="${TEST_FILE_FOLDER}")
target_sources(FuzzFailTest_Single PUBLIC ${PROJECT_SOURCE_DIR}/fuzz/fuzzApp.cpp)
endif()
endif()
# Add -Wno-deprecated-declarations to DeprecatedTest
set(no-deprecated-declarations $<$<CXX_COMPILER_ID:MSVC>:/wd4996>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated-declarations>)
target_compile_options(DeprecatedTest PRIVATE ${no-deprecated-declarations})
if(TARGET DeprecatedTest_Single)
target_compile_options(DeprecatedTest_Single PRIVATE ${no-deprecated-declarations})
endif()
# Link test (build error if inlines missing)
add_library(link_test_1 link_test_1.cpp)
target_link_libraries(link_test_1 PUBLIC CLI11)
set_target_properties(link_test_1 PROPERTIES FOLDER "Tests")
add_executable(link_test_2 link_test_2.cpp)
target_link_libraries(link_test_2 PUBLIC CLI11 link_test_1)
add_catch_test(link_test_2)
if(CLI11_FORCE_LIBCXX)
set_property(
TARGET link_test_1
APPEND_STRING
PROPERTY LINK_FLAGS -stdlib=libc++)
set_property(
TARGET link_test_2
APPEND_STRING
PROPERTY LINK_FLAGS -stdlib=libc++)
endif()
# Add informational printout
add_executable(informational informational.cpp)
target_link_libraries(informational PUBLIC CLI11)
if(CLI11_FORCE_LIBCXX)
set_property(
TARGET informational
APPEND_STRING
PROPERTY LINK_FLAGS -stdlib=libc++)
endif()
# Force this to be in a standard location so CTest can find it
set_target_properties(
informational
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}"
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_BINARY_DIR}")
# Adding this printout to CTest
file(WRITE "${PROJECT_BINARY_DIR}/CTestCustom.cmake"
"set(CTEST_CUSTOM_PRE_TEST \"${CMAKE_BINARY_DIR}/informational\")")
target_compile_definitions(informational PRIVATE ${boost-optional-def})
target_compile_definitions(OptionalTest PRIVATE ${boost-optional-def})
if(TARGET Boost::boost)
message(STATUS "including boost target")
target_link_libraries(informational PRIVATE Boost::boost)
target_link_libraries(OptionalTest PRIVATE Boost::boost)
target_link_libraries(BoostOptionTypeTest PRIVATE Boost::boost)
if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
target_link_libraries(OptionalTest_Single PRIVATE Boost::boost)
target_link_libraries(BoostOptionTypeTest_Single PRIVATE Boost::boost)
endif()
message(STATUS "Boost libs=${Boost_INCLUDE_DIRS}")
elseif(BOOST_FOUND)
message(STATUS "no boost target")
target_include_directories(informational PRIVATE ${Boost_INCLUDE_DIRS})
target_include_directories(OptionalTest PRIVATE ${Boost_INCLUDE_DIRS})
target_include_directories(BoostOptionTypeTest PRIVATE ${Boost_INCLUDE_DIRS})
if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
target_include_directories(OptionalTest_Single PRIVATE ${Boost_INCLUDE_DIRS})
target_include_directories(BoostOptionTypeTest_Single PRIVATE ${Boost_INCLUDE_DIRS})
endif()
message(STATUS "Boost libs=${Boost_INCLUDE_DIRS}")
else()
message(STATUS "Boost not found, not adding boost tests")
endif()
if(CMAKE_BUILD_TYPE STREQUAL Coverage)
include(CodeCoverage)
setup_target_for_coverage(
NAME
CLI11_coverage
EXECUTABLE
ctest
DEPENDENCIES
${CLI11_TESTS}
${CLI11_MULTIONLY_TESTS})
endif()
set(CLI11_PACKAGE_SEARCH_LOC "")
# tests of the cmake package and pkg-config package
if(CLI11_INSTALL_PACKAGE_TESTS)
if(NOT MSVC)
set(package_test_command --test-command "${CMAKE_CTEST_COMMAND}")
else() # don't try to run the tests on MSVC since that would require copying the dll's and doing
# some other setup that isn't that important to run on all OS
set(package_test_command)
endif()
if(CMAKE_BUILD_TYPE)
set(CLI11_PACKAGE_TEST_BUILD_TYPE ${CMAKE_BUILD_TYPE})
else()
set(CLI11_PACKAGE_TEST_BUILD_TYPE Release)
endif()
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/find_package_tests")
if(MSVC AND ${CMAKE_VERSION} VERSION_GREATER 3.12.9)
# Tests for other CMake projects including and using CLI11 using find_package
add_test(
NAME find-package-testsA
COMMAND
${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" -A "${CMAKE_GENERATOR_PLATFORM}"
"-DCLI11_DIR=${CMAKE_INSTALL_PREFIX}" "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
"${CMAKE_CURRENT_SOURCE_DIR}/find_package_tests"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/find_package_tests")
else()
add_test(
NAME find-package-testsA
COMMAND
${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" "-DCLI11_DIR=${CMAKE_INSTALL_PREFIX}"
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
"${CMAKE_CURRENT_SOURCE_DIR}/find_package_tests"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/find_package_tests")
endif()
add_test(NAME find-package-testsB
COMMAND ${CMAKE_COMMAND} --build "${CMAKE_CURRENT_BINARY_DIR}/find_package_tests"
--config ${CLI11_PACKAGE_TEST_BUILD_TYPE})
add_test(
NAME find-package-testsC
COMMAND ${CMAKE_CTEST_COMMAND} -C ${CLI11_PACKAGE_TEST_BUILD_TYPE}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/find_package_tests")
set_property(TEST find-package-testsA PROPERTY LABELS Packaging)
set_property(TEST find-package-testsB PROPERTY LABELS Packaging)
set_property(TEST find-package-testsB PROPERTY DEPENDS find-package-testsA)
set_property(TEST find-package-testsC PROPERTY LABELS Packaging)
set_property(TEST find-package-testsC PROPERTY DEPENDS find-package-testsB)
if(NOT MSVC)
# Tests for other CMake projects using the package_config files
add_test(
package-config-tests
${CMAKE_CTEST_COMMAND}
-C
--build-and-test
"${CMAKE_CURRENT_SOURCE_DIR}/package_config_tests"
"${CMAKE_CURRENT_BINARY_DIR}/package_config_tests"
--build-generator
"${CMAKE_GENERATOR}"
--build-generator-platform
"${CMAKE_GENERATOR_PLATFORM}"
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCLI11_DIR=${CMAKE_INSTALL_PREFIX}"
${package_test_command})
set_property(TEST package-config-tests PROPERTY LABELS Packaging)
endif()
endif()