CTest stdin pipe

CTest can be used to run test executables that require input from stdin. This is accomplished by having add_test call a CMake script that uses execute_process to run the test executable with the input piped in from a file. Null stdin is also possible.

Suppose CMakeLists.txt contains:

enable_testing()

add_executable(main main.c)

add_test(NAME stdin_null
  COMMAND ${CMAKE_COMMAND} -Dexe:FILEPATH=$<TARGET_FILE:main> -P ${CMAKE_CURRENT_SOURCE_DIR}/stdin_null.cmake
)

add_test(NAME stdin_pipe
  COMMAND ${CMAKE_COMMAND} -Dexe:FILEPATH=$<TARGET_FILE:main> -P ${CMAKE_CURRENT_SOURCE_DIR}/stdin_pipe.cmake
)

In the non-CMakeLists.txt *.cmake script files, we set a reasonable cmake_minimum_required(VERSION) to avoid issues with defaulting to pre-CMake 3.0 behavior for strings, especially for regular expressions.

The null input to stdin may be required for some executables that may hang forever waiting for stdin.

cmake_minimum_required(VERSION 3.19)

if(UNIX)
  set(devnull INPUT_FILE /dev/null)
elseif(WIN32)
  set(devnull INPUT_FILE NUL)
endif()

execute_process(COMMAND ${exe}
${devnull}
COMMAND_ERROR_IS_FATAL ANY
)

A file (typically a text file) may be piped to stdin to replace interactive input.

cmake_minimum_required(VERSION 3.19)

execute_process(COMMAND ${exe}
INPUT_FILE ${CMAKE_CURRENT_LIST_DIR}/cli_exercise.txt
COMMAND_ERROR_IS_FATAL ANY
OUTPUT_VARIABLE out
ERROR_VARIABLE err
)

if(out MATCHES "TRACE")
  message(FATAL_ERROR "TRACE found in stdout")
endif()

if(err MATCHES "TRACE")
  message(FATAL_ERROR "TRACE found in stderr")
endif()

if(NOT err STREQUAL "")
  message(FATAL_ERROR "stderr output is not empty:
  ${err}")
endif()

message(STATUS "stdout:
${out}")

In this example, the developer wishes to ensure the program ran with no unexpected stdout text and no stderr text at all. This can be helpful to catch debugging output that should not be in the final program output.