Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 52 additions & 40 deletions CMake/ITKModuleTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,29 @@ endfunction()
# to the value of its containing module.
#
function(itk_add_test)
# Optional ITK_REMOVE_TEMPORARY_TEST_FILES <file>... lists the transient
# outputs to remove after the test. It is the only parsed keyword, so it
# must appear LAST: every argument following it is consumed as a file to
# remove. Arguments preceding it form the add_test specification.
cmake_parse_arguments(_iat "" "" "ITK_REMOVE_TEMPORARY_TEST_FILES" ${ARGN})
set(_iat_args ${_iat_UNPARSED_ARGUMENTS})
Comment thread
hjmjohnson marked this conversation as resolved.

# Add tests with data in the ITKData group.
ExternalData_Add_Test(
ITKData
${ARGN}
${_iat_args}
)

if("NAME" STREQUAL "${ARGV0}")
set(_iat_testname ${ARGV1})
list(GET _iat_args 0 _iat_arg0)
if("NAME" STREQUAL "${_iat_arg0}")
list(GET _iat_args 1 _iat_testname)
else()
set(_iat_testname ${ARGV0})
set(_iat_testname ${_iat_arg0})
endif()

if(itk-module)
set(_label ${itk-module})
if(TARGET ${itk-module}-all AND "${ARGN}" MATCHES "DATA{")
if(TARGET ${itk-module}-all AND "${_iat_args}" MATCHES "DATA{")
add_dependencies(${itk-module}-all ITKData)
endif()
else()
Expand All @@ -129,6 +137,13 @@ function(itk_add_test)
LABELS
${_label}
)

if(_iat_ITK_REMOVE_TEMPORARY_TEST_FILES)
itk_add_file_test_cleanup(
${_iat_testname}
${_iat_ITK_REMOVE_TEMPORARY_TEST_FILES}
)
endif()
endfunction()

#-----------------------------------------------------------------------------
Expand Down Expand Up @@ -343,15 +358,19 @@ function(itk_memcheck_ignore)
endfunction()

#-----------------------------------------------------------------------------
# Option to automatically remove large test output files after completion.
# BigIO write-read tests can produce multi-gigabyte temporary files
# that exhaust disk space on CI runners and local builds.
# Removing transient test outputs is the default behavior: each wired test
# gets a companion cleanup test that deletes its ${ITK_TEST_OUTPUT_DIR}
# outputs, which otherwise accumulate (BigIO write-read tests alone produce
# multi-gigabyte files that exhaust disk on CI runners and local builds).
# Cleanup runs unconditionally after the test (pass, fail, or skip); a
# developer who needs to inspect outputs must opt out by configuring with
# -DITK_REMOVE_TEMPORARY_TEST_FILES=OFF, which retains all test outputs.
option(
ITK_REMOVE_TEST_FILES_ON_SUCCESS
"Remove large test output files after test completion. Set OFF to retain files for debugging."
ITK_REMOVE_TEMPORARY_TEST_FILES
"Remove transient test outputs after each test (default ON; removed even on failure). Set OFF to retain all outputs for debugging."
ON
)
mark_as_advanced(ITK_REMOVE_TEST_FILES_ON_SUCCESS)
mark_as_advanced(ITK_REMOVE_TEMPORARY_TEST_FILES)

#-----------------------------------------------------------------------------
# itk_add_file_test_cleanup(<test_name> <output_file> [<output_file2> ...])
Expand All @@ -363,19 +382,19 @@ mark_as_advanced(ITK_REMOVE_TEST_FILES_ON_SUCCESS)
# NOTE: Per CMake documentation, FIXTURES_CLEANUP tests execute
# unconditionally after their fixture — they run regardless of whether the
# SETUP test passed, failed, or was skipped. To retain output files for
# debugging after a failure, set ITK_REMOVE_TEST_FILES_ON_SUCCESS=OFF.
# debugging after a failure, set ITK_REMOVE_TEMPORARY_TEST_FILES=OFF.
#
# NOTE: In a full unfiltered run all tests (including *_cleanup variants)
# are in the active set and fixture ordering is respected. When rerunning
# a single test with a strict filter (e.g. ctest -R "^<test_name>$"),
# the *_cleanup test does not match; omit the anchors (ctest -R <test_name>)
# so both the main test and its cleanup are selected.
#
# When ITK_REMOVE_TEST_FILES_ON_SUCCESS is OFF, no cleanup test is added
# When ITK_REMOVE_TEMPORARY_TEST_FILES is OFF, no cleanup test is added
# and the output files are retained for manual inspection.
#
function(itk_add_file_test_cleanup TEST_NAME)
if(NOT ITK_REMOVE_TEST_FILES_ON_SUCCESS)
if(NOT ITK_REMOVE_TEMPORARY_TEST_FILES)
return()
endif()

Expand All @@ -389,31 +408,24 @@ function(itk_add_file_test_cleanup TEST_NAME)
${FIXTURE_NAME}
)

