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
7 changes: 4 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ jobs:

- name: Run tests
run: |
ctest --preset default --verbose
ctest --preset default --output-on-failure -j8

- name: Build documentation
run: |
Expand Down Expand Up @@ -224,7 +224,7 @@ jobs:
- name: Run tests
shell: cmd
run: |
ctest --preset default --verbose
ctest --preset default --output-on-failure -j8

build-macos:
runs-on: macos-latest
Expand Down Expand Up @@ -311,7 +311,8 @@ jobs:

- name: Run tests
run: |
ctest --preset default --verbose
# Parallel test execution on macOS often causes failures in EventListener tests
ctest --preset default --output-on-failure

deploy-docs:
if: github.repository == 'asfernandes/fb-cpp' && github.ref == 'refs/heads/main'
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ jobs:

- name: Run tests
run: |
ctest --preset default --verbose
ctest --preset default --output-on-failure -j8

- name: Build documentation
run: |
Expand Down Expand Up @@ -217,7 +217,7 @@ jobs:
run: |
set ISC_USER=sysdba
set ISC_PASSWORD=masterkey
ctest --preset default --verbose
ctest --preset default --output-on-failure -j8

build-macos:
runs-on: macos-latest
Expand Down Expand Up @@ -304,4 +304,5 @@ jobs:

- name: Run tests
run: |
ctest --preset default --verbose
# Parallel test execution on macOS often causes failures in EventListener tests
ctest --preset default --output-on-failure
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)

set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR} ${CMAKE_MODULE_PATH})
set(CMAKE_MODULE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
${CMAKE_BINARY_DIR}
${CMAKE_MODULE_PATH}
)
set(CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR} ${CMAKE_PREFIX_PATH})

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out/lib)
Expand Down
312 changes: 312 additions & 0 deletions cmake/BoostTestAddTests.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
# Copyright 2020, 2021 Deniz Bahadir and contributors
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
#
# This code is based on an implementation of the `gtest_discover_tests()`
# functionality that was originally distributed together with CMake unter the
# OSI-approved BSD 3-Clause License. The original authors and contributors of
# that code were so kind to agree to dual-license their work also under the
# Boost Software License, Version 1.0, so that this derived worked can be
# distributed under the same license as well.
# A public record of their granted permission can be found in this discussion
# of merge-request 4145 in the CMake issue tracker:
# https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4145#note_998500
#
# Therefore many thanks go to the following original authors and contributors:
# Matthew Woehlke <matthew.woehlke@kitware.com>
# Steffen Seckler <steffen.seckler@smartronic.de>
# Ryan Thornton <ThorntonRyan@JohnDeere.com>
# Kevin Puetz <PuetzKevinA@JohnDeere.com>
# Stefan Floeren <stefan.floeren@smartronic.de>
# Alexander Stein <alexander.stein@mailbox.org>
#
# Deniz Bahadir in August of 2021.
#

cmake_minimum_required(VERSION ${CMAKE_VERSION})

# Overwrite possibly existing ${__CTEST_FILE} with empty file.
set(flush_tests_MODE WRITE)


# Flushes script to ${__CTEST_FILE}.
macro(flush_script)
file(${flush_tests_MODE} "${__CTEST_FILE}" "${script}")
set(flush_tests_MODE APPEND)
set(script "")
endmacro()


# Flushes tests_buffer to tests variable.
macro(flush_tests_buffer)
list(APPEND tests "${tests_buffer}")
set(tests_buffer "")
endmacro()


# Removes surrounding double quotes (if any) from value of given variable VAR.
function(remove_outer_quotes VAR)
string(REGEX REPLACE "^\"(.*)\"$" "\\1" ${VAR} "${${VAR}}")
set(${VAR} "${${VAR}}" PARENT_SCOPE)
endfunction()


# Adds commands to script.
macro(add_command NAME)
set(_args "")
foreach(_arg ${ARGN})
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
string(APPEND _args " [==[${_arg}]==]") # form a bracket argument
else()
string(APPEND _args " ${_arg}")
endif()
endforeach()
string(APPEND script "${NAME}(${_args})\n")
string(LENGTH "${script}" _script_len)
if(${_script_len} GREATER "50000")
flush_script()
endif()
# Unsets macro local variables to prevent leakage outside of this macro.
unset(_args)
unset(_script_len)
endmacro()

