Repository navigation
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
529 lines (475 loc) · 19.5 KB
/
Copy pathCMakeLists.txt
File metadata and controls
529 lines (475 loc) · 19.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
cmake_minimum_required(VERSION 3.26.3)
# Derive the version with the following precedence:
# 1. -DTRIMJA_VERSION_OVERRIDE=<version> (set by CI from the release tag)
# 2. `git describe` against the most recent `vX.Y.Z` tag
# 3. the fallback "0.0.0" when neither is available
# TRIMJA_VERSION_FULL is the full descriptive version for display, which may
# carry a commit/-dirty suffix such as `1.3.1-5-g1234abcd-dirty`.
# TRIMJA_VERSION_NUMERIC is the plain `X.Y.Z` fed to `project()` (and hence
# CPack). This runs before `project()` so the result can set the version, and
# is computed at configure time, so a new commit is only reflected after CMake
# re-configures.
if(DEFINED TRIMJA_VERSION_OVERRIDE)
set(TRIMJA_VERSION_FULL "${TRIMJA_VERSION_OVERRIDE}")
else()
set(TRIMJA_VERSION_FULL "")
find_package(Git QUIET)
if(GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe
--tags --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8 --dirty
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE TRIMJA_GIT_DESCRIBE_STATUS
OUTPUT_VARIABLE TRIMJA_VERSION_FULL
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
if(NOT TRIMJA_GIT_DESCRIBE_STATUS EQUAL 0)
set(TRIMJA_VERSION_FULL "")
endif()
endif()
endif()
if(TRIMJA_VERSION_FULL STREQUAL "")
set(TRIMJA_VERSION_FULL "0.0.0")
endif()
# Drop a leading `v` so `v1.3.1` becomes `1.3.1`.
string(REGEX REPLACE "^v" "" TRIMJA_VERSION_FULL "${TRIMJA_VERSION_FULL}")
# `project(VERSION ...)` only accepts numeric components, so pull the leading
# `X.Y.Z` out of the (possibly suffixed) descriptive version.
if(TRIMJA_VERSION_FULL MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)")
set(TRIMJA_VERSION_NUMERIC "${CMAKE_MATCH_1}")
else()
set(TRIMJA_VERSION_NUMERIC "0.0.0")
endif()
message(STATUS "trimja version: ${TRIMJA_VERSION_FULL}")
project(trimja VERSION ${TRIMJA_VERSION_NUMERIC})
enable_testing()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_COMPILE_WARNING_AS_ERROR ON)
# Add an option to enable or disable clang-tidy
option(ENABLE_CLANG_TIDY "Enable clang-tidy static analysis" OFF)
if(ENABLE_CLANG_TIDY)
find_program(CLANG_TIDY_EXE NAMES "clang-tidy")
if(CLANG_TIDY_EXE)
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE}")
else()
message(WARNING "clang-tidy not found. Static analysis will be skipped.")
endif()
endif()
# Enable ASAN in debug mode for supported compilers
# MSVC is not supported yet as we need to set up the PATH to `clang_rt.asan_dynamic*.dll`
set(ENABLE_SANITIZERS $<AND:$<NOT:$<CXX_COMPILER_ID:MSVC>>,$<CONFIG:Debug>>)
# Decide when to enable fuzzing
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_BUILD_TYPE STREQUAL "Debug")
set(ENABLE_FUZZING 1)
else()
set(ENABLE_FUZZING 0)
endif()
###############################################################################
# trimja #
###############################################################################
add_library(
core
STATIC
src/all.natvis
src/allocationprofiler.cpp
src/basicscope.cpp
src/builddirutil.cpp
src/cpuprofiler.cpp
src/depsreader.cpp
src/depswriter.cpp
src/edgescope.cpp
src/evalstring.cpp
src/fileutil.cpp
src/graph.cpp
src/fixed_string.cpp
src/logreader.cpp
src/logwriter.cpp
src/manifestparser.cpp
src/murmur_hash.cpp
src/nestedscope.cpp
src/ninja_clock.cpp
src/rulevariables.cpp
src/stringstack.cpp
src/trimutil.cpp
thirdparty/gch/small_vector.natvis
thirdparty/ninja/lexer.cc
thirdparty/ninja/util.cc
$<$<BOOL:${WIN32}>:thirdparty/ninja/getopt.c>
)
set_source_files_properties(
thirdparty/ninja/lexer.cc
thirdparty/ninja/util.cc
thirdparty/ninja/getopt.cc
PROPERTIES SKIP_LINTING ON
)
target_include_directories(core PUBLIC src)
target_include_directories(core SYSTEM PUBLIC thirdparty)
target_compile_options(core PUBLIC
$<IF:$<CXX_COMPILER_ID:MSVC>,/W4,-Wall -Wextra -Wpedantic>
)
target_compile_definitions(core PUBLIC
# debug iterators cause default ctor of std::string and std::vector to allocate
$<$<CXX_COMPILER_ID:MSVC>:_ITERATOR_DEBUG_LEVEL=0 NOMINMAX>
# Issues with unsupported architecture in MacOS 14
TINY_OPTIONAL_USE_SEPARATE_BOOL_INSTEAD_OF_UNUSED_BITS
)
# Decide when to enable link-time optimization.
# This is enabled unless we are fuzzing on earlier versions of Clang. e.g. on Clang 12.0.0
# we see:
# /usr/bin/ld: /tmp/lto-llvm-2c8b48.o: warning: sh_link not set for section `__sancov_cntrs'
# /usr/bin/ld: /tmp/lto-llvm-2c8b48.o: warning: sh_link not set for section `__sancov_pcs'
# Note that this is fixed by using fat LTO instead of thin LTO, but CMake only has a
# cross-platform option to enable thin LTO. This issue is also is fixed in Clang 18.1.3,
# but I'm unsure of the earliest version of Clang that isn't affected.
if(ENABLE_FUZZING)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "18.1.3")
set(ENABLE_LTO OFF)
message("Info: Link-time optimization has been disabled for this build")
else()
set(ENABLE_LTO ON)
endif()
else()
set(ENABLE_LTO ON)
endif()
# MSVC's Debug flags include /RTC1 (runtime checks), which is incompatible
# with /GL (the flag CMake's IPO property adds).
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(ENABLE_LTO_DEBUG OFF)
else()
set(ENABLE_LTO_DEBUG ${ENABLE_LTO})
endif()
set_property(TARGET core PROPERTY INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
set_property(TARGET core PROPERTY INTERPROCEDURAL_OPTIMIZATION_DEBUG ${ENABLE_LTO_DEBUG})
target_compile_options(
core PUBLIC
$<$<AND:${ENABLE_SANITIZERS},$<CXX_COMPILER_ID:MSVC>>:/fsanitize=address>
$<$<AND:${ENABLE_SANITIZERS},$<NOT:$<CXX_COMPILER_ID:MSVC>>>:-fsanitize=address,undefined>
$<${ENABLE_FUZZING}:-fsanitize=fuzzer-no-link>
)
target_link_options(
core PUBLIC
# MSVC Incremental linking does not work when address sanitizer is enabled
$<$<AND:${ENABLE_SANITIZERS},$<CXX_COMPILER_ID:MSVC>>:/INCREMENTAL:NO>
$<$<AND:${ENABLE_SANITIZERS},$<NOT:$<CXX_COMPILER_ID:MSVC>>>:-fsanitize=address,undefined -fno-omit-frame-pointer>
)
add_executable(
trimja
src/trimja.m.cpp
)
target_compile_definitions(trimja PRIVATE TRIMJA_VERSION="${TRIMJA_VERSION_FULL}")
set_property(TARGET trimja PROPERTY INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
set_property(TARGET trimja PROPERTY INTERPROCEDURAL_OPTIMIZATION_DEBUG ${ENABLE_LTO_DEBUG})
target_link_libraries(trimja core)
install(TARGETS trimja RUNTIME DESTINATION bin)
if(WIN32)
set(CPACK_GENERATOR ZIP NSIS)
else()
set(CPACK_GENERATOR TGZ)
endif()
set(CPACK_PACKAGE_INSTALL_DIRECTORY trimja)
set(CPACK_NSIS_MODIFY_PATH ON)
set(CPACK_NSIS_IGNORE_LICENSE_PAGE ON)
include(CPack)
file(
GLOB TRIMJA_FUZZING_TARGETS
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src/
${CMAKE_CURRENT_SOURCE_DIR}/src/*.fuzz.cpp
)
foreach(FUZZ_TARGET ${TRIMJA_FUZZING_TARGETS})
if(${FUZZ_TARGET} MATCHES "^(.+)\.fuzz\.cpp$")
string(CONCAT FUZZ_TARGET_NAME "fuzz" ${CMAKE_MATCH_1})
add_executable(
${FUZZ_TARGET_NAME}
src/${FUZZ_TARGET}
$<$<NOT:${ENABLE_FUZZING}>:src/nofuzzing.m.cpp>
)
set_property(TARGET ${FUZZ_TARGET_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
set_property(TARGET ${FUZZ_TARGET_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION_DEBUG ${ENABLE_LTO_DEBUG})
target_link_options(${FUZZ_TARGET_NAME} PRIVATE $<${ENABLE_FUZZING}:-fsanitize=fuzzer>)
target_link_libraries(${FUZZ_TARGET_NAME} core)
# Add tests for the corpora
if(ENABLE_FUZZING)
file(
GLOB TRIMJA_FUZZING_CORPORA
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/corpora/${FUZZ_TARGET_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/corpora/${FUZZ_TARGET_NAME}/*
)
list(LENGTH TRIMJA_FUZZING_CORPORA CORPORA_COUNT)
if(CORPORA_COUNT GREATER 0)
add_test(
NAME trimja.fuzz.${FUZZ_TARGET_NAME}
COMMAND $<TARGET_FILE:${FUZZ_TARGET_NAME}> ${TRIMJA_FUZZING_CORPORA}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/corpora/${FUZZ_TARGET_NAME}/
COMMAND_EXPAND_LISTS
)
endif()
else()
# If fuzzing isn't available, then we build an executable with our own `main` that
# can iterate through a directory and run the corpora within it
add_test(
NAME trimja.fuzz.${FUZZ_TARGET_NAME}
COMMAND $<TARGET_FILE:${FUZZ_TARGET_NAME}> --directory ${FUZZ_TARGET_NAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/corpora/
)
endif()
else()
message(FATAL_ERROR "Regex should match")
endif()
endforeach()
# Generate test files for the absolute/relative unit test
get_filename_component(ABSOLUTE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests/good/absolute/relative" ABSOLUTE)
string(REPLACE ":" "$:" ABSOLUTE_PATH_ESCAPED "${ABSOLUTE_PATH}")
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/tests/good/absolute/changed.txt" "${ABSOLUTE_PATH}\nabsolute")
string(APPEND NINJA_CONTENTS "rule copy\n")
string(APPEND NINJA_CONTENTS " command = ninja --version \$in -> \$out\n")
string(APPEND NINJA_CONTENTS "build out_relative: copy absolute\n")
string(APPEND NINJA_CONTENTS "build out_absolute: copy ${ABSOLUTE_PATH_ESCAPED}\n")
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/tests/good/absolute/build.ninja" "${NINJA_CONTENTS}")
file(COPY_FILE "${CMAKE_CURRENT_SOURCE_DIR}/tests/good/absolute/build.ninja" "${CMAKE_CURRENT_SOURCE_DIR}/tests/good/absolute/expected.ninja")
# Positive tests: each directory under `tests/good/` is a self-contained ninja
# project that is run through `ninja` and then trimmed, comparing trimja's
# output against its `expected.ninja`.
file(
GLOB TRIMJA_TESTS
LIST_DIRECTORIES true
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/
${CMAKE_CURRENT_SOURCE_DIR}/tests/good/*
)
# Sometimes test execution on MSVC leaves behind `_err1_.txt` and `_out1_.txt`
# from previous runs so we filter these out so they don't get mistaken for tests.
list(FILTER TRIMJA_TESTS EXCLUDE REGEX "\.txt$")
# Some tests are Windows-specific due to their use of backslashes as a path separator
if(NOT(WIN32))
list(FILTER TRIMJA_TESTS EXCLUDE REGEX "win32")
endif()
# Set up test case fixtures
foreach(TEST ${TRIMJA_TESTS})
# Run ninja over all test directories to generate `.ninja_log` and `.ninja_deps`
add_test(
NAME trimja.snapshot.${TEST}.ninja
COMMAND ninja -d keepdepfile -d keeprsp -f bootstrap.ninja
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/${TEST}/
)
set_tests_properties(
trimja.snapshot.${TEST}.ninja
PROPERTIES FIXTURES_SETUP trimja.snapshot.${TEST}.fixture
)
endforeach()
# --version
add_test(NAME trimja.--version COMMAND trimja --version)
string(REPLACE "." "\." TRIMJA_VERSION_REGEX "${TRIMJA_VERSION_FULL}")
set_property(
TEST trimja.--version
PROPERTY PASS_REGULAR_EXPRESSION "^${TRIMJA_VERSION_REGEX}\n$"
)
# --help
add_test(NAME trimja.--help COMMAND trimja --help)
set_property(TEST trimja.--help PROPERTY PASS_REGULAR_EXPRESSION "Usage:")
add_test(NAME trimja.-h COMMAND trimja -h)
set_property(TEST trimja.-h PROPERTY PASS_REGULAR_EXPRESSION "Usage:")
# --unknown
add_test(NAME trimja.--unknown COMMAND trimja --unknown)
set_property(TEST trimja.--unknown PROPERTY WILL_FAIL true)
add_test(NAME trimja.-u COMMAND trimja -u)
set_property(TEST trimja.-u PROPERTY WILL_FAIL true)
# No arguments
add_test(NAME trimja.no-args COMMAND trimja)
set_property(TEST trimja.no-args PROPERTY WILL_FAIL true)
# too many arguments
add_test(NAME trimja.--write_and_--output COMMAND trimja --write --output ${CMAKE_CURRENT_BINARY_DIR}/foo.ninja)
set_property(TEST trimja.--write_and_--output PROPERTY WILL_FAIL true)
add_test(NAME trimja.--output_and_--write COMMAND trimja --output ${CMAKE_CURRENT_BINARY_DIR}/foo.ninja --write)
set_property(TEST trimja.--output_and_--write PROPERTY WILL_FAIL true)
add_test(NAME trimja.--affected_and_dash COMMAND trimja --affected changed.txt -)
set_property(TEST trimja.--affected_and_dash PROPERTY WILL_FAIL true)
# Check we can avoid passing `-f`
add_test(
NAME trimja.snapshot.no-f
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/passthrough/
COMMAND trimja
--expected expected.ninja
--affected changed.txt
)
set_tests_properties(
trimja.snapshot.no-f
PROPERTIES FIXTURES_REQUIRED trimja.snapshot.passthrough.fixture
)
# Check we can write to the same file we read
add_test(
NAME trimja.big-in-out
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/bigpassthrough/
COMMAND trimja --write --affected changed.txt
)
set_tests_properties(
trimja.big-in-out
PROPERTIES FIXTURES_REQUIRED trimja.snapshot.bigpassthrough.fixture
)
# Check we can write to a different file
add_test(
NAME trimja.--write
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/passthrough/
COMMAND trimja --output ${CMAKE_CURRENT_BINARY_DIR}/trimja.ninja --affected changed.txt
)
set_tests_properties(
trimja.--write
PROPERTIES FIXTURES_REQUIRED trimja.snapshot.passthrough.fixture
)
add_test(
NAME trimja.--write.cmp
COMMAND ${CMAKE_COMMAND} -E compare_files --ignore-eol ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/passthrough/expected.ninja ${CMAKE_CURRENT_BINARY_DIR}/trimja.ninja
)
set_tests_properties(
trimja.--write
PROPERTIES FIXTURES_SETUP trimja.--write.fixture
)
set_tests_properties(
trimja.--write.cmp
PROPERTIES FIXTURES_REQUIRED trimja.--write.fixture
)
# Check redirection from a file
if (WIN32)
add_test(
NAME trimja.stdin
COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/simple/ $ENV{ComSpec} /c $<TARGET_FILE:trimja> - < changed.txt
)
else()
add_test(
NAME trimja.stdin
COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/simple/ sh -c "$<TARGET_FILE:trimja> - < changed.txt"
)
endif()
set_property(TEST trimja.stdin PROPERTY PASS_REGULAR_EXPRESSION "build out1")
set_tests_properties(
trimja.stdin
PROPERTIES FIXTURES_REQUIRED trimja.snapshot.simple.fixture
)
# --memory-stats
if(WIN32)
add_test(
NAME trimja.--memory-stats
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/passthrough/
COMMAND trimja
--memory-stats=3
--affected changed.txt
)
set_tests_properties(
trimja.--memory-stats
PROPERTIES FIXTURES_REQUIRED trimja.snapshot.passthrough.fixture
)
add_test(
NAME trimja.--memory-stats2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/builddir/
COMMAND trimja
--memory-stats=3
--builddir
)
set_tests_properties(
trimja.--memory-stats2
PROPERTIES FIXTURES_REQUIRED trimja.snapshot.builddir.fixture
)
endif()
# --cpu-stats
add_test(
NAME trimja.--cpu-stats
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/passthrough/
COMMAND trimja
--cpu-stats
--affected changed.txt
)
set_tests_properties(
trimja.--cpu-stats
PROPERTIES FIXTURES_REQUIRED trimja.snapshot.passthrough.fixture
)
# --builddir
add_test(
NAME trimja.--builddir
COMMAND trimja -f builddir/build.ninja --builddir
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good
)
set_property(TEST trimja.--builddir PROPERTY PASS_REGULAR_EXPRESSION "builddir\/x64\/build")
# Snapshot tests
foreach(TEST ${TRIMJA_TESTS})
# If a test directory has an `additional_arguments.txt` file, read it (one
# argument per line, mirroring the one-path-per-line convention already
# used by `changed.txt`) and pass those extra arguments to `trimja` too.
# This lets a fixture exercise flags like `--target`/`--target-default`
# without needing a bespoke `add_test` of its own.
set(ADDITIONAL_ARGS "")
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/${TEST}/additional_arguments.txt)
file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/tests/good/${TEST}/additional_arguments.txt ADDITIONAL_ARGS)
endif()
add_test(
NAME trimja.snapshot.${TEST}
COMMAND trimja -f ${TEST}/build.ninja --expected ${TEST}/expected.ninja --affected ${TEST}/changed.txt --explain ${ADDITIONAL_ARGS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good
)
set_tests_properties(
trimja.snapshot.${TEST}
PROPERTIES FIXTURES_REQUIRED trimja.snapshot.${TEST}.fixture
)
# Check that --builddir at least returns success on all tests
add_test(
NAME trimja.smoke.builddir.${TEST}
COMMAND trimja -f ${TEST}/build.ninja --builddir
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/good
)
endforeach()
# Negative tests: each directory under `tests/bad/` describes a trimja
# invocation that must fail. It contains an `args.txt` (one trimja argument per
# line, mirroring `changed.txt`), an `expected.txt` holding the error message
# trimja must print, and whatever input files the arguments reference. Unlike
# the positive tests these are not run through `ninja` first: the failure
# happens while parsing the build file, so no fixture is needed. `expected.txt`
# is used as the test's `PASS_REGULAR_EXPRESSION` (matched against trimja's
# output), the same mechanism used by e.g. `trimja.stdin` above.
file(
GLOB TRIMJA_BAD_TESTS
LIST_DIRECTORIES true
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/tests/bad/
${CMAKE_CURRENT_SOURCE_DIR}/tests/bad/*
)
foreach(TEST ${TRIMJA_BAD_TESTS})
file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/tests/bad/${TEST}/args.txt BAD_ARGS)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/tests/bad/${TEST}/expected.txt BAD_EXPECTED)
string(STRIP "${BAD_EXPECTED}" BAD_EXPECTED)
add_test(
NAME trimja.bad.${TEST}
COMMAND trimja ${BAD_ARGS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests/bad/${TEST}
)
set_property(TEST trimja.bad.${TEST} PROPERTY PASS_REGULAR_EXPRESSION "${BAD_EXPECTED}")
endforeach()
# Integration ("ugly") tests: each directory under `integrations/ugly/` is a
# self-contained scenario carrying its own `CMakeLists.txt` that registers
# whatever bespoke tests it needs.
file(
GLOB TRIMJA_UGLY_TESTS
LIST_DIRECTORIES true
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/integrations/ugly/
${CMAKE_CURRENT_SOURCE_DIR}/integrations/ugly/*
)
# Some tests may be Windows-specific due to e.g. their use of backslashes as a
# path separator, mirroring the `win32` convention used by `tests/good`.
if(NOT(WIN32))
list(FILTER TRIMJA_UGLY_TESTS EXCLUDE REGEX "win32")
endif()
foreach(TEST ${TRIMJA_UGLY_TESTS})
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/integrations/ugly/${TEST} AND
EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/integrations/ugly/${TEST}/CMakeLists.txt)
add_subdirectory(integrations/ugly/${TEST})
endif()
endforeach()
# CMake's built-in `test` target has no dependencies on the binaries it
# exercises (it is not a real target, so `add_dependencies(test ...)` is
# rejected), which means a ninja build graph built from this project never
# shows `test` depending on `trimja` itself. Provide a real custom target
# that depends on every executable used by the test suite so that tools
# consuming build.ninja, such as trimja, see the correct edges.
add_custom_target(
run_test_with_dependencies
COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIG> --output-on-failure
DEPENDS trimja fuzzbuilddirutil fuzzdepsreader fuzzlogreader
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)