2
0
mirror of https://github.com/boostorg/url.git synced 2026-01-19 04:42:15 +00:00
Files
url/extra/test_suite/DiscoverAndWriteTestsScripts.cmake
2025-08-29 12:01:50 -05:00

173 lines
7.1 KiB
CMake

#
# Copyright (c) 2025 Alan de Freitas (alandefreitas@gmail.com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# Official repository: https://github.com/boostorg/url
#
# This file defines a script that can be used to create another
# CMake script that will discover tests from a Boost.URL test suite executable
# and write them to a CTest script file.
# Define a custom message function that prints the message only if some
# special debug variable is set from the command line when calling the script.
# This is useful to avoid cluttering the output with debug messages but allowing
# us to debug this script since the CMake debugger cannot step in here.
function(debug_message)
if (TEST_SUITE_SCRIPT_DEBUG)
message(STATUS "${ARGV0}")
endif ()
endfunction()
# Appends a formatted CMake command to the FULL_SCRIPT variable in the parent scope.
#
# Arguments:
# NAME - The CMake command name (e.g., add_test, set).
# ... - The arguments to the command. Each argument is checked for special
# characters; if present, it is wrapped as a CMake bracket argument [==[...]==].
#
# Details:
# - Arguments are processed to ensure correct escaping for script generation.
# - The resulting command line is appended to the FULL_SCRIPT variable in the parent scope,
# followed by a newline.
#
# Example:
# push_command_safe(add_test my_test /path/to/exe "test name with spaces")
# # Appends: add_test(my_test /path/to/exe [==[test name with spaces]==])
function(push_command_safe NAME)
set(PUSH_COMMAND_ARGS "")
math(EXPR PUSH_COMMAND_LAST_ARG_INDEX ${ARGC}-1)
foreach (PUSH_COMMAND_ARG_IDX RANGE 1 ${PUSH_COMMAND_LAST_ARG_INDEX})
set(PUSH_COMMAND_ARG "${ARGV${PUSH_COMMAND_ARG_IDX}}")
if (PUSH_COMMAND_ARG MATCHES "[^-./:a-zA-Z0-9_]")
set(PUSH_COMMAND_ARGS "${PUSH_COMMAND_ARGS} [==[${PUSH_COMMAND_ARG}]==]") # form a bracket_argument
else ()
set(PUSH_COMMAND_ARGS "${PUSH_COMMAND_ARGS} ${PUSH_COMMAND_ARG}")
endif ()
endforeach ()
set(FULL_SCRIPT "${FULL_SCRIPT}${NAME}(${PUSH_COMMAND_ARGS})\n" PARENT_SCOPE)
debug_message("Adding command to script: ${NAME}(${PUSH_COMMAND_ARGS})")
endfunction()
# Function to write CTest script for discovering tests from a Boost.URL test suite executable
# This function discovers tests from an executable target that uses the Boost.URL test suite
# and creates individual CTest targets for each test.
# The tests are defined in an external script that is later included by CMake.
function(boost_url_test_suite_write_tests_file)
debug_message("Parsing test parameters...")
cmake_parse_arguments(
# prefix
"TEST_SUITE"
# options
""
# single-value arguments
"TEST_TARGET;TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_PREFIX;TEST_SPEC;TEST_SUFFIX;CTEST_FILE"
# multi-value arguments
"TEST_EXTRA_ARGS;TEST_PROPERTIES"
${ARGN}
)
# Variables for arguments
if (NOT EXISTS "${TEST_SUITE_TEST_EXECUTABLE}")
debug_message(FATAL_ERROR "Specified test executable '${TEST_SUITE_TEST_EXECUTABLE}' does not exist")
endif ()
# Run the test executable to get a list of available tests
debug_message("Running test executable to discover tests...")
debug_message("${TEST_SUITE_TEST_EXECUTABLE} ${TEST_SUITE_TEST_SPEC} --list-tests")
execute_process(
COMMAND "${TEST_SUITE_TEST_EXECUTABLE}" ${TEST_SUITE_TEST_SPEC} --list-tests
OUTPUT_VARIABLE TEST_SUITE_LIST_TESTS_OUTPUT
ERROR_VARIABLE TEST_SUITE_LIST_TESTS_OUTPUT
RESULT_VARIABLE TEST_SUITE_RESULT
WORKING_DIRECTORY "${TEST_SUITE_TEST_WORKING_DIR}"
)
if (NOT ${TEST_SUITE_RESULT} EQUAL 0)
debug_message(FATAL_ERROR
"Error listing tests from executable '${TEST_SUITE_TEST_EXECUTABLE}':\n"
" Result: ${TEST_SUITE_RESULT}\n"
" Output: ${TEST_SUITE_LIST_TESTS_OUTPUT}\n"
)
endif ()
# Split lines into a list
# Normalize line endings to \n
string(REPLACE "\r\n" "\n" TEST_SUITE_LIST_TESTS_OUTPUT "${TEST_SUITE_LIST_TESTS_OUTPUT}")
string(REPLACE "\r" "\n" TEST_SUITE_LIST_TESTS_OUTPUT "${TEST_SUITE_LIST_TESTS_OUTPUT}")
separate_arguments(TEST_SUITE_LIST UNIX_COMMAND "${TEST_SUITE_LIST_TESTS_OUTPUT}")
debug_message("Discovered tests: ${TEST_SUITE_LIST}")
# Exit early if no tests are detected
list(LENGTH TEST_SUITE_LIST TEST_SUITE_NUMBER_OF_TESTS)
if (TEST_SUITE_NUMBER_OF_TESTS EQUAL 0)
return()
endif ()
debug_message("Number of discovered tests: ${TEST_SUITE_NUMBER_OF_TESTS}")
set(FULL_SCRIPT "# This file is automatically generated by CMake to define tests for the Boost.URL test suite.\n")
set(TEST_SUITE_CMAKE_TESTS)
foreach (TEST_SUITE_PLAIN_NAME IN LISTS TEST_SUITE_LIST)
# Escape test names
set(TEST_SUITE_ESCAPED_NAME "${TEST_SUITE_PLAIN_NAME}")
foreach (char \\ , [ ] ;)
string(REPLACE ${char} "\\${char}" TEST_SUITE_ESCAPED_NAME "${TEST_SUITE_ESCAPED_NAME}")
endforeach ()
# Add test to file
set(CTEST_TEST_NAME "${TEST_SUITE_TEST_PREFIX}${TEST_SUITE_PLAIN_NAME}${TEST_SUITE_TEST_SUFFIX}")
push_command_safe(add_test
"${CTEST_TEST_NAME}"
"${TEST_SUITE_TEST_EXECUTABLE}"
"${TEST_SUITE_ESCAPED_NAME}"
${TEST_SUITE_TEST_EXTRA_ARGS}
)
# Append to the list of tests
list(APPEND TEST_SUITE_CMAKE_TESTS "${CTEST_TEST_NAME}")
endforeach ()
# Debug message showing the file we're about to write
debug_message("Writing test suite script to: ${TEST_SUITE_CTEST_FILE}")
file(WRITE "${TEST_SUITE_CTEST_FILE}" "${FULL_SCRIPT}")
endfunction()
if (CMAKE_SCRIPT_MODE_FILE)
debug_message("Discovering tests for ${TEST_TARGET}")
debug_message("Test executable: ${TEST_EXECUTABLE}")
debug_message("Test target: ${TEST_TARGET}")
if (TEST_WORKING_DIR)
debug_message("Working directory: ${TEST_WORKING_DIR}")
endif ()
if (TEST_SPEC)
debug_message("Test spec: ${TEST_SPEC}")
endif ()
if (TEST_EXTRA_ARGS)
debug_message("Extra arguments: ${TEST_EXTRA_ARGS}")
endif ()
if (TEST_PROPERTIES)
debug_message("Test properties: ${TEST_PROPERTIES}")
endif ()
if (TEST_PREFIX)
debug_message("Test prefix: ${TEST_PREFIX}")
endif ()
if (TEST_SUFFIX)
debug_message("Test suffix: ${TEST_SUFFIX}")
endif ()
debug_message("CTest file: ${CTEST_FILE}")
# Call the function to write the test file
boost_url_test_suite_write_tests_file(
TEST_TARGET ${TEST_TARGET}
TEST_EXECUTABLE ${TEST_EXECUTABLE}
TEST_WORKING_DIR ${TEST_WORKING_DIR}
TEST_SPEC ${TEST_SPEC}
TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS}
TEST_PROPERTIES ${TEST_PROPERTIES}
TEST_PREFIX ${TEST_PREFIX}
TEST_SUFFIX ${TEST_SUFFIX}
CTEST_FILE ${CTEST_FILE}
)
endif ()