# Adds another test to the script.
macro(add_another_test hierarchy_list enabled source_line separator)
# Create the name and path of the test-case...
if (CMAKE_VERSION VERSION_LESS "3.12")
set(test_name)
set(test_path)
foreach(hierarchy_entry IN LISTS ${hierarchy_list})
if ("${test_name}" STREQUAL "")
set(test_name "${hierarchy_entry}")
else()
set(test_name "${test_name}${separator}${hierarchy_entry}")
endif()
if ("${test_path}" STREQUAL "")
set(test_path "${hierarchy_entry}")
else()
set(test_path "${test_path}/${hierarchy_entry}")
endif()
endforeach()
else()
list(JOIN ${hierarchy_list} ${separator} test_name)
list(JOIN ${hierarchy_list} "/" test_path)
endif()
# ...and add to script.
add_command(add_test
"${prefix}${test_name}${suffix}"
${__TEST_EXECUTOR}
"${__TEST_EXECUTABLE}"
"--run_test=${test_path}"
${extra_args}
)
if(NOT ${enabled})
add_command(set_tests_properties
"${prefix}${test_name}${suffix}"
PROPERTIES
DISABLED TRUE
)
endif()
add_command(set_tests_properties
"${prefix}${test_name}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${__TEST_WORKING_DIR}"
DEF_SOURCE_LINE "${source_line}"
${properties}
)
list(APPEND tests_buffer "${prefix}${test_name}${suffix}")
list(LENGTH tests_buffer tests_buffer_length)
if(${tests_buffer_length} GREATER "250")
flush_tests_buffer()
endif()
endmacro()


# Internal implementation for boost_test_discover_tests.
function(boost_test_discover_tests_impl)

cmake_parse_arguments(
"_"
""
"TEST_TARGET;TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_PREFIX;TEST_SUFFIX;TEST_NAME_SEPARATOR;TEST_LIST;TEST_SKIP_DISABLED;CTEST_FILE;TEST_DISCOVERY_TIMEOUT"
"TEST_EXTRA_ARGS;TEST_PROPERTIES;TEST_EXECUTOR"
${ARGN}
)

set(prefix "${__TEST_PREFIX}")
set(suffix "${__TEST_SUFFIX}")
set(extra_args ${__TEST_EXTRA_ARGS})
set(properties ${__TEST_PROPERTIES})
set(script)
set(tests)
set(tests_buffer)

# Make sure the working directory exists.
file(MAKE_DIRECTORY "${__TEST_WORKING_DIR}")
# Run test executable to get list of available tests.
if(NOT EXISTS "${__TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable does not exist.\n"
" Path: '${__TEST_EXECUTABLE}'"
)
endif()

# DOT format is used to get the source file and line number of a test case.
execute_process(
COMMAND ${__TEST_EXECUTOR} "${__TEST_EXECUTABLE}" --list_content=DOT --detect_memory_leaks=0
WORKING_DIRECTORY "${__TEST_WORKING_DIR}"
TIMEOUT ${__TEST_DISCOVERY_TIMEOUT}
OUTPUT_VARIABLE dot_output
ERROR_VARIABLE dot_output # Boost.Test writes the requested content to stderr!
RESULT_VARIABLE result
)

if(NOT ${result} EQUAL 0)
message(FATAL_ERROR
"Error running test executable.\n"
" Path: '${__TEST_EXECUTABLE}'\n"
" Result: ${result}\n"
" Output:\n"
" ${dot_output}\n"
)
endif()

# Replace \ with / to prevent invalid escape sequence error when parsing DOT output
string(REPLACE [[\]] [[/]] dot_output "${dot_output}")

# HRF format is used to build the test suite / test case hierarchy and determine which tests are enabled / disabled
execute_process(
COMMAND ${__TEST_EXECUTOR} "${__TEST_EXECUTABLE}" --list_content=HRF --detect_memory_leaks=0
WORKING_DIRECTORY "${__TEST_WORKING_DIR}"
TIMEOUT ${__TEST_DISCOVERY_TIMEOUT}
OUTPUT_VARIABLE hrf_output
ERROR_VARIABLE hrf_output # Boost.Test writes the requested content to stderr!
RESULT_VARIABLE result
)

if(NOT ${result} EQUAL 0)
string(REPLACE "\n" "\n " HRF output "${hrf_output}")
message(FATAL_ERROR
"Error running test executable.\n"
" Path: '${__TEST_EXECUTABLE}'\n"
" Result: ${result}\n"
" Output:\n"
" ${hrf_output}\n"
)
endif()

# Preserve semicolon in test-parameters
string(REPLACE [[;]] [[\;]] hrf_output "${hrf_output}")
string(REPLACE "\n" ";" hrf_output "${hrf_output}")

# The hierarchy and its depth-level of the test of the former line.
set(test_hierarchy "${TEST_TARGET}_MISSING_TESTS")
set(former_level NaN)
set(test_enabled 0)
set(test_source_line "")

