Skip to content

Commit 472e744

Browse files
authored
feat(test): run tests and update build result (#88)
* refactor(test): update results as fixture cleanups This is less wasteful as it makes use of the output of existing tests. It should simplify adding support for running the tests. * refactor(test): order build after codegen Ordering by relative cost reduces turnarounds. Previously, codegen update happened last. * feat(test): run tests and update build result Although the project's language is now `CXX`, the setup of the C++ environment is as was before. I.e., - The environment of the build test can only be set globally (through CMake defaults, the environment, etc.). - The environment of this project should match that of the build test. It doesn't attempt to propagate any aspect explicitly. * fix(test): remove outdated condition See <https://cpp2.godbolt.org/z/4r1P6f34E>. * refactor: execute tests without developer mode * feat(test): copy new or changed build results only * feat(test): check expected build results * fix(test): add non-`check` tests when developing Test results will be updated, so make the tests use those results without a reconfiguration in-between. Also, trigger reconfiguration to add the `check` tests. * fix(test): add glob for new error tests * fix: account for C++23 tests
1 parent 165ab20 commit 472e744

9 files changed

+305
-66
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,4 @@ processing the directory.
139139

140140
The CMake project `regression-tests/CMakeLists.txt` runs the test suite of cppfront.
141141
See "Regression tests" at [`./.github/workflows/ci.yml`](./.github/workflows/ci.yml) for how to set it up.
142-
To update the test results, build with `--target cppfront_update_test_results`.
142+
To have the test results updated, configure with `-DCPPFRONT_DEVELOPING=TRUE`.

regression-tests/CMakeLists.txt

+176-49
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,61 @@
11
cmake_minimum_required(VERSION 3.23)
2-
project(cppfront-regression-tests LANGUAGES NONE)
2+
project(cppfront-regression-tests LANGUAGES CXX)
3+
4+
option(CPPFRONT_DEVELOPING "Test results are updated.")
35

46
enable_testing()
57

68
set(CPPFRONT_NO_MAGIC 1)
79
find_package(cppfront REQUIRED)
810

911
set(REGRESSION_TESTS_DIR "${CMAKE_CURRENT_LIST_DIR}/../cppfront/regression-tests")
12+
set(TEST_RESULTS_DIR "${REGRESSION_TESTS_DIR}/test-results")
13+
14+
# Set `COMPILER_ITEM_NAME`.
15+
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
16+
set(compiler_id "gcc")
17+
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
18+
set(compiler_id "apple-clang")
19+
else ()
20+
string(TOLOWER "${CMAKE_CXX_COMPILER_ID}" compiler_id)
21+
endif ()
22+
string(REGEX MATCH "[0-9]+" compiler_major_version "${CMAKE_CXX_COMPILER_VERSION}")
23+
set(COMPILER_ITEM_NAME "${compiler_id}-${compiler_major_version}")
24+
25+
# Setup `BUILD_RESULTS_DIR`.
26+
set(BUILD_RESULTS_DIR "${TEST_RESULTS_DIR}/${COMPILER_ITEM_NAME}")
27+
28+
if (CPPFRONT_DEVELOPING)
29+
file(MAKE_DIRECTORY "${BUILD_RESULTS_DIR}")
30+
31+
# Write compiler version output.
32+
set(compiler_version_command "${CMAKE_CXX_COMPILER}" "--version")
33+
if (CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
34+
set(compiler_id "clang")
35+
endif ()
36+
execute_process(
37+
COMMAND ${compiler_version_command}
38+
OUTPUT_FILE "${BUILD_RESULTS_DIR}/${compiler_id}-version.output"
39+
)
40+
endif ()
41+
42+
configure_file("cmake/ExecuteWithRedirection.cmake" "ExecuteWithRedirection.cmake" COPYONLY)
43+
configure_file("cmake/ExecuteTestCase.cmake.in" "ExecuteTestCase.cmake" @ONLY)
44+
configure_file("cmake/FindBuildResultFile.cmake.in" "FindBuildResultFile.cmake" @ONLY)
45+
configure_file("cmake/UpdateBuildOutput.cmake.in" "UpdateBuildOutput.cmake" @ONLY)
1046

11-
configure_file("cmake/UpdateTestResults.cmake.in" "UpdateTestResults.cmake" @ONLY)
12-
add_custom_target(cppfront_update_test_results)
47+
include("${CMAKE_CURRENT_BINARY_DIR}/FindBuildResultFile.cmake")
48+
49+
function(cppfront_add_check_test)
50+
cmake_parse_arguments(PARSE_ARGV 0 ARG "" "NAME;NEW_FILE;OLD_FILE;FIXTURES_REQUIRED" "")
51+
52+
add_test(
53+
NAME "${ARG_NAME}"
54+
COMMAND "${CMAKE_COMMAND}" -E compare_files "${ARG_NEW_FILE}" "${ARG_OLD_FILE}"
55+
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
56+
)
57+
set_tests_properties("${ARG_NAME}" PROPERTIES FIXTURES_REQUIRED "${ARG_FIXTURES_REQUIRED}")
58+
endfunction()
1359

1460
function(cppfront_command_tests)
1561
cmake_parse_arguments(PARSE_ARGV 0 ARG "" "SOURCE;EXPECTED_FILE" "EXTRA_FLAGS")
@@ -18,24 +64,39 @@ function(cppfront_command_tests)
1864

1965
cmake_path(GET ARG_SOURCE STEM test_name)
2066

21-
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${test_name}")
22-
add_custom_target(
23-
"${test_name}"
24-
COMMAND
25-
"${CMAKE_COMMAND}"
26-
-D "TEST_NAME=${test_name}"
27-
-D "EXTRA_FLAGS=${ARG_EXTRA_FLAGS}"
28-
-P "UpdateTestResults.cmake"
29-
)
30-
add_dependencies(cppfront_update_test_results "${test_name}")
31-
67+
if (NOT "${test_name}" MATCHES [[.*-error$]])
68+
set(gen_cpp_src "${test_name}.cpp")
69+
set(COMMAND_ERROR_IS_FATAL "COMMAND_ERROR_IS_FATAL" "ANY")
70+
endif ()
3271
add_test(
3372
NAME "codegen/${test_name}"
34-
COMMAND cppfront::cppfront "${ARG_SOURCE}" ${ARG_EXTRA_FLAGS}
73+
COMMAND
74+
"${CMAKE_COMMAND}"
75+
-D "OUTPUT_FILE=${ARG_SOURCE}.output"
76+
-P "ExecuteWithRedirection.cmake"
77+
--
78+
"${CPPFRONT_EXECUTABLE}" "${ARG_SOURCE}" ${ARG_EXTRA_FLAGS}
79+
${COMMAND_ERROR_IS_FATAL}
3580
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
3681
)
82+
set_tests_properties("codegen/${test_name}" PROPERTIES FIXTURES_SETUP "codegen/${test_name}")
3783

38-
set(expected_output_file "${REGRESSION_TESTS_DIR}/test-results/${ARG_SOURCE}.output")
84+
unset(build_test_depends)
85+
if (CPPFRONT_DEVELOPING)
86+
add_test(
87+
NAME "codegen/update/${test_name}"
88+
COMMAND
89+
"${CMAKE_COMMAND}"
90+
-E copy_if_different
91+
"${gen_cpp_src}"
92+
"${ARG_SOURCE}.output"
93+
"${TEST_RESULTS_DIR}"
94+
)
95+
set_tests_properties("codegen/update/${test_name}" PROPERTIES FIXTURES_CLEANUP "codegen/${test_name}")
96+
set(build_test_depends "codegen/update/${test_name}")
97+
endif ()
98+
99+
set(expected_output_file "${TEST_RESULTS_DIR}/${ARG_SOURCE}.output")
39100
if (EXISTS "${expected_output_file}")
40101
file(READ "${expected_output_file}" expected_output)
41102
string(REPLACE "\\" "\\\\" expected_output "${expected_output}")
@@ -48,25 +109,24 @@ function(cppfront_command_tests)
48109
string(REPLACE "*" "\\*" expected_output "${expected_output}")
49110
string(REPLACE "?" "\\?" expected_output "${expected_output}")
50111

51-
set_tests_properties(
52-
"codegen/${test_name}"
53-
PROPERTIES
54-
FIXTURES_SETUP "codegen/${test_name}"
55-
PASS_REGULAR_EXPRESSION "^${expected_output}$"
56-
)
112+
set_tests_properties("codegen/${test_name}" PROPERTIES PASS_REGULAR_EXPRESSION "^${expected_output}$")
57113
endif ()
58114

59-
if (ARG_EXPECTED_FILE)
60-
cmake_path(REPLACE_EXTENSION ARG_SOURCE "cpp" OUTPUT_VARIABLE gen_cpp_src)
61-
62-
add_test(
115+
if (EXISTS "${ARG_EXPECTED_FILE}")
116+
configure_file("${ARG_EXPECTED_FILE}" "${gen_cpp_src}.original" COPYONLY)
117+
cppfront_add_check_test(
63118
NAME "codegen/check/${test_name}"
64-
COMMAND "${CMAKE_COMMAND}" -E compare_files "${gen_cpp_src}" "${ARG_EXPECTED_FILE}"
65-
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
119+
NEW_FILE "${gen_cpp_src}"
120+
OLD_FILE "${gen_cpp_src}.original"
121+
FIXTURES_REQUIRED "codegen/${test_name}"
66122
)
123+
list(APPEND build_test_depends "codegen/check/${test_name}")
124+
elseif (CPPFRONT_DEVELOPING)
125+
# Trigger regeneration to add the `check` tests for newly added results.
126+
file(GLOB unused CONFIGURE_DEPENDS "${ARG_EXPECTED_FILE}")
127+
endif ()
67128

68-
set_tests_properties("codegen/check/${test_name}" PROPERTIES FIXTURES_REQUIRED "codegen/${test_name}")
69-
129+
if (DEFINED build_test_depends AND DEFINED gen_cpp_src)
70130
cppfront_build_tests(
71131
SOURCE ${ARG_SOURCE}
72132
EXTRA_FLAGS ${ARG_EXTRA_FLAGS}
@@ -77,26 +137,25 @@ endfunction()
77137
function(cppfront_build_tests)
78138
cmake_parse_arguments(PARSE_ARGV 0 ARG "" "SOURCE" "EXTRA_FLAGS")
79139

80-
# The following tests aren't expected to be buildable C++, even if
81-
# cppfront succeeds.
82-
set(
83-
codegen_only_tests
84-
mixed-postfix-expression-custom-formatting
85-
)
86-
87-
cmake_path(GET ARG_SOURCE STEM stem)
88-
if (stem IN_LIST codegen_only_tests)
89-
return()
90-
endif ()
140+
cmake_path(GET ARG_SOURCE STEM test_name)
91141

92-
set(test_dir "${CMAKE_CURRENT_BINARY_DIR}/${stem}")
93-
set(test_name "build/${stem}")
142+
set(test_dir "${CMAKE_CURRENT_BINARY_DIR}/${test_name}")
94143

95144
configure_file("${REGRESSION_TESTS_DIR}/${ARG_SOURCE}" "${test_dir}/${ARG_SOURCE}" COPYONLY)
96145
configure_file("cmake/CMakeLists.txt.in" "${test_dir}/CMakeLists.txt" @ONLY)
146+
configure_file("cmake/test-case-config.cmake.in" "${test_dir}/test-case-config.cmake.in" COPYONLY)
147+
148+
set(
149+
cxx_23_tests
150+
pure2-bugfix-for-empty-index
151+
)
152+
set(extra_flags)
153+
if (test_name IN_LIST cxx_23_tests)
154+
list(APPEND extra_flags "-DCMAKE_CXX_STANDARD=23")
155+
endif ()
97156

98157
add_test(
99-
NAME "${test_name}"
158+
NAME "build/${test_name}"
100159
COMMAND
101160
"${CMAKE_CTEST_COMMAND}"
102161
--build-and-test "${test_dir}" "${test_dir}/build"
@@ -107,7 +166,74 @@ function(cppfront_build_tests)
107166
"-Dcppfront_DIR=${cppfront_DIR}"
108167
"-Dcppfront-exe_DIR=${cppfront-exe_DIR}"
109168
"-DCPPFRONT_FLAGS=${ARG_EXTRA_FLAGS}"
169+
${extra_flags}
170+
# There's `CMAKE_CXX_LINKER_LAUNCHER`, too. So far, it's not needed.
171+
"-DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_COMMAND};-D;OUTPUT_FILE=${gen_cpp_src}.output;-P;../../ExecuteWithRedirection.cmake;--"
110172
)
173+
set_tests_properties(
174+
"build/${test_name}"
175+
PROPERTIES
176+
DEPENDS "${build_test_depends}"
177+
FIXTURES_SETUP "build/${test_name}"
178+
)
179+
180+
cppfront_find_build_result_file(expected_output_file RESULT_FILE "${gen_cpp_src}.output")
181+
if (expected_output_file)
182+
cppfront_add_check_test(
183+
NAME "build/check/${test_name}"
184+
NEW_FILE "${test_dir}/build/${gen_cpp_src}.output"
185+
OLD_FILE "${expected_output_file}"
186+
FIXTURES_REQUIRED "build/${test_name}"
187+
)
188+
endif()
189+
190+
add_test(
191+
NAME "build/execute/${test_name}"
192+
COMMAND
193+
"${CMAKE_COMMAND}"
194+
-D "OUTPUT_FILE=${test_dir}/${gen_cpp_src}.execution"
195+
-P "../ExecuteTestCase.cmake"
196+
WORKING_DIRECTORY "${test_dir}"
197+
)
198+
set_tests_properties(
199+
"build/execute/${test_name}"
200+
PROPERTIES
201+
FIXTURES_REQUIRED "build/${test_name}"
202+
FIXTURES_SETUP "build/execute/${test_name}"
203+
RESOURCE_LOCK "test.exe")
204+
205+
cppfront_find_build_result_file(expected_execution_file RESULT_FILE "${gen_cpp_src}.execution")
206+
if (expected_execution_file)
207+
cppfront_add_check_test(
208+
NAME "build/execute/check/${test_name}"
209+
NEW_FILE "${test_dir}/${gen_cpp_src}.execution"
210+
OLD_FILE "${expected_execution_file}"
211+
FIXTURES_REQUIRED "build/execute/${test_name}"
212+
)
213+
endif()
214+
215+
if (CPPFRONT_DEVELOPING)
216+
# Trigger regeneration to add the `check` tests for newly added results.
217+
if (NOT DEFINED expected_output_file OR NOT DEFINED expected_execution_file)
218+
file(GLOB unused CONFIGURE_DEPENDS "${BUILD_RESULTS_DIR}/${gen_cpp_src}.*")
219+
endif()
220+
221+
add_test(
222+
NAME "build/update/${test_name}"
223+
COMMAND
224+
"${CMAKE_COMMAND}"
225+
-D "GEN_CPP_SRC=${gen_cpp_src}"
226+
-D "OUTPUT_FILE=build/${gen_cpp_src}.output"
227+
-D "EXECUTION_FILE=${gen_cpp_src}.execution"
228+
-P "../UpdateBuildOutput.cmake"
229+
WORKING_DIRECTORY "${test_dir}"
230+
)
231+
set_tests_properties(
232+
"build/update/${test_name}"
233+
PROPERTIES
234+
FIXTURES_CLEANUP "build/${test_name};build/execute/${test_name}"
235+
)
236+
endif ()
111237
endfunction()
112238

113239
function(cppfront_tests)
@@ -119,14 +245,15 @@ function(cppfront_tests)
119245
RELATIVE "${REGRESSION_TESTS_DIR}"
120246
CONFIGURE_DEPENDS "${REGRESSION_TESTS_DIR}/${ARG_GROUP}-*.cpp2"
121247
)
248+
# Trigger regeneration to recognize as a test to fail codegen.
249+
file(
250+
GLOB unused
251+
CONFIGURE_DEPENDS "${REGRESSION_TESTS_DIR}/${ARG_GROUP}-*-error.cpp2"
252+
)
122253

123254
foreach (src IN LISTS sources)
124255
cmake_path(REPLACE_EXTENSION src "cpp" OUTPUT_VARIABLE expected_file)
125-
set(expected_file "${REGRESSION_TESTS_DIR}/test-results/${expected_file}")
126-
127-
if (NOT EXISTS "${expected_file}")
128-
set(expected_file "")
129-
endif ()
256+
set(expected_file "${TEST_RESULTS_DIR}/${expected_file}")
130257

131258
cppfront_command_tests(
132259
SOURCE ${src}

regression-tests/cmake/CMakeLists.txt.in

+27
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,30 @@ target_compile_options(
1313
PRIVATE
1414
"$<$<CXX_COMPILER_ID:MSVC>:/experimental:module>"
1515
)
16+
17+
include(GNUInstallDirs)
18+
include(CMakePackageConfigHelpers)
19+
20+
set(TEST_CASE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_DATADIR}/cmake/test-case")
21+
22+
install(
23+
TARGETS test-case
24+
EXPORT test-case-targets
25+
)
26+
27+
install(
28+
EXPORT test-case-targets
29+
DESTINATION "${TEST_CASE_INSTALL_CMAKEDIR}"
30+
)
31+
32+
configure_package_config_file(
33+
"test-case-config.cmake.in"
34+
"test-case-config.cmake"
35+
INSTALL_DESTINATION "${TEST_CASE_INSTALL_CMAKEDIR}"
36+
PATH_VARS CMAKE_INSTALL_BINDIR
37+
)
38+
39+
install(
40+
FILES "${CMAKE_CURRENT_BINARY_DIR}/test-case-config.cmake"
41+
DESTINATION "${TEST_CASE_INSTALL_CMAKEDIR}"
42+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
execute_process(
2+
COMMAND "${CMAKE_COMMAND}" --install "build" --prefix "_local"
3+
COMMAND_ERROR_IS_FATAL ANY
4+
)
5+
find_package(test-case REQUIRED PATHS "${CMAKE_CURRENT_BINARY_DIR}/_local" NO_DEFAULT_PATH)
6+
execute_process(
7+
COMMAND
8+
"${CMAKE_COMMAND}"
9+
-E copy
10+
"${TEST_CASE_EXECUTABLE}"
11+
"@BUILD_RESULTS_DIR@/test.exe"
12+
)
13+
execute_process(
14+
COMMAND
15+
"${CMAKE_COMMAND}"
16+
-D "OUTPUT_FILE=${OUTPUT_FILE}"
17+
-P "@CMAKE_CURRENT_BINARY_DIR@/ExecuteWithRedirection.cmake"
18+
--
19+
"./test.exe"
20+
COMMAND_ERROR_IS_FATAL ANY
21+
WORKING_DIRECTORY "@BUILD_RESULTS_DIR@"
22+
)
23+
execute_process(COMMAND "${CMAKE_COMMAND}" -E rm "@BUILD_RESULTS_DIR@/test.exe")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
if (NOT "${CMAKE_ARGV5}" STREQUAL "--")
2+
message(FATAL_ERROR "Unexpected argument.")
3+
endif ()
4+
foreach (i RANGE 6 ${CMAKE_ARGC})
5+
list(APPEND command_args "${CMAKE_ARGV${i}}") # Probably doesn't handle nested `;`.
6+
endforeach ()
7+
execute_process(
8+
COMMAND ${command_args}
9+
OUTPUT_VARIABLE OUTPUT
10+
ERROR_VARIABLE OUTPUT
11+
ECHO_OUTPUT_VARIABLE
12+
ECHO_ERROR_VARIABLE
13+
)
14+
file(WRITE "${OUTPUT_FILE}" "${OUTPUT}")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Set `OLD_BUILD_RESULTS_DIRS`.
2+
file(
3+
GLOB build_result_dirs
4+
RELATIVE "@TEST_RESULTS_DIR@"
5+
"@TEST_RESULTS_DIR@/@compiler_id@-*"
6+
)
7+
list(SORT build_result_dirs)
8+
list(FIND build_result_dirs "@COMPILER_ITEM_NAME@" i)
9+
list(SUBLIST build_result_dirs 0 ${i} OLD_BUILD_RESULTS_DIRS)
10+
list(REVERSE OLD_BUILD_RESULTS_DIRS)
11+
12+
function(cppfront_find_build_result_file out_var)
13+
cmake_parse_arguments(PARSE_ARGV 0 ARG "OLD_ONLY" "RESULT_FILE" "")
14+
15+
if (NOT ARG_OLD_ONLY)
16+
set(extra_item "@COMPILER_ITEM_NAME@")
17+
endif ()
18+
19+
foreach (build_results_dir IN ITEMS "${extra_item}" LISTS OLD_BUILD_RESULTS_DIRS)
20+
set(result_file "@TEST_RESULTS_DIR@/${build_results_dir}/${ARG_RESULT_FILE}")
21+
if (EXISTS "${result_file}")
22+
set("${out_var}" "${result_file}" PARENT_SCOPE)
23+
return()
24+
endif ()
25+
endforeach ()
26+
27+
unset("${out_var}" PARENT_SCOPE)
28+
endfunction()

0 commit comments

Comments
 (0)