Skip to content

Commit 092e666

Browse files
committed
Use a test launcher
1 parent 2e2b14e commit 092e666

4 files changed

Lines changed: 123 additions & 88 deletions

File tree

test/CMakeLists.txt

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,31 @@ set_tests_properties(
3131

3232
# Helper — creates a test executable and registers it with CTest.
3333
#
34-
# PASS_REGEX: the test passes only if its output matches this pattern.
35-
# FAIL_REGEX: the test fails if its output matches any of these patterns.
3634
# EXITS C: the expected exit code (defaults to 0).
35+
# FAIL_REGEX: the test fails if its output matches any of these patterns
36+
# (repeatable).
37+
# PASS_REGEX: the test passes only if its output matches all of these patterns
38+
# (repeatable).
3739
function(add_lib_test name)
3840
cmake_parse_arguments(
3941
ARG
4042
""
41-
"EXITS;PASS_REGEX"
42-
"ARGS;FAIL_REGEX;SOURCES"
43+
"EXITS"
44+
"ARGS;FAIL_REGEX;PASS_REGEX;SOURCES"
4345
${ARGN}
4446
)
45-
47+
if(ARG_KEYWORDS_MISSING_VALUES)
48+
message(
49+
FATAL_ERROR
50+
"add_lib_test(${name}): missing values for keyword(s): ${ARG_KEYWORDS_MISSING_VALUES}"
51+
)
52+
endif()
53+
if(ARG_UNPARSED_ARGUMENTS)
54+
message(
55+
FATAL_ERROR
56+
"add_lib_test(${name}): unrecognized arguments: ${ARG_UNPARSED_ARGUMENTS}"
57+
)
58+
endif()
4659
list(LENGTH ARG_SOURCES _n)
4760
if(_n EQUAL 1)
4861
get_filename_component(_stem ${ARG_SOURCES} NAME_WLE)
@@ -53,26 +66,31 @@ function(add_lib_test name)
5366
if(NOT TARGET _eggs_test.${_stem})
5467
add_executable(_eggs_test.${_stem} ${ARG_SOURCES})
5568
target_link_libraries(_eggs_test.${_stem} PRIVATE Eggs::TestMain)
56-
set_target_properties(_eggs_test.${_stem} PROPERTIES FOLDER "test")
57-
endif()
58-
59-
if(NOT DEFINED ARG_EXITS)
60-
set(ARG_EXITS 0)
69+
set_target_properties(
70+
_eggs_test.${_stem}
71+
PROPERTIES
72+
FOLDER "test"
73+
TEST_LAUNCHER
74+
"${CMAKE_COMMAND};-P;${CMAKE_CURRENT_FUNCTION_LIST_DIR}/test_launcher.cmake;--"
75+
)
6176
endif()
6277

63-
if(ARG_PASS_REGEX OR ARG_FAIL_REGEX OR NOT ARG_EXITS EQUAL 0)
64-
list(LENGTH ARG_FAIL_REGEX _nfail)
65-
add_test(
66-
NAME eggs.test.${name}
67-
COMMAND
68-
${CMAKE_COMMAND} -P
69-
"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/run_test.cmake" --
70-
${ARG_EXITS} "R:${ARG_PASS_REGEX}" ${_nfail} ${ARG_FAIL_REGEX}
71-
$<TARGET_FILE:_eggs_test.${_stem}> ${ARG_ARGS}
72-
)
73-
else()
74-
add_test(NAME eggs.test.${name} COMMAND _eggs_test.${_stem} ${ARG_ARGS})
78+
# test_launcher.cmake picks these control args.
79+
set(_control_args)
80+
if(DEFINED ARG_EXITS AND NOT ARG_EXITS EQUAL 0)
81+
list(APPEND _control_args "--eggs-run-test-exits=${ARG_EXITS}")
7582
endif()
83+
foreach(_pat IN LISTS ARG_FAIL_REGEX)
84+
list(APPEND _control_args "--eggs-run-test-fail-regex=${_pat}")
85+
endforeach()
86+
foreach(_pat IN LISTS ARG_PASS_REGEX)
87+
list(APPEND _control_args "--eggs-run-test-pass-regex=${_pat}")
88+
endforeach()
89+
90+
add_test(
91+
NAME eggs.test.${name}
92+
COMMAND _eggs_test.${_stem} ${_control_args} ${ARG_ARGS}
93+
)
7694
set_tests_properties(eggs.test.${name} PROPERTIES LABELS "unit")
7795
endfunction()
7896

@@ -166,7 +184,9 @@ add_lib_test(
166184
SOURCES check.pass.cpp
167185
ARGS "--help"
168186
PASS_REGEX
169-
"Usage: .*_eggs_test\\.check\\.pass.*\\[options\\].*-h, --help.*--list.*list selected test case"
187+
"Usage: .*_eggs_test\\.check\\.pass.*\\[options\\]"
188+
"-h, --help"
189+
"--list.*list selected test case"
170190
EXITS 0
171191
)
172192

@@ -176,7 +196,9 @@ add_lib_test(
176196
SOURCES check.pass.cpp
177197
ARGS "-h"
178198
PASS_REGEX
179-
"Usage: .*_eggs_test\\.check\\.pass.*\\[options\\].*-h, --help.*--list.*list selected test case"
199+
"Usage: .*_eggs_test\\.check\\.pass.*\\[options\\]"
200+
"-h, --help"
201+
"--list.*list selected test case"
180202
EXITS 0
181203
)
182204

test/cli/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ add_lib_test(
1313
cli/print_options.bare.pass
1414
SOURCES print_options.pass.cpp
1515
ARGS "--run=print_options_bare"
16-
PASS_REGEX "--list.*list selected test case.*--run=<test_case>"
16+
PASS_REGEX "--list.*list selected test case" "--run=<test_case>"
1717
)
1818

1919
# print_options: ns form prefixes every flag with --<ns>:<flag>.
2020
add_lib_test(
2121
cli/print_options.ns.pass
2222
SOURCES print_options.pass.cpp
2323
ARGS "--run=print_options_ns"
24-
PASS_REGEX "--ns:list.*list selected test case.*--ns:run=<test_case>"
24+
PASS_REGEX "--ns:list.*list selected test case" "--ns:run=<test_case>"
2525
FAIL_REGEX " --list"
2626
)
2727

test/run_test.cmake

Lines changed: 0 additions & 62 deletions
This file was deleted.

test/test_launcher.cmake

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Eggs.Test
2+
#
3+
# Copyright Agustin K-ballo Berge, Fusion Fenix 2026
4+
#
5+
# Distributed under the Boost Software License, Version 1.0. (See accompanying
6+
# file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7+
8+
# Usage:
9+
# cmake -P test_launcher.cmake -- <exe> [<control-arg>...] [<arg>...]
10+
#
11+
# Recognized <control-arg>:
12+
# --eggs-run-test-exits=<N> expected exit code (default 0)
13+
# --eggs-run-test-fail-regex=<regex> must NOT match (repeatable)
14+
# --eggs-run-test-pass-regex=<regex> must match (repeatable)
15+
#
16+
# Runs <exe> with <args>, echoes its output (stdout and stderr merged),
17+
# then checks:
18+
# 1. exit code equals the expected exit code (0 unless overridden)
19+
# 2. output does not match any --eggs-run-test-fail-regex=<pattern>
20+
# 3. output matches every --eggs-run-test-pass-regex=<pattern>
21+
22+
# CMAKE_ARGV0/1/2 are cmake/-P/<this-script>, CMAKE_ARGV3 is "--";
23+
# CMAKE_ARGV4 is <exe>, the rest are control args and/or passthrough args.
24+
if(CMAKE_ARGC LESS 5 OR NOT CMAKE_ARGV3 STREQUAL "--")
25+
message(
26+
FATAL_ERROR
27+
"Usage: cmake -P test_launcher.cmake -- <exe> [<control-arg>...] [<arg>...]"
28+
)
29+
endif()
30+
31+
set(_exe "${CMAKE_ARGV4}")
32+
set(_args)
33+
set(_exits 0)
34+
set(_fail_patterns)
35+
set(_pass_patterns)
36+
37+
set(_i 5)
38+
while(_i LESS CMAKE_ARGC)
39+
set(_arg "${CMAKE_ARGV${_i}}")
40+
if(_arg MATCHES "^--eggs-run-test-exits=(.*)$")
41+
set(_exits "${CMAKE_MATCH_1}")
42+
elseif(_arg MATCHES "^--eggs-run-test-fail-regex=(.*)$")
43+
list(APPEND _fail_patterns "${CMAKE_MATCH_1}")
44+
elseif(_arg MATCHES "^--eggs-run-test-pass-regex=(.*)$")
45+
list(APPEND _pass_patterns "${CMAKE_MATCH_1}")
46+
else()
47+
list(APPEND _args "${_arg}")
48+
endif()
49+
math(EXPR _i "${_i} + 1")
50+
endwhile()
51+
52+
execute_process(
53+
COMMAND "${_exe}" ${_args}
54+
OUTPUT_VARIABLE _output
55+
ERROR_VARIABLE _output
56+
ECHO_OUTPUT_VARIABLE
57+
ECHO_ERROR_VARIABLE
58+
RESULT_VARIABLE _status
59+
)
60+
61+
if(NOT _status EQUAL _exits)
62+
message(SEND_ERROR "exit code ${_status} (expected ${_exits})")
63+
endif()
64+
65+
foreach(_pat IN LISTS _fail_patterns)
66+
if(_output MATCHES "${_pat}")
67+
message(SEND_ERROR "output matched FAIL_REGEX: ${_pat}")
68+
endif()
69+
endforeach()
70+
71+
foreach(_pat IN LISTS _pass_patterns)
72+
if(NOT _output MATCHES "${_pat}")
73+
message(SEND_ERROR "output did not match PASS_REGEX: ${_pat}")
74+
endif()
75+
endforeach()

0 commit comments

Comments
 (0)