# Parse output
foreach(line ${hrf_output})
# Determine the depth-level of the next test-hierarchy.
# Note: Each new depth-level (except for the top one) is indented
# by 4 spaces. So we need to count the spaces.
string(REGEX MATCH "^[ ]+" next_level "${line}")
string(LENGTH "${next_level}" next_level)
math(EXPR next_level "${next_level} / 4")

# Add the test for the test-case from the former loop-run?
if ((next_level LESS former_level) OR (next_level EQUAL former_level))
# Add test-case to the script.
add_another_test(test_hierarchy ${test_enabled} "${test_source_line}" "${__TEST_NAME_SEPARATOR}")

# Prepare the hierarchy list for the next test-case.
math(EXPR diff "${former_level} - ${next_level}")
foreach(i RANGE ${diff})
if (CMAKE_VERSION VERSION_LESS "3.15")
list(LENGTH test_hierarchy length)
math(EXPR index "${length} - 1")
list(REMOVE_AT test_hierarchy ${index})
else()
list(POP_BACK test_hierarchy)
endif()
endforeach()
endif()
if (former_level STREQUAL NaN)
set(test_hierarchy "") # Clear hierarchy, as we have at least one test.
set(test_source_line "")
endif()
set(former_level ${next_level}) # Store depth-level for next loop-run.

# Extract the name of the next test suite/case and determine if enabled.
# Note: A trailing '*' indicates that the test is enabled (by default).
string(REGEX REPLACE ":( .*)?$" "" name "${line}")
string(STRIP "${name}" name)
if(name MATCHES "\\*$")
set(test_enabled 1)
string(REGEX REPLACE "\\*$" "" name "${name}")
elseif(__TEST_SKIP_DISABLED)
set(test_enabled 0)
endif()

# Sanitize name for further processing downstream:
# - escape \ ; $
string(REGEX REPLACE [[([\;$])]] [[\\\1]] name "${name}")

# Extract the source file and line number name of the next test case.
string(REGEX MATCH "${name}\\|[^\"]+" test_source_line "${dot_output}")
string(REGEX REPLACE "${name}\\|([^\\(]+)\\(([0-9]+)\\)" "\\1:\\2" test_source_line "${test_source_line}")

# Add the name to the hierarchy list.
list(APPEND test_hierarchy "${name}")
endforeach()

# Add last test-case to the script (if any).
add_another_test(test_hierarchy ${test_enabled} "${test_source_line}" "${__TEST_NAME_SEPARATOR}")

# Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests.
flush_tests_buffer()
if (NOT former_level STREQUAL "NaN")
add_command(set ${__TEST_LIST} ${tests})
endif()

# # Write (remaining) content to the CTest script
flush_script()

endfunction()


if(CMAKE_SCRIPT_MODE_FILE)
# Note: Make sure to remove the outer layer of quotes that were added
# to preserve whitespace when handed over via cmdline.
remove_outer_quotes(TEST_TARGET)
remove_outer_quotes(TEST_EXECUTABLE)
remove_outer_quotes(TEST_EXECUTOR)
remove_outer_quotes(TEST_WORKING_DIR)
remove_outer_quotes(TEST_EXTRA_ARGS)
remove_outer_quotes(TEST_PROPERTIES)
remove_outer_quotes(TEST_PREFIX)
remove_outer_quotes(TEST_SUFFIX)
remove_outer_quotes(TEST_NAME_SEPARATOR)
remove_outer_quotes(TEST_LIST)
remove_outer_quotes(TEST_SKIP_DISABLED)
remove_outer_quotes(CTEST_FILE)
remove_outer_quotes(TEST_DISCOVERY_TIMEOUT)

boost_test_discover_tests_impl(
TEST_TARGET ${TEST_TARGET}
TEST_EXECUTABLE ${TEST_EXECUTABLE}
TEST_EXECUTOR ${TEST_EXECUTOR}
TEST_WORKING_DIR ${TEST_WORKING_DIR}
TEST_PREFIX ${TEST_PREFIX}
TEST_SUFFIX ${TEST_SUFFIX}
TEST_NAME_SEPARATOR ${TEST_NAME_SEPARATOR}
TEST_LIST ${TEST_LIST}
TEST_SKIP_DISABLED ${TEST_SKIP_DISABLED}
CTEST_FILE ${CTEST_FILE}
TEST_DISCOVERY_TIMEOUT ${TEST_DISCOVERY_TIMEOUT}
TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS}
TEST_PROPERTIES ${TEST_PROPERTIES}
)
endif()
Loading
Loading