# Build the removal command for all output files
set(RM_ARGS "")
foreach(OUTPUT_FILE ${ARGN})
# For .mhd files, also remove the companion .raw/.zraw
get_filename_component(EXT "${OUTPUT_FILE}" LAST_EXT)
get_filename_component(BASE_NAME "${OUTPUT_FILE}" NAME_WLE)
get_filename_component(DIR "${OUTPUT_FILE}" DIRECTORY)
list(APPEND RM_ARGS "${OUTPUT_FILE}")
if("${EXT}" STREQUAL ".mhd")
list(APPEND RM_ARGS "${DIR}/${BASE_NAME}.raw")
list(APPEND RM_ARGS "${DIR}/${BASE_NAME}.zraw")
endif()
endforeach()
# The developer supplies the exact files and glob patterns to remove. Each
# entry is forwarded verbatim; itkRemoveTestFiles.cmake expands patterns at
# test time and removes only the matching files (never directories).
set(RM_ARGS ${ARGN})

add_test(
NAME ${TEST_NAME}_cleanup
COMMAND
${CMAKE_COMMAND} -E rm -f ${RM_ARGS}
)
set_tests_properties(
${TEST_NAME}_cleanup
PROPERTIES
FIXTURES_CLEANUP
${FIXTURE_NAME}
LABELS
"CLEANUP"
)
if(RM_ARGS)
add_test(
NAME ${TEST_NAME}_cleanup
COMMAND
${CMAKE_COMMAND} -P ${ITK_CMAKE_DIR}/itkRemoveTestFiles.cmake ${RM_ARGS}
)
set_tests_properties(
${TEST_NAME}_cleanup
PROPERTIES
FIXTURES_CLEANUP
${FIXTURE_NAME}
LABELS
"CLEANUP"
)
endif()
endfunction()
50 changes: 50 additions & 0 deletions CMake/itkRemoveTestFiles.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Remove transient test output files matching the given path patterns.
#
# Invoked as a fixture cleanup command:
# cmake -P itkRemoveTestFiles.cmake <pattern> [<pattern> ...]
#
# Each pattern is expanded with file(GLOB) at test time and only the matching
# regular files are removed. Directories are never removed, so an unintended
# pattern can delete individual files but can never recurse into a tree.
#
# A pattern may contain a single brace set "{a,b,c}" listing the extensions a
# test actually writes for a shared stem, e.g. "foo.{mhd,raw}" expands to
# "foo.mhd" and "foo.raw" before globbing.
if(CMAKE_ARGC LESS 4)
return()
endif()

# Expand one "{a,b,c}" brace set in PATTERN into OUT_VAR (a list).
function(_itk_expand_braces PATTERN OUT_VAR)
string(FIND "${PATTERN}" "{" _open)
string(FIND "${PATTERN}" "}" _close)
if(_open EQUAL -1 OR _close EQUAL -1 OR _close LESS _open)
set(${OUT_VAR} "${PATTERN}" PARENT_SCOPE)
return()
endif()
string(SUBSTRING "${PATTERN}" 0 ${_open} _prefix)
math(EXPR _glen "${_close} - ${_open} - 1")
math(EXPR _gstart "${_open} + 1")
string(SUBSTRING "${PATTERN}" ${_gstart} ${_glen} _group)
math(EXPR _sstart "${_close} + 1")
string(SUBSTRING "${PATTERN}" ${_sstart} -1 _suffix)
string(REPLACE "," ";" _opts "${_group}")
set(_result "")
foreach(_o IN LISTS _opts)
list(APPEND _result "${_prefix}${_o}${_suffix}")
endforeach()
set(${OUT_VAR} "${_result}" PARENT_SCOPE)
endfunction()

math(EXPR _last "${CMAKE_ARGC} - 1")
foreach(_i RANGE 3 ${_last})
_itk_expand_braces("${CMAKE_ARGV${_i}}" _patterns)
foreach(_pat IN LISTS _patterns)
file(GLOB _matches "${_pat}")
foreach(_match IN LISTS _matches)
if(NOT IS_DIRECTORY "${_match}")
file(REMOVE "${_match}")
endif()
endforeach()
endforeach()
endforeach()
2 changes: 1 addition & 1 deletion CMake/stubs/itk_add_test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function(itk_add_test)
ARG
"COMMAND_EXPAND_LISTS"
"NAME;WORKING_DIRECTORY"
"COMMAND;CONFIGURATIONS"
"COMMAND;CONFIGURATIONS;ITK_REMOVE_TEMPORARY_TEST_FILES"
)

# This is a stub function to assist code formatting
Expand Down
2 changes: 2 additions & 0 deletions Modules/Bridge/VtkGlue/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ if(NOT VTK_RENDERING_BACKEND STREQUAL "None")
QuickViewTest
DATA{${ITK_DATA_ROOT}/Input/peppers.png}
${ITK_TEST_OUTPUT_DIR}
ITK_REMOVE_TEMPORARY_TEST_FILES
${ITK_TEST_OUTPUT_DIR}/QuickViewTest0.png
)
set_property(
TEST
Expand Down
Loading
Loading