mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2026-01-06 06:47:41 -07:00
Vendor a 3.x version of Catch2
Everything is surely broken at this point.
This commit is contained in:
parent
87c9b92a1c
commit
b48dd917fd
319 changed files with 58599 additions and 18935 deletions
|
|
@ -1,175 +0,0 @@
|
|||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
Catch
|
||||
-----
|
||||
|
||||
This module defines a function to help use the Catch test framework.
|
||||
|
||||
The :command:`catch_discover_tests` discovers tests by asking the compiled test
|
||||
executable to enumerate its tests. This does not require CMake to be re-run
|
||||
when tests change. However, it may not work in a cross-compiling environment,
|
||||
and setting test properties is less convenient.
|
||||
|
||||
This command is intended to replace use of :command:`add_test` to register
|
||||
tests, and will create a separate CTest test for each Catch test case. Note
|
||||
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||
cannot be shared by multiple test cases executing in the same instance.
|
||||
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||
usually considered as more beneficial. By default, the CTest test name is the
|
||||
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
.. command:: catch_discover_tests
|
||||
|
||||
Automatically add tests with CTest by querying the compiled test executable
|
||||
for available tests::
|
||||
|
||||
catch_discover_tests(target
|
||||
[TEST_SPEC arg1...]
|
||||
[EXTRA_ARGS arg1...]
|
||||
[WORKING_DIRECTORY dir]
|
||||
[TEST_PREFIX prefix]
|
||||
[TEST_SUFFIX suffix]
|
||||
[PROPERTIES name1 value1...]
|
||||
[TEST_LIST var]
|
||||
)
|
||||
|
||||
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||
that generates the list of tests by parsing the output from running the test
|
||||
with the ``--list-test-names-only`` argument. This ensures that the full
|
||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||
not necessary to re-run CMake when the list of tests changes.
|
||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||
in order to function in a cross-compiling environment.
|
||||
|
||||
Additionally, setting properties on tests is somewhat less convenient, since
|
||||
the tests are not available at CMake time. Additional test properties may be
|
||||
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||
more fine-grained test control is needed, custom content may be provided
|
||||
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||
directory property. The set of discovered tests is made accessible to such a
|
||||
script via the ``<target>_TESTS`` variable.
|
||||
|
||||
The options are:
|
||||
|
||||
``target``
|
||||
Specifies the Catch executable, which must be a known CMake executable
|
||||
target. CMake will substitute the location of the built executable when
|
||||
running the test.
|
||||
|
||||
``TEST_SPEC arg1...``
|
||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
||||
|
||||
``EXTRA_ARGS arg1...``
|
||||
Any extra arguments to pass on the command line to each test case.
|
||||
|
||||
``WORKING_DIRECTORY dir``
|
||||
Specifies the directory in which to run the discovered test cases. If this
|
||||
option is not provided, the current binary directory is used.
|
||||
|
||||
``TEST_PREFIX prefix``
|
||||
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
||||
case. This can be useful when the same test executable is being used in
|
||||
multiple calls to ``catch_discover_tests()`` but with different
|
||||
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||
|
||||
``TEST_SUFFIX suffix``
|
||||
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||
be specified.
|
||||
|
||||
``PROPERTIES name1 value1...``
|
||||
Specifies additional properties to be set on all tests discovered by this
|
||||
invocation of ``catch_discover_tests``.
|
||||
|
||||
``TEST_LIST var``
|
||||
Make the list of tests available in the variable ``var``, rather than the
|
||||
default ``<target>_TESTS``. This can be useful when the same test
|
||||
executable is being used in multiple calls to ``catch_discover_tests()``.
|
||||
Note that this variable is only available in CTest.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
function(catch_discover_tests TARGET)
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
""
|
||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
|
||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(NOT _WORKING_DIRECTORY)
|
||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if(NOT _TEST_LIST)
|
||||
set(_TEST_LIST ${TARGET}_TESTS)
|
||||
endif()
|
||||
|
||||
## Generate a unique name based on the extra arguments
|
||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||
|
||||
# Define rule to generate test list for aforementioned test executable
|
||||
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
|
||||
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
||||
get_property(crosscompiling_emulator
|
||||
TARGET ${TARGET}
|
||||
PROPERTY CROSSCOMPILING_EMULATOR
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
BYPRODUCTS "${ctest_tests_file}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "TEST_TARGET=${TARGET}"
|
||||
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||
-D "TEST_PREFIX='${_TEST_PREFIX}'"
|
||||
-D "TEST_SUFFIX='${_TEST_SUFFIX}'"
|
||||
-D "TEST_LIST=${_TEST_LIST}"
|
||||
-D "CTEST_FILE=${ctest_tests_file}"
|
||||
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
file(WRITE "${ctest_include_file}"
|
||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||
" include(\"${ctest_tests_file}\")\n"
|
||||
"else()\n"
|
||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||
"endif()\n"
|
||||
)
|
||||
|
||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
||||
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
||||
if (NOT ${test_include_file_set})
|
||||
set_property(DIRECTORY
|
||||
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Cannot set more than one TEST_INCLUDE_FILE"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||
)
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
set(prefix "${TEST_PREFIX}")
|
||||
set(suffix "${TEST_SUFFIX}")
|
||||
set(spec ${TEST_SPEC})
|
||||
set(extra_args ${TEST_EXTRA_ARGS})
|
||||
set(properties ${TEST_PROPERTIES})
|
||||
set(script)
|
||||
set(suite)
|
||||
set(tests)
|
||||
|
||||
function(add_command NAME)
|
||||
set(_args "")
|
||||
foreach(_arg ${ARGN})
|
||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||
else()
|
||||
set(_args "${_args} ${_arg}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
macro(_add_catch_test_labels LINE)
|
||||
# convert to list of tags
|
||||
string(REPLACE "][" "]\\;[" tags ${line})
|
||||
|
||||
add_command(
|
||||
set_tests_properties "${prefix}${test}${suffix}"
|
||||
PROPERTIES
|
||||
LABELS "${tags}"
|
||||
)
|
||||
endmacro()
|
||||
|
||||
macro(_add_catch_test LINE)
|
||||
set(test ${line})
|
||||
# use escape commas to handle properly test cases with commans inside the name
|
||||
string(REPLACE "," "\\," test_name ${test})
|
||||
# ...and add to script
|
||||
add_command(
|
||||
add_test "${prefix}${test}${suffix}"
|
||||
${TEST_EXECUTOR}
|
||||
"${TEST_EXECUTABLE}"
|
||||
"${test_name}"
|
||||
${extra_args}
|
||||
)
|
||||
|
||||
add_command(
|
||||
set_tests_properties "${prefix}${test}${suffix}"
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
${properties}
|
||||
)
|
||||
list(APPEND tests "${prefix}${test}${suffix}")
|
||||
endmacro()
|
||||
|
||||
# Run test executable to get list of available tests
|
||||
if(NOT EXISTS "${TEST_EXECUTABLE}")
|
||||
message(FATAL_ERROR
|
||||
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
|
||||
)
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-tests
|
||||
OUTPUT_VARIABLE output
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
|
||||
if(${result} EQUAL 0)
|
||||
message(WARNING
|
||||
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
|
||||
)
|
||||
elseif(${result} LESS 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${result}\n"
|
||||
" Output: ${output}\n"
|
||||
)
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" output "${output}")
|
||||
set(test)
|
||||
set(tags_regex "(\\[([^\\[]*)\\])+$")
|
||||
|
||||
# Parse output
|
||||
foreach(line ${output})
|
||||
# lines without leading whitespaces are catch output not tests
|
||||
if(${line} MATCHES "^[ \t]+")
|
||||
# strip leading spaces and tabs
|
||||
string(REGEX REPLACE "^[ \t]+" "" line ${line})
|
||||
|
||||
if(${line} MATCHES "${tags_regex}")
|
||||
_add_catch_test_labels(${line})
|
||||
else()
|
||||
_add_catch_test(${line})
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Create a list of all discovered tests, which users may use to e.g. set
|
||||
# properties on the tests
|
||||
add_command(set ${TEST_LIST} ${tests})
|
||||
|
||||
# Write CTest script
|
||||
file(WRITE "${CTEST_FILE}" "${script}")
|
||||
9
tests/catch2/CMake/Catch2Config.cmake.in
Normal file
9
tests/catch2/CMake/Catch2Config.cmake.in
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
# Avoid repeatedly including the targets
|
||||
if(NOT TARGET Catch2::Catch2)
|
||||
# Provide path for scripts
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/Catch2Targets.cmake)
|
||||
endif()
|
||||
91
tests/catch2/CMake/CatchConfigOptions.cmake
Normal file
91
tests/catch2/CMake/CatchConfigOptions.cmake
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
# Copyright Catch2 Authors
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE.txt or copy at
|
||||
# https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
##
|
||||
# This file contains options that are materialized into the Catch2
|
||||
# compiled library. All of them default to OFF, as even the positive
|
||||
# forms correspond to the user _forcing_ them to ON, while being OFF
|
||||
# means that Catch2 can use its own autodetection.
|
||||
#
|
||||
# For detailed docs look into docs/configuration.md
|
||||
|
||||
macro(AddOverridableConfigOption OptionBaseName)
|
||||
option(CATCH_CONFIG_${OptionBaseName} "Read docs/configuration.md for details" OFF)
|
||||
option(CATCH_CONFIG_NO_${OptionBaseName} "Read docs/configuration.md for details" OFF)
|
||||
mark_as_advanced(CATCH_CONFIG_${OptionBaseName} CATCH_CONFIG_NO_${OptionBaseName})
|
||||
endmacro()
|
||||
|
||||
macro(AddConfigOption OptionBaseName)
|
||||
option(CATCH_CONFIG_${OptionBaseName} "Read docs/configuration.md for details" OFF)
|
||||
mark_as_advanced(CATCH_CONFIG_${OptionBaseName})
|
||||
endmacro()
|
||||
|
||||
set(_OverridableOptions
|
||||
"ANDROID_LOGWRITE"
|
||||
"BAZEL_SUPPORT"
|
||||
"COLOUR_WIN32"
|
||||
"COUNTER"
|
||||
"CPP11_TO_STRING"
|
||||
"CPP17_BYTE"
|
||||
"CPP17_OPTIONAL"
|
||||
"CPP17_STRING_VIEW"
|
||||
"CPP17_UNCAUGHT_EXCEPTIONS"
|
||||
"CPP17_VARIANT"
|
||||
"GLOBAL_NEXTAFTER"
|
||||
"POSIX_SIGNALS"
|
||||
"USE_ASYNC"
|
||||
"WCHAR"
|
||||
"WINDOWS_SEH"
|
||||
"GETENV"
|
||||
"EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT"
|
||||
"USE_BUILTIN_CONSTANT_P"
|
||||
"DEPRECATION_ANNOTATIONS"
|
||||
"EXPERIMENTAL_THREAD_SAFE_ASSERTIONS"
|
||||
)
|
||||
|
||||
foreach(OptionName ${_OverridableOptions})
|
||||
AddOverridableConfigOption(${OptionName})
|
||||
endforeach()
|
||||
|
||||
set(_OtherConfigOptions
|
||||
"DISABLE_EXCEPTIONS"
|
||||
"DISABLE_EXCEPTIONS_CUSTOM_HANDLER"
|
||||
"DISABLE"
|
||||
"DISABLE_STRINGIFICATION"
|
||||
"ENABLE_ALL_STRINGMAKERS"
|
||||
"ENABLE_OPTIONAL_STRINGMAKER"
|
||||
"ENABLE_PAIR_STRINGMAKER"
|
||||
"ENABLE_TUPLE_STRINGMAKER"
|
||||
"ENABLE_VARIANT_STRINGMAKER"
|
||||
"EXPERIMENTAL_REDIRECT"
|
||||
"FAST_COMPILE"
|
||||
"NOSTDOUT"
|
||||
"PREFIX_ALL"
|
||||
"PREFIX_MESSAGES"
|
||||
"WINDOWS_CRTDBG"
|
||||
)
|
||||
|
||||
|
||||
foreach(OptionName ${_OtherConfigOptions})
|
||||
AddConfigOption(${OptionName})
|
||||
endforeach()
|
||||
if(DEFINED BUILD_SHARED_LIBS)
|
||||
set(CATCH_CONFIG_SHARED_LIBRARY ${BUILD_SHARED_LIBS})
|
||||
else()
|
||||
set(CATCH_CONFIG_SHARED_LIBRARY "")
|
||||
endif()
|
||||
|
||||
set(CATCH_CONFIG_DEFAULT_REPORTER "console" CACHE STRING "Read docs/configuration.md for details. The name of the reporter should be without quotes.")
|
||||
set(CATCH_CONFIG_CONSOLE_WIDTH "80" CACHE STRING "Read docs/configuration.md for details. Must form a valid integer literal.")
|
||||
|
||||
mark_as_advanced(CATCH_CONFIG_SHARED_LIBRARY CATCH_CONFIG_DEFAULT_REPORTER CATCH_CONFIG_CONSOLE_WIDTH)
|
||||
|
||||
# There is no good way to both turn this into a CMake cache variable,
|
||||
# and keep reasonable default semantics inside the project. Thus we do
|
||||
# not define it and users have to provide it as an outside variable.
|
||||
#set(CATCH_CONFIG_FALLBACK_STRINGIFIER "" CACHE STRING "Read docs/configuration.md for details.")
|
||||
121
tests/catch2/CMake/CatchMiscFunctions.cmake
Normal file
121
tests/catch2/CMake/CatchMiscFunctions.cmake
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
# Copyright Catch2 Authors
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE.txt or copy at
|
||||
# https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
function(add_cxx_flag_if_supported_to_targets flagname targets)
|
||||
string(MAKE_C_IDENTIFIER ${flagname} flag_identifier)
|
||||
check_cxx_compiler_flag("${flagname}" HAVE_FLAG_${flag_identifier})
|
||||
|
||||
if(HAVE_FLAG_${flag_identifier})
|
||||
foreach(target ${targets})
|
||||
target_compile_options(${target} PRIVATE ${flagname})
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Assumes that it is only called for development builds, where warnings
|
||||
# and Werror is desired, so it also enables Werror.
|
||||
function(add_warnings_to_targets targets)
|
||||
LIST(LENGTH targets TARGETS_LEN)
|
||||
# For now we just assume 2 possibilities: msvc and msvc-like compilers,
|
||||
# and other.
|
||||
if(MSVC)
|
||||
foreach(target ${targets})
|
||||
# Force MSVC to consider everything as encoded in utf-8
|
||||
target_compile_options(${target} PRIVATE /utf-8)
|
||||
# Enable Werror equivalent
|
||||
if(CATCH_ENABLE_WERROR)
|
||||
target_compile_options(${target} PRIVATE /WX)
|
||||
endif()
|
||||
|
||||
# MSVC is currently handled specially
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
STRING(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # override default warning level
|
||||
target_compile_options(${target} PRIVATE /w44265 /w44061 /w44062 /w45038)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CHECKED_WARNING_FLAGS
|
||||
"-Wabsolute-value"
|
||||
"-Wall"
|
||||
"-Wcall-to-pure-virtual-from-ctor-dtor"
|
||||
"-Wcast-align"
|
||||
"-Wcatch-value"
|
||||
"-Wdangling"
|
||||
"-Wdeprecated"
|
||||
"-Wdeprecated-register"
|
||||
"-Wexceptions"
|
||||
"-Wexit-time-destructors"
|
||||
"-Wextra"
|
||||
"-Wextra-semi"
|
||||
"-Wfloat-equal"
|
||||
"-Wglobal-constructors"
|
||||
"-Winit-self"
|
||||
"-Wmisleading-indentation"
|
||||
"-Wmismatched-new-delete"
|
||||
"-Wmismatched-return-types"
|
||||
"-Wmismatched-tags"
|
||||
"-Wmissing-braces"
|
||||
"-Wmissing-declarations"
|
||||
"-Wmissing-noreturn"
|
||||
"-Wmissing-prototypes"
|
||||
"-Wmissing-variable-declarations"
|
||||
"-Wnon-virtual-dtor"
|
||||
"-Wnull-dereference"
|
||||
"-Wold-style-cast"
|
||||
"-Woverloaded-virtual"
|
||||
"-Wparentheses"
|
||||
"-Wpedantic"
|
||||
"-Wredundant-decls"
|
||||
"-Wreorder"
|
||||
"-Wreturn-std-move"
|
||||
"-Wshadow"
|
||||
"-Wstrict-aliasing"
|
||||
"-Wsubobject-linkage"
|
||||
"-Wsuggest-destructor-override"
|
||||
"-Wsuggest-override"
|
||||
"-Wundef"
|
||||
"-Wuninitialized"
|
||||
"-Wunneeded-internal-declaration"
|
||||
"-Wunreachable-code-aggressive"
|
||||
"-Wunused"
|
||||
"-Wunused-function"
|
||||
"-Wunused-parameter"
|
||||
"-Wvla"
|
||||
"-Wweak-vtables"
|
||||
|
||||
# This is a useful warning, but our tests sometimes rely on
|
||||
# functions being present, but not picked (e.g. various checks
|
||||
# for stringification implementation ordering).
|
||||
# Ergo, we should use it every now and then, but we cannot
|
||||
# enable it by default.
|
||||
# "-Wunused-member-function"
|
||||
)
|
||||
foreach(warning ${CHECKED_WARNING_FLAGS})
|
||||
add_cxx_flag_if_supported_to_targets(${warning} "${targets}")
|
||||
endforeach()
|
||||
|
||||
if(CATCH_ENABLE_WERROR)
|
||||
foreach(target ${targets})
|
||||
# Enable Werror equivalent
|
||||
target_compile_options(${target} PRIVATE -Werror)
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Adds flags required for reproducible build to the target
|
||||
# Currently only supports GCC and Clang
|
||||
function(add_build_reproducibility_settings target)
|
||||
# Make the build reproducible on versions of g++ and clang that supports -ffile-prefix-map
|
||||
if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
||||
add_cxx_flag_if_supported_to_targets("-ffile-prefix-map=${CATCH_DIR}/=" "${target}")
|
||||
endif()
|
||||
endfunction()
|
||||
157
tests/catch2/CMake/FindGcov.cmake
Normal file
157
tests/catch2/CMake/FindGcov.cmake
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
|
||||
# include required Modules
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
|
||||
# Search for gcov binary.
|
||||
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
|
||||
set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY})
|
||||
|
||||
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
foreach (LANG ${ENABLED_LANGUAGES})
|
||||
# Gcov evaluation is dependent on the used compiler. Check gcov support for
|
||||
# each compiler that is used. If gcov binary was already found for this
|
||||
# compiler, do not try to find it again.
|
||||
if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN)
|
||||
get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH)
|
||||
|
||||
if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU")
|
||||
# Some distributions like OSX (homebrew) ship gcov with the compiler
|
||||
# version appended as gcov-x. To find this binary we'll build the
|
||||
# suggested binary name with the compiler version.
|
||||
string(REGEX MATCH "^[0-9]+" GCC_VERSION
|
||||
"${CMAKE_${LANG}_COMPILER_VERSION}")
|
||||
|
||||
find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov
|
||||
HINTS ${COMPILER_PATH})
|
||||
|
||||
elseif ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Clang")
|
||||
# Some distributions like Debian ship llvm-cov with the compiler
|
||||
# version appended as llvm-cov-x.y. To find this binary we'll build
|
||||
# the suggested binary name with the compiler version.
|
||||
string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION
|
||||
"${CMAKE_${LANG}_COMPILER_VERSION}")
|
||||
|
||||
# llvm-cov prior version 3.5 seems to be not working with coverage
|
||||
# evaluation tools, but these versions are compatible with the gcc
|
||||
# gcov tool.
|
||||
if(LLVM_VERSION VERSION_GREATER 3.4)
|
||||
find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}"
|
||||
"llvm-cov" HINTS ${COMPILER_PATH})
|
||||
mark_as_advanced(LLVM_COV_BIN)
|
||||
|
||||
if (LLVM_COV_BIN)
|
||||
find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS
|
||||
${CMAKE_MODULE_PATH})
|
||||
if (LLVM_COV_WRAPPER)
|
||||
set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "")
|
||||
|
||||
# set additional parameters
|
||||
set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV
|
||||
"LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING
|
||||
"Environment variables for llvm-cov-wrapper.")
|
||||
mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (NOT GCOV_BIN)
|
||||
# Fall back to gcov binary if llvm-cov was not found or is
|
||||
# incompatible. This is the default on OSX, but may crash on
|
||||
# recent Linux versions.
|
||||
find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
if (GCOV_BIN)
|
||||
set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING
|
||||
"${LANG} gcov binary.")
|
||||
|
||||
if (NOT CMAKE_REQUIRED_QUIET)
|
||||
message("-- Found gcov evaluation for "
|
||||
"${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}")
|
||||
endif()
|
||||
|
||||
unset(GCOV_BIN CACHE)
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target for all gcov targets. This target could be used to
|
||||
# generate the gcov files for the whole project instead of calling <TARGET>-gcov
|
||||
# for each target.
|
||||
if (NOT TARGET gcov)
|
||||
add_custom_target(gcov)
|
||||
endif (NOT TARGET gcov)
|
||||
|
||||
|
||||
|
||||
# This function will add gcov evaluation for target <TNAME>. Only sources of
|
||||
# this target will be evaluated and no dependencies will be added. It will call
|
||||
# Gcov on any source file of <TNAME> once and store the gcov file in the same
|
||||
# directory.
|
||||
function (add_gcov_target TNAME)
|
||||
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
||||
|
||||
# We don't have to check, if the target has support for coverage, thus this
|
||||
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
||||
# have to determine which gcov binary to use.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(SOURCES "")
|
||||
set(TCOMPILER "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
if (NOT "${FILE}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (NOT "${LANG}" STREQUAL "")
|
||||
list(APPEND SOURCES "${FILE}")
|
||||
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# If no gcov binary was found, coverage data can't be evaluated.
|
||||
if (NOT GCOV_${TCOMPILER}_BIN)
|
||||
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
||||
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
||||
|
||||
|
||||
set(BUFFER "")
|
||||
foreach(FILE ${SOURCES})
|
||||
get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH)
|
||||
|
||||
# call gcov
|
||||
add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov
|
||||
COMMAND ${GCOV_ENV} ${GCOV_BIN} ${TDIR}/${FILE}.gcno > /dev/null
|
||||
DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno
|
||||
WORKING_DIRECTORY ${FILE_PATH}
|
||||
)
|
||||
|
||||
list(APPEND BUFFER ${TDIR}/${FILE}.gcov)
|
||||
endforeach()
|
||||
|
||||
|
||||
# add target for gcov evaluation of <TNAME>
|
||||
add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER})
|
||||
|
||||
# add evaluation target to the global gcov target.
|
||||
add_dependencies(gcov ${TNAME}-gcov)
|
||||
endfunction (add_gcov_target)
|
||||
354
tests/catch2/CMake/FindLcov.cmake
Normal file
354
tests/catch2/CMake/FindLcov.cmake
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
|
||||
# configuration
|
||||
set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data")
|
||||
set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init")
|
||||
set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture")
|
||||
set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html")
|
||||
|
||||
|
||||
|
||||
|
||||
# Search for Gcov which is used by Lcov.
|
||||
find_package(Gcov)
|
||||
|
||||
|
||||
|
||||
|
||||
# This function will add lcov evaluation for target <TNAME>. Only sources of
|
||||
# this target will be evaluated and no dependencies will be added. It will call
|
||||
# geninfo on any source file of <TNAME> once and store the info file in the same
|
||||
# directory.
|
||||
#
|
||||
# Note: This function is only a wrapper to define this function always, even if
|
||||
# coverage is not supported by the compiler or disabled. This function must
|
||||
# be defined here, because the module will be exited, if there is no coverage
|
||||
# support by the compiler or it is disabled by the user.
|
||||
function (add_lcov_target TNAME)
|
||||
if (LCOV_FOUND)
|
||||
# capture initial coverage data
|
||||
lcov_capture_initial_tgt(${TNAME})
|
||||
|
||||
# capture coverage data after execution
|
||||
lcov_capture_tgt(${TNAME})
|
||||
endif ()
|
||||
endfunction (add_lcov_target)
|
||||
|
||||
|
||||
|
||||
|
||||
# include required Modules
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
# Search for required lcov binaries.
|
||||
find_program(LCOV_BIN lcov)
|
||||
find_program(GENINFO_BIN geninfo)
|
||||
find_program(GENHTML_BIN genhtml)
|
||||
find_package_handle_standard_args(lcov
|
||||
REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN
|
||||
)
|
||||
|
||||
# enable genhtml C++ demangeling, if c++filt is found.
|
||||
set(GENHTML_CPPFILT_FLAG "")
|
||||
find_program(CPPFILT_BIN c++filt)
|
||||
if (NOT CPPFILT_BIN STREQUAL "")
|
||||
set(GENHTML_CPPFILT_FLAG "--demangle-cpp")
|
||||
endif (NOT CPPFILT_BIN STREQUAL "")
|
||||
|
||||
# enable no-external flag for lcov, if available.
|
||||
if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG)
|
||||
set(FLAG "")
|
||||
execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP)
|
||||
string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}")
|
||||
if (GENINFO_RES)
|
||||
set(FLAG "--no-external")
|
||||
endif ()
|
||||
|
||||
set(GENINFO_EXTERN_FLAG "${FLAG}"
|
||||
CACHE STRING "Geninfo flag to exclude system sources.")
|
||||
endif ()
|
||||
|
||||
# If Lcov was not found, exit module now.
|
||||
if (NOT LCOV_FOUND)
|
||||
return()
|
||||
endif (NOT LCOV_FOUND)
|
||||
|
||||
|
||||
|
||||
|
||||
# Create directories to be used.
|
||||
file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT})
|
||||
file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE})
|
||||
|
||||
set(LCOV_REMOVE_PATTERNS "")
|
||||
|
||||
# This function will merge lcov files to a single target file. Additional lcov
|
||||
# flags may be set with setting LCOV_EXTRA_FLAGS before calling this function.
|
||||
function (lcov_merge_files OUTFILE ...)
|
||||
# Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files.
|
||||
list(REMOVE_AT ARGV 0)
|
||||
|
||||
# Generate merged file.
|
||||
string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}")
|
||||
add_custom_command(OUTPUT "${OUTFILE}.raw"
|
||||
COMMAND cat ${ARGV} > ${OUTFILE}.raw
|
||||
DEPENDS ${ARGV}
|
||||
COMMENT "Generating ${FILE_REL}"
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT "${OUTFILE}"
|
||||
COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE}
|
||||
--base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS}
|
||||
COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS}
|
||||
--output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS}
|
||||
DEPENDS ${OUTFILE}.raw
|
||||
COMMENT "Post-processing ${FILE_REL}"
|
||||
)
|
||||
endfunction ()
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target to generate initial coverage reports for all targets.
|
||||
# This target will be used to generate the global initial info file, which is
|
||||
# used to gather even empty report data.
|
||||
if (NOT TARGET lcov-capture-init)
|
||||
add_custom_target(lcov-capture-init)
|
||||
set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "")
|
||||
endif (NOT TARGET lcov-capture-init)
|
||||
|
||||
|
||||
# This function will add initial capture of coverage data for target <TNAME>,
|
||||
# which is needed to get also data for objects, which were not loaded at
|
||||
# execution time. It will call geninfo for every source file of <TNAME> once and
|
||||
# store the info file in the same directory.
|
||||
function (lcov_capture_initial_tgt TNAME)
|
||||
# We don't have to check, if the target has support for coverage, thus this
|
||||
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
||||
# have to determine which gcov binary to use.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(SOURCES "")
|
||||
set(TCOMPILER "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
if (NOT "${FILE}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (NOT "${LANG}" STREQUAL "")
|
||||
list(APPEND SOURCES "${FILE}")
|
||||
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# If no gcov binary was found, coverage data can't be evaluated.
|
||||
if (NOT GCOV_${TCOMPILER}_BIN)
|
||||
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
||||
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
||||
|
||||
|
||||
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
||||
set(GENINFO_FILES "")
|
||||
foreach(FILE ${SOURCES})
|
||||
# generate empty coverage files
|
||||
set(OUTFILE "${TDIR}/${FILE}.info.init")
|
||||
list(APPEND GENINFO_FILES ${OUTFILE})
|
||||
|
||||
add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN}
|
||||
--quiet --base-directory ${PROJECT_SOURCE_DIR} --initial
|
||||
--gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE}
|
||||
${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno
|
||||
DEPENDS ${TNAME}
|
||||
COMMENT "Capturing initial coverage data for ${FILE}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Concatenate all files generated by geninfo to a single file per target.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info")
|
||||
set(LCOV_EXTRA_FLAGS "--initial")
|
||||
lcov_merge_files("${OUTFILE}" ${GENINFO_FILES})
|
||||
add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE})
|
||||
|
||||
# add geninfo file generation to global lcov-geninfo target
|
||||
add_dependencies(lcov-capture-init ${TNAME}-capture-init)
|
||||
set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}"
|
||||
"${OUTFILE}" CACHE INTERNAL ""
|
||||
)
|
||||
endfunction (lcov_capture_initial_tgt)
|
||||
|
||||
|
||||
# This function will generate the global info file for all targets. It has to be
|
||||
# called after all other CMake functions in the root CMakeLists.txt file, to get
|
||||
# a full list of all targets that generate coverage data.
|
||||
function (lcov_capture_initial)
|
||||
# Skip this function (and do not create the following targets), if there are
|
||||
# no input files.
|
||||
if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# Add a new target to merge the files of all targets.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info")
|
||||
lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES})
|
||||
add_custom_target(lcov-geninfo-init ALL DEPENDS ${OUTFILE}
|
||||
lcov-capture-init
|
||||
)
|
||||
endfunction (lcov_capture_initial)
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target to generate coverage reports for all targets. This
|
||||
# target will be used to generate the global info file.
|
||||
if (NOT TARGET lcov-capture)
|
||||
add_custom_target(lcov-capture)
|
||||
set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "")
|
||||
endif (NOT TARGET lcov-capture)
|
||||
|
||||
|
||||
# This function will add capture of coverage data for target <TNAME>, which is
|
||||
# needed to get also data for objects, which were not loaded at execution time.
|
||||
# It will call geninfo for every source file of <TNAME> once and store the info
|
||||
# file in the same directory.
|
||||
function (lcov_capture_tgt TNAME)
|
||||
# We don't have to check, if the target has support for coverage, thus this
|
||||
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
||||
# have to determine which gcov binary to use.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(SOURCES "")
|
||||
set(TCOMPILER "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
if (NOT "${FILE}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (NOT "${LANG}" STREQUAL "")
|
||||
list(APPEND SOURCES "${FILE}")
|
||||
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# If no gcov binary was found, coverage data can't be evaluated.
|
||||
if (NOT GCOV_${TCOMPILER}_BIN)
|
||||
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
||||
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
||||
|
||||
|
||||
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
||||
set(GENINFO_FILES "")
|
||||
foreach(FILE ${SOURCES})
|
||||
# Generate coverage files. If no .gcda file was generated during
|
||||
# execution, the empty coverage file will be used instead.
|
||||
set(OUTFILE "${TDIR}/${FILE}.info")
|
||||
list(APPEND GENINFO_FILES ${OUTFILE})
|
||||
|
||||
add_custom_command(OUTPUT ${OUTFILE}
|
||||
COMMAND test -f "${TDIR}/${FILE}.gcda"
|
||||
&& ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory
|
||||
${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN}
|
||||
--output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG}
|
||||
${TDIR}/${FILE}.gcda
|
||||
|| cp ${OUTFILE}.init ${OUTFILE}
|
||||
DEPENDS ${TNAME} ${TNAME}-capture-init
|
||||
COMMENT "Capturing coverage data for ${FILE}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Concatenate all files generated by geninfo to a single file per target.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info")
|
||||
lcov_merge_files("${OUTFILE}" ${GENINFO_FILES})
|
||||
add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE})
|
||||
|
||||
# add geninfo file generation to global lcov-capture target
|
||||
add_dependencies(lcov-capture ${TNAME}-geninfo)
|
||||
set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL
|
||||
""
|
||||
)
|
||||
|
||||
# Add target for generating html output for this target only.
|
||||
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME})
|
||||
add_custom_target(${TNAME}-genhtml
|
||||
COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR}
|
||||
--baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info
|
||||
--output-directory ${LCOV_HTML_PATH}/${TNAME}
|
||||
--title "${CMAKE_PROJECT_NAME} - target ${TNAME}"
|
||||
${GENHTML_CPPFILT_FLAG} ${OUTFILE}
|
||||
DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init
|
||||
)
|
||||
endfunction (lcov_capture_tgt)
|
||||
|
||||
|
||||
# This function will generate the global info file for all targets. It has to be
|
||||
# called after all other CMake functions in the root CMakeLists.txt file, to get
|
||||
# a full list of all targets that generate coverage data.
|
||||
function (lcov_capture)
|
||||
# Skip this function (and do not create the following targets), if there are
|
||||
# no input files.
|
||||
if ("${LCOV_CAPTURE_FILES}" STREQUAL "")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# Add a new target to merge the files of all targets.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info")
|
||||
lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES})
|
||||
add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture)
|
||||
|
||||
# Add a new global target for all lcov targets. This target could be used to
|
||||
# generate the lcov html output for the whole project instead of calling
|
||||
# <TARGET>-geninfo and <TARGET>-genhtml for each target. It will also be
|
||||
# used to generate a html site for all project data together instead of one
|
||||
# for each target.
|
||||
if (NOT TARGET lcov)
|
||||
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets)
|
||||
add_custom_target(lcov
|
||||
COMMAND ${GENHTML_BIN} --quiet --sort
|
||||
--baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info
|
||||
--output-directory ${LCOV_HTML_PATH}/all_targets
|
||||
--title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}"
|
||||
${GENHTML_CPPFILT_FLAG} ${OUTFILE}
|
||||
DEPENDS lcov-geninfo-init lcov-geninfo
|
||||
)
|
||||
endif ()
|
||||
endfunction (lcov_capture)
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target to generate the lcov html report for the whole project
|
||||
# instead of calling <TARGET>-genhtml for each target (to create an own report
|
||||
# for each target). Instead of the lcov target it does not require geninfo for
|
||||
# all targets, so you have to call <TARGET>-geninfo to generate the info files
|
||||
# the targets you'd like to have in your report or lcov-geninfo for generating
|
||||
# info files for all targets before calling lcov-genhtml.
|
||||
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets)
|
||||
if (NOT TARGET lcov-genhtml)
|
||||
add_custom_target(lcov-genhtml
|
||||
COMMAND ${GENHTML_BIN}
|
||||
--quiet
|
||||
--output-directory ${LCOV_HTML_PATH}/selected_targets
|
||||
--title \"${CMAKE_PROJECT_NAME} - targets `find
|
||||
${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name
|
||||
\"all_targets.info\" -exec basename {} .info \\\;`\"
|
||||
--prefix ${PROJECT_SOURCE_DIR}
|
||||
--sort
|
||||
${GENHTML_CPPFILT_FLAG}
|
||||
`find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name
|
||||
\"all_targets.info\"`
|
||||
)
|
||||
endif (NOT TARGET lcov-genhtml)
|
||||
258
tests/catch2/CMake/Findcodecov.cmake
Normal file
258
tests/catch2/CMake/Findcodecov.cmake
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
|
||||
# Add an option to choose, if coverage should be enabled or not. If enabled
|
||||
# marked targets will be build with coverage support and appropriate targets
|
||||
# will be added. If disabled coverage will be ignored for *ALL* targets.
|
||||
option(ENABLE_COVERAGE "Enable coverage build." OFF)
|
||||
|
||||
set(COVERAGE_FLAG_CANDIDATES
|
||||
# gcc and clang
|
||||
"-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
|
||||
# gcc and clang fallback
|
||||
"-O0 -g --coverage"
|
||||
)
|
||||
|
||||
|
||||
# Add coverage support for target ${TNAME} and register target for coverage
|
||||
# evaluation. If coverage is disabled or not supported, this function will
|
||||
# simply do nothing.
|
||||
#
|
||||
# Note: This function is only a wrapper to define this function always, even if
|
||||
# coverage is not supported by the compiler or disabled. This function must
|
||||
# be defined here, because the module will be exited, if there is no coverage
|
||||
# support by the compiler or it is disabled by the user.
|
||||
function (add_coverage TNAME)
|
||||
# only add coverage for target, if coverage is support and enabled.
|
||||
if (ENABLE_COVERAGE)
|
||||
foreach (TNAME ${ARGV})
|
||||
add_coverage_target(${TNAME})
|
||||
endforeach ()
|
||||
endif ()
|
||||
endfunction (add_coverage)
|
||||
|
||||
|
||||
# Add global target to gather coverage information after all targets have been
|
||||
# added. Other evaluation functions could be added here, after checks for the
|
||||
# specific module have been passed.
|
||||
#
|
||||
# Note: This function is only a wrapper to define this function always, even if
|
||||
# coverage is not supported by the compiler or disabled. This function must
|
||||
# be defined here, because the module will be exited, if there is no coverage
|
||||
# support by the compiler or it is disabled by the user.
|
||||
function (coverage_evaluate)
|
||||
# add lcov evaluation
|
||||
if (LCOV_FOUND)
|
||||
lcov_capture_initial()
|
||||
lcov_capture()
|
||||
endif (LCOV_FOUND)
|
||||
endfunction ()
|
||||
|
||||
|
||||
# Exit this module, if coverage is disabled. add_coverage is defined before this
|
||||
# return, so this module can be exited now safely without breaking any build-
|
||||
# scripts.
|
||||
if (NOT ENABLE_COVERAGE)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
|
||||
|
||||
|
||||
# Find the reuired flags foreach language.
|
||||
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
|
||||
set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY})
|
||||
|
||||
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
foreach (LANG ${ENABLED_LANGUAGES})
|
||||
# Coverage flags are not dependent on language, but the used compiler. So
|
||||
# instead of searching flags foreach language, search flags foreach compiler
|
||||
# used.
|
||||
set(COMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
if (NOT COVERAGE_${COMPILER}_FLAGS)
|
||||
foreach (FLAG ${COVERAGE_FLAG_CANDIDATES})
|
||||
if(NOT CMAKE_REQUIRED_QUIET)
|
||||
message(STATUS "Try ${COMPILER} code coverage flag = [${FLAG}]")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "${FLAG}")
|
||||
unset(COVERAGE_FLAG_DETECTED CACHE)
|
||||
|
||||
if (${LANG} STREQUAL "C")
|
||||
include(CheckCCompilerFlag)
|
||||
check_c_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED)
|
||||
|
||||
elseif (${LANG} STREQUAL "CXX")
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED)
|
||||
|
||||
elseif (${LANG} STREQUAL "Fortran")
|
||||
# CheckFortranCompilerFlag was introduced in CMake 3.x. To be
|
||||
# compatible with older Cmake versions, we will check if this
|
||||
# module is present before we use it. Otherwise we will define
|
||||
# Fortran coverage support as not available.
|
||||
include(CheckFortranCompilerFlag OPTIONAL
|
||||
RESULT_VARIABLE INCLUDED)
|
||||
if (INCLUDED)
|
||||
check_fortran_compiler_flag("${FLAG}"
|
||||
COVERAGE_FLAG_DETECTED)
|
||||
elseif (NOT CMAKE_REQUIRED_QUIET)
|
||||
message("-- Performing Test COVERAGE_FLAG_DETECTED")
|
||||
message("-- Performing Test COVERAGE_FLAG_DETECTED - Failed"
|
||||
" (Check not supported)")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (COVERAGE_FLAG_DETECTED)
|
||||
set(COVERAGE_${COMPILER}_FLAGS "${FLAG}"
|
||||
CACHE STRING "${COMPILER} flags for code coverage.")
|
||||
mark_as_advanced(COVERAGE_${COMPILER}_FLAGS)
|
||||
break()
|
||||
else ()
|
||||
message(WARNING "Code coverage is not available for ${COMPILER}"
|
||||
" compiler. Targets using this compiler will be "
|
||||
"compiled without it.")
|
||||
endif ()
|
||||
endforeach ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
|
||||
|
||||
|
||||
|
||||
|
||||
# Helper function to get the language of a source file.
|
||||
function (codecov_lang_of_source FILE RETURN_VAR)
|
||||
get_filename_component(FILE_EXT "${FILE}" EXT)
|
||||
string(TOLOWER "${FILE_EXT}" FILE_EXT)
|
||||
string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT)
|
||||
|
||||
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
foreach (LANG ${ENABLED_LANGUAGES})
|
||||
list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP)
|
||||
if (NOT ${TEMP} EQUAL -1)
|
||||
set(${RETURN_VAR} "${LANG}" PARENT_SCOPE)
|
||||
return()
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
set(${RETURN_VAR} "" PARENT_SCOPE)
|
||||
endfunction ()
|
||||
|
||||
|
||||
# Helper function to get the relative path of the source file destination path.
|
||||
# This path is needed by FindGcov and FindLcov cmake files to locate the
|
||||
# captured data.
|
||||
function (codecov_path_of_source FILE RETURN_VAR)
|
||||
string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _source ${FILE})
|
||||
|
||||
# If expression was found, SOURCEFILE is a generator-expression for an
|
||||
# object library. Currently we found no way to call this function automatic
|
||||
# for the referenced target, so it must be called in the directoryso of the
|
||||
# object library definition.
|
||||
if (NOT "${_source}" STREQUAL "")
|
||||
set(${RETURN_VAR} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
|
||||
string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" FILE "${FILE}")
|
||||
if(IS_ABSOLUTE ${FILE})
|
||||
file(RELATIVE_PATH FILE ${CMAKE_CURRENT_SOURCE_DIR} ${FILE})
|
||||
endif()
|
||||
|
||||
# get the right path for file
|
||||
string(REPLACE ".." "__" PATH "${FILE}")
|
||||
|
||||
set(${RETURN_VAR} "${PATH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
|
||||
# Add coverage support for target ${TNAME} and register target for coverage
|
||||
# evaluation.
|
||||
function(add_coverage_target TNAME)
|
||||
# Check if all sources for target use the same compiler. If a target uses
|
||||
# e.g. C and Fortran mixed and uses different compilers (e.g. clang and
|
||||
# gfortran) this can trigger huge problems, because different compilers may
|
||||
# use different implementations for code coverage.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(TARGET_COMPILER "")
|
||||
set(ADDITIONAL_FILES "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
# If expression was found, FILE is a generator-expression for an object
|
||||
# library. Object libraries will be ignored.
|
||||
string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE})
|
||||
if ("${_file}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (LANG)
|
||||
list(APPEND TARGET_COMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
|
||||
list(APPEND ADDITIONAL_FILES "${FILE}.gcno")
|
||||
list(APPEND ADDITIONAL_FILES "${FILE}.gcda")
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
list(REMOVE_DUPLICATES TARGET_COMPILER)
|
||||
list(LENGTH TARGET_COMPILER NUM_COMPILERS)
|
||||
|
||||
if (NUM_COMPILERS GREATER 1)
|
||||
message(WARNING "Can't use code coverage for target ${TNAME}, because "
|
||||
"it will be compiled by incompatible compilers. Target will be "
|
||||
"compiled without code coverage.")
|
||||
return()
|
||||
|
||||
elseif (NUM_COMPILERS EQUAL 0)
|
||||
message(WARNING "Can't use code coverage for target ${TNAME}, because "
|
||||
"it uses an unknown compiler. Target will be compiled without "
|
||||
"code coverage.")
|
||||
return()
|
||||
|
||||
elseif (NOT DEFINED "COVERAGE_${TARGET_COMPILER}_FLAGS")
|
||||
# A warning has been printed before, so just return if flags for this
|
||||
# compiler aren't available.
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
# enable coverage for target
|
||||
set_property(TARGET ${TNAME} APPEND_STRING
|
||||
PROPERTY COMPILE_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}")
|
||||
set_property(TARGET ${TNAME} APPEND_STRING
|
||||
PROPERTY LINK_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}")
|
||||
|
||||
|
||||
# Add gcov files generated by compiler to clean target.
|
||||
set(CLEAN_FILES "")
|
||||
foreach (FILE ${ADDITIONAL_FILES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
list(APPEND CLEAN_FILES "CMakeFiles/${TNAME}.dir/${FILE}")
|
||||
endforeach()
|
||||
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${CLEAN_FILES}")
|
||||
|
||||
|
||||
add_gcov_target(${TNAME})
|
||||
add_lcov_target(${TNAME})
|
||||
endfunction(add_coverage_target)
|
||||
|
||||
|
||||
|
||||
|
||||
# Include modules for parsing the collected data and output it in a readable
|
||||
# format (like gcov and lcov).
|
||||
find_package(Gcov)
|
||||
find_package(Lcov)
|
||||
10
tests/catch2/CMake/catch2-with-main.pc.in
Normal file
10
tests/catch2/CMake/catch2-with-main.pc.in
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=${prefix}/@lib_dir@
|
||||
pkg_version=@Catch2_VERSION@
|
||||
|
||||
Name: Catch2 with main function
|
||||
Description: A modern, C++-native test framework for C++14 and above (links in default main)
|
||||
URL: https://github.com/catchorg/Catch2
|
||||
Version: ${pkg_version}
|
||||
Requires: catch2 = ${pkg_version}
|
||||
Libs: -L${libdir} -l@lib_name@
|
||||
11
tests/catch2/CMake/catch2.pc.in
Normal file
11
tests/catch2/CMake/catch2.pc.in
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
includedir=${prefix}/@include_dir@
|
||||
libdir=${prefix}/@lib_dir@
|
||||
|
||||
Name: Catch2
|
||||
Description: A modern, C++-native, test framework for C++14 and above
|
||||
URL: https://github.com/catchorg/Catch2
|
||||
Version: @Catch2_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -l@lib_name@
|
||||
56
tests/catch2/CMake/llvm-cov-wrapper
Executable file
56
tests/catch2/CMake/llvm-cov-wrapper
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
if [ -z "$LLVM_COV_BIN" ]
|
||||
then
|
||||
echo "LLVM_COV_BIN not set!" >& 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Get LLVM version to find out.
|
||||
LLVM_VERSION=$($LLVM_COV_BIN -version | grep -i "LLVM version" \
|
||||
| sed "s/^\([A-Za-z ]*\)\([0-9]\).\([0-9]\).*$/\2.\3/g")
|
||||
|
||||
if [ "$1" = "-v" ]
|
||||
then
|
||||
echo "llvm-cov-wrapper $LLVM_VERSION"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$LLVM_VERSION" ]
|
||||
then
|
||||
MAJOR=$(echo $LLVM_VERSION | cut -d'.' -f1)
|
||||
MINOR=$(echo $LLVM_VERSION | cut -d'.' -f2)
|
||||
|
||||
if [ $MAJOR -eq 3 ] && [ $MINOR -le 4 ]
|
||||
then
|
||||
if [ -f "$1" ]
|
||||
then
|
||||
filename=$(basename "$1")
|
||||
extension="${filename##*.}"
|
||||
|
||||
case "$extension" in
|
||||
"gcno") exec $LLVM_COV_BIN --gcno="$1" ;;
|
||||
"gcda") exec $LLVM_COV_BIN --gcda="$1" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $MAJOR -eq 3 ] && [ $MINOR -le 5 ]
|
||||
then
|
||||
exec $LLVM_COV_BIN $@
|
||||
fi
|
||||
fi
|
||||
|
||||
exec $LLVM_COV_BIN gcov $@
|
||||
230
tests/catch2/CMakeLists.txt
Normal file
230
tests/catch2/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# detect if Catch is being bundled,
|
||||
# disable testsuite in that case
|
||||
if(NOT DEFINED PROJECT_NAME)
|
||||
set(NOT_SUBPROJECT ON)
|
||||
else()
|
||||
set(NOT_SUBPROJECT OFF)
|
||||
endif()
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
option(CATCH_INSTALL_DOCS "Install documentation alongside library" ON)
|
||||
option(CATCH_INSTALL_EXTRAS "Install extras (CMake scripts, debugger helpers) alongside library" ON)
|
||||
option(CATCH_DEVELOPMENT_BUILD "Build tests, enable warnings, enable Werror, etc" OFF)
|
||||
option(CATCH_ENABLE_REPRODUCIBLE_BUILD "Add compiler flags for improving build reproducibility" ON)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
cmake_dependent_option(CATCH_BUILD_TESTING "Build the SelfTest project" ON "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_BUILD_EXAMPLES "Build code examples" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_BUILD_EXTRA_TESTS "Build extra tests" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_BUILD_FUZZERS "Build fuzzers" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_BUILD_BENCHMARKS "Build the benchmarks" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_ENABLE_WERROR "Enables Werror during build" ON "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_BUILD_SURROGATES "Enable generating and building surrogate TUs for the main headers" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_ENABLE_CONFIGURE_TESTS "Enable CMake configuration tests. WARNING: VERY EXPENSIVE" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
cmake_dependent_option(CATCH_ENABLE_CMAKE_HELPER_TESTS "Enable CMake helper tests. WARNING: VERY EXPENSIVE" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||
|
||||
# Catch2's build breaks if done in-tree. You probably should not build
|
||||
# things in tree anyway, but we can allow projects that include Catch2
|
||||
# as a subproject to build in-tree as long as it is not in our tree.
|
||||
if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
message(FATAL_ERROR "Building in-source is not supported! Create a build dir and remove ${CMAKE_SOURCE_DIR}/CMakeCache.txt")
|
||||
endif()
|
||||
|
||||
project(Catch2
|
||||
VERSION 3.11.0 # CML version placeholder, don't delete
|
||||
LANGUAGES CXX
|
||||
HOMEPAGE_URL "https://github.com/catchorg/Catch2"
|
||||
DESCRIPTION "A modern, C++-native, unit test framework."
|
||||
)
|
||||
|
||||
# Provide path for scripts. We first add path to the scripts we don't use,
|
||||
# but projects including us might, and set the path up to parent scope.
|
||||
# Then we also add path that we use to configure the project, but is of
|
||||
# no use to top level projects.
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/extras")
|
||||
if(NOT NOT_SUBPROJECT)
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE)
|
||||
endif()
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CatchConfigOptions)
|
||||
if(CATCH_DEVELOPMENT_BUILD)
|
||||
include(CTest)
|
||||
endif()
|
||||
|
||||
# This variable is used in some subdirectories, so we need it here, rather
|
||||
# than later in the install block
|
||||
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
|
||||
|
||||
# We have some Windows builds that test `wmain` entry point,
|
||||
# and we need this change to be present in all binaries that
|
||||
# are built during these tests, so this is required here, before
|
||||
# the subdirectories are added.
|
||||
if(CATCH_TEST_USE_WMAIN)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
||||
endif()
|
||||
|
||||
# Basic paths
|
||||
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(SOURCES_DIR ${CATCH_DIR}/src/catch2)
|
||||
set(SELF_TEST_DIR ${CATCH_DIR}/tests/SelfTest)
|
||||
|
||||
# We need to bring-in the variables defined there to this scope
|
||||
add_subdirectory(src)
|
||||
|
||||
if (CATCH_BUILD_BENCHMARKS)
|
||||
set(CMAKE_FOLDER "benchmarks")
|
||||
add_subdirectory(benchmarks)
|
||||
endif()
|
||||
|
||||
# Build tests only if requested
|
||||
if(BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
if(NOT TARGET Python3::Interpreter)
|
||||
message(FATAL_ERROR "Python not found, but required for tests")
|
||||
endif()
|
||||
set(CMAKE_FOLDER "tests")
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if(CATCH_BUILD_EXAMPLES)
|
||||
set(CMAKE_FOLDER "Examples")
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
if(CATCH_BUILD_EXTRA_TESTS)
|
||||
set(CMAKE_FOLDER "tests/ExtraTests")
|
||||
add_subdirectory(tests/ExtraTests)
|
||||
endif()
|
||||
|
||||
if(CATCH_BUILD_FUZZERS)
|
||||
set(CMAKE_FOLDER "fuzzing")
|
||||
add_subdirectory(fuzzing)
|
||||
endif()
|
||||
|
||||
if(CATCH_DEVELOPMENT_BUILD)
|
||||
set(CATCH_ALL_TARGETS ${CATCH_IMPL_TARGETS} ${CATCH_TEST_TARGETS})
|
||||
add_warnings_to_targets("${CATCH_ALL_TARGETS}")
|
||||
# After we added the noreturn hint to FAIL and SKIP, Clang became
|
||||
# extremely good at diagnosing tests that test these macros as being
|
||||
# noreturn, but not marked as such. This made the warning useless for
|
||||
# our test files.
|
||||
add_cxx_flag_if_supported_to_targets("-Wno-missing-noreturn" "${CATCH_TEST_TARGETS}")
|
||||
endif()
|
||||
|
||||
# Only perform the installation steps when Catch is not being used as
|
||||
# a subproject via `add_subdirectory`, or the destinations will break,
|
||||
# see https://github.com/catchorg/Catch2/issues/1373
|
||||
if(NOT_SUBPROJECT)
|
||||
configure_package_config_file(
|
||||
${CMAKE_CURRENT_LIST_DIR}/CMake/Catch2Config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake
|
||||
INSTALL_DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||
COMPATIBILITY
|
||||
SameMajorVersion
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||
DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
|
||||
# Install documentation
|
||||
if(CATCH_INSTALL_DOCS)
|
||||
install(
|
||||
DIRECTORY
|
||||
docs/
|
||||
DESTINATION
|
||||
"${CMAKE_INSTALL_DOCDIR}"
|
||||
PATTERN "doxygen" EXCLUDE
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CATCH_INSTALL_EXTRAS)
|
||||
# Install CMake scripts
|
||||
install(
|
||||
FILES
|
||||
"extras/ParseAndAddCatchTests.cmake"
|
||||
"extras/Catch.cmake"
|
||||
"extras/CatchAddTests.cmake"
|
||||
"extras/CatchShardTests.cmake"
|
||||
"extras/CatchShardTestsImpl.cmake"
|
||||
DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
|
||||
# Install debugger helpers
|
||||
install(
|
||||
FILES
|
||||
"extras/gdbinit"
|
||||
"extras/lldbinit"
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_DATAROOTDIR}/Catch2
|
||||
)
|
||||
endif()
|
||||
|
||||
## Provide some pkg-config integration
|
||||
set(PKGCONFIG_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
|
||||
CACHE PATH "Path where catch2.pc is installed"
|
||||
)
|
||||
|
||||
# Generate the pkg-config files
|
||||
# To understand the script below, you have to understand that it works in two steps.
|
||||
# 1) A CMake script is generated at configuration time
|
||||
# 2) It is executed at install time.
|
||||
# And both of these have access to different parts of the information we need.
|
||||
#
|
||||
# Further, the variables before "[[" are expanded at configuration time,
|
||||
# while the ones inside the [[]] block are expanded at script execution (install) time.
|
||||
string(
|
||||
JOIN "\n"
|
||||
install_script
|
||||
"set(install_pkgconfdir \"${PKGCONFIG_INSTALL_DIR}\")"
|
||||
"set(impl_pc_file \"${CMAKE_CURRENT_SOURCE_DIR}/CMake/catch2.pc.in\")"
|
||||
"set(main_pc_file \"${CMAKE_CURRENT_SOURCE_DIR}/CMake/catch2-with-main.pc.in\")"
|
||||
"set(Catch2_VERSION ${Catch2_VERSION})"
|
||||
"set(include_dir \"${CMAKE_INSTALL_INCLUDEDIR}\")"
|
||||
"set(lib_dir \"${CMAKE_INSTALL_LIBDIR}\")"
|
||||
[[
|
||||
message(STATUS "DESTDIR: $ENV{DESTDIR}")
|
||||
set(DESTDIR_PREFIX "")
|
||||
if (DEFINED ENV{DESTDIR})
|
||||
set(DESTDIR_PREFIX "$ENV{DESTDIR}")
|
||||
endif ()
|
||||
message(STATUS "PREFIX: ${DESTDIR_PREFIX}")
|
||||
set(lib_name "$<TARGET_FILE_BASE_NAME:Catch2>")
|
||||
configure_file(
|
||||
"${impl_pc_file}"
|
||||
"${DESTDIR_PREFIX}${CMAKE_INSTALL_PREFIX}/${install_pkgconfdir}/catch2.pc"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
set(lib_name "$<TARGET_FILE_BASE_NAME:Catch2WithMain>")
|
||||
configure_file(
|
||||
"${main_pc_file}"
|
||||
"${DESTDIR_PREFIX}${CMAKE_INSTALL_PREFIX}/${install_pkgconfdir}/catch2-with-main.pc"
|
||||
@ONLY
|
||||
)
|
||||
]]
|
||||
)
|
||||
install(CODE "${install_script}")
|
||||
|
||||
set(CPACK_PACKAGE_CONTACT "https://github.com/catchorg/Catch2/")
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
40
tests/catch2/CMakePresets.json
Normal file
40
tests/catch2/CMakePresets.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"version": 3,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "basic-tests",
|
||||
"binaryDir": "build",
|
||||
"installDir": "build/install",
|
||||
"displayName": "Basic development build",
|
||||
"description": "Enables development build with basic tests that are cheap to build and run",
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_EXTENSIONS": "OFF",
|
||||
"CMAKE_CXX_STANDARD_REQUIRED": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
|
||||
"CATCH_DEVELOPMENT_BUILD": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "most-tests",
|
||||
"inherits": "basic-tests",
|
||||
"displayName": "Full development build",
|
||||
"description": "Enables development build with extended set of tests (still relatively cheap to build)",
|
||||
"cacheVariables": {
|
||||
"CATCH_BUILD_EXAMPLES": "ON",
|
||||
"CATCH_BUILD_EXTRA_TESTS": "ON",
|
||||
"CATCH_BUILD_SURROGATES": "ON",
|
||||
"CATCH_BUILD_BENCHMARKS": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "all-tests",
|
||||
"inherits": "most-tests",
|
||||
"displayName": "Full development build",
|
||||
"description": "Enables development build with examples and ALL tests",
|
||||
"cacheVariables": {
|
||||
"CATCH_ENABLE_CONFIGURE_TESTS": "ON",
|
||||
"CATCH_ENABLE_CMAKE_HELPER_TESTS": "ON"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
1
tests/catch2/COMMIT
Normal file
1
tests/catch2/COMMIT
Normal file
|
|
@ -0,0 +1 @@
|
|||
31ee3beb0a474463e0101674c22f2fef0311d601
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
2.9.2 g2c869e1
|
||||
|
||||
17937
tests/catch2/catch.hpp
17937
tests/catch2/catch.hpp
File diff suppressed because it is too large
Load diff
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Created by Justin R. Wilson on 2/19/2017.
|
||||
* Copyright 2017 Justin R. Wilson. All rights reserved.
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
|
||||
|
||||
// Don't #include any Catch headers here - we can assume they are already
|
||||
// included before this header.
|
||||
// This is not good practice in general but is necessary in this case so this
|
||||
// file can be distributed as a single header that works with the main
|
||||
// Catch single header.
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct AutomakeReporter : StreamingReporterBase<AutomakeReporter> {
|
||||
AutomakeReporter( ReporterConfig const& _config )
|
||||
: StreamingReporterBase( _config )
|
||||
{}
|
||||
|
||||
~AutomakeReporter() override;
|
||||
|
||||
static std::string getDescription() {
|
||||
return "Reports test results in the format of Automake .trs files";
|
||||
}
|
||||
|
||||
void assertionStarting( AssertionInfo const& ) override {}
|
||||
|
||||
bool assertionEnded( AssertionStats const& /*_assertionStats*/ ) override { return true; }
|
||||
|
||||
void testCaseEnded( TestCaseStats const& _testCaseStats ) override {
|
||||
// Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
|
||||
stream << ":test-result: ";
|
||||
if (_testCaseStats.totals.assertions.allPassed()) {
|
||||
stream << "PASS";
|
||||
} else if (_testCaseStats.totals.assertions.allOk()) {
|
||||
stream << "XFAIL";
|
||||
} else {
|
||||
stream << "FAIL";
|
||||
}
|
||||
stream << ' ' << _testCaseStats.testInfo.name << '\n';
|
||||
StreamingReporterBase::testCaseEnded( _testCaseStats );
|
||||
}
|
||||
|
||||
void skipTest( TestCaseInfo const& testInfo ) override {
|
||||
stream << ":test-result: SKIP " << testInfo.name << '\n';
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
AutomakeReporter::~AutomakeReporter() {}
|
||||
#endif
|
||||
|
||||
CATCH_REGISTER_REPORTER( "automake", AutomakeReporter)
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
/*
|
||||
* Created by Colton Wolkins on 2015-08-15.
|
||||
* Copyright 2015 Martin Moene. All rights reserved.
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
|
||||
|
||||
|
||||
// Don't #include any Catch headers here - we can assume they are already
|
||||
// included before this header.
|
||||
// This is not good practice in general but is necessary in this case so this
|
||||
// file can be distributed as a single header that works with the main
|
||||
// Catch single header.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TAPReporter : StreamingReporterBase<TAPReporter> {
|
||||
|
||||
using StreamingReporterBase::StreamingReporterBase;
|
||||
|
||||
~TAPReporter() override;
|
||||
|
||||
static std::string getDescription() {
|
||||
return "Reports test results in TAP format, suitable for test harnesses";
|
||||
}
|
||||
|
||||
ReporterPreferences getPreferences() const override {
|
||||
return m_reporterPrefs;
|
||||
}
|
||||
|
||||
void noMatchingTestCases( std::string const& spec ) override {
|
||||
stream << "# No test cases matched '" << spec << "'" << std::endl;
|
||||
}
|
||||
|
||||
void assertionStarting( AssertionInfo const& ) override {}
|
||||
|
||||
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
||||
++counter;
|
||||
|
||||
stream << "# " << currentTestCaseInfo->name << std::endl;
|
||||
AssertionPrinter printer( stream, _assertionStats, counter );
|
||||
printer.print();
|
||||
|
||||
stream << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void testRunEnded( TestRunStats const& _testRunStats ) override {
|
||||
printTotals( _testRunStats.totals );
|
||||
stream << "\n" << std::endl;
|
||||
StreamingReporterBase::testRunEnded( _testRunStats );
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t counter = 0;
|
||||
class AssertionPrinter {
|
||||
public:
|
||||
AssertionPrinter& operator= ( AssertionPrinter const& ) = delete;
|
||||
AssertionPrinter( AssertionPrinter const& ) = delete;
|
||||
AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter )
|
||||
: stream( _stream )
|
||||
, result( _stats.assertionResult )
|
||||
, messages( _stats.infoMessages )
|
||||
, itMessage( _stats.infoMessages.begin() )
|
||||
, printInfoMessages( true )
|
||||
, counter(_counter)
|
||||
{}
|
||||
|
||||
void print() {
|
||||
itMessage = messages.begin();
|
||||
|
||||
switch( result.getResultType() ) {
|
||||
case ResultWas::Ok:
|
||||
printResultType( passedString() );
|
||||
printOriginalExpression();
|
||||
printReconstructedExpression();
|
||||
if ( ! result.hasExpression() )
|
||||
printRemainingMessages( Colour::None );
|
||||
else
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::ExpressionFailed:
|
||||
if (result.isOk()) {
|
||||
printResultType(passedString());
|
||||
} else {
|
||||
printResultType(failedString());
|
||||
}
|
||||
printOriginalExpression();
|
||||
printReconstructedExpression();
|
||||
if (result.isOk()) {
|
||||
printIssue(" # TODO");
|
||||
}
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::ThrewException:
|
||||
printResultType( failedString() );
|
||||
printIssue( "unexpected exception with message:" );
|
||||
printMessage();
|
||||
printExpressionWas();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::FatalErrorCondition:
|
||||
printResultType( failedString() );
|
||||
printIssue( "fatal error condition with message:" );
|
||||
printMessage();
|
||||
printExpressionWas();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::DidntThrowException:
|
||||
printResultType( failedString() );
|
||||
printIssue( "expected exception, got none" );
|
||||
printExpressionWas();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::Info:
|
||||
printResultType( "info" );
|
||||
printMessage();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::Warning:
|
||||
printResultType( "warning" );
|
||||
printMessage();
|
||||
printRemainingMessages();
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
printResultType( failedString() );
|
||||
printIssue( "explicitly" );
|
||||
printRemainingMessages( Colour::None );
|
||||
break;
|
||||
// These cases are here to prevent compiler warnings
|
||||
case ResultWas::Unknown:
|
||||
case ResultWas::FailureBit:
|
||||
case ResultWas::Exception:
|
||||
printResultType( "** internal error **" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static Colour::Code dimColour() { return Colour::FileName; }
|
||||
|
||||
static const char* failedString() { return "not ok"; }
|
||||
static const char* passedString() { return "ok"; }
|
||||
|
||||
void printSourceInfo() const {
|
||||
Colour colourGuard( dimColour() );
|
||||
stream << result.getSourceInfo() << ":";
|
||||
}
|
||||
|
||||
void printResultType( std::string const& passOrFail ) const {
|
||||
if( !passOrFail.empty() ) {
|
||||
stream << passOrFail << ' ' << counter << " -";
|
||||
}
|
||||
}
|
||||
|
||||
void printIssue( std::string const& issue ) const {
|
||||
stream << " " << issue;
|
||||
}
|
||||
|
||||
void printExpressionWas() {
|
||||
if( result.hasExpression() ) {
|
||||
stream << ";";
|
||||
{
|
||||
Colour colour( dimColour() );
|
||||
stream << " expression was:";
|
||||
}
|
||||
printOriginalExpression();
|
||||
}
|
||||
}
|
||||
|
||||
void printOriginalExpression() const {
|
||||
if( result.hasExpression() ) {
|
||||
stream << " " << result.getExpression();
|
||||
}
|
||||
}
|
||||
|
||||
void printReconstructedExpression() const {
|
||||
if( result.hasExpandedExpression() ) {
|
||||
{
|
||||
Colour colour( dimColour() );
|
||||
stream << " for: ";
|
||||
}
|
||||
std::string expr = result.getExpandedExpression();
|
||||
std::replace( expr.begin(), expr.end(), '\n', ' ');
|
||||
stream << expr;
|
||||
}
|
||||
}
|
||||
|
||||
void printMessage() {
|
||||
if ( itMessage != messages.end() ) {
|
||||
stream << " '" << itMessage->message << "'";
|
||||
++itMessage;
|
||||
}
|
||||
}
|
||||
|
||||
void printRemainingMessages( Colour::Code colour = dimColour() ) {
|
||||
if (itMessage == messages.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// using messages.end() directly (or auto) yields compilation error:
|
||||
std::vector<MessageInfo>::const_iterator itEnd = messages.end();
|
||||
const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
|
||||
|
||||
{
|
||||
Colour colourGuard( colour );
|
||||
stream << " with " << pluralise( N, "message" ) << ":";
|
||||
}
|
||||
|
||||
for(; itMessage != itEnd; ) {
|
||||
// If this assertion is a warning ignore any INFO messages
|
||||
if( printInfoMessages || itMessage->type != ResultWas::Info ) {
|
||||
stream << " '" << itMessage->message << "'";
|
||||
if ( ++itMessage != itEnd ) {
|
||||
Colour colourGuard( dimColour() );
|
||||
stream << " and";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream& stream;
|
||||
AssertionResult const& result;
|
||||
std::vector<MessageInfo> messages;
|
||||
std::vector<MessageInfo>::const_iterator itMessage;
|
||||
bool printInfoMessages;
|
||||
std::size_t counter;
|
||||
};
|
||||
|
||||
void printTotals( const Totals& totals ) const {
|
||||
if( totals.testCases.total() == 0 ) {
|
||||
stream << "1..0 # Skipped: No tests ran.";
|
||||
} else {
|
||||
stream << "1.." << counter;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
TAPReporter::~TAPReporter() {}
|
||||
#endif
|
||||
|
||||
CATCH_REGISTER_REPORTER( "tap", TAPReporter )
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
|
||||
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
* Created by Phil Nash on 19th December 2014
|
||||
* Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
|
||||
|
||||
// Don't #include any Catch headers here - we can assume they are already
|
||||
// included before this header.
|
||||
// This is not good practice in general but is necessary in this case so this
|
||||
// file can be distributed as a single header that works with the main
|
||||
// Catch single header.
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wpadded"
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TeamCityReporter : StreamingReporterBase<TeamCityReporter> {
|
||||
TeamCityReporter( ReporterConfig const& _config )
|
||||
: StreamingReporterBase( _config )
|
||||
{
|
||||
m_reporterPrefs.shouldRedirectStdOut = true;
|
||||
}
|
||||
|
||||
static std::string escape( std::string const& str ) {
|
||||
std::string escaped = str;
|
||||
replaceInPlace( escaped, "|", "||" );
|
||||
replaceInPlace( escaped, "'", "|'" );
|
||||
replaceInPlace( escaped, "\n", "|n" );
|
||||
replaceInPlace( escaped, "\r", "|r" );
|
||||
replaceInPlace( escaped, "[", "|[" );
|
||||
replaceInPlace( escaped, "]", "|]" );
|
||||
return escaped;
|
||||
}
|
||||
~TeamCityReporter() override;
|
||||
|
||||
static std::string getDescription() {
|
||||
return "Reports test results as TeamCity service messages";
|
||||
}
|
||||
|
||||
void skipTest( TestCaseInfo const& /* testInfo */ ) override {
|
||||
}
|
||||
|
||||
void noMatchingTestCases( std::string const& /* spec */ ) override {}
|
||||
|
||||
void testGroupStarting( GroupInfo const& groupInfo ) override {
|
||||
StreamingReporterBase::testGroupStarting( groupInfo );
|
||||
stream << "##teamcity[testSuiteStarted name='"
|
||||
<< escape( groupInfo.name ) << "']\n";
|
||||
}
|
||||
void testGroupEnded( TestGroupStats const& testGroupStats ) override {
|
||||
StreamingReporterBase::testGroupEnded( testGroupStats );
|
||||
stream << "##teamcity[testSuiteFinished name='"
|
||||
<< escape( testGroupStats.groupInfo.name ) << "']\n";
|
||||
}
|
||||
|
||||
|
||||
void assertionStarting( AssertionInfo const& ) override {}
|
||||
|
||||
bool assertionEnded( AssertionStats const& assertionStats ) override {
|
||||
AssertionResult const& result = assertionStats.assertionResult;
|
||||
if( !result.isOk() ) {
|
||||
|
||||
ReusableStringStream msg;
|
||||
if( !m_headerPrintedForThisSection )
|
||||
printSectionHeader( msg.get() );
|
||||
m_headerPrintedForThisSection = true;
|
||||
|
||||
msg << result.getSourceInfo() << "\n";
|
||||
|
||||
switch( result.getResultType() ) {
|
||||
case ResultWas::ExpressionFailed:
|
||||
msg << "expression failed";
|
||||
break;
|
||||
case ResultWas::ThrewException:
|
||||
msg << "unexpected exception";
|
||||
break;
|
||||
case ResultWas::FatalErrorCondition:
|
||||
msg << "fatal error condition";
|
||||
break;
|
||||
case ResultWas::DidntThrowException:
|
||||
msg << "no exception was thrown where one was expected";
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
msg << "explicit failure";
|
||||
break;
|
||||
|
||||
// We shouldn't get here because of the isOk() test
|
||||
case ResultWas::Ok:
|
||||
case ResultWas::Info:
|
||||
case ResultWas::Warning:
|
||||
CATCH_ERROR( "Internal error in TeamCity reporter" );
|
||||
// These cases are here to prevent compiler warnings
|
||||
case ResultWas::Unknown:
|
||||
case ResultWas::FailureBit:
|
||||
case ResultWas::Exception:
|
||||
CATCH_ERROR( "Not implemented" );
|
||||
}
|
||||
if( assertionStats.infoMessages.size() == 1 )
|
||||
msg << " with message:";
|
||||
if( assertionStats.infoMessages.size() > 1 )
|
||||
msg << " with messages:";
|
||||
for( auto const& messageInfo : assertionStats.infoMessages )
|
||||
msg << "\n \"" << messageInfo.message << "\"";
|
||||
|
||||
|
||||
if( result.hasExpression() ) {
|
||||
msg <<
|
||||
"\n " << result.getExpressionInMacro() << "\n"
|
||||
"with expansion:\n" <<
|
||||
" " << result.getExpandedExpression() << "\n";
|
||||
}
|
||||
|
||||
if( currentTestCaseInfo->okToFail() ) {
|
||||
msg << "- failure ignore as test marked as 'ok to fail'\n";
|
||||
stream << "##teamcity[testIgnored"
|
||||
<< " name='" << escape( currentTestCaseInfo->name )<< "'"
|
||||
<< " message='" << escape( msg.str() ) << "'"
|
||||
<< "]\n";
|
||||
}
|
||||
else {
|
||||
stream << "##teamcity[testFailed"
|
||||
<< " name='" << escape( currentTestCaseInfo->name )<< "'"
|
||||
<< " message='" << escape( msg.str() ) << "'"
|
||||
<< "]\n";
|
||||
}
|
||||
}
|
||||
stream.flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
void sectionStarting( SectionInfo const& sectionInfo ) override {
|
||||
m_headerPrintedForThisSection = false;
|
||||
StreamingReporterBase::sectionStarting( sectionInfo );
|
||||
}
|
||||
|
||||
void testCaseStarting( TestCaseInfo const& testInfo ) override {
|
||||
m_testTimer.start();
|
||||
StreamingReporterBase::testCaseStarting( testInfo );
|
||||
stream << "##teamcity[testStarted name='"
|
||||
<< escape( testInfo.name ) << "']\n";
|
||||
stream.flush();
|
||||
}
|
||||
|
||||
void testCaseEnded( TestCaseStats const& testCaseStats ) override {
|
||||
StreamingReporterBase::testCaseEnded( testCaseStats );
|
||||
if( !testCaseStats.stdOut.empty() )
|
||||
stream << "##teamcity[testStdOut name='"
|
||||
<< escape( testCaseStats.testInfo.name )
|
||||
<< "' out='" << escape( testCaseStats.stdOut ) << "']\n";
|
||||
if( !testCaseStats.stdErr.empty() )
|
||||
stream << "##teamcity[testStdErr name='"
|
||||
<< escape( testCaseStats.testInfo.name )
|
||||
<< "' out='" << escape( testCaseStats.stdErr ) << "']\n";
|
||||
stream << "##teamcity[testFinished name='"
|
||||
<< escape( testCaseStats.testInfo.name ) << "' duration='"
|
||||
<< m_testTimer.getElapsedMilliseconds() << "']\n";
|
||||
stream.flush();
|
||||
}
|
||||
|
||||
private:
|
||||
void printSectionHeader( std::ostream& os ) {
|
||||
assert( !m_sectionStack.empty() );
|
||||
|
||||
if( m_sectionStack.size() > 1 ) {
|
||||
os << getLineOfChars<'-'>() << "\n";
|
||||
|
||||
std::vector<SectionInfo>::const_iterator
|
||||
it = m_sectionStack.begin()+1, // Skip first section (test case)
|
||||
itEnd = m_sectionStack.end();
|
||||
for( ; it != itEnd; ++it )
|
||||
printHeaderString( os, it->name );
|
||||
os << getLineOfChars<'-'>() << "\n";
|
||||
}
|
||||
|
||||
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
|
||||
|
||||
if( !lineInfo.empty() )
|
||||
os << lineInfo << "\n";
|
||||
os << getLineOfChars<'.'>() << "\n\n";
|
||||
}
|
||||
|
||||
// if string has a : in first line will set indent to follow it on
|
||||
// subsequent lines
|
||||
static void printHeaderString( std::ostream& os, std::string const& _string, std::size_t indent = 0 ) {
|
||||
std::size_t i = _string.find( ": " );
|
||||
if( i != std::string::npos )
|
||||
i+=2;
|
||||
else
|
||||
i = 0;
|
||||
os << Column( _string )
|
||||
.indent( indent+i)
|
||||
.initialIndent( indent ) << "\n";
|
||||
}
|
||||
private:
|
||||
bool m_headerPrintedForThisSection = false;
|
||||
Timer m_testTimer;
|
||||
};
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
TeamCityReporter::~TeamCityReporter() {}
|
||||
#endif
|
||||
|
||||
CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter )
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
|
||||
318
tests/catch2/extras/Catch.cmake
Normal file
318
tests/catch2/extras/Catch.cmake
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
Catch
|
||||
-----
|
||||
|
||||
This module defines a function to help use the Catch test framework.
|
||||
|
||||
The :command:`catch_discover_tests` discovers tests by asking the compiled test
|
||||
executable to enumerate its tests. This does not require CMake to be re-run
|
||||
when tests change. However, it may not work in a cross-compiling environment,
|
||||
and setting test properties is less convenient.
|
||||
|
||||
This command is intended to replace use of :command:`add_test` to register
|
||||
tests, and will create a separate CTest test for each Catch test case. Note
|
||||
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||
cannot be shared by multiple test cases executing in the same instance.
|
||||
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||
usually considered as more beneficial. By default, the CTest test name is the
|
||||
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
.. command:: catch_discover_tests
|
||||
|
||||
Automatically add tests with CTest by querying the compiled test executable
|
||||
for available tests::
|
||||
|
||||
catch_discover_tests(target
|
||||
[TEST_SPEC arg1...]
|
||||
[EXTRA_ARGS arg1...]
|
||||
[WORKING_DIRECTORY dir]
|
||||
[TEST_PREFIX prefix]
|
||||
[TEST_SUFFIX suffix]
|
||||
[PROPERTIES name1 value1...]
|
||||
[TEST_LIST var]
|
||||
[REPORTER reporter]
|
||||
[OUTPUT_DIR dir]
|
||||
[OUTPUT_PREFIX prefix]
|
||||
[OUTPUT_SUFFIX suffix]
|
||||
[DISCOVERY_MODE <POST_BUILD|PRE_TEST>]
|
||||
[SKIP_IS_FAILURE]
|
||||
[ADD_TAGS_AS_LABELS]
|
||||
)
|
||||
|
||||
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||
that generates the list of tests by parsing the output from running the test
|
||||
with the ``--list-test-names-only`` argument. This ensures that the full
|
||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||
not necessary to re-run CMake when the list of tests changes.
|
||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||
in order to function in a cross-compiling environment.
|
||||
|
||||
Additionally, setting properties on tests is somewhat less convenient, since
|
||||
the tests are not available at CMake time. Additional test properties may be
|
||||
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||
more fine-grained test control is needed, custom content may be provided
|
||||
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||
directory property. The set of discovered tests is made accessible to such a
|
||||
script via the ``<target>_TESTS`` variable.
|
||||
|
||||
The options are:
|
||||
|
||||
``target``
|
||||
Specifies the Catch executable, which must be a known CMake executable
|
||||
target. CMake will substitute the location of the built executable when
|
||||
running the test.
|
||||
|
||||
``TEST_SPEC arg1...``
|
||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
||||
|
||||
``EXTRA_ARGS arg1...``
|
||||
Any extra arguments to pass on the command line to each test case.
|
||||
|
||||
``WORKING_DIRECTORY dir``
|
||||
Specifies the directory in which to run the discovered test cases. If this
|
||||
option is not provided, the current binary directory is used.
|
||||
|
||||
``TEST_PREFIX prefix``
|
||||
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
||||
case. This can be useful when the same test executable is being used in
|
||||
multiple calls to ``catch_discover_tests()`` but with different
|
||||
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||
|
||||
``TEST_SUFFIX suffix``
|
||||
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||
be specified.
|
||||
|
||||
``PROPERTIES name1 value1...``
|
||||
Specifies additional properties to be set on all tests discovered by this
|
||||
invocation of ``catch_discover_tests``.
|
||||
|
||||
``TEST_LIST var``
|
||||
Make the list of tests available in the variable ``var``, rather than the
|
||||
default ``<target>_TESTS``. This can be useful when the same test
|
||||
executable is being used in multiple calls to ``catch_discover_tests()``.
|
||||
Note that this variable is only available in CTest.
|
||||
|
||||
``REPORTER reporter``
|
||||
Use the specified reporter when running the test case. The reporter will
|
||||
be passed to the Catch executable as ``--reporter reporter``.
|
||||
|
||||
``OUTPUT_DIR dir``
|
||||
If specified, the parameter is passed along as
|
||||
``--out dir/<test_name>`` to Catch executable. The actual file name is the
|
||||
same as the test name. This should be used instead of
|
||||
``EXTRA_ARGS --out foo`` to avoid race conditions writing the result output
|
||||
when using parallel test execution.
|
||||
|
||||
``OUTPUT_PREFIX prefix``
|
||||
May be used in conjunction with ``OUTPUT_DIR``.
|
||||
If specified, ``prefix`` is added to each output file name, like so
|
||||
``--out dir/prefix<test_name>``.
|
||||
|
||||
``OUTPUT_SUFFIX suffix``
|
||||
May be used in conjunction with ``OUTPUT_DIR``.
|
||||
If specified, ``suffix`` is added to each output file name, like so
|
||||
``--out dir/<test_name>suffix``. This can be used to add a file extension to
|
||||
the output e.g. ".xml".
|
||||
|
||||
``DL_PATHS path...``
|
||||
Specifies paths that need to be set for the dynamic linker to find shared
|
||||
libraries/DLLs when running the test executable (PATH/LD_LIBRARY_PATH respectively).
|
||||
These paths will both be set when retrieving the list of test cases from the
|
||||
test executable and when the tests are executed themselves. This requires
|
||||
cmake/ctest >= 3.22.
|
||||
|
||||
``DL_FRAMEWORK_PATHS path...``
|
||||
Specifies paths that need to be set for the dynamic linker to find libraries
|
||||
packaged as frameworks on Apple platforms when running the test executable
|
||||
(DYLD_FRAMEWORK_PATH). These paths will both be set when retrieving the list
|
||||
of test cases from the test executable and when the tests are executed themselves.
|
||||
This requires cmake/ctest >= 3.22.
|
||||
|
||||
``DISCOVERY_MODE mode``
|
||||
Provides control over when ``catch_discover_tests`` performs test discovery.
|
||||
By default, ``POST_BUILD`` sets up a post-build command to perform test discovery
|
||||
at build time. In certain scenarios, like cross-compiling, this ``POST_BUILD``
|
||||
behavior is not desirable. By contrast, ``PRE_TEST`` delays test discovery until
|
||||
just prior to test execution. This way test discovery occurs in the target environment
|
||||
where the test has a better chance at finding appropriate runtime dependencies.
|
||||
|
||||
``DISCOVERY_MODE`` defaults to the value of the
|
||||
``CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not passed when
|
||||
calling ``catch_discover_tests``. This provides a mechanism for globally selecting
|
||||
a preferred test discovery behavior without having to modify each call site.
|
||||
|
||||
``SKIP_IS_FAILURE``
|
||||
Disables skipped test detection.
|
||||
|
||||
``ADD_TAGS_AS_LABELS``
|
||||
Adds all test tags as CTest labels.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
function(catch_discover_tests TARGET)
|
||||
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
"SKIP_IS_FAILURE;ADD_TAGS_AS_LABELS"
|
||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX;DISCOVERY_MODE"
|
||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES;DL_PATHS;DL_FRAMEWORK_PATHS"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.19")
|
||||
message(FATAL_ERROR "This script requires JSON support from CMake version 3.19 or greater.")
|
||||
endif()
|
||||
|
||||
if(NOT _WORKING_DIRECTORY)
|
||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if(NOT _TEST_LIST)
|
||||
set(_TEST_LIST ${TARGET}_TESTS)
|
||||
endif()
|
||||
if(_DL_PATHS AND ${CMAKE_VERSION} VERSION_LESS "3.22.0")
|
||||
message(FATAL_ERROR "The DL_PATHS option requires at least cmake 3.22")
|
||||
endif()
|
||||
if(_DL_FRAMEWORK_PATHS AND ${CMAKE_VERSION} VERSION_LESS "3.22.0")
|
||||
message(FATAL_ERROR "The DL_FRAMEWORK_PATHS option requires at least cmake 3.22")
|
||||
endif()
|
||||
if(NOT _DISCOVERY_MODE)
|
||||
if(NOT CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE)
|
||||
set(CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE "POST_BUILD")
|
||||
endif()
|
||||
set(_DISCOVERY_MODE ${CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE})
|
||||
endif()
|
||||
if(NOT _DISCOVERY_MODE MATCHES "^(POST_BUILD|PRE_TEST)$")
|
||||
message(FATAL_ERROR "Unknown DISCOVERY_MODE: ${_DISCOVERY_MODE}")
|
||||
endif()
|
||||
|
||||
## Generate a unique name based on the extra arguments
|
||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}")
|
||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||
|
||||
# Define rule to generate test list for aforementioned test executable
|
||||
set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-${args_hash}")
|
||||
set(ctest_include_file "${ctest_file_base}_include.cmake")
|
||||
set(ctest_tests_file "${ctest_file_base}_tests.cmake")
|
||||
|
||||
get_property(crosscompiling_emulator
|
||||
TARGET ${TARGET}
|
||||
PROPERTY CROSSCOMPILING_EMULATOR
|
||||
)
|
||||
if(NOT _SKIP_IS_FAILURE)
|
||||
set(_PROPERTIES ${_PROPERTIES} SKIP_RETURN_CODE 4)
|
||||
endif()
|
||||
|
||||
if(_DISCOVERY_MODE STREQUAL "POST_BUILD")
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
BYPRODUCTS "${ctest_tests_file}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "TEST_TARGET=${TARGET}"
|
||||
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
||||
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
||||
-D "TEST_LIST=${_TEST_LIST}"
|
||||
-D "TEST_REPORTER=${_REPORTER}"
|
||||
-D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}"
|
||||
-D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}"
|
||||
-D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}"
|
||||
-D "TEST_DL_PATHS=${_DL_PATHS}"
|
||||
-D "TEST_DL_FRAMEWORK_PATHS=${_DL_FRAMEWORK_PATHS}"
|
||||
-D "CTEST_FILE=${ctest_tests_file}"
|
||||
-D "ADD_TAGS_AS_LABELS=${_ADD_TAGS_AS_LABELS}"
|
||||
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
file(WRITE "${ctest_include_file}"
|
||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||
" include(\"${ctest_tests_file}\")\n"
|
||||
"else()\n"
|
||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||
"endif()\n"
|
||||
)
|
||||
|
||||
elseif(_DISCOVERY_MODE STREQUAL "PRE_TEST")
|
||||
|
||||
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL
|
||||
PROPERTY GENERATOR_IS_MULTI_CONFIG
|
||||
)
|
||||
|
||||
if(GENERATOR_IS_MULTI_CONFIG)
|
||||
set(ctest_tests_file "${ctest_file_base}_tests-$<CONFIG>.cmake")
|
||||
endif()
|
||||
|
||||
string(CONCAT ctest_include_content
|
||||
"if(EXISTS \"$<TARGET_FILE:${TARGET}>\")" "\n"
|
||||
" if(NOT EXISTS \"${ctest_tests_file}\" OR" "\n"
|
||||
" NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$<TARGET_FILE:${TARGET}>\" OR\n"
|
||||
" NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"\${CMAKE_CURRENT_LIST_FILE}\")\n"
|
||||
" include(\"${_CATCH_DISCOVER_TESTS_SCRIPT}\")" "\n"
|
||||
" catch_discover_tests_impl(" "\n"
|
||||
" TEST_EXECUTABLE" " [==[" "$<TARGET_FILE:${TARGET}>" "]==]" "\n"
|
||||
" TEST_EXECUTOR" " [==[" "${crosscompiling_emulator}" "]==]" "\n"
|
||||
" TEST_WORKING_DIR" " [==[" "${_WORKING_DIRECTORY}" "]==]" "\n"
|
||||
" TEST_SPEC" " [==[" "${_TEST_SPEC}" "]==]" "\n"
|
||||
" TEST_EXTRA_ARGS" " [==[" "${_EXTRA_ARGS}" "]==]" "\n"
|
||||
" TEST_PROPERTIES" " [==[" "${_PROPERTIES}" "]==]" "\n"
|
||||
" TEST_PREFIX" " [==[" "${_TEST_PREFIX}" "]==]" "\n"
|
||||
" TEST_SUFFIX" " [==[" "${_TEST_SUFFIX}" "]==]" "\n"
|
||||
" TEST_LIST" " [==[" "${_TEST_LIST}" "]==]" "\n"
|
||||
" TEST_REPORTER" " [==[" "${_REPORTER}" "]==]" "\n"
|
||||
" TEST_OUTPUT_DIR" " [==[" "${_OUTPUT_DIR}" "]==]" "\n"
|
||||
" TEST_OUTPUT_PREFIX" " [==[" "${_OUTPUT_PREFIX}" "]==]" "\n"
|
||||
" TEST_OUTPUT_SUFFIX" " [==[" "${_OUTPUT_SUFFIX}" "]==]" "\n"
|
||||
" CTEST_FILE" " [==[" "${ctest_tests_file}" "]==]" "\n"
|
||||
" TEST_DL_PATHS" " [==[" "${_DL_PATHS}" "]==]" "\n"
|
||||
" TEST_DL_FRAMEWORK_PATHS" " [==[" "${_DL_FRAMEWORK_PATHS}" "]==]" "\n"
|
||||
" ADD_TAGS_AS_LABELS" " [==[" "${_ADD_TAGS_AS_LABELS}" "]==]" "\n"
|
||||
" )" "\n"
|
||||
" endif()" "\n"
|
||||
" include(\"${ctest_tests_file}\")" "\n"
|
||||
"else()" "\n"
|
||||
" add_test(${TARGET}_NOT_BUILT ${TARGET}_NOT_BUILT)" "\n"
|
||||
"endif()" "\n"
|
||||
)
|
||||
|
||||
if(GENERATOR_IS_MULTI_CONFIG)
|
||||
foreach(_config ${CMAKE_CONFIGURATION_TYPES})
|
||||
file(GENERATE OUTPUT "${ctest_file_base}_include-${_config}.cmake" CONTENT "${ctest_include_content}" CONDITION $<CONFIG:${_config}>)
|
||||
endforeach()
|
||||
string(CONCAT ctest_include_multi_content
|
||||
"if(NOT CTEST_CONFIGURATION_TYPE)" "\n"
|
||||
" message(\"No configuration for testing specified, use '-C <cfg>'.\")" "\n"
|
||||
"else()" "\n"
|
||||
" include(\"${ctest_file_base}_include-\${CTEST_CONFIGURATION_TYPE}.cmake\")" "\n"
|
||||
"endif()" "\n"
|
||||
)
|
||||
file(GENERATE OUTPUT "${ctest_include_file}" CONTENT "${ctest_include_multi_content}")
|
||||
else()
|
||||
file(GENERATE OUTPUT "${ctest_file_base}_include.cmake" CONTENT "${ctest_include_content}")
|
||||
file(WRITE "${ctest_include_file}" "include(\"${ctest_file_base}_include.cmake\")")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
|
||||
endfunction()
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||
CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file"
|
||||
)
|
||||
253
tests/catch2/extras/CatchAddTests.cmake
Normal file
253
tests/catch2/extras/CatchAddTests.cmake
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
function(add_command NAME)
|
||||
set(_args "")
|
||||
# use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments
|
||||
math(EXPR _last_arg ${ARGC}-1)
|
||||
foreach(_n RANGE 1 ${_last_arg})
|
||||
set(_arg "${ARGV${_n}}")
|
||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||
else()
|
||||
set(_args "${_args} ${_arg}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(catch_discover_tests_impl)
|
||||
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
""
|
||||
"TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_OUTPUT_DIR;TEST_OUTPUT_PREFIX;TEST_OUTPUT_SUFFIX;TEST_PREFIX;TEST_REPORTER;TEST_SPEC;TEST_SUFFIX;TEST_LIST;CTEST_FILE"
|
||||
"TEST_EXTRA_ARGS;TEST_PROPERTIES;TEST_EXECUTOR;TEST_DL_PATHS;TEST_DL_FRAMEWORK_PATHS;ADD_TAGS_AS_LABELS"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
set(add_tags "${_ADD_TAGS_AS_LABELS}")
|
||||
set(prefix "${_TEST_PREFIX}")
|
||||
set(suffix "${_TEST_SUFFIX}")
|
||||
set(spec ${_TEST_SPEC})
|
||||
set(extra_args ${_TEST_EXTRA_ARGS})
|
||||
set(properties ${_TEST_PROPERTIES})
|
||||
set(reporter ${_TEST_REPORTER})
|
||||
set(output_dir ${_TEST_OUTPUT_DIR})
|
||||
set(output_prefix ${_TEST_OUTPUT_PREFIX})
|
||||
set(output_suffix ${_TEST_OUTPUT_SUFFIX})
|
||||
set(dl_paths ${_TEST_DL_PATHS})
|
||||
set(dl_framework_paths ${_TEST_DL_FRAMEWORK_PATHS})
|
||||
set(environment_modifications "")
|
||||
set(script)
|
||||
set(suite)
|
||||
set(tests)
|
||||
|
||||
if(WIN32)
|
||||
set(dl_paths_variable_name PATH)
|
||||
elseif(APPLE)
|
||||
set(dl_paths_variable_name DYLD_LIBRARY_PATH)
|
||||
else()
|
||||
set(dl_paths_variable_name LD_LIBRARY_PATH)
|
||||
endif()
|
||||
|
||||
# Run test executable to get list of available tests
|
||||
if(NOT EXISTS "${_TEST_EXECUTABLE}")
|
||||
message(FATAL_ERROR
|
||||
"Specified test executable '${_TEST_EXECUTABLE}' does not exist"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(dl_paths)
|
||||
cmake_path(CONVERT "$ENV{${dl_paths_variable_name}}" TO_NATIVE_PATH_LIST env_dl_paths)
|
||||
list(PREPEND env_dl_paths "${dl_paths}")
|
||||
cmake_path(CONVERT "${env_dl_paths}" TO_NATIVE_PATH_LIST paths)
|
||||
set(ENV{${dl_paths_variable_name}} "${paths}")
|
||||
endif()
|
||||
|
||||
if(APPLE AND dl_framework_paths)
|
||||
cmake_path(CONVERT "$ENV{DYLD_FRAMEWORK_PATH}" TO_NATIVE_PATH_LIST env_dl_framework_paths)
|
||||
list(PREPEND env_dl_framework_paths "${dl_framework_paths}")
|
||||
cmake_path(CONVERT "${env_dl_framework_paths}" TO_NATIVE_PATH_LIST paths)
|
||||
set(ENV{DYLD_FRAMEWORK_PATH} "${paths}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} --list-tests --reporter json
|
||||
OUTPUT_VARIABLE listing_output
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
||||
)
|
||||
if(NOT ${result} EQUAL 0)
|
||||
message(FATAL_ERROR
|
||||
"Error listing tests from executable '${_TEST_EXECUTABLE}':\n"
|
||||
" Result: ${result}\n"
|
||||
" Output: ${listing_output}\n"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Prepare reporter
|
||||
if(reporter)
|
||||
set(reporter_arg "--reporter ${reporter}")
|
||||
|
||||
# Run test executable to check whether reporter is available
|
||||
# note that the use of --list-reporters is not the important part,
|
||||
# we only want to check whether the execution succeeds with ${reporter_arg}
|
||||
execute_process(
|
||||
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} ${reporter_arg} --list-reporters
|
||||
OUTPUT_VARIABLE reporter_check_output
|
||||
RESULT_VARIABLE reporter_check_result
|
||||
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
||||
)
|
||||
if(${reporter_check_result} EQUAL 255)
|
||||
message(FATAL_ERROR
|
||||
"\"${reporter}\" is not a valid reporter!\n"
|
||||
)
|
||||
elseif(NOT ${reporter_check_result} EQUAL 0)
|
||||
message(FATAL_ERROR
|
||||
"Error checking for reporter in test executable '${_TEST_EXECUTABLE}':\n"
|
||||
" Result: ${reporter_check_result}\n"
|
||||
" Output: ${reporter_check_output}\n"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Prepare output dir
|
||||
if(output_dir AND NOT IS_ABSOLUTE ${output_dir})
|
||||
set(output_dir "${_TEST_WORKING_DIR}/${output_dir}")
|
||||
if(NOT EXISTS ${output_dir})
|
||||
file(MAKE_DIRECTORY ${output_dir})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(dl_paths)
|
||||
foreach(path ${dl_paths})
|
||||
cmake_path(NATIVE_PATH path native_path)
|
||||
list(PREPEND environment_modifications "${dl_paths_variable_name}=path_list_prepend:${native_path}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(APPLE AND dl_framework_paths)
|
||||
foreach(path ${dl_framework_paths})
|
||||
cmake_path(NATIVE_PATH path native_path)
|
||||
list(PREPEND environment_modifications "DYLD_FRAMEWORK_PATH=path_list_prepend:${native_path}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Parse JSON output for list of tests/class names/tags
|
||||
string(JSON version GET "${listing_output}" "version")
|
||||
if(NOT version STREQUAL "1")
|
||||
message(FATAL_ERROR "Unsupported catch output version: '${version}'")
|
||||
endif()
|
||||
|
||||
# Speed-up reparsing by cutting away unneeded parts of JSON.
|
||||
string(JSON test_listing GET "${listing_output}" "listings" "tests")
|
||||
string(JSON num_tests LENGTH "${test_listing}")
|
||||
|
||||
# Exit early if no tests are detected
|
||||
if(num_tests STREQUAL "0")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# CMake's foreach-RANGE is inclusive, so we have to subtract 1
|
||||
math(EXPR num_tests "${num_tests} - 1")
|
||||
|
||||
foreach(idx RANGE ${num_tests})
|
||||
string(JSON single_test GET ${test_listing} ${idx})
|
||||
string(JSON test_tags GET "${single_test}" "tags")
|
||||
string(JSON plain_name GET "${single_test}" "name")
|
||||
|
||||
# Escape characters in test case names that would be parsed by Catch2
|
||||
# Note that the \ escaping must happen FIRST! Do not change the order.
|
||||
set(escaped_name "${plain_name}")
|
||||
foreach(char \\ , [ ] ;)
|
||||
string(REPLACE ${char} "\\${char}" escaped_name "${escaped_name}")
|
||||
endforeach(char)
|
||||
# ...add output dir
|
||||
if(output_dir)
|
||||
string(REGEX REPLACE "[^A-Za-z0-9_]" "_" escaped_name_clean "${escaped_name}")
|
||||
set(output_dir_arg "--out ${output_dir}/${output_prefix}${escaped_name_clean}${output_suffix}")
|
||||
endif()
|
||||
|
||||
# ...and add to script
|
||||
add_command(add_test
|
||||
"${prefix}${plain_name}${suffix}"
|
||||
${_TEST_EXECUTOR}
|
||||
"${_TEST_EXECUTABLE}"
|
||||
"${escaped_name}"
|
||||
${extra_args}
|
||||
"${reporter_arg}"
|
||||
"${output_dir_arg}"
|
||||
)
|
||||
add_command(set_tests_properties
|
||||
"${prefix}${plain_name}${suffix}"
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
||||
${properties}
|
||||
)
|
||||
|
||||
if(add_tags)
|
||||
string(JSON num_tags LENGTH "${test_tags}")
|
||||
math(EXPR num_tags "${num_tags} - 1")
|
||||
set(tag_list "")
|
||||
if(num_tags GREATER_EQUAL "0")
|
||||
foreach(tag_idx RANGE ${num_tags})
|
||||
string(JSON a_tag GET "${test_tags}" "${tag_idx}")
|
||||
# Catch2's tags can contain semicolons, which are list element separators
|
||||
# in CMake, so we have to escape them. Ideally we could use the [=[...]=]
|
||||
# syntax for this, but CTest currently keeps the square quotes in the label
|
||||
# name. So we add 2 backslashes to escape it instead.
|
||||
# **IMPORTANT**: The number of backslashes depends on how many layers
|
||||
# of CMake the tag goes. If this script is changed, the
|
||||
# number of backslashes to escape may change as well.
|
||||
string(REPLACE ";" "\\;" a_tag "${a_tag}")
|
||||
list(APPEND tag_list "${a_tag}")
|
||||
endforeach()
|
||||
|
||||
add_command(set_tests_properties
|
||||
"${prefix}${plain_name}${suffix}"
|
||||
PROPERTIES
|
||||
LABELS "${tag_list}"
|
||||
)
|
||||
endif()
|
||||
endif(add_tags)
|
||||
|
||||
if(environment_modifications)
|
||||
add_command(set_tests_properties
|
||||
"${prefix}${plain_name}${suffix}"
|
||||
PROPERTIES
|
||||
ENVIRONMENT_MODIFICATION "${environment_modifications}")
|
||||
endif()
|
||||
|
||||
list(APPEND tests "${prefix}${plain_name}${suffix}")
|
||||
endforeach()
|
||||
|
||||
# Create a list of all discovered tests, which users may use to e.g. set
|
||||
# properties on the tests
|
||||
add_command(set ${_TEST_LIST} ${tests})
|
||||
|
||||
# Write CTest script
|
||||
file(WRITE "${_CTEST_FILE}" "${script}")
|
||||
endfunction()
|
||||
|
||||
if(CMAKE_SCRIPT_MODE_FILE)
|
||||
catch_discover_tests_impl(
|
||||
TEST_EXECUTABLE ${TEST_EXECUTABLE}
|
||||
TEST_EXECUTOR ${TEST_EXECUTOR}
|
||||
TEST_WORKING_DIR ${TEST_WORKING_DIR}
|
||||
TEST_SPEC ${TEST_SPEC}
|
||||
TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS}
|
||||
TEST_PROPERTIES ${TEST_PROPERTIES}
|
||||
TEST_PREFIX ${TEST_PREFIX}
|
||||
TEST_SUFFIX ${TEST_SUFFIX}
|
||||
TEST_LIST ${TEST_LIST}
|
||||
TEST_REPORTER ${TEST_REPORTER}
|
||||
TEST_OUTPUT_DIR ${TEST_OUTPUT_DIR}
|
||||
TEST_OUTPUT_PREFIX ${TEST_OUTPUT_PREFIX}
|
||||
TEST_OUTPUT_SUFFIX ${TEST_OUTPUT_SUFFIX}
|
||||
TEST_DL_PATHS ${TEST_DL_PATHS}
|
||||
TEST_DL_FRAMEWORK_PATHS ${TEST_DL_FRAMEWORK_PATHS}
|
||||
CTEST_FILE ${CTEST_FILE}
|
||||
ADD_TAGS_AS_LABELS ${ADD_TAGS_AS_LABELS}
|
||||
)
|
||||
endif()
|
||||
72
tests/catch2/extras/CatchShardTests.cmake
Normal file
72
tests/catch2/extras/CatchShardTests.cmake
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
# Copyright Catch2 Authors
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE.txt or copy at
|
||||
# https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
# Supported optional args:
|
||||
# * SHARD_COUNT - number of shards to split target's tests into
|
||||
# * REPORTER - reporter spec to use for tests
|
||||
# * TEST_SPEC - test spec used for filtering tests
|
||||
function(catch_add_sharded_tests TARGET)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
||||
message(FATAL_ERROR "add_sharded_catch_tests only supports CMake versions 3.10.0 and up")
|
||||
endif()
|
||||
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
""
|
||||
"SHARD_COUNT;REPORTER;TEST_SPEC"
|
||||
""
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(NOT DEFINED _SHARD_COUNT)
|
||||
set(_SHARD_COUNT 2)
|
||||
endif()
|
||||
|
||||
# Generate a unique name based on the extra arguments
|
||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX} ${_SHARD_COUNT}")
|
||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||
|
||||
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-sharded-tests-include-${args_hash}.cmake")
|
||||
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-sharded-tests-impl-${args_hash}.cmake")
|
||||
|
||||
file(WRITE "${ctest_include_file}"
|
||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||
" include(\"${ctest_tests_file}\")\n"
|
||||
"else()\n"
|
||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||
"endif()\n"
|
||||
)
|
||||
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
|
||||
set(shard_impl_script_file "${_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT}")
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
BYPRODUCTS "${ctest_tests_file}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "TARGET_NAME=${TARGET}"
|
||||
-D "TEST_BINARY=$<TARGET_FILE:${TARGET}>"
|
||||
-D "CTEST_FILE=${ctest_tests_file}"
|
||||
-D "SHARD_COUNT=${_SHARD_COUNT}"
|
||||
-D "REPORTER_SPEC=${_REPORTER}"
|
||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||
-P "${shard_impl_script_file}"
|
||||
VERBATIM
|
||||
)
|
||||
endfunction()
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/CatchShardTestsImpl.cmake
|
||||
CACHE INTERNAL "Catch2 full path to CatchShardTestsImpl.cmake helper file"
|
||||
)
|
||||
52
tests/catch2/extras/CatchShardTestsImpl.cmake
Normal file
52
tests/catch2/extras/CatchShardTestsImpl.cmake
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
# Copyright Catch2 Authors
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE.txt or copy at
|
||||
# https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
# Indirection for CatchShardTests that allows us to delay the script
|
||||
# file generation until build time.
|
||||
|
||||
# Expected args:
|
||||
# * TEST_BINARY - full path to the test binary to run sharded
|
||||
# * CTEST_FILE - full path to ctest script file to write to
|
||||
# * TARGET_NAME - name of the target to shard (used for test names)
|
||||
# * SHARD_COUNT - number of shards to split the binary into
|
||||
# Optional args:
|
||||
# * REPORTER_SPEC - reporter specs to be passed down to the binary
|
||||
# * TEST_SPEC - test spec to pass down to the test binary
|
||||
|
||||
if(NOT EXISTS "${TEST_BINARY}")
|
||||
message(FATAL_ERROR
|
||||
"Specified test binary '${TEST_BINARY}' does not exist"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(other_args "")
|
||||
if(TEST_SPEC)
|
||||
set(other_args "${other_args} ${TEST_SPEC}")
|
||||
endif()
|
||||
if(REPORTER_SPEC)
|
||||
set(other_args "${other_args} --reporter ${REPORTER_SPEC}")
|
||||
endif()
|
||||
|
||||
# foreach RANGE in cmake is inclusive of the end, so we have to adjust it
|
||||
math(EXPR adjusted_shard_count "${SHARD_COUNT} - 1")
|
||||
|
||||
file(WRITE "${CTEST_FILE}"
|
||||
"string(RANDOM LENGTH 8 ALPHABET \"0123456789abcdef\" rng_seed)\n"
|
||||
"\n"
|
||||
"foreach(shard_idx RANGE ${adjusted_shard_count})\n"
|
||||
" add_test(${TARGET_NAME}-shard-" [[${shard_idx}]] "/${adjusted_shard_count}\n"
|
||||
" ${TEST_BINARY}"
|
||||
" --shard-index " [[${shard_idx}]]
|
||||
" --shard-count ${SHARD_COUNT}"
|
||||
" --rng-seed " [[0x${rng_seed}]]
|
||||
" --order rand"
|
||||
"${other_args}"
|
||||
"\n"
|
||||
" )\n"
|
||||
"endforeach()\n"
|
||||
)
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
#==================================================================================================#
|
||||
# supported macros #
|
||||
# - TEST_CASE, #
|
||||
# - TEMPLATE_TEST_CASE #
|
||||
# - SCENARIO, #
|
||||
# - TEST_CASE_METHOD, #
|
||||
# - CATCH_TEST_CASE, #
|
||||
# - CATCH_TEMPLATE_TEST_CASE #
|
||||
# - CATCH_SCENARIO, #
|
||||
# - CATCH_TEST_CASE_METHOD. #
|
||||
# #
|
||||
|
|
@ -54,7 +56,7 @@
|
|||
# #
|
||||
#==================================================================================================#
|
||||
|
||||
if (CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
|
||||
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
|
||||
message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer")
|
||||
endif()
|
||||
|
||||
|
|
@ -65,9 +67,9 @@ option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test na
|
|||
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
|
||||
|
||||
function(ParseAndAddCatchTests_PrintDebugMessage)
|
||||
if(PARSE_CATCH_TESTS_VERBOSE)
|
||||
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
|
||||
endif()
|
||||
if(PARSE_CATCH_TESTS_VERBOSE)
|
||||
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# This removes the contents between
|
||||
|
|
@ -88,138 +90,161 @@ endfunction()
|
|||
|
||||
# Worker function
|
||||
function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
|
||||
# If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
|
||||
if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
|
||||
return()
|
||||
# If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
|
||||
if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
|
||||
return()
|
||||
endif()
|
||||
# According to CMake docs EXISTS behavior is well-defined only for full paths.
|
||||
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
|
||||
if(NOT EXISTS ${SourceFile})
|
||||
message(WARNING "Cannot find source file: ${SourceFile}")
|
||||
return()
|
||||
endif()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
|
||||
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
|
||||
|
||||
# Remove block and fullline comments
|
||||
ParseAndAddCatchTests_RemoveComments(Contents)
|
||||
|
||||
# Find definition of test names
|
||||
# https://regex101.com/r/JygOND/1
|
||||
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([ \t\n]*\"[^\"]*\"[ \t\n]*(,[ \t\n]*\"[^\"]*\")?(,[ \t\n]*[^\,\)]*)*\\)[ \t\n]*\{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
|
||||
|
||||
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
|
||||
set_property(
|
||||
DIRECTORY
|
||||
APPEND
|
||||
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
|
||||
)
|
||||
endif()
|
||||
|
||||
# check CMP0110 policy for new add_test() behavior
|
||||
if(POLICY CMP0110)
|
||||
cmake_policy(GET CMP0110 _cmp0110_value) # new add_test() behavior
|
||||
else()
|
||||
# just to be thorough explicitly set the variable
|
||||
set(_cmp0110_value)
|
||||
endif()
|
||||
|
||||
foreach(TestName ${Tests})
|
||||
# Strip newlines
|
||||
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
|
||||
|
||||
# Get test type and fixture if applicable
|
||||
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
||||
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
||||
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
|
||||
|
||||
# Get string parts of test definition
|
||||
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
||||
|
||||
# Strip wrapping quotation marks
|
||||
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
|
||||
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
|
||||
|
||||
# Validate that a test name and tags have been provided
|
||||
list(LENGTH TestStrings TestStringsLength)
|
||||
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
|
||||
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
|
||||
endif()
|
||||
# According to CMake docs EXISTS behavior is well-defined only for full paths.
|
||||
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
|
||||
if(NOT EXISTS ${SourceFile})
|
||||
message(WARNING "Cannot find source file: ${SourceFile}")
|
||||
return()
|
||||
|
||||
# Assign name and tags
|
||||
list(GET TestStrings 0 Name)
|
||||
if("${TestType}" STREQUAL "SCENARIO")
|
||||
set(Name "Scenario: ${Name}")
|
||||
endif()
|
||||
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND "${TestType}" MATCHES "(CATCH_)?TEST_CASE_METHOD" AND TestFixture)
|
||||
set(CTestName "${TestFixture}:${Name}")
|
||||
else()
|
||||
set(CTestName "${Name}")
|
||||
endif()
|
||||
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
|
||||
set(CTestName "${TestTarget}:${CTestName}")
|
||||
endif()
|
||||
# add target to labels to enable running all tests added from this target
|
||||
set(Labels ${TestTarget})
|
||||
if(TestStringsLength EQUAL 2)
|
||||
list(GET TestStrings 1 Tags)
|
||||
string(TOLOWER "${Tags}" Tags)
|
||||
# remove target from labels if the test is hidden
|
||||
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
|
||||
list(REMOVE_ITEM Labels ${TestTarget})
|
||||
endif()
|
||||
string(REPLACE "]" ";" Tags "${Tags}")
|
||||
string(REPLACE "[" "" Tags "${Tags}")
|
||||
else()
|
||||
# unset tags variable from previous loop
|
||||
unset(Tags)
|
||||
endif()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
|
||||
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
|
||||
|
||||
# Remove block and fullline comments
|
||||
ParseAndAddCatchTests_RemoveComments(Contents)
|
||||
list(APPEND Labels ${Tags})
|
||||
|
||||
# Find definition of test names
|
||||
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
|
||||
set(HiddenTagFound OFF)
|
||||
foreach(label ${Labels})
|
||||
string(REGEX MATCH "^!hide|^\\." result ${label})
|
||||
if(result)
|
||||
set(HiddenTagFound ON)
|
||||
break()
|
||||
endif()
|
||||
endforeach(label)
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
||||
else()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
|
||||
if(Labels)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
|
||||
endif()
|
||||
|
||||
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
|
||||
# Escape commas in the test spec
|
||||
string(REPLACE "," "\\," Name ${Name})
|
||||
|
||||
# Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were necessary,
|
||||
# only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
|
||||
# And properly introduced in 3.19 with the CMP0110 policy
|
||||
if(_cmp0110_value STREQUAL "NEW" OR ${CMAKE_VERSION} VERSION_EQUAL "3.18")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to NEW, no need for add_test(\"\") workaround")
|
||||
else()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to OLD adding \"\" for add_test() workaround")
|
||||
set(CTestName "\"${CTestName}\"")
|
||||
endif()
|
||||
|
||||
# Handle template test cases
|
||||
if("${TestTypeAndFixture}" MATCHES ".*TEMPLATE_.*")
|
||||
set(Name "${Name} - *")
|
||||
endif()
|
||||
|
||||
# Add the test and set its properties
|
||||
add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
|
||||
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
|
||||
set_tests_properties("${CTestName}" PROPERTIES DISABLED ON)
|
||||
else()
|
||||
set_tests_properties("${CTestName}" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||
LABELS "${Labels}")
|
||||
endif()
|
||||
set_property(
|
||||
DIRECTORY
|
||||
TARGET ${TestTarget}
|
||||
APPEND
|
||||
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
|
||||
)
|
||||
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
|
||||
set_property(
|
||||
SOURCE ${SourceFile}
|
||||
APPEND
|
||||
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
|
||||
endif()
|
||||
|
||||
foreach(TestName ${Tests})
|
||||
# Strip newlines
|
||||
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
|
||||
|
||||
# Get test type and fixture if applicable
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
||||
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
|
||||
|
||||
# Get string parts of test definition
|
||||
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
||||
|
||||
# Strip wrapping quotation marks
|
||||
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
|
||||
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
|
||||
|
||||
# Validate that a test name and tags have been provided
|
||||
list(LENGTH TestStrings TestStringsLength)
|
||||
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
|
||||
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
|
||||
endif()
|
||||
|
||||
# Assign name and tags
|
||||
list(GET TestStrings 0 Name)
|
||||
if("${TestType}" STREQUAL "SCENARIO")
|
||||
set(Name "Scenario: ${Name}")
|
||||
endif()
|
||||
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
|
||||
set(CTestName "${TestFixture}:${Name}")
|
||||
else()
|
||||
set(CTestName "${Name}")
|
||||
endif()
|
||||
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
|
||||
set(CTestName "${TestTarget}:${CTestName}")
|
||||
endif()
|
||||
# add target to labels to enable running all tests added from this target
|
||||
set(Labels ${TestTarget})
|
||||
if(TestStringsLength EQUAL 2)
|
||||
list(GET TestStrings 1 Tags)
|
||||
string(TOLOWER "${Tags}" Tags)
|
||||
# remove target from labels if the test is hidden
|
||||
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
|
||||
list(REMOVE_ITEM Labels ${TestTarget})
|
||||
endif()
|
||||
string(REPLACE "]" ";" Tags "${Tags}")
|
||||
string(REPLACE "[" "" Tags "${Tags}")
|
||||
else()
|
||||
# unset tags variable from previous loop
|
||||
unset(Tags)
|
||||
endif()
|
||||
|
||||
list(APPEND Labels ${Tags})
|
||||
|
||||
set(HiddenTagFound OFF)
|
||||
foreach(label ${Labels})
|
||||
string(REGEX MATCH "^!hide|^\\." result ${label})
|
||||
if(result)
|
||||
set(HiddenTagFound ON)
|
||||
break()
|
||||
endif(result)
|
||||
endforeach(label)
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
||||
else()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
|
||||
if(Labels)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
|
||||
endif()
|
||||
|
||||
# Escape commas in the test spec
|
||||
string(REPLACE "," "\\," Name ${Name})
|
||||
|
||||
# Add the test and set its properties
|
||||
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
|
||||
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
|
||||
set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
|
||||
else()
|
||||
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||
LABELS "${Labels}")
|
||||
endif()
|
||||
set_property(
|
||||
TARGET ${TestTarget}
|
||||
APPEND
|
||||
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
|
||||
set_property(
|
||||
SOURCE ${SourceFile}
|
||||
APPEND
|
||||
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
|
||||
endif()
|
||||
|
||||
|
||||
endforeach()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# entry point
|
||||
function(ParseAndAddCatchTests TestTarget)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
|
||||
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
||||
foreach(SourceFile ${SourceFiles})
|
||||
ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
|
||||
endforeach()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
|
||||
message(DEPRECATION "ParseAndAddCatchTest: function deprecated because of possibility of missed test cases. Consider using 'catch_discover_tests' from 'Catch.cmake'")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
|
||||
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
||||
foreach(SourceFile ${SourceFiles})
|
||||
ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
|
||||
endforeach()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
|
||||
endfunction()
|
||||
12083
tests/catch2/extras/catch_amalgamated.cpp
Normal file
12083
tests/catch2/extras/catch_amalgamated.cpp
Normal file
File diff suppressed because it is too large
Load diff
14314
tests/catch2/extras/catch_amalgamated.hpp
Normal file
14314
tests/catch2/extras/catch_amalgamated.hpp
Normal file
File diff suppressed because it is too large
Load diff
16
tests/catch2/extras/gdbinit
Normal file
16
tests/catch2/extras/gdbinit
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# This file provides a way to skip stepping into Catch code when debugging with gdb.
|
||||
#
|
||||
# With the gdb "skip" command you can tell gdb to skip files or functions during debugging.
|
||||
# see https://xaizek.github.io/2016-05-26/skipping-standard-library-in-gdb/ for an example
|
||||
#
|
||||
# Basically the following line tells gdb to skip all functions containing the
|
||||
# regexp "Catch", which matches the complete Catch namespace.
|
||||
# If you want to skip just some parts of the Catch code you can modify the
|
||||
# regexp accordingly.
|
||||
#
|
||||
# If you want to permanently skip stepping into Catch code copy the following
|
||||
# line into your ~/.gdbinit file
|
||||
#
|
||||
|
||||
skip -rfu Catch
|
||||
16
tests/catch2/extras/lldbinit
Normal file
16
tests/catch2/extras/lldbinit
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# This file provides a way to skip stepping into Catch code when debugging with lldb.
|
||||
#
|
||||
# With the setting "target.process.thread.step-avoid-regexp" you can tell lldb
|
||||
# to skip functions matching the regexp
|
||||
#
|
||||
# Basically the following line tells lldb to skip all functions containing the
|
||||
# regexp "Catch", which matches the complete Catch namespace.
|
||||
# If you want to skip just some parts of the Catch code you can modify the
|
||||
# regexp accordingly.
|
||||
#
|
||||
# If you want to permanently skip stepping into Catch code copy the following
|
||||
# line into your ~/.lldbinit file
|
||||
#
|
||||
|
||||
settings set target.process.thread.step-avoid-regexp Catch
|
||||
479
tests/catch2/src/CMakeLists.txt
Normal file
479
tests/catch2/src/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
include(CatchMiscFunctions)
|
||||
|
||||
# CMake derives a Visual Studio project GUID from the file path but can be overridden via a property
|
||||
# (see https://gitlab.kitware.com/cmake/cmake/-/commit/c85367f4). Using a non-constant GUID
|
||||
# can cause problems if other projects/repos want to reference the vcxproj file,
|
||||
# so we force a constant GUID here.
|
||||
set(Catch2_GUID_CMAKE "8d538cbe-01bf-4a2e-a98a-6c368fdf13d7" CACHE INTERNAL "Project GUID")
|
||||
set(Catch2WithMain_GUID_CMAKE "8bd3552a-2cfb-4a59-ab15-2031b97ada1e" CACHE INTERNAL "Project GUID")
|
||||
|
||||
set(BENCHMARK_HEADERS
|
||||
${SOURCES_DIR}/benchmark/catch_benchmark.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_benchmark_all.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_chronometer.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_clock.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_constructor.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_environment.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_estimate.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_execution_plan.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_optimizer.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_outlier_classification.hpp
|
||||
${SOURCES_DIR}/benchmark/catch_sample_analysis.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_analyse.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_benchmark_function.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_benchmark_stats.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_benchmark_stats_fwd.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_complete_invoke.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_estimate_clock.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_measure.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_repeat.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_run_for_at_least.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_stats.hpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_timing.hpp
|
||||
)
|
||||
set(BENCHMARK_SOURCES
|
||||
${SOURCES_DIR}/benchmark/catch_chronometer.cpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_analyse.cpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_benchmark_function.cpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_run_for_at_least.cpp
|
||||
${SOURCES_DIR}/benchmark/detail/catch_stats.cpp
|
||||
)
|
||||
set(BENCHMARK_FILES ${BENCHMARK_HEADERS} ${BENCHMARK_SOURCES})
|
||||
|
||||
set(IMPL_HEADERS
|
||||
"${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp"
|
||||
${SOURCES_DIR}/catch_user_config.hpp.in
|
||||
${SOURCES_DIR}/catch_all.hpp
|
||||
${SOURCES_DIR}/catch_approx.hpp
|
||||
${SOURCES_DIR}/catch_assertion_info.hpp
|
||||
${SOURCES_DIR}/catch_assertion_result.hpp
|
||||
${SOURCES_DIR}/catch_case_sensitive.hpp
|
||||
${SOURCES_DIR}/catch_config.hpp
|
||||
${SOURCES_DIR}/catch_get_random_seed.hpp
|
||||
${SOURCES_DIR}/catch_message.hpp
|
||||
${SOURCES_DIR}/catch_section_info.hpp
|
||||
${SOURCES_DIR}/catch_session.hpp
|
||||
${SOURCES_DIR}/catch_tag_alias.hpp
|
||||
${SOURCES_DIR}/catch_tag_alias_autoregistrar.hpp
|
||||
${SOURCES_DIR}/catch_template_test_macros.hpp
|
||||
${SOURCES_DIR}/catch_test_case_info.hpp
|
||||
${SOURCES_DIR}/catch_test_macros.hpp
|
||||
${SOURCES_DIR}/catch_test_run_info.hpp
|
||||
${SOURCES_DIR}/catch_test_spec.hpp
|
||||
${SOURCES_DIR}/catch_timer.hpp
|
||||
${SOURCES_DIR}/catch_tostring.hpp
|
||||
${SOURCES_DIR}/catch_totals.hpp
|
||||
${SOURCES_DIR}/catch_translate_exception.hpp
|
||||
${SOURCES_DIR}/catch_version.hpp
|
||||
${SOURCES_DIR}/catch_version_macros.hpp
|
||||
${SOURCES_DIR}/internal/catch_assertion_handler.hpp
|
||||
${SOURCES_DIR}/internal/catch_case_insensitive_comparisons.hpp
|
||||
${SOURCES_DIR}/internal/catch_clara.hpp
|
||||
${SOURCES_DIR}/internal/catch_commandline.hpp
|
||||
${SOURCES_DIR}/internal/catch_compare_traits.hpp
|
||||
${SOURCES_DIR}/internal/catch_compiler_capabilities.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_android_logwrite.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_counter.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_prefix_messages.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_static_analysis_support.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_uncaught_exceptions.hpp
|
||||
${SOURCES_DIR}/internal/catch_config_wchar.hpp
|
||||
${SOURCES_DIR}/internal/catch_console_colour.hpp
|
||||
${SOURCES_DIR}/internal/catch_console_width.hpp
|
||||
${SOURCES_DIR}/internal/catch_container_nonmembers.hpp
|
||||
${SOURCES_DIR}/internal/catch_context.hpp
|
||||
${SOURCES_DIR}/internal/catch_debug_console.hpp
|
||||
${SOURCES_DIR}/internal/catch_debugger.hpp
|
||||
${SOURCES_DIR}/internal/catch_decomposer.hpp
|
||||
${SOURCES_DIR}/internal/catch_deprecation_macro.hpp
|
||||
${SOURCES_DIR}/internal/catch_enforce.hpp
|
||||
${SOURCES_DIR}/internal/catch_enum_values_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_errno_guard.hpp
|
||||
${SOURCES_DIR}/internal/catch_exception_translator_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_fatal_condition_handler.hpp
|
||||
${SOURCES_DIR}/internal/catch_floating_point_helpers.hpp
|
||||
${SOURCES_DIR}/internal/catch_getenv.hpp
|
||||
${SOURCES_DIR}/internal/catch_istream.hpp
|
||||
${SOURCES_DIR}/internal/catch_is_permutation.hpp
|
||||
${SOURCES_DIR}/internal/catch_jsonwriter.hpp
|
||||
${SOURCES_DIR}/internal/catch_lazy_expr.hpp
|
||||
${SOURCES_DIR}/internal/catch_leak_detector.hpp
|
||||
${SOURCES_DIR}/internal/catch_lifetimebound.hpp
|
||||
${SOURCES_DIR}/internal/catch_list.hpp
|
||||
${SOURCES_DIR}/internal/catch_logical_traits.hpp
|
||||
${SOURCES_DIR}/internal/catch_message_info.hpp
|
||||
${SOURCES_DIR}/internal/catch_meta.hpp
|
||||
${SOURCES_DIR}/internal/catch_move_and_forward.hpp
|
||||
${SOURCES_DIR}/internal/catch_noncopyable.hpp
|
||||
${SOURCES_DIR}/internal/catch_optional.hpp
|
||||
${SOURCES_DIR}/internal/catch_output_redirect.hpp
|
||||
${SOURCES_DIR}/internal/catch_parse_numbers.hpp
|
||||
${SOURCES_DIR}/internal/catch_platform.hpp
|
||||
${SOURCES_DIR}/internal/catch_polyfills.hpp
|
||||
${SOURCES_DIR}/internal/catch_preprocessor.hpp
|
||||
${SOURCES_DIR}/internal/catch_preprocessor_remove_parens.hpp
|
||||
${SOURCES_DIR}/internal/catch_random_floating_point_helpers.hpp
|
||||
${SOURCES_DIR}/internal/catch_random_integer_helpers.hpp
|
||||
${SOURCES_DIR}/internal/catch_random_number_generator.hpp
|
||||
${SOURCES_DIR}/internal/catch_random_seed_generation.hpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_spec_parser.hpp
|
||||
${SOURCES_DIR}/internal/catch_result_type.hpp
|
||||
${SOURCES_DIR}/internal/catch_reusable_string_stream.hpp
|
||||
${SOURCES_DIR}/internal/catch_run_context.hpp
|
||||
${SOURCES_DIR}/internal/catch_section.hpp
|
||||
${SOURCES_DIR}/internal/catch_sharding.hpp
|
||||
${SOURCES_DIR}/internal/catch_singletons.hpp
|
||||
${SOURCES_DIR}/internal/catch_source_line_info.hpp
|
||||
${SOURCES_DIR}/internal/catch_startup_exception_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_stdstreams.hpp
|
||||
${SOURCES_DIR}/internal/catch_stream_end_stop.hpp
|
||||
${SOURCES_DIR}/internal/catch_string_manip.hpp
|
||||
${SOURCES_DIR}/internal/catch_stringref.hpp
|
||||
${SOURCES_DIR}/internal/catch_tag_alias_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_template_test_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_info_hasher.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_registry_impl.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_tracker.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_failure_exception.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_macro_impl.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_test_spec_parser.hpp
|
||||
${SOURCES_DIR}/internal/catch_textflow.hpp
|
||||
${SOURCES_DIR}/internal/catch_thread_support.hpp
|
||||
${SOURCES_DIR}/internal/catch_to_string.hpp
|
||||
${SOURCES_DIR}/internal/catch_uncaught_exceptions.hpp
|
||||
${SOURCES_DIR}/internal/catch_uniform_floating_point_distribution.hpp
|
||||
${SOURCES_DIR}/internal/catch_uniform_integer_distribution.hpp
|
||||
${SOURCES_DIR}/internal/catch_unique_name.hpp
|
||||
${SOURCES_DIR}/internal/catch_unique_ptr.hpp
|
||||
${SOURCES_DIR}/internal/catch_unreachable.hpp
|
||||
${SOURCES_DIR}/internal/catch_void_type.hpp
|
||||
${SOURCES_DIR}/internal/catch_wildcard_pattern.hpp
|
||||
${SOURCES_DIR}/internal/catch_windows_h_proxy.hpp
|
||||
${SOURCES_DIR}/internal/catch_xmlwriter.hpp
|
||||
)
|
||||
set(IMPL_SOURCES
|
||||
${SOURCES_DIR}/catch_approx.cpp
|
||||
${SOURCES_DIR}/catch_assertion_result.cpp
|
||||
${SOURCES_DIR}/catch_config.cpp
|
||||
${SOURCES_DIR}/catch_get_random_seed.cpp
|
||||
${SOURCES_DIR}/catch_message.cpp
|
||||
${SOURCES_DIR}/catch_registry_hub.cpp
|
||||
${SOURCES_DIR}/catch_session.cpp
|
||||
${SOURCES_DIR}/catch_tag_alias_autoregistrar.cpp
|
||||
${SOURCES_DIR}/catch_test_case_info.cpp
|
||||
${SOURCES_DIR}/catch_test_spec.cpp
|
||||
${SOURCES_DIR}/catch_timer.cpp
|
||||
${SOURCES_DIR}/catch_tostring.cpp
|
||||
${SOURCES_DIR}/catch_totals.cpp
|
||||
${SOURCES_DIR}/catch_translate_exception.cpp
|
||||
${SOURCES_DIR}/catch_version.cpp
|
||||
${SOURCES_DIR}/internal/catch_assertion_handler.cpp
|
||||
${SOURCES_DIR}/internal/catch_case_insensitive_comparisons.cpp
|
||||
${SOURCES_DIR}/internal/catch_clara.cpp
|
||||
${SOURCES_DIR}/internal/catch_commandline.cpp
|
||||
${SOURCES_DIR}/internal/catch_console_colour.cpp
|
||||
${SOURCES_DIR}/internal/catch_context.cpp
|
||||
${SOURCES_DIR}/internal/catch_debug_console.cpp
|
||||
${SOURCES_DIR}/internal/catch_debugger.cpp
|
||||
${SOURCES_DIR}/internal/catch_decomposer.cpp
|
||||
${SOURCES_DIR}/internal/catch_enforce.cpp
|
||||
${SOURCES_DIR}/internal/catch_enum_values_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_errno_guard.cpp
|
||||
${SOURCES_DIR}/internal/catch_exception_translator_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_fatal_condition_handler.cpp
|
||||
${SOURCES_DIR}/internal/catch_floating_point_helpers.cpp
|
||||
${SOURCES_DIR}/internal/catch_getenv.cpp
|
||||
${SOURCES_DIR}/internal/catch_istream.cpp
|
||||
${SOURCES_DIR}/internal/catch_jsonwriter.cpp
|
||||
${SOURCES_DIR}/internal/catch_lazy_expr.cpp
|
||||
${SOURCES_DIR}/internal/catch_leak_detector.cpp
|
||||
${SOURCES_DIR}/internal/catch_list.cpp
|
||||
${SOURCES_DIR}/internal/catch_message_info.cpp
|
||||
${SOURCES_DIR}/internal/catch_output_redirect.cpp
|
||||
${SOURCES_DIR}/internal/catch_parse_numbers.cpp
|
||||
${SOURCES_DIR}/internal/catch_polyfills.cpp
|
||||
${SOURCES_DIR}/internal/catch_random_number_generator.cpp
|
||||
${SOURCES_DIR}/internal/catch_random_seed_generation.cpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_spec_parser.cpp
|
||||
${SOURCES_DIR}/internal/catch_reusable_string_stream.cpp
|
||||
${SOURCES_DIR}/internal/catch_run_context.cpp
|
||||
${SOURCES_DIR}/internal/catch_section.cpp
|
||||
${SOURCES_DIR}/internal/catch_singletons.cpp
|
||||
${SOURCES_DIR}/internal/catch_source_line_info.cpp
|
||||
${SOURCES_DIR}/internal/catch_startup_exception_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_stdstreams.cpp
|
||||
${SOURCES_DIR}/internal/catch_string_manip.cpp
|
||||
${SOURCES_DIR}/internal/catch_stringref.cpp
|
||||
${SOURCES_DIR}/internal/catch_tag_alias_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_info_hasher.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_registry_impl.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_case_tracker.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_failure_exception.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_test_spec_parser.cpp
|
||||
${SOURCES_DIR}/internal/catch_textflow.cpp
|
||||
${SOURCES_DIR}/internal/catch_uncaught_exceptions.cpp
|
||||
${SOURCES_DIR}/internal/catch_wildcard_pattern.cpp
|
||||
${SOURCES_DIR}/internal/catch_xmlwriter.cpp
|
||||
)
|
||||
set(INTERNAL_FILES ${IMPL_SOURCES} ${IMPL_HEADERS})
|
||||
|
||||
set(INTERFACE_HEADERS
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_all.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_capture.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_config.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_enum_values_registry.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_exception.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_generatortracker.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_tag_alias_registry.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_test_invoker.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_testcase.hpp
|
||||
)
|
||||
set(INTERFACE_SOURCES
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_capture.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_config.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_exception.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_generatortracker.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_testcase.cpp
|
||||
)
|
||||
set(INTERFACE_FILES ${INTERFACE_HEADERS} ${INTERFACE_SOURCES})
|
||||
|
||||
set(GENERATOR_HEADERS
|
||||
${SOURCES_DIR}/generators/catch_generator_exception.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators_adapters.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators_all.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators_random.hpp
|
||||
${SOURCES_DIR}/generators/catch_generators_range.hpp
|
||||
)
|
||||
set(GENERATOR_SOURCES
|
||||
${SOURCES_DIR}/generators/catch_generator_exception.cpp
|
||||
${SOURCES_DIR}/generators/catch_generators.cpp
|
||||
${SOURCES_DIR}/generators/catch_generators_random.cpp
|
||||
)
|
||||
set(GENERATOR_FILES ${GENERATOR_HEADERS} ${GENERATOR_SOURCES})
|
||||
|
||||
set(MATCHER_HEADERS
|
||||
${SOURCES_DIR}/matchers/catch_matchers.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_all.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_container_properties.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_contains.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_range_equals.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_exception.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_floating_point.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_predicate.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_quantifiers.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_string.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_templated.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_vector.hpp
|
||||
${SOURCES_DIR}/matchers/internal/catch_matchers_impl.hpp
|
||||
)
|
||||
set(MATCHER_SOURCES
|
||||
${SOURCES_DIR}/matchers/catch_matchers.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_container_properties.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_exception.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_floating_point.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_predicate.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_quantifiers.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_string.cpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_templated.cpp
|
||||
${SOURCES_DIR}/matchers/internal/catch_matchers_impl.cpp
|
||||
)
|
||||
set(MATCHER_FILES ${MATCHER_HEADERS} ${MATCHER_SOURCES})
|
||||
|
||||
set(REPORTER_HEADERS
|
||||
${SOURCES_DIR}/reporters/catch_reporter_automake.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_common_base.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_compact.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_console.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_cumulative_base.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_event_listener.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_helpers.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_json.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_junit.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_multi.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_registrars.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_sonarqube.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_streaming_base.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_tap.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_teamcity.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_xml.hpp
|
||||
${SOURCES_DIR}/reporters/catch_reporters_all.hpp
|
||||
)
|
||||
set(REPORTER_SOURCES
|
||||
${SOURCES_DIR}/reporters/catch_reporter_automake.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_common_base.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_compact.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_console.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_cumulative_base.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_event_listener.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_helpers.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_json.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_junit.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_multi.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_registrars.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_sonarqube.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_streaming_base.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_tap.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_teamcity.cpp
|
||||
${SOURCES_DIR}/reporters/catch_reporter_xml.cpp
|
||||
)
|
||||
set(REPORTER_FILES ${REPORTER_HEADERS} ${REPORTER_SOURCES})
|
||||
|
||||
set(ALL_FILES
|
||||
${BENCHMARK_FILES}
|
||||
${GENERATOR_FILES}
|
||||
${REPORTER_FILES}
|
||||
${INTERFACE_FILES}
|
||||
${INTERNAL_FILES}
|
||||
${MATCHER_FILES}
|
||||
)
|
||||
|
||||
set(FILTERED_FILES ${ALL_FILES})
|
||||
list(REMOVE_ITEM FILTERED_FILES "${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp")
|
||||
source_group(
|
||||
TREE ${SOURCES_DIR}
|
||||
PREFIX sources
|
||||
FILES ${FILTERED_FILES}
|
||||
)
|
||||
source_group("generated headers"
|
||||
FILES
|
||||
"${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp"
|
||||
)
|
||||
|
||||
add_library(Catch2 ${ALL_FILES})
|
||||
if(CATCH_ENABLE_REPRODUCIBLE_BUILD)
|
||||
add_build_reproducibility_settings(Catch2)
|
||||
endif()
|
||||
add_library(Catch2::Catch2 ALIAS Catch2)
|
||||
|
||||
if(ANDROID)
|
||||
target_link_libraries(Catch2 PRIVATE log)
|
||||
endif()
|
||||
|
||||
set_target_properties(Catch2 PROPERTIES
|
||||
DEBUG_POSTFIX "d"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION}
|
||||
)
|
||||
|
||||
# require C++14
|
||||
target_compile_features(Catch2 PUBLIC cxx_std_14)
|
||||
|
||||
configure_file(
|
||||
"${SOURCES_DIR}/catch_user_config.hpp.in"
|
||||
"${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp"
|
||||
)
|
||||
|
||||
target_include_directories(Catch2
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${SOURCES_DIR}/..>
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/generated-includes>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
|
||||
add_library(Catch2WithMain
|
||||
${SOURCES_DIR}/internal/catch_main.cpp
|
||||
)
|
||||
if(CATCH_ENABLE_REPRODUCIBLE_BUILD)
|
||||
add_build_reproducibility_settings(Catch2WithMain)
|
||||
endif()
|
||||
add_library(Catch2::Catch2WithMain ALIAS Catch2WithMain)
|
||||
target_link_libraries(Catch2WithMain PUBLIC Catch2)
|
||||
set_target_properties(Catch2WithMain
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "Catch2Main"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION}
|
||||
)
|
||||
set_target_properties(Catch2WithMain PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
||||
if(NOT_SUBPROJECT)
|
||||
# create and install an export set for catch target as Catch2::Catch
|
||||
install(
|
||||
TARGETS
|
||||
Catch2
|
||||
Catch2WithMain
|
||||
EXPORT
|
||||
Catch2Targets
|
||||
LIBRARY DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION
|
||||
${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT
|
||||
Catch2Targets
|
||||
NAMESPACE
|
||||
Catch2::
|
||||
DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
# Install the headers
|
||||
install(
|
||||
DIRECTORY
|
||||
"${SOURCES_DIR}"
|
||||
"${PROJECT_BINARY_DIR}/generated-includes/catch2" # Also install the generated header
|
||||
DESTINATION
|
||||
"${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
FILES_MATCHING
|
||||
PATTERN "*.hpp"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Some tests require a full recompilation of Catch2 lib with different
|
||||
# compilation flags. They can link against this target to recompile all
|
||||
# the sources into the binary.
|
||||
if(CATCH_BUILD_EXAMPLES OR CATCH_BUILD_EXTRA_TESTS)
|
||||
add_library(Catch2_buildall_interface INTERFACE)
|
||||
target_sources(Catch2_buildall_interface INTERFACE
|
||||
${ALL_FILES}
|
||||
# Also include main entry point
|
||||
${SOURCES_DIR}/internal/catch_main.cpp
|
||||
)
|
||||
target_include_directories(Catch2_buildall_interface
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${SOURCES_DIR}/..>
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/generated-includes>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_compile_definitions(Catch2_buildall_interface INTERFACE CATCH_CONFIG_STATIC)
|
||||
target_compile_features(Catch2_buildall_interface INTERFACE cxx_std_14)
|
||||
endif()
|
||||
|
||||
list(APPEND CATCH_IMPL_TARGETS Catch2 Catch2WithMain)
|
||||
set(CATCH_IMPL_TARGETS ${CATCH_IMPL_TARGETS} PARENT_SCOPE)
|
||||
|
||||
# We still do not support building dynamic library with hidden visibility
|
||||
# so we want to check & warn users if they do this. However, we won't abort
|
||||
# the configuration step so that we don't have to also provide an override.
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set_target_properties(Catch2 Catch2WithMain
|
||||
PROPERTIES
|
||||
WINDOWS_EXPORT_ALL_SYMBOLS ON
|
||||
)
|
||||
|
||||
get_target_property(_VisPreset Catch2 CXX_VISIBILITY_PRESET)
|
||||
if(NOT MSVC AND _VisPreset STREQUAL "hidden")
|
||||
set_target_properties(Catch2 Catch2WithMain
|
||||
PROPERTIES
|
||||
CXX_VISIBILITY_PRESET "default"
|
||||
VISIBILITY_INLINES_HIDDEN OFF
|
||||
)
|
||||
message(WARNING "Setting Catch2's visibility to default."
|
||||
" Hidden visibility is not supported.")
|
||||
endif()
|
||||
endif()
|
||||
146
tests/catch2/src/catch2/benchmark/catch_benchmark.hpp
Normal file
146
tests/catch2/src/catch2/benchmark/catch_benchmark.hpp
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_BENCHMARK_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_stats.hpp>
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_environment.hpp>
|
||||
#include <catch2/benchmark/catch_execution_plan.hpp>
|
||||
#include <catch2/benchmark/detail/catch_estimate_clock.hpp>
|
||||
#include <catch2/benchmark/detail/catch_analyse.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
struct Benchmark {
|
||||
Benchmark(std::string&& benchmarkName)
|
||||
: name(CATCH_MOVE(benchmarkName)) {}
|
||||
|
||||
template <class FUN>
|
||||
Benchmark(std::string&& benchmarkName , FUN &&func)
|
||||
: fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
|
||||
|
||||
template <typename Clock>
|
||||
ExecutionPlan prepare(const IConfig &cfg, Environment env) {
|
||||
auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
|
||||
auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
|
||||
auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<IDuration>(run_time), 1, fun);
|
||||
int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
|
||||
return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), CATCH_MOVE(fun), std::chrono::duration_cast<FDuration>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
|
||||
}
|
||||
|
||||
template <typename Clock = default_clock>
|
||||
void run() {
|
||||
static_assert( Clock::is_steady,
|
||||
"Benchmarking clock should be steady" );
|
||||
auto const* cfg = getCurrentContext().getConfig();
|
||||
|
||||
auto env = Detail::measure_environment<Clock>();
|
||||
|
||||
getResultCapture().benchmarkPreparing(name);
|
||||
CATCH_TRY{
|
||||
auto plan = user_code([&] {
|
||||
return prepare<Clock>(*cfg, env);
|
||||
});
|
||||
|
||||
BenchmarkInfo info {
|
||||
CATCH_MOVE(name),
|
||||
plan.estimated_duration.count(),
|
||||
plan.iterations_per_sample,
|
||||
cfg->benchmarkSamples(),
|
||||
cfg->benchmarkResamples(),
|
||||
env.clock_resolution.mean.count(),
|
||||
env.clock_cost.mean.count()
|
||||
};
|
||||
|
||||
getResultCapture().benchmarkStarting(info);
|
||||
|
||||
auto samples = user_code([&] {
|
||||
return plan.template run<Clock>(*cfg, env);
|
||||
});
|
||||
|
||||
auto analysis = Detail::analyse(*cfg, samples.data(), samples.data() + samples.size());
|
||||
BenchmarkStats<> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||
getResultCapture().benchmarkEnded(stats);
|
||||
} CATCH_CATCH_ALL {
|
||||
getResultCapture().benchmarkFailed(translateActiveException());
|
||||
// We let the exception go further up so that the
|
||||
// test case is marked as failed.
|
||||
std::rethrow_exception(std::current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
// sets lambda to be used in fun *and* executes benchmark!
|
||||
template <typename Fun, std::enable_if_t<!Detail::is_related_v<Fun, Benchmark>, int> = 0>
|
||||
Benchmark & operator=(Fun func) {
|
||||
auto const* cfg = getCurrentContext().getConfig();
|
||||
if (!cfg->skipBenchmarks()) {
|
||||
fun = Detail::BenchmarkFunction(func);
|
||||
run();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Detail::BenchmarkFunction fun;
|
||||
std::string name;
|
||||
};
|
||||
}
|
||||
} // namespace Catch
|
||||
|
||||
#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
|
||||
#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
|
||||
|
||||
#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
|
||||
if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
|
||||
BenchmarkName = [&](int benchmarkIndex)
|
||||
|
||||
#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
|
||||
if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
|
||||
BenchmarkName = [&]
|
||||
|
||||
#if defined(CATCH_CONFIG_PREFIX_ALL)
|
||||
|
||||
#define CATCH_BENCHMARK(...) \
|
||||
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
|
||||
#define CATCH_BENCHMARK_ADVANCED(name) \
|
||||
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
|
||||
|
||||
#else
|
||||
|
||||
#define BENCHMARK(...) \
|
||||
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
|
||||
#define BENCHMARK_ADVANCED(name) \
|
||||
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CATCH_BENCHMARK_HPP_INCLUDED
|
||||
46
tests/catch2/src/catch2/benchmark/catch_benchmark_all.hpp
Normal file
46
tests/catch2/src/catch2/benchmark/catch_benchmark_all.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/** \file
|
||||
* This is a convenience header for Catch2's benchmarking. It includes
|
||||
* **all** of Catch2 headers related to benchmarking.
|
||||
*
|
||||
* Generally the Catch2 users should use specific includes they need,
|
||||
* but this header can be used instead for ease-of-experimentation, or
|
||||
* just plain convenience, at the cost of (significantly) increased
|
||||
* compilation times.
|
||||
*
|
||||
* When a new header is added to either the `benchmark` folder, or to
|
||||
* the corresponding internal (detail) subfolder, it should be added here.
|
||||
*/
|
||||
|
||||
#ifndef CATCH_BENCHMARK_ALL_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_ALL_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_constructor.hpp>
|
||||
#include <catch2/benchmark/catch_environment.hpp>
|
||||
#include <catch2/benchmark/catch_estimate.hpp>
|
||||
#include <catch2/benchmark/catch_execution_plan.hpp>
|
||||
#include <catch2/benchmark/catch_optimizer.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
#include <catch2/benchmark/catch_sample_analysis.hpp>
|
||||
#include <catch2/benchmark/detail/catch_analyse.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_stats.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
#include <catch2/benchmark/detail/catch_estimate_clock.hpp>
|
||||
#include <catch2/benchmark/detail/catch_measure.hpp>
|
||||
#include <catch2/benchmark/detail/catch_repeat.hpp>
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||
#include <catch2/benchmark/detail/catch_timing.hpp>
|
||||
|
||||
#endif // CATCH_BENCHMARK_ALL_HPP_INCLUDED
|
||||
17
tests/catch2/src/catch2/benchmark/catch_chronometer.cpp
Normal file
17
tests/catch2/src/catch2/benchmark/catch_chronometer.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
ChronometerConcept::~ChronometerConcept() = default;
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
77
tests/catch2/src/catch2/benchmark/catch_chronometer.hpp
Normal file
77
tests/catch2/src/catch2/benchmark/catch_chronometer.hpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_CHRONOMETER_HPP_INCLUDED
|
||||
#define CATCH_CHRONOMETER_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_optimizer.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
struct ChronometerConcept {
|
||||
virtual void start() = 0;
|
||||
virtual void finish() = 0;
|
||||
virtual ~ChronometerConcept(); // = default;
|
||||
|
||||
ChronometerConcept() = default;
|
||||
ChronometerConcept(ChronometerConcept const&) = default;
|
||||
ChronometerConcept& operator=(ChronometerConcept const&) = default;
|
||||
};
|
||||
template <typename Clock>
|
||||
struct ChronometerModel final : public ChronometerConcept {
|
||||
void start() override { started = Clock::now(); }
|
||||
void finish() override { finished = Clock::now(); }
|
||||
|
||||
IDuration elapsed() const {
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
finished - started );
|
||||
}
|
||||
|
||||
TimePoint<Clock> started;
|
||||
TimePoint<Clock> finished;
|
||||
};
|
||||
} // namespace Detail
|
||||
|
||||
struct Chronometer {
|
||||
public:
|
||||
template <typename Fun>
|
||||
void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable<Fun(int)>()); }
|
||||
|
||||
int runs() const { return repeats; }
|
||||
|
||||
Chronometer(Detail::ChronometerConcept& meter, int repeats_)
|
||||
: impl(&meter)
|
||||
, repeats(repeats_) {}
|
||||
|
||||
private:
|
||||
template <typename Fun>
|
||||
void measure(Fun&& fun, std::false_type) {
|
||||
measure([&fun](int) { return fun(); }, std::true_type());
|
||||
}
|
||||
|
||||
template <typename Fun>
|
||||
void measure(Fun&& fun, std::true_type) {
|
||||
Detail::optimizer_barrier();
|
||||
impl->start();
|
||||
for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i);
|
||||
impl->finish();
|
||||
Detail::optimizer_barrier();
|
||||
}
|
||||
|
||||
Detail::ChronometerConcept* impl;
|
||||
int repeats;
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_CHRONOMETER_HPP_INCLUDED
|
||||
27
tests/catch2/src/catch2/benchmark/catch_clock.hpp
Normal file
27
tests/catch2/src/catch2/benchmark/catch_clock.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_CLOCK_HPP_INCLUDED
|
||||
#define CATCH_CLOCK_HPP_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
using IDuration = std::chrono::nanoseconds;
|
||||
using FDuration = std::chrono::duration<double, std::nano>;
|
||||
|
||||
template <typename Clock>
|
||||
using TimePoint = typename Clock::time_point;
|
||||
|
||||
using default_clock = std::chrono::steady_clock;
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_CLOCK_HPP_INCLUDED
|
||||
82
tests/catch2/src/catch2/benchmark/catch_constructor.hpp
Normal file
82
tests/catch2/src/catch2/benchmark/catch_constructor.hpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||
#define CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename T, bool Destruct>
|
||||
struct ObjectStorage
|
||||
{
|
||||
ObjectStorage() = default;
|
||||
|
||||
ObjectStorage(const ObjectStorage& other)
|
||||
{
|
||||
new(&data) T(other.stored_object());
|
||||
}
|
||||
|
||||
ObjectStorage(ObjectStorage&& other)
|
||||
{
|
||||
new(data) T(CATCH_MOVE(other.stored_object()));
|
||||
}
|
||||
|
||||
~ObjectStorage() { destruct_on_exit<T>(); }
|
||||
|
||||
template <typename... Args>
|
||||
void construct(Args&&... args)
|
||||
{
|
||||
new (data) T(CATCH_FORWARD(args)...);
|
||||
}
|
||||
|
||||
template <bool AllowManualDestruction = !Destruct>
|
||||
std::enable_if_t<AllowManualDestruction> destruct()
|
||||
{
|
||||
stored_object().~T();
|
||||
}
|
||||
|
||||
private:
|
||||
// If this is a constructor benchmark, destruct the underlying object
|
||||
template <typename U>
|
||||
void destruct_on_exit(std::enable_if_t<Destruct, U>* = nullptr) { destruct<true>(); }
|
||||
// Otherwise, don't
|
||||
template <typename U>
|
||||
void destruct_on_exit(std::enable_if_t<!Destruct, U>* = nullptr) { }
|
||||
|
||||
#if defined( __GNUC__ ) && __GNUC__ <= 6
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#endif
|
||||
T& stored_object() { return *reinterpret_cast<T*>( data ); }
|
||||
|
||||
T const& stored_object() const {
|
||||
return *reinterpret_cast<T const*>( data );
|
||||
}
|
||||
#if defined( __GNUC__ ) && __GNUC__ <= 6
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
alignas( T ) unsigned char data[sizeof( T )]{};
|
||||
};
|
||||
} // namespace Detail
|
||||
|
||||
template <typename T>
|
||||
using storage_for = Detail::ObjectStorage<T, true>;
|
||||
|
||||
template <typename T>
|
||||
using destructable_object = Detail::ObjectStorage<T, false>;
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||
29
tests/catch2/src/catch2/benchmark/catch_environment.hpp
Normal file
29
tests/catch2/src/catch2/benchmark/catch_environment.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED
|
||||
#define CATCH_ENVIRONMENT_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
struct EnvironmentEstimate {
|
||||
FDuration mean;
|
||||
OutlierClassification outliers;
|
||||
};
|
||||
struct Environment {
|
||||
EnvironmentEstimate clock_resolution;
|
||||
EnvironmentEstimate clock_cost;
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_ENVIRONMENT_HPP_INCLUDED
|
||||
25
tests/catch2/src/catch2/benchmark/catch_estimate.hpp
Normal file
25
tests/catch2/src/catch2/benchmark/catch_estimate.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_ESTIMATE_HPP_INCLUDED
|
||||
#define CATCH_ESTIMATE_HPP_INCLUDED
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
template <typename Type>
|
||||
struct Estimate {
|
||||
Type point;
|
||||
Type lower_bound;
|
||||
Type upper_bound;
|
||||
double confidence_interval;
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_ESTIMATE_HPP_INCLUDED
|
||||
58
tests/catch2/src/catch2/benchmark/catch_execution_plan.hpp
Normal file
58
tests/catch2/src/catch2/benchmark/catch_execution_plan.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED
|
||||
#define CATCH_EXECUTION_PLAN_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_environment.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
#include <catch2/benchmark/detail/catch_repeat.hpp>
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
struct ExecutionPlan {
|
||||
int iterations_per_sample;
|
||||
FDuration estimated_duration;
|
||||
Detail::BenchmarkFunction benchmark;
|
||||
FDuration warmup_time;
|
||||
int warmup_iterations;
|
||||
|
||||
template <typename Clock>
|
||||
std::vector<FDuration> run(const IConfig &cfg, Environment env) const {
|
||||
// warmup a bit
|
||||
Detail::run_for_at_least<Clock>(
|
||||
std::chrono::duration_cast<IDuration>( warmup_time ),
|
||||
warmup_iterations,
|
||||
Detail::repeat( []() { return Clock::now(); } )
|
||||
);
|
||||
|
||||
std::vector<FDuration> times;
|
||||
const auto num_samples = cfg.benchmarkSamples();
|
||||
times.reserve( num_samples );
|
||||
for ( size_t i = 0; i < num_samples; ++i ) {
|
||||
Detail::ChronometerModel<Clock> model;
|
||||
this->benchmark( Chronometer( model, iterations_per_sample ) );
|
||||
auto sample_time = model.elapsed() - env.clock_cost.mean;
|
||||
if ( sample_time < FDuration::zero() ) {
|
||||
sample_time = FDuration::zero();
|
||||
}
|
||||
times.push_back(sample_time / iterations_per_sample);
|
||||
}
|
||||
return times;
|
||||
}
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED
|
||||
78
tests/catch2/src/catch2/benchmark/catch_optimizer.hpp
Normal file
78
tests/catch2/src/catch2/benchmark/catch_optimizer.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_OPTIMIZER_HPP_INCLUDED
|
||||
#define CATCH_OPTIMIZER_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
|
||||
# include <atomic> // atomic_thread_fence
|
||||
#endif
|
||||
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
template <typename T>
|
||||
inline void keep_memory(T* p) {
|
||||
asm volatile("" : : "g"(p) : "memory");
|
||||
}
|
||||
inline void keep_memory() {
|
||||
asm volatile("" : : : "memory");
|
||||
}
|
||||
|
||||
namespace Detail {
|
||||
inline void optimizer_barrier() { keep_memory(); }
|
||||
} // namespace Detail
|
||||
#elif defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
|
||||
|
||||
#if defined(_MSVC_VER)
|
||||
#pragma optimize("", off)
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
// For IAR the pragma only affects the following function
|
||||
#pragma optimize=disable
|
||||
#endif
|
||||
template <typename T>
|
||||
inline void keep_memory(T* p) {
|
||||
// thanks @milleniumbug
|
||||
*reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
|
||||
}
|
||||
// TODO equivalent keep_memory()
|
||||
#if defined(_MSVC_VER)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
namespace Detail {
|
||||
inline void optimizer_barrier() {
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
}
|
||||
} // namespace Detail
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline void deoptimize_value(T&& x) {
|
||||
keep_memory(&x);
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<!std::is_same<void, decltype(fn(args...))>::value> {
|
||||
deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...));
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<std::is_same<void, decltype(fn(args...))>::value> {
|
||||
CATCH_FORWARD((fn)) (CATCH_FORWARD(args)...);
|
||||
}
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_OPTIMIZER_HPP_INCLUDED
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
|
||||
#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
struct OutlierClassification {
|
||||
int samples_seen = 0;
|
||||
int low_severe = 0; // more than 3 times IQR below Q1
|
||||
int low_mild = 0; // 1.5 to 3 times IQR below Q1
|
||||
int high_mild = 0; // 1.5 to 3 times IQR above Q3
|
||||
int high_severe = 0; // more than 3 times IQR above Q3
|
||||
|
||||
constexpr int total() const {
|
||||
return low_severe + low_mild + high_mild + high_severe;
|
||||
}
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED
|
||||
31
tests/catch2/src/catch2/benchmark/catch_sample_analysis.hpp
Normal file
31
tests/catch2/src/catch2/benchmark/catch_sample_analysis.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
|
||||
#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_estimate.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
struct SampleAnalysis {
|
||||
std::vector<FDuration> samples;
|
||||
Estimate<FDuration> mean;
|
||||
Estimate<FDuration> standard_deviation;
|
||||
OutlierClassification outliers;
|
||||
double outlier_variance;
|
||||
};
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
|
||||
85
tests/catch2/src/catch2/benchmark/detail/catch_analyse.cpp
Normal file
85
tests/catch2/src/catch2/benchmark/detail/catch_analyse.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#include <catch2/benchmark/detail/catch_analyse.hpp>
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_sample_analysis.hpp>
|
||||
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) {
|
||||
if (!cfg.benchmarkNoAnalysis()) {
|
||||
std::vector<double> samples;
|
||||
samples.reserve(static_cast<size_t>(last - first));
|
||||
for (auto current = first; current != last; ++current) {
|
||||
samples.push_back( current->count() );
|
||||
}
|
||||
|
||||
auto analysis = Catch::Benchmark::Detail::analyse_samples(
|
||||
cfg.benchmarkConfidenceInterval(),
|
||||
cfg.benchmarkResamples(),
|
||||
samples.data(),
|
||||
samples.data() + samples.size() );
|
||||
auto outliers = Catch::Benchmark::Detail::classify_outliers(
|
||||
samples.data(), samples.data() + samples.size() );
|
||||
|
||||
auto wrap_estimate = [](Estimate<double> e) {
|
||||
return Estimate<FDuration> {
|
||||
FDuration(e.point),
|
||||
FDuration(e.lower_bound),
|
||||
FDuration(e.upper_bound),
|
||||
e.confidence_interval,
|
||||
};
|
||||
};
|
||||
std::vector<FDuration> samples2;
|
||||
samples2.reserve(samples.size());
|
||||
for (auto s : samples) {
|
||||
samples2.push_back( FDuration( s ) );
|
||||
}
|
||||
|
||||
return {
|
||||
CATCH_MOVE(samples2),
|
||||
wrap_estimate(analysis.mean),
|
||||
wrap_estimate(analysis.standard_deviation),
|
||||
outliers,
|
||||
analysis.outlier_variance,
|
||||
};
|
||||
} else {
|
||||
std::vector<FDuration> samples;
|
||||
samples.reserve(static_cast<size_t>(last - first));
|
||||
|
||||
FDuration mean = FDuration(0);
|
||||
int i = 0;
|
||||
for (auto it = first; it < last; ++it, ++i) {
|
||||
samples.push_back(*it);
|
||||
mean += *it;
|
||||
}
|
||||
mean /= i;
|
||||
|
||||
return SampleAnalysis{
|
||||
CATCH_MOVE(samples),
|
||||
Estimate<FDuration>{ mean, mean, mean, 0.0 },
|
||||
Estimate<FDuration>{ FDuration( 0 ),
|
||||
FDuration( 0 ),
|
||||
FDuration( 0 ),
|
||||
0.0 },
|
||||
OutlierClassification{},
|
||||
0.0
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
27
tests/catch2/src/catch2/benchmark/detail/catch_analyse.hpp
Normal file
27
tests/catch2/src/catch2/benchmark/detail/catch_analyse.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_ANALYSE_HPP_INCLUDED
|
||||
#define CATCH_ANALYSE_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_sample_analysis.hpp>
|
||||
|
||||
|
||||
namespace Catch {
|
||||
class IConfig;
|
||||
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last);
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_ANALYSE_HPP_INCLUDED
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
struct do_nothing {
|
||||
void operator()() const {}
|
||||
};
|
||||
|
||||
BenchmarkFunction::callable::~callable() = default;
|
||||
BenchmarkFunction::BenchmarkFunction():
|
||||
f( new model<do_nothing>{ {} } ){}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename T, typename U>
|
||||
static constexpr bool is_related_v = std::is_same<std::decay_t<T>, std::decay_t<U>>::value;
|
||||
|
||||
/// We need to reinvent std::function because every piece of code that might add overhead
|
||||
/// in a measurement context needs to have consistent performance characteristics so that we
|
||||
/// can account for it in the measurement.
|
||||
/// Implementations of std::function with optimizations that aren't always applicable, like
|
||||
/// small buffer optimizations, are not uncommon.
|
||||
/// This is effectively an implementation of std::function without any such optimizations;
|
||||
/// it may be slow, but it is consistently slow.
|
||||
struct BenchmarkFunction {
|
||||
private:
|
||||
struct callable {
|
||||
virtual void call(Chronometer meter) const = 0;
|
||||
virtual ~callable(); // = default;
|
||||
|
||||
callable() = default;
|
||||
callable(callable&&) = default;
|
||||
callable& operator=(callable&&) = default;
|
||||
};
|
||||
template <typename Fun>
|
||||
struct model : public callable {
|
||||
model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
|
||||
model(Fun const& fun_) : fun(fun_) {}
|
||||
|
||||
void call(Chronometer meter) const override {
|
||||
call(meter, is_callable<Fun(Chronometer)>());
|
||||
}
|
||||
void call(Chronometer meter, std::true_type) const {
|
||||
fun(meter);
|
||||
}
|
||||
void call(Chronometer meter, std::false_type) const {
|
||||
meter.measure(fun);
|
||||
}
|
||||
|
||||
Fun fun;
|
||||
};
|
||||
|
||||
public:
|
||||
BenchmarkFunction();
|
||||
|
||||
template <typename Fun,
|
||||
std::enable_if_t<!is_related_v<Fun, BenchmarkFunction>, int> = 0>
|
||||
BenchmarkFunction(Fun&& fun)
|
||||
: f(new model<std::decay_t<Fun>>(CATCH_FORWARD(fun))) {}
|
||||
|
||||
BenchmarkFunction( BenchmarkFunction&& that ) noexcept:
|
||||
f( CATCH_MOVE( that.f ) ) {}
|
||||
|
||||
BenchmarkFunction&
|
||||
operator=( BenchmarkFunction&& that ) noexcept {
|
||||
f = CATCH_MOVE( that.f );
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()(Chronometer meter) const { f->call(meter); }
|
||||
|
||||
private:
|
||||
Catch::Detail::unique_ptr<callable> f;
|
||||
};
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_STATS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_estimate.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
// The fwd decl & default specialization needs to be seen by VS2017 before
|
||||
// BenchmarkStats itself, or VS2017 will report compilation error.
|
||||
#include <catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct BenchmarkInfo {
|
||||
std::string name;
|
||||
double estimatedDuration;
|
||||
int iterations;
|
||||
unsigned int samples;
|
||||
unsigned int resamples;
|
||||
double clockResolution;
|
||||
double clockCost;
|
||||
};
|
||||
|
||||
// We need to keep template parameter for backwards compatibility,
|
||||
// but we also do not want to use the template paraneter.
|
||||
template <class Dummy>
|
||||
struct BenchmarkStats {
|
||||
BenchmarkInfo info;
|
||||
|
||||
std::vector<Benchmark::FDuration> samples;
|
||||
Benchmark::Estimate<Benchmark::FDuration> mean;
|
||||
Benchmark::Estimate<Benchmark::FDuration> standardDeviation;
|
||||
Benchmark::OutlierClassification outliers;
|
||||
double outlierVariance;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_BENCHMARK_STATS_HPP_INCLUDED
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// We cannot forward declare the type with default template argument
|
||||
// multiple times, so it is split out into a separate header so that
|
||||
// we can prevent multiple declarations in dependees
|
||||
template <typename Duration = Benchmark::FDuration>
|
||||
struct BenchmarkStats;
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED
|
||||
#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename T>
|
||||
struct CompleteType { using type = T; };
|
||||
template <>
|
||||
struct CompleteType<void> { struct type {}; };
|
||||
|
||||
template <typename T>
|
||||
using CompleteType_t = typename CompleteType<T>::type;
|
||||
|
||||
template <typename Result>
|
||||
struct CompleteInvoker {
|
||||
template <typename Fun, typename... Args>
|
||||
static Result invoke(Fun&& fun, Args&&... args) {
|
||||
return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct CompleteInvoker<void> {
|
||||
template <typename Fun, typename... Args>
|
||||
static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
|
||||
CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// invoke and not return void :(
|
||||
template <typename Fun, typename... Args>
|
||||
CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
|
||||
return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
template <typename Fun>
|
||||
Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
|
||||
return Detail::complete_invoke(CATCH_FORWARD(fun));
|
||||
}
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
|
||||
#define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_environment.hpp>
|
||||
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||
#include <catch2/benchmark/detail/catch_measure.hpp>
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename Clock>
|
||||
std::vector<double> resolution(int k) {
|
||||
const size_t points = static_cast<size_t>( k + 1 );
|
||||
// To avoid overhead from the branch inside vector::push_back,
|
||||
// we allocate them all and then overwrite.
|
||||
std::vector<TimePoint<Clock>> times(points);
|
||||
for ( auto& time : times ) {
|
||||
time = Clock::now();
|
||||
}
|
||||
|
||||
std::vector<double> deltas;
|
||||
deltas.reserve(static_cast<size_t>(k));
|
||||
for ( size_t idx = 1; idx < points; ++idx ) {
|
||||
deltas.push_back( static_cast<double>(
|
||||
( times[idx] - times[idx - 1] ).count() ) );
|
||||
}
|
||||
|
||||
return deltas;
|
||||
}
|
||||
|
||||
constexpr auto warmup_iterations = 10000;
|
||||
constexpr auto warmup_time = std::chrono::milliseconds(100);
|
||||
constexpr auto minimum_ticks = 1000;
|
||||
constexpr auto warmup_seed = 10000;
|
||||
constexpr auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
|
||||
constexpr auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
|
||||
constexpr auto clock_cost_estimation_tick_limit = 100000;
|
||||
constexpr auto clock_cost_estimation_time = std::chrono::milliseconds(10);
|
||||
constexpr auto clock_cost_estimation_iterations = 10000;
|
||||
|
||||
template <typename Clock>
|
||||
int warmup() {
|
||||
return run_for_at_least<Clock>(warmup_time, warmup_seed, &resolution<Clock>)
|
||||
.iterations;
|
||||
}
|
||||
template <typename Clock>
|
||||
EnvironmentEstimate estimate_clock_resolution(int iterations) {
|
||||
auto r = run_for_at_least<Clock>(clock_resolution_estimation_time, iterations, &resolution<Clock>)
|
||||
.result;
|
||||
return {
|
||||
FDuration(mean(r.data(), r.data() + r.size())),
|
||||
classify_outliers(r.data(), r.data() + r.size()),
|
||||
};
|
||||
}
|
||||
template <typename Clock>
|
||||
EnvironmentEstimate estimate_clock_cost(FDuration resolution) {
|
||||
auto time_limit = (std::min)(
|
||||
resolution * clock_cost_estimation_tick_limit,
|
||||
FDuration(clock_cost_estimation_time_limit));
|
||||
auto time_clock = [](int k) {
|
||||
return Detail::measure<Clock>([k] {
|
||||
for (int i = 0; i < k; ++i) {
|
||||
volatile auto ignored = Clock::now();
|
||||
(void)ignored;
|
||||
}
|
||||
}).elapsed;
|
||||
};
|
||||
time_clock(1);
|
||||
int iters = clock_cost_estimation_iterations;
|
||||
auto&& r = run_for_at_least<Clock>(clock_cost_estimation_time, iters, time_clock);
|
||||
std::vector<double> times;
|
||||
int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
|
||||
times.reserve(static_cast<size_t>(nsamples));
|
||||
for ( int s = 0; s < nsamples; ++s ) {
|
||||
times.push_back( static_cast<double>(
|
||||
( time_clock( r.iterations ) / r.iterations )
|
||||
.count() ) );
|
||||
}
|
||||
return {
|
||||
FDuration(mean(times.data(), times.data() + times.size())),
|
||||
classify_outliers(times.data(), times.data() + times.size()),
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Clock>
|
||||
Environment measure_environment() {
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#endif
|
||||
static Catch::Detail::unique_ptr<Environment> env;
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
if (env) {
|
||||
return *env;
|
||||
}
|
||||
|
||||
auto iters = Detail::warmup<Clock>();
|
||||
auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
|
||||
auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
|
||||
|
||||
env = Catch::Detail::make_unique<Environment>( Environment{resolution, cost} );
|
||||
return *env;
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
|
||||
32
tests/catch2/src/catch2/benchmark/detail/catch_measure.hpp
Normal file
32
tests/catch2/src/catch2/benchmark/detail/catch_measure.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_MEASURE_HPP_INCLUDED
|
||||
#define CATCH_MEASURE_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
#include <catch2/benchmark/detail/catch_timing.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename Clock, typename Fun, typename... Args>
|
||||
TimingOf<Fun, Args...> measure(Fun&& fun, Args&&... args) {
|
||||
auto start = Clock::now();
|
||||
auto&& r = Detail::complete_invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
|
||||
auto end = Clock::now();
|
||||
auto delta = end - start;
|
||||
return { delta, CATCH_FORWARD(r), 1 };
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_MEASURE_HPP_INCLUDED
|
||||
36
tests/catch2/src/catch2/benchmark/detail/catch_repeat.hpp
Normal file
36
tests/catch2/src/catch2/benchmark/detail/catch_repeat.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_REPEAT_HPP_INCLUDED
|
||||
#define CATCH_REPEAT_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename Fun>
|
||||
struct repeater {
|
||||
void operator()(int k) const {
|
||||
for (int i = 0; i < k; ++i) {
|
||||
fun();
|
||||
}
|
||||
}
|
||||
Fun fun;
|
||||
};
|
||||
template <typename Fun>
|
||||
repeater<std::decay_t<Fun>> repeat(Fun&& fun) {
|
||||
return { CATCH_FORWARD(fun) };
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_REPEAT_HPP_INCLUDED
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
struct optimized_away_error : std::exception {
|
||||
const char* what() const noexcept override;
|
||||
};
|
||||
|
||||
const char* optimized_away_error::what() const noexcept {
|
||||
return "could not measure benchmark, maybe it was optimized away";
|
||||
}
|
||||
|
||||
void throw_optimized_away_error() {
|
||||
Catch::throw_exception(optimized_away_error{});
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
|
||||
#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
#include <catch2/benchmark/detail/catch_measure.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
#include <catch2/benchmark/detail/catch_timing.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
template <typename Clock, typename Fun>
|
||||
TimingOf<Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
|
||||
return Detail::measure<Clock>(fun, iters);
|
||||
}
|
||||
template <typename Clock, typename Fun>
|
||||
TimingOf<Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
|
||||
Detail::ChronometerModel<Clock> meter;
|
||||
auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
|
||||
|
||||
return { meter.elapsed(), CATCH_MOVE(result), iters };
|
||||
}
|
||||
|
||||
template <typename Clock, typename Fun>
|
||||
using run_for_at_least_argument_t = std::conditional_t<is_callable<Fun(Chronometer)>::value, Chronometer, int>;
|
||||
|
||||
|
||||
[[noreturn]]
|
||||
void throw_optimized_away_error();
|
||||
|
||||
template <typename Clock, typename Fun>
|
||||
TimingOf<Fun, run_for_at_least_argument_t<Clock, Fun>>
|
||||
run_for_at_least(IDuration how_long,
|
||||
const int initial_iterations,
|
||||
Fun&& fun) {
|
||||
auto iters = initial_iterations;
|
||||
while (iters < (1 << 30)) {
|
||||
auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
|
||||
|
||||
if (Timing.elapsed >= how_long) {
|
||||
return { Timing.elapsed, CATCH_MOVE(Timing.result), iters };
|
||||
}
|
||||
iters *= 2;
|
||||
}
|
||||
throw_optimized_away_error();
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
|
||||
393
tests/catch2/src/catch2/benchmark/detail/catch_stats.cpp
Normal file
393
tests/catch2/src/catch2/benchmark/detail/catch_stats.cpp
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#include <catch2/benchmark/detail/catch_stats.hpp>
|
||||
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_floating_point_helpers.hpp>
|
||||
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||
#include <catch2/internal/catch_uniform_integer_distribution.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
|
||||
|
||||
#if defined(CATCH_CONFIG_USE_ASYNC)
|
||||
#include <future>
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
namespace {
|
||||
|
||||
template <typename URng, typename Estimator>
|
||||
static sample
|
||||
resample( URng& rng,
|
||||
unsigned int resamples,
|
||||
double const* first,
|
||||
double const* last,
|
||||
Estimator& estimator ) {
|
||||
auto n = static_cast<size_t>( last - first );
|
||||
Catch::uniform_integer_distribution<size_t> dist( 0, n - 1 );
|
||||
|
||||
sample out;
|
||||
out.reserve( resamples );
|
||||
std::vector<double> resampled;
|
||||
resampled.reserve( n );
|
||||
for ( size_t i = 0; i < resamples; ++i ) {
|
||||
resampled.clear();
|
||||
for ( size_t s = 0; s < n; ++s ) {
|
||||
resampled.push_back( first[dist( rng )] );
|
||||
}
|
||||
const auto estimate =
|
||||
estimator( resampled.data(), resampled.data() + resampled.size() );
|
||||
out.push_back( estimate );
|
||||
}
|
||||
std::sort( out.begin(), out.end() );
|
||||
return out;
|
||||
}
|
||||
|
||||
static double outlier_variance( Estimate<double> mean,
|
||||
Estimate<double> stddev,
|
||||
int n ) {
|
||||
double sb = stddev.point;
|
||||
double mn = mean.point / n;
|
||||
double mg_min = mn / 2.;
|
||||
double sg = (std::min)( mg_min / 4., sb / std::sqrt( n ) );
|
||||
double sg2 = sg * sg;
|
||||
double sb2 = sb * sb;
|
||||
|
||||
auto c_max = [n, mn, sb2, sg2]( double x ) -> double {
|
||||
double k = mn - x;
|
||||
double d = k * k;
|
||||
double nd = n * d;
|
||||
double k0 = -n * nd;
|
||||
double k1 = sb2 - n * sg2 + nd;
|
||||
double det = k1 * k1 - 4 * sg2 * k0;
|
||||
return static_cast<int>( -2. * k0 /
|
||||
( k1 + std::sqrt( det ) ) );
|
||||
};
|
||||
|
||||
auto var_out = [n, sb2, sg2]( double c ) {
|
||||
double nc = n - c;
|
||||
return ( nc / n ) * ( sb2 - nc * sg2 );
|
||||
};
|
||||
|
||||
return (std::min)( var_out( 1 ),
|
||||
var_out(
|
||||
(std::min)( c_max( 0. ),
|
||||
c_max( mg_min ) ) ) ) /
|
||||
sb2;
|
||||
}
|
||||
|
||||
static double erf_inv( double x ) {
|
||||
// Code accompanying the article "Approximating the erfinv
|
||||
// function" in GPU Computing Gems, Volume 2
|
||||
double w, p;
|
||||
|
||||
w = -log( ( 1.0 - x ) * ( 1.0 + x ) );
|
||||
|
||||
if ( w < 6.250000 ) {
|
||||
w = w - 3.125000;
|
||||
p = -3.6444120640178196996e-21;
|
||||
p = -1.685059138182016589e-19 + p * w;
|
||||
p = 1.2858480715256400167e-18 + p * w;
|
||||
p = 1.115787767802518096e-17 + p * w;
|
||||
p = -1.333171662854620906e-16 + p * w;
|
||||
p = 2.0972767875968561637e-17 + p * w;
|
||||
p = 6.6376381343583238325e-15 + p * w;
|
||||
p = -4.0545662729752068639e-14 + p * w;
|
||||
p = -8.1519341976054721522e-14 + p * w;
|
||||
p = 2.6335093153082322977e-12 + p * w;
|
||||
p = -1.2975133253453532498e-11 + p * w;
|
||||
p = -5.4154120542946279317e-11 + p * w;
|
||||
p = 1.051212273321532285e-09 + p * w;
|
||||
p = -4.1126339803469836976e-09 + p * w;
|
||||
p = -2.9070369957882005086e-08 + p * w;
|
||||
p = 4.2347877827932403518e-07 + p * w;
|
||||
p = -1.3654692000834678645e-06 + p * w;
|
||||
p = -1.3882523362786468719e-05 + p * w;
|
||||
p = 0.0001867342080340571352 + p * w;
|
||||
p = -0.00074070253416626697512 + p * w;
|
||||
p = -0.0060336708714301490533 + p * w;
|
||||
p = 0.24015818242558961693 + p * w;
|
||||
p = 1.6536545626831027356 + p * w;
|
||||
} else if ( w < 16.000000 ) {
|
||||
w = sqrt( w ) - 3.250000;
|
||||
p = 2.2137376921775787049e-09;
|
||||
p = 9.0756561938885390979e-08 + p * w;
|
||||
p = -2.7517406297064545428e-07 + p * w;
|
||||
p = 1.8239629214389227755e-08 + p * w;
|
||||
p = 1.5027403968909827627e-06 + p * w;
|
||||
p = -4.013867526981545969e-06 + p * w;
|
||||
p = 2.9234449089955446044e-06 + p * w;
|
||||
p = 1.2475304481671778723e-05 + p * w;
|
||||
p = -4.7318229009055733981e-05 + p * w;
|
||||
p = 6.8284851459573175448e-05 + p * w;
|
||||
p = 2.4031110387097893999e-05 + p * w;
|
||||
p = -0.0003550375203628474796 + p * w;
|
||||
p = 0.00095328937973738049703 + p * w;
|
||||
p = -0.0016882755560235047313 + p * w;
|
||||
p = 0.0024914420961078508066 + p * w;
|
||||
p = -0.0037512085075692412107 + p * w;
|
||||
p = 0.005370914553590063617 + p * w;
|
||||
p = 1.0052589676941592334 + p * w;
|
||||
p = 3.0838856104922207635 + p * w;
|
||||
} else {
|
||||
w = sqrt( w ) - 5.000000;
|
||||
p = -2.7109920616438573243e-11;
|
||||
p = -2.5556418169965252055e-10 + p * w;
|
||||
p = 1.5076572693500548083e-09 + p * w;
|
||||
p = -3.7894654401267369937e-09 + p * w;
|
||||
p = 7.6157012080783393804e-09 + p * w;
|
||||
p = -1.4960026627149240478e-08 + p * w;
|
||||
p = 2.9147953450901080826e-08 + p * w;
|
||||
p = -6.7711997758452339498e-08 + p * w;
|
||||
p = 2.2900482228026654717e-07 + p * w;
|
||||
p = -9.9298272942317002539e-07 + p * w;
|
||||
p = 4.5260625972231537039e-06 + p * w;
|
||||
p = -1.9681778105531670567e-05 + p * w;
|
||||
p = 7.5995277030017761139e-05 + p * w;
|
||||
p = -0.00021503011930044477347 + p * w;
|
||||
p = -0.00013871931833623122026 + p * w;
|
||||
p = 1.0103004648645343977 + p * w;
|
||||
p = 4.8499064014085844221 + p * w;
|
||||
}
|
||||
return p * x;
|
||||
}
|
||||
|
||||
static double
|
||||
standard_deviation( double const* first, double const* last ) {
|
||||
auto m = Catch::Benchmark::Detail::mean( first, last );
|
||||
double variance =
|
||||
std::accumulate( first,
|
||||
last,
|
||||
0.,
|
||||
[m]( double a, double b ) {
|
||||
double diff = b - m;
|
||||
return a + diff * diff;
|
||||
} ) /
|
||||
static_cast<double>( last - first );
|
||||
return std::sqrt( variance );
|
||||
}
|
||||
|
||||
static sample jackknife( double ( *estimator )( double const*,
|
||||
double const* ),
|
||||
double* first,
|
||||
double* last ) {
|
||||
const auto second = first + 1;
|
||||
sample results;
|
||||
results.reserve( static_cast<size_t>( last - first ) );
|
||||
|
||||
for ( auto it = first; it != last; ++it ) {
|
||||
std::iter_swap( it, first );
|
||||
results.push_back( estimator( second, last ) );
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
|
||||
double weighted_average_quantile( int k,
|
||||
int q,
|
||||
double* first,
|
||||
double* last ) {
|
||||
auto count = last - first;
|
||||
double idx = static_cast<double>((count - 1) * k) / static_cast<double>(q);
|
||||
int j = static_cast<int>(idx);
|
||||
double g = idx - j;
|
||||
std::nth_element(first, first + j, last);
|
||||
auto xj = first[j];
|
||||
if ( Catch::Detail::directCompare( g, 0 ) ) {
|
||||
return xj;
|
||||
}
|
||||
|
||||
auto xj1 = *std::min_element(first + (j + 1), last);
|
||||
return xj + g * (xj1 - xj);
|
||||
}
|
||||
|
||||
OutlierClassification
|
||||
classify_outliers( double const* first, double const* last ) {
|
||||
std::vector<double> copy( first, last );
|
||||
|
||||
auto q1 = weighted_average_quantile( 1, 4, copy.data(), copy.data() + copy.size() );
|
||||
auto q3 = weighted_average_quantile( 3, 4, copy.data(), copy.data() + copy.size() );
|
||||
auto iqr = q3 - q1;
|
||||
auto los = q1 - ( iqr * 3. );
|
||||
auto lom = q1 - ( iqr * 1.5 );
|
||||
auto him = q3 + ( iqr * 1.5 );
|
||||
auto his = q3 + ( iqr * 3. );
|
||||
|
||||
OutlierClassification o;
|
||||
for ( ; first != last; ++first ) {
|
||||
const double t = *first;
|
||||
if ( t < los ) {
|
||||
++o.low_severe;
|
||||
} else if ( t < lom ) {
|
||||
++o.low_mild;
|
||||
} else if ( t > his ) {
|
||||
++o.high_severe;
|
||||
} else if ( t > him ) {
|
||||
++o.high_mild;
|
||||
}
|
||||
++o.samples_seen;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
double mean( double const* first, double const* last ) {
|
||||
auto count = last - first;
|
||||
double sum = 0.;
|
||||
while (first != last) {
|
||||
sum += *first;
|
||||
++first;
|
||||
}
|
||||
return sum / static_cast<double>(count);
|
||||
}
|
||||
|
||||
double normal_cdf( double x ) {
|
||||
return std::erfc( -x / std::sqrt( 2.0 ) ) / 2.0;
|
||||
}
|
||||
|
||||
double erfc_inv(double x) {
|
||||
return erf_inv(1.0 - x);
|
||||
}
|
||||
|
||||
double normal_quantile(double p) {
|
||||
static const double ROOT_TWO = std::sqrt(2.0);
|
||||
|
||||
double result = 0.0;
|
||||
assert(p >= 0 && p <= 1);
|
||||
if (p < 0 || p > 1) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = -erfc_inv(2.0 * p);
|
||||
// result *= normal distribution standard deviation (1.0) * sqrt(2)
|
||||
result *= /*sd * */ ROOT_TWO;
|
||||
// result += normal disttribution mean (0)
|
||||
return result;
|
||||
}
|
||||
|
||||
Estimate<double>
|
||||
bootstrap( double confidence_level,
|
||||
double* first,
|
||||
double* last,
|
||||
sample const& resample,
|
||||
double ( *estimator )( double const*, double const* ) ) {
|
||||
auto n_samples = last - first;
|
||||
|
||||
double point = estimator( first, last );
|
||||
// Degenerate case with a single sample
|
||||
if ( n_samples == 1 )
|
||||
return { point, point, point, confidence_level };
|
||||
|
||||
sample jack = jackknife( estimator, first, last );
|
||||
double jack_mean =
|
||||
mean( jack.data(), jack.data() + jack.size() );
|
||||
double sum_squares = 0, sum_cubes = 0;
|
||||
for ( double x : jack ) {
|
||||
auto difference = jack_mean - x;
|
||||
auto square = difference * difference;
|
||||
auto cube = square * difference;
|
||||
sum_squares += square;
|
||||
sum_cubes += cube;
|
||||
}
|
||||
|
||||
double accel = sum_cubes / ( 6 * std::pow( sum_squares, 1.5 ) );
|
||||
long n = static_cast<long>( resample.size() );
|
||||
double prob_n = static_cast<double>(
|
||||
std::count_if( resample.begin(),
|
||||
resample.end(),
|
||||
[point]( double x ) { return x < point; } )) /
|
||||
static_cast<double>( n );
|
||||
// degenerate case with uniform samples
|
||||
if ( Catch::Detail::directCompare( prob_n, 0. ) ) {
|
||||
return { point, point, point, confidence_level };
|
||||
}
|
||||
|
||||
double bias = normal_quantile( prob_n );
|
||||
double z1 = normal_quantile( ( 1. - confidence_level ) / 2. );
|
||||
|
||||
auto cumn = [n]( double x ) -> long {
|
||||
return std::lround( normal_cdf( x ) *
|
||||
static_cast<double>( n ) );
|
||||
};
|
||||
auto a = [bias, accel]( double b ) {
|
||||
return bias + b / ( 1. - accel * b );
|
||||
};
|
||||
double b1 = bias + z1;
|
||||
double b2 = bias - z1;
|
||||
double a1 = a( b1 );
|
||||
double a2 = a( b2 );
|
||||
auto lo = static_cast<size_t>( (std::max)( cumn( a1 ), 0l ) );
|
||||
auto hi =
|
||||
static_cast<size_t>( (std::min)( cumn( a2 ), n - 1 ) );
|
||||
|
||||
return { point, resample[lo], resample[hi], confidence_level };
|
||||
}
|
||||
|
||||
bootstrap_analysis analyse_samples(double confidence_level,
|
||||
unsigned int n_resamples,
|
||||
double* first,
|
||||
double* last) {
|
||||
auto mean = &Detail::mean;
|
||||
auto stddev = &standard_deviation;
|
||||
|
||||
#if defined(CATCH_CONFIG_USE_ASYNC)
|
||||
auto Estimate = [=](double(*f)(double const*, double const*)) {
|
||||
std::random_device rd;
|
||||
auto seed = rd();
|
||||
return std::async(std::launch::async, [=] {
|
||||
SimplePcg32 rng( seed );
|
||||
auto resampled = resample(rng, n_resamples, first, last, f);
|
||||
return bootstrap(confidence_level, first, last, resampled, f);
|
||||
});
|
||||
};
|
||||
|
||||
auto mean_future = Estimate(mean);
|
||||
auto stddev_future = Estimate(stddev);
|
||||
|
||||
auto mean_estimate = mean_future.get();
|
||||
auto stddev_estimate = stddev_future.get();
|
||||
#else
|
||||
auto Estimate = [=](double(*f)(double const* , double const*)) {
|
||||
std::random_device rd;
|
||||
auto seed = rd();
|
||||
SimplePcg32 rng( seed );
|
||||
auto resampled = resample(rng, n_resamples, first, last, f);
|
||||
return bootstrap(confidence_level, first, last, resampled, f);
|
||||
};
|
||||
|
||||
auto mean_estimate = Estimate(mean);
|
||||
auto stddev_estimate = Estimate(stddev);
|
||||
#endif // CATCH_USE_ASYNC
|
||||
|
||||
auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
|
||||
double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
|
||||
|
||||
return { mean_estimate, stddev_estimate, outlier_variance };
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
60
tests/catch2/src/catch2/benchmark/detail/catch_stats.hpp
Normal file
60
tests/catch2/src/catch2/benchmark/detail/catch_stats.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_STATS_HPP_INCLUDED
|
||||
#define CATCH_STATS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_estimate.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
namespace Detail {
|
||||
using sample = std::vector<double>;
|
||||
|
||||
double weighted_average_quantile( int k,
|
||||
int q,
|
||||
double* first,
|
||||
double* last );
|
||||
|
||||
OutlierClassification
|
||||
classify_outliers( double const* first, double const* last );
|
||||
|
||||
double mean( double const* first, double const* last );
|
||||
|
||||
double normal_cdf( double x );
|
||||
|
||||
double erfc_inv(double x);
|
||||
|
||||
double normal_quantile(double p);
|
||||
|
||||
Estimate<double>
|
||||
bootstrap( double confidence_level,
|
||||
double* first,
|
||||
double* last,
|
||||
sample const& resample,
|
||||
double ( *estimator )( double const*, double const* ) );
|
||||
|
||||
struct bootstrap_analysis {
|
||||
Estimate<double> mean;
|
||||
Estimate<double> standard_deviation;
|
||||
double outlier_variance;
|
||||
};
|
||||
|
||||
bootstrap_analysis analyse_samples(double confidence_level,
|
||||
unsigned int n_resamples,
|
||||
double* first,
|
||||
double* last);
|
||||
} // namespace Detail
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_STATS_HPP_INCLUDED
|
||||
29
tests/catch2/src/catch2/benchmark/detail/catch_timing.hpp
Normal file
29
tests/catch2/src/catch2/benchmark/detail/catch_timing.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
// Adapted from donated nonius code.
|
||||
|
||||
#ifndef CATCH_TIMING_HPP_INCLUDED
|
||||
#define CATCH_TIMING_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Benchmark {
|
||||
template <typename Result>
|
||||
struct Timing {
|
||||
IDuration elapsed;
|
||||
Result result;
|
||||
int iterations;
|
||||
};
|
||||
template <typename Func, typename... Args>
|
||||
using TimingOf = Timing<Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
|
||||
} // namespace Benchmark
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_TIMING_HPP_INCLUDED
|
||||
139
tests/catch2/src/catch2/catch_all.hpp
Normal file
139
tests/catch2/src/catch2/catch_all.hpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/** \file
|
||||
* This is a convenience header for Catch2. It includes **all** of Catch2 headers.
|
||||
*
|
||||
* Generally the Catch2 users should use specific includes they need,
|
||||
* but this header can be used instead for ease-of-experimentation, or
|
||||
* just plain convenience, at the cost of (significantly) increased
|
||||
* compilation times.
|
||||
*
|
||||
* When a new header is added to either the top level folder, or to the
|
||||
* corresponding internal subfolder, it should be added here. Headers
|
||||
* added to the various subparts (e.g. matchers, generators, etc...),
|
||||
* should go their respective catch-all headers.
|
||||
*/
|
||||
|
||||
#ifndef CATCH_ALL_HPP_INCLUDED
|
||||
#define CATCH_ALL_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_benchmark_all.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_assertion_info.hpp>
|
||||
#include <catch2/catch_assertion_result.hpp>
|
||||
#include <catch2/catch_case_sensitive.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/catch_get_random_seed.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/catch_section_info.hpp>
|
||||
#include <catch2/catch_session.hpp>
|
||||
#include <catch2/catch_tag_alias.hpp>
|
||||
#include <catch2/catch_tag_alias_autoregistrar.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_test_run_info.hpp>
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
#include <catch2/catch_timer.hpp>
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
#include <catch2/catch_totals.hpp>
|
||||
#include <catch2/catch_translate_exception.hpp>
|
||||
#include <catch2/catch_version.hpp>
|
||||
#include <catch2/catch_version_macros.hpp>
|
||||
#include <catch2/generators/catch_generators_all.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_all.hpp>
|
||||
#include <catch2/internal/catch_assertion_handler.hpp>
|
||||
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||
#include <catch2/internal/catch_clara.hpp>
|
||||
#include <catch2/internal/catch_commandline.hpp>
|
||||
#include <catch2/internal/catch_compare_traits.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_config_android_logwrite.hpp>
|
||||
#include <catch2/internal/catch_config_counter.hpp>
|
||||
#include <catch2/internal/catch_config_prefix_messages.hpp>
|
||||
#include <catch2/internal/catch_config_static_analysis_support.hpp>
|
||||
#include <catch2/internal/catch_config_uncaught_exceptions.hpp>
|
||||
#include <catch2/internal/catch_config_wchar.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_console_width.hpp>
|
||||
#include <catch2/internal/catch_container_nonmembers.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_debug_console.hpp>
|
||||
#include <catch2/internal/catch_debugger.hpp>
|
||||
#include <catch2/internal/catch_decomposer.hpp>
|
||||
#include <catch2/internal/catch_deprecation_macro.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_enum_values_registry.hpp>
|
||||
#include <catch2/internal/catch_errno_guard.hpp>
|
||||
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||
#include <catch2/internal/catch_fatal_condition_handler.hpp>
|
||||
#include <catch2/internal/catch_floating_point_helpers.hpp>
|
||||
#include <catch2/internal/catch_getenv.hpp>
|
||||
#include <catch2/internal/catch_is_permutation.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
#include <catch2/internal/catch_jsonwriter.hpp>
|
||||
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||
#include <catch2/internal/catch_leak_detector.hpp>
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
#include <catch2/internal/catch_logical_traits.hpp>
|
||||
#include <catch2/internal/catch_message_info.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/internal/catch_optional.hpp>
|
||||
#include <catch2/internal/catch_output_redirect.hpp>
|
||||
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||
#include <catch2/internal/catch_platform.hpp>
|
||||
#include <catch2/internal/catch_polyfills.hpp>
|
||||
#include <catch2/internal/catch_preprocessor.hpp>
|
||||
#include <catch2/internal/catch_preprocessor_internal_stringify.hpp>
|
||||
#include <catch2/internal/catch_preprocessor_remove_parens.hpp>
|
||||
#include <catch2/internal/catch_random_floating_point_helpers.hpp>
|
||||
#include <catch2/internal/catch_random_integer_helpers.hpp>
|
||||
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||
#include <catch2/internal/catch_random_seed_generation.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_reporter_spec_parser.hpp>
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/internal/catch_section.hpp>
|
||||
#include <catch2/internal/catch_sharding.hpp>
|
||||
#include <catch2/internal/catch_singletons.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_startup_exception_registry.hpp>
|
||||
#include <catch2/internal/catch_stdstreams.hpp>
|
||||
#include <catch2/internal/catch_stream_end_stop.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_template_test_registry.hpp>
|
||||
#include <catch2/internal/catch_test_case_info_hasher.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_test_case_tracker.hpp>
|
||||
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||
#include <catch2/internal/catch_test_macro_impl.hpp>
|
||||
#include <catch2/internal/catch_test_registry.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/internal/catch_textflow.hpp>
|
||||
#include <catch2/internal/catch_thread_support.hpp>
|
||||
#include <catch2/internal/catch_to_string.hpp>
|
||||
#include <catch2/internal/catch_uncaught_exceptions.hpp>
|
||||
#include <catch2/internal/catch_uniform_floating_point_distribution.hpp>
|
||||
#include <catch2/internal/catch_uniform_integer_distribution.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_unreachable.hpp>
|
||||
#include <catch2/internal/catch_void_type.hpp>
|
||||
#include <catch2/internal/catch_wildcard_pattern.hpp>
|
||||
#include <catch2/internal/catch_xmlwriter.hpp>
|
||||
#include <catch2/matchers/catch_matchers_all.hpp>
|
||||
#include <catch2/reporters/catch_reporters_all.hpp>
|
||||
|
||||
#endif // CATCH_ALL_HPP_INCLUDED
|
||||
85
tests/catch2/src/catch2/catch_approx.cpp
Normal file
85
tests/catch2/src/catch2/catch_approx.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace {
|
||||
|
||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||
// But without the subtraction to allow for INFINITY in comparison
|
||||
bool marginComparison(double lhs, double rhs, double margin) {
|
||||
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Approx::Approx ( double value )
|
||||
: m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ),
|
||||
m_margin( 0.0 ),
|
||||
m_scale( 0.0 ),
|
||||
m_value( value )
|
||||
{}
|
||||
|
||||
Approx Approx::custom() {
|
||||
return Approx( 0 );
|
||||
}
|
||||
|
||||
Approx Approx::operator-() const {
|
||||
auto temp(*this);
|
||||
temp.m_value = -temp.m_value;
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
std::string Approx::toString() const {
|
||||
ReusableStringStream rss;
|
||||
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
bool Approx::equalityComparisonImpl(const double other) const {
|
||||
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
|
||||
// Thanks to Richard Harris for his help refining the scaled margin value
|
||||
return marginComparison(m_value, other, m_margin)
|
||||
|| marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
|
||||
}
|
||||
|
||||
void Approx::setMargin(double newMargin) {
|
||||
CATCH_ENFORCE(newMargin >= 0,
|
||||
"Invalid Approx::margin: " << newMargin << '.'
|
||||
<< " Approx::Margin has to be non-negative.");
|
||||
m_margin = newMargin;
|
||||
}
|
||||
|
||||
void Approx::setEpsilon(double newEpsilon) {
|
||||
CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
|
||||
"Invalid Approx::epsilon: " << newEpsilon << '.'
|
||||
<< " Approx::epsilon has to be in [0, 1]");
|
||||
m_epsilon = newEpsilon;
|
||||
}
|
||||
|
||||
namespace literals {
|
||||
Approx operator ""_a(long double val) {
|
||||
return Approx(val);
|
||||
}
|
||||
Approx operator ""_a(unsigned long long val) {
|
||||
return Approx(val);
|
||||
}
|
||||
} // end namespace literals
|
||||
|
||||
std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
128
tests/catch2/src/catch2/catch_approx.hpp
Normal file
128
tests/catch2/src/catch2/catch_approx.hpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_APPROX_HPP_INCLUDED
|
||||
#define CATCH_APPROX_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class Approx {
|
||||
private:
|
||||
bool equalityComparisonImpl(double other) const;
|
||||
// Sets and validates the new margin (margin >= 0)
|
||||
void setMargin(double margin);
|
||||
// Sets and validates the new epsilon (0 < epsilon < 1)
|
||||
void setEpsilon(double epsilon);
|
||||
|
||||
public:
|
||||
explicit Approx ( double value );
|
||||
|
||||
static Approx custom();
|
||||
|
||||
Approx operator-() const;
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
Approx operator()( T const& value ) const {
|
||||
Approx approx( static_cast<double>(value) );
|
||||
approx.m_epsilon = m_epsilon;
|
||||
approx.m_margin = m_margin;
|
||||
approx.m_scale = m_scale;
|
||||
return approx;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
explicit Approx( T const& value ): Approx(static_cast<double>(value))
|
||||
{}
|
||||
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator == ( const T& lhs, Approx const& rhs ) {
|
||||
auto lhs_v = static_cast<double>(lhs);
|
||||
return rhs.equalityComparisonImpl(lhs_v);
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator == ( Approx const& lhs, const T& rhs ) {
|
||||
return operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator != ( T const& lhs, Approx const& rhs ) {
|
||||
return !operator==( lhs, rhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator != ( Approx const& lhs, T const& rhs ) {
|
||||
return !operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator <= ( T const& lhs, Approx const& rhs ) {
|
||||
return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator <= ( Approx const& lhs, T const& rhs ) {
|
||||
return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator >= ( T const& lhs, Approx const& rhs ) {
|
||||
return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
friend bool operator >= ( Approx const& lhs, T const& rhs ) {
|
||||
return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
Approx& epsilon( T const& newEpsilon ) {
|
||||
const auto epsilonAsDouble = static_cast<double>(newEpsilon);
|
||||
setEpsilon(epsilonAsDouble);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
Approx& margin( T const& newMargin ) {
|
||||
const auto marginAsDouble = static_cast<double>(newMargin);
|
||||
setMargin(marginAsDouble);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
|
||||
Approx& scale( T const& newScale ) {
|
||||
m_scale = static_cast<double>(newScale);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
private:
|
||||
double m_epsilon;
|
||||
double m_margin;
|
||||
double m_scale;
|
||||
double m_value;
|
||||
};
|
||||
|
||||
namespace literals {
|
||||
Approx operator ""_a(long double val);
|
||||
Approx operator ""_a(unsigned long long val);
|
||||
} // end namespace literals
|
||||
|
||||
template<>
|
||||
struct StringMaker<Catch::Approx> {
|
||||
static std::string convert(Catch::Approx const& value);
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_APPROX_HPP_INCLUDED
|
||||
28
tests/catch2/src/catch2/catch_assertion_info.hpp
Normal file
28
tests/catch2/src/catch2/catch_assertion_info.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED
|
||||
#define CATCH_ASSERTION_INFO_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct AssertionInfo {
|
||||
// AssertionInfo() = delete;
|
||||
|
||||
StringRef macroName;
|
||||
SourceLineInfo lineInfo;
|
||||
StringRef capturedExpression;
|
||||
ResultDisposition::Flags resultDisposition;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED
|
||||
105
tests/catch2/src/catch2/catch_assertion_result.cpp
Normal file
105
tests/catch2/src/catch2/catch_assertion_result.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_assertion_result.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const& _lazyExpression):
|
||||
lazyExpression(_lazyExpression),
|
||||
resultType(_resultType) {}
|
||||
|
||||
std::string AssertionResultData::reconstructExpression() const {
|
||||
|
||||
if( reconstructedExpression.empty() ) {
|
||||
if( lazyExpression ) {
|
||||
ReusableStringStream rss;
|
||||
rss << lazyExpression;
|
||||
reconstructedExpression = rss.str();
|
||||
}
|
||||
}
|
||||
return reconstructedExpression;
|
||||
}
|
||||
|
||||
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data )
|
||||
: m_info( info ),
|
||||
m_resultData( CATCH_MOVE(data) )
|
||||
{}
|
||||
|
||||
// Result was a success
|
||||
bool AssertionResult::succeeded() const {
|
||||
return Catch::isOk( m_resultData.resultType );
|
||||
}
|
||||
|
||||
// Result was a success, or failure is suppressed
|
||||
bool AssertionResult::isOk() const {
|
||||
return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
|
||||
}
|
||||
|
||||
ResultWas::OfType AssertionResult::getResultType() const {
|
||||
return m_resultData.resultType;
|
||||
}
|
||||
|
||||
bool AssertionResult::hasExpression() const {
|
||||
return !m_info.capturedExpression.empty();
|
||||
}
|
||||
|
||||
bool AssertionResult::hasMessage() const {
|
||||
return !m_resultData.message.empty();
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpression() const {
|
||||
// Possibly overallocating by 3 characters should be basically free
|
||||
std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
|
||||
if (isFalseTest(m_info.resultDisposition)) {
|
||||
expr += "!(";
|
||||
}
|
||||
expr += m_info.capturedExpression;
|
||||
if (isFalseTest(m_info.resultDisposition)) {
|
||||
expr += ')';
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpressionInMacro() const {
|
||||
if ( m_info.macroName.empty() ) {
|
||||
return static_cast<std::string>( m_info.capturedExpression );
|
||||
}
|
||||
std::string expr;
|
||||
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
|
||||
expr += m_info.macroName;
|
||||
expr += "( ";
|
||||
expr += m_info.capturedExpression;
|
||||
expr += " )";
|
||||
return expr;
|
||||
}
|
||||
|
||||
bool AssertionResult::hasExpandedExpression() const {
|
||||
return hasExpression() && getExpandedExpression() != getExpression();
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpandedExpression() const {
|
||||
std::string expr = m_resultData.reconstructExpression();
|
||||
return expr.empty()
|
||||
? getExpression()
|
||||
: expr;
|
||||
}
|
||||
|
||||
StringRef AssertionResult::getMessage() const {
|
||||
return m_resultData.message;
|
||||
}
|
||||
SourceLineInfo AssertionResult::getSourceInfo() const {
|
||||
return m_info.lineInfo;
|
||||
}
|
||||
|
||||
StringRef AssertionResult::getTestMacroName() const {
|
||||
return m_info.macroName;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
60
tests/catch2/src/catch2/catch_assertion_result.hpp
Normal file
60
tests/catch2/src/catch2/catch_assertion_result.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
||||
#define CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_assertion_info.hpp>
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct AssertionResultData
|
||||
{
|
||||
AssertionResultData() = delete;
|
||||
|
||||
AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
|
||||
|
||||
std::string message;
|
||||
mutable std::string reconstructedExpression;
|
||||
LazyExpression lazyExpression;
|
||||
ResultWas::OfType resultType;
|
||||
|
||||
std::string reconstructExpression() const;
|
||||
};
|
||||
|
||||
class AssertionResult {
|
||||
public:
|
||||
AssertionResult() = delete;
|
||||
AssertionResult( AssertionInfo const& info, AssertionResultData&& data );
|
||||
|
||||
bool isOk() const;
|
||||
bool succeeded() const;
|
||||
ResultWas::OfType getResultType() const;
|
||||
bool hasExpression() const;
|
||||
bool hasMessage() const;
|
||||
std::string getExpression() const;
|
||||
std::string getExpressionInMacro() const;
|
||||
bool hasExpandedExpression() const;
|
||||
std::string getExpandedExpression() const;
|
||||
StringRef getMessage() const;
|
||||
SourceLineInfo getSourceInfo() const;
|
||||
StringRef getTestMacroName() const;
|
||||
|
||||
//protected:
|
||||
AssertionInfo m_info;
|
||||
AssertionResultData m_resultData;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
||||
17
tests/catch2/src/catch2/catch_case_sensitive.hpp
Normal file
17
tests/catch2/src/catch2/catch_case_sensitive.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED
|
||||
#define CATCH_CASE_SENSITIVE_HPP_INCLUDED
|
||||
|
||||
namespace Catch {
|
||||
|
||||
enum class CaseSensitive { Yes, No };
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED
|
||||
273
tests/catch2/src/catch2/catch_config.cpp
Normal file
273
tests/catch2/src/catch2/catch_config.cpp
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||
#include <catch2/internal/catch_stdstreams.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_getenv.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
static bool enableBazelEnvSupport() {
|
||||
#if defined( CATCH_CONFIG_BAZEL_SUPPORT )
|
||||
return true;
|
||||
#else
|
||||
return Detail::getEnv( "BAZEL_TEST" ) != nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct bazelShardingOptions {
|
||||
unsigned int shardIndex, shardCount;
|
||||
std::string shardFilePath;
|
||||
};
|
||||
|
||||
static Optional<bazelShardingOptions> readBazelShardingOptions() {
|
||||
const auto bazelShardIndex = Detail::getEnv( "TEST_SHARD_INDEX" );
|
||||
const auto bazelShardTotal = Detail::getEnv( "TEST_TOTAL_SHARDS" );
|
||||
const auto bazelShardInfoFile = Detail::getEnv( "TEST_SHARD_STATUS_FILE" );
|
||||
|
||||
|
||||
const bool has_all =
|
||||
bazelShardIndex && bazelShardTotal && bazelShardInfoFile;
|
||||
if ( !has_all ) {
|
||||
// We provide nice warning message if the input is
|
||||
// misconfigured.
|
||||
auto warn = []( const char* env_var ) {
|
||||
Catch::cerr()
|
||||
<< "Warning: Bazel shard configuration is missing '"
|
||||
<< env_var << "'. Shard configuration is skipped.\n";
|
||||
};
|
||||
if ( !bazelShardIndex ) {
|
||||
warn( "TEST_SHARD_INDEX" );
|
||||
}
|
||||
if ( !bazelShardTotal ) {
|
||||
warn( "TEST_TOTAL_SHARDS" );
|
||||
}
|
||||
if ( !bazelShardInfoFile ) {
|
||||
warn( "TEST_SHARD_STATUS_FILE" );
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
auto shardIndex = parseUInt( bazelShardIndex );
|
||||
if ( !shardIndex ) {
|
||||
Catch::cerr()
|
||||
<< "Warning: could not parse 'TEST_SHARD_INDEX' ('" << bazelShardIndex
|
||||
<< "') as unsigned int.\n";
|
||||
return {};
|
||||
}
|
||||
auto shardTotal = parseUInt( bazelShardTotal );
|
||||
if ( !shardTotal ) {
|
||||
Catch::cerr()
|
||||
<< "Warning: could not parse 'TEST_TOTAL_SHARD' ('"
|
||||
<< bazelShardTotal << "') as unsigned int.\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
return bazelShardingOptions{
|
||||
*shardIndex, *shardTotal, bazelShardInfoFile };
|
||||
|
||||
}
|
||||
} // end namespace
|
||||
|
||||
|
||||
bool operator==( ProcessedReporterSpec const& lhs,
|
||||
ProcessedReporterSpec const& rhs ) {
|
||||
return lhs.name == rhs.name &&
|
||||
lhs.outputFilename == rhs.outputFilename &&
|
||||
lhs.colourMode == rhs.colourMode &&
|
||||
lhs.customOptions == rhs.customOptions;
|
||||
}
|
||||
|
||||
Config::Config( ConfigData const& data ):
|
||||
m_data( data ) {
|
||||
// We need to trim filter specs to avoid trouble with superfluous
|
||||
// whitespace (esp. important for bdd macros, as those are manually
|
||||
// aligned with whitespace).
|
||||
|
||||
for (auto& elem : m_data.testsOrTags) {
|
||||
elem = trim(elem);
|
||||
}
|
||||
for (auto& elem : m_data.sectionsToRun) {
|
||||
elem = trim(elem);
|
||||
}
|
||||
|
||||
// Insert the default reporter if user hasn't asked for a specific one
|
||||
if ( m_data.reporterSpecifications.empty() ) {
|
||||
#if defined( CATCH_CONFIG_DEFAULT_REPORTER )
|
||||
const auto default_spec = CATCH_CONFIG_DEFAULT_REPORTER;
|
||||
#else
|
||||
const auto default_spec = "console";
|
||||
#endif
|
||||
auto parsed = parseReporterSpec(default_spec);
|
||||
CATCH_ENFORCE( parsed,
|
||||
"Cannot parse the provided default reporter spec: '"
|
||||
<< default_spec << '\'' );
|
||||
m_data.reporterSpecifications.push_back( std::move( *parsed ) );
|
||||
}
|
||||
|
||||
// Reading bazel env vars can change some parts of the config data,
|
||||
// so we have to process the bazel env before acting on the config.
|
||||
if ( enableBazelEnvSupport() ) {
|
||||
readBazelEnvVars();
|
||||
}
|
||||
|
||||
// Bazel support can modify the test specs, so parsing has to happen
|
||||
// after reading Bazel env vars.
|
||||
TestSpecParser parser( ITagAliasRegistry::get() );
|
||||
if ( !m_data.testsOrTags.empty() ) {
|
||||
m_hasTestFilters = true;
|
||||
for ( auto const& testOrTags : m_data.testsOrTags ) {
|
||||
parser.parse( testOrTags );
|
||||
}
|
||||
}
|
||||
m_testSpec = parser.testSpec();
|
||||
|
||||
|
||||
// We now fixup the reporter specs to handle default output spec,
|
||||
// default colour spec, etc
|
||||
bool defaultOutputUsed = false;
|
||||
for ( auto const& reporterSpec : m_data.reporterSpecifications ) {
|
||||
// We do the default-output check separately, while always
|
||||
// using the default output below to make the code simpler
|
||||
// and avoid superfluous copies.
|
||||
if ( reporterSpec.outputFile().none() ) {
|
||||
CATCH_ENFORCE( !defaultOutputUsed,
|
||||
"Internal error: cannot use default output for "
|
||||
"multiple reporters" );
|
||||
defaultOutputUsed = true;
|
||||
}
|
||||
|
||||
m_processedReporterSpecs.push_back( ProcessedReporterSpec{
|
||||
reporterSpec.name(),
|
||||
reporterSpec.outputFile() ? *reporterSpec.outputFile()
|
||||
: data.defaultOutputFilename,
|
||||
reporterSpec.colourMode().valueOr( data.defaultColourMode ),
|
||||
reporterSpec.customOptions() } );
|
||||
}
|
||||
}
|
||||
|
||||
Config::~Config() = default;
|
||||
|
||||
|
||||
bool Config::listTests() const { return m_data.listTests; }
|
||||
bool Config::listTags() const { return m_data.listTags; }
|
||||
bool Config::listReporters() const { return m_data.listReporters; }
|
||||
bool Config::listListeners() const { return m_data.listListeners; }
|
||||
|
||||
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
|
||||
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||
|
||||
std::vector<ReporterSpec> const& Config::getReporterSpecs() const {
|
||||
return m_data.reporterSpecifications;
|
||||
}
|
||||
|
||||
std::vector<ProcessedReporterSpec> const&
|
||||
Config::getProcessedReporterSpecs() const {
|
||||
return m_processedReporterSpecs;
|
||||
}
|
||||
|
||||
TestSpec const& Config::testSpec() const { return m_testSpec; }
|
||||
bool Config::hasTestFilters() const { return m_hasTestFilters; }
|
||||
|
||||
bool Config::showHelp() const { return m_data.showHelp; }
|
||||
|
||||
std::string const& Config::getExitGuardFilePath() const { return m_data.prematureExitGuardFilePath; }
|
||||
|
||||
// IConfig interface
|
||||
bool Config::allowThrows() const { return !m_data.noThrow; }
|
||||
StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
||||
bool Config::warnAboutMissingAssertions() const {
|
||||
return !!( m_data.warnings & WarnAbout::NoAssertions );
|
||||
}
|
||||
bool Config::warnAboutUnmatchedTestSpecs() const {
|
||||
return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
|
||||
}
|
||||
bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
|
||||
ShowDurations Config::showDurations() const { return m_data.showDurations; }
|
||||
double Config::minDuration() const { return m_data.minDuration; }
|
||||
TestRunOrder Config::runOrder() const { return m_data.runOrder; }
|
||||
uint32_t Config::rngSeed() const { return m_data.rngSeed; }
|
||||
unsigned int Config::shardCount() const { return m_data.shardCount; }
|
||||
unsigned int Config::shardIndex() const { return m_data.shardIndex; }
|
||||
ColourMode Config::defaultColourMode() const { return m_data.defaultColourMode; }
|
||||
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
||||
int Config::abortAfter() const { return m_data.abortAfter; }
|
||||
bool Config::showInvisibles() const { return m_data.showInvisibles; }
|
||||
Verbosity Config::verbosity() const { return m_data.verbosity; }
|
||||
|
||||
bool Config::skipBenchmarks() const { return m_data.skipBenchmarks; }
|
||||
bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
|
||||
unsigned int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
|
||||
double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
|
||||
unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
|
||||
std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
|
||||
|
||||
void Config::readBazelEnvVars() {
|
||||
// Register a JUnit reporter for Bazel. Bazel sets an environment
|
||||
// variable with the path to XML output. If this file is written to
|
||||
// during test, Bazel will not generate a default XML output.
|
||||
// This allows the XML output file to contain higher level of detail
|
||||
// than what is possible otherwise.
|
||||
const auto bazelOutputFile = Detail::getEnv( "XML_OUTPUT_FILE" );
|
||||
|
||||
if ( bazelOutputFile ) {
|
||||
m_data.reporterSpecifications.push_back(
|
||||
{ "junit", std::string( bazelOutputFile ), {}, {} } );
|
||||
}
|
||||
|
||||
const auto bazelTestSpec = Detail::getEnv( "TESTBRIDGE_TEST_ONLY" );
|
||||
if ( bazelTestSpec ) {
|
||||
// Presumably the test spec from environment should overwrite
|
||||
// the one we got from CLI (if we got any)
|
||||
m_data.testsOrTags.clear();
|
||||
m_data.testsOrTags.push_back( bazelTestSpec );
|
||||
}
|
||||
|
||||
const auto bazelShardOptions = readBazelShardingOptions();
|
||||
if ( bazelShardOptions ) {
|
||||
std::ofstream f( bazelShardOptions->shardFilePath,
|
||||
std::ios_base::out | std::ios_base::trunc );
|
||||
if ( f.is_open() ) {
|
||||
f << "";
|
||||
m_data.shardIndex = bazelShardOptions->shardIndex;
|
||||
m_data.shardCount = bazelShardOptions->shardCount;
|
||||
}
|
||||
}
|
||||
|
||||
const auto bazelExitGuardFile = Detail::getEnv( "TEST_PREMATURE_EXIT_FILE" );
|
||||
if (bazelExitGuardFile) {
|
||||
m_data.prematureExitGuardFilePath = bazelExitGuardFile;
|
||||
}
|
||||
|
||||
const auto bazelRandomSeed = Detail::getEnv( "TEST_RANDOM_SEED" );
|
||||
if ( bazelRandomSeed ) {
|
||||
auto parsedSeed = parseUInt( bazelRandomSeed, 0 );
|
||||
if ( !parsedSeed ) {
|
||||
// Currently we handle issues with parsing other Bazel Env
|
||||
// options by warning and ignoring the issue. So we do the
|
||||
// same for random seed option.
|
||||
Catch::cerr()
|
||||
<< "Warning: could not parse 'TEST_RANDOM_SEED' ('"
|
||||
<< bazelRandomSeed << "') as proper seed.\n";
|
||||
} else {
|
||||
m_data.rngSeed = *parsedSeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
157
tests/catch2/src/catch2/catch_config.hpp
Normal file
157
tests/catch2/src/catch2/catch_config.hpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_CONFIG_HPP_INCLUDED
|
||||
#define CATCH_CONFIG_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_optional.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_random_seed_generation.hpp>
|
||||
#include <catch2/internal/catch_reporter_spec_parser.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class IStream;
|
||||
|
||||
/**
|
||||
* `ReporterSpec` but with the defaults filled in.
|
||||
*
|
||||
* Like `ReporterSpec`, the semantics are unchecked.
|
||||
*/
|
||||
struct ProcessedReporterSpec {
|
||||
std::string name;
|
||||
std::string outputFilename;
|
||||
ColourMode colourMode;
|
||||
std::map<std::string, std::string> customOptions;
|
||||
friend bool operator==( ProcessedReporterSpec const& lhs,
|
||||
ProcessedReporterSpec const& rhs );
|
||||
friend bool operator!=( ProcessedReporterSpec const& lhs,
|
||||
ProcessedReporterSpec const& rhs ) {
|
||||
return !( lhs == rhs );
|
||||
}
|
||||
};
|
||||
|
||||
struct ConfigData {
|
||||
|
||||
bool listTests = false;
|
||||
bool listTags = false;
|
||||
bool listReporters = false;
|
||||
bool listListeners = false;
|
||||
|
||||
bool showSuccessfulTests = false;
|
||||
bool shouldDebugBreak = false;
|
||||
bool noThrow = false;
|
||||
bool showHelp = false;
|
||||
bool showInvisibles = false;
|
||||
bool filenamesAsTags = false;
|
||||
bool libIdentify = false;
|
||||
bool allowZeroTests = false;
|
||||
|
||||
int abortAfter = -1;
|
||||
uint32_t rngSeed = generateRandomSeed(GenerateFrom::Default);
|
||||
|
||||
unsigned int shardCount = 1;
|
||||
unsigned int shardIndex = 0;
|
||||
|
||||
bool skipBenchmarks = false;
|
||||
bool benchmarkNoAnalysis = false;
|
||||
unsigned int benchmarkSamples = 100;
|
||||
double benchmarkConfidenceInterval = 0.95;
|
||||
unsigned int benchmarkResamples = 100'000;
|
||||
std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
|
||||
|
||||
Verbosity verbosity = Verbosity::Normal;
|
||||
WarnAbout::What warnings = WarnAbout::Nothing;
|
||||
ShowDurations showDurations = ShowDurations::DefaultForReporter;
|
||||
double minDuration = -1;
|
||||
TestRunOrder runOrder = TestRunOrder::Randomized;
|
||||
ColourMode defaultColourMode = ColourMode::PlatformDefault;
|
||||
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
|
||||
|
||||
std::string defaultOutputFilename;
|
||||
std::string name;
|
||||
std::string processName;
|
||||
std::vector<ReporterSpec> reporterSpecifications;
|
||||
|
||||
std::vector<std::string> testsOrTags;
|
||||
std::vector<std::string> sectionsToRun;
|
||||
|
||||
std::string prematureExitGuardFilePath;
|
||||
};
|
||||
|
||||
|
||||
class Config : public IConfig {
|
||||
public:
|
||||
|
||||
Config() = default;
|
||||
Config( ConfigData const& data );
|
||||
~Config() override; // = default in the cpp file
|
||||
|
||||
bool listTests() const;
|
||||
bool listTags() const;
|
||||
bool listReporters() const;
|
||||
bool listListeners() const;
|
||||
|
||||
std::vector<ReporterSpec> const& getReporterSpecs() const;
|
||||
std::vector<ProcessedReporterSpec> const&
|
||||
getProcessedReporterSpecs() const;
|
||||
|
||||
std::vector<std::string> const& getTestsOrTags() const override;
|
||||
std::vector<std::string> const& getSectionsToRun() const override;
|
||||
|
||||
TestSpec const& testSpec() const override;
|
||||
bool hasTestFilters() const override;
|
||||
|
||||
bool showHelp() const;
|
||||
|
||||
std::string const& getExitGuardFilePath() const;
|
||||
|
||||
// IConfig interface
|
||||
bool allowThrows() const override;
|
||||
StringRef name() const override;
|
||||
bool includeSuccessfulResults() const override;
|
||||
bool warnAboutMissingAssertions() const override;
|
||||
bool warnAboutUnmatchedTestSpecs() const override;
|
||||
bool zeroTestsCountAsSuccess() const override;
|
||||
ShowDurations showDurations() const override;
|
||||
double minDuration() const override;
|
||||
TestRunOrder runOrder() const override;
|
||||
uint32_t rngSeed() const override;
|
||||
unsigned int shardCount() const override;
|
||||
unsigned int shardIndex() const override;
|
||||
ColourMode defaultColourMode() const override;
|
||||
bool shouldDebugBreak() const override;
|
||||
int abortAfter() const override;
|
||||
bool showInvisibles() const override;
|
||||
Verbosity verbosity() const override;
|
||||
bool skipBenchmarks() const override;
|
||||
bool benchmarkNoAnalysis() const override;
|
||||
unsigned int benchmarkSamples() const override;
|
||||
double benchmarkConfidenceInterval() const override;
|
||||
unsigned int benchmarkResamples() const override;
|
||||
std::chrono::milliseconds benchmarkWarmupTime() const override;
|
||||
|
||||
private:
|
||||
// Reads Bazel env vars and applies them to the config
|
||||
void readBazelEnvVars();
|
||||
|
||||
ConfigData m_data;
|
||||
std::vector<ProcessedReporterSpec> m_processedReporterSpecs;
|
||||
TestSpec m_testSpec;
|
||||
bool m_hasTestFilters = false;
|
||||
};
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_CONFIG_HPP_INCLUDED
|
||||
18
tests/catch2/src/catch2/catch_get_random_seed.cpp
Normal file
18
tests/catch2/src/catch2/catch_get_random_seed.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_get_random_seed.hpp>
|
||||
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
|
||||
namespace Catch {
|
||||
std::uint32_t getSeed() {
|
||||
return getCurrentContext().getConfig()->rngSeed();
|
||||
}
|
||||
}
|
||||
18
tests/catch2/src/catch2/catch_get_random_seed.hpp
Normal file
18
tests/catch2/src/catch2/catch_get_random_seed.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_GET_RANDOM_SEED_HPP_INCLUDED
|
||||
#define CATCH_GET_RANDOM_SEED_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Catch {
|
||||
//! Returns Catch2's current RNG seed.
|
||||
std::uint32_t getSeed();
|
||||
}
|
||||
|
||||
#endif // CATCH_GET_RANDOM_SEED_HPP_INCLUDED
|
||||
114
tests/catch2/src/catch2/catch_message.cpp
Normal file
114
tests/catch2/src/catch2/catch_message.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <stack>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
|
||||
m_messageId( builder.m_info.sequence ) {
|
||||
MessageInfo info( CATCH_MOVE( builder.m_info ) );
|
||||
info.message = builder.m_stream.str();
|
||||
IResultCapture::pushScopedMessage( CATCH_MOVE( info ) );
|
||||
}
|
||||
|
||||
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
|
||||
m_messageId( old.m_messageId ) {
|
||||
old.m_moved = true;
|
||||
}
|
||||
|
||||
ScopedMessage::~ScopedMessage() {
|
||||
if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); }
|
||||
}
|
||||
|
||||
|
||||
Capturer::Capturer( StringRef macroName,
|
||||
SourceLineInfo const& lineInfo,
|
||||
ResultWas::OfType resultType,
|
||||
StringRef names ) {
|
||||
auto trimmed = [&] (size_t start, size_t end) {
|
||||
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
|
||||
++start;
|
||||
}
|
||||
while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
|
||||
--end;
|
||||
}
|
||||
return names.substr(start, end - start + 1);
|
||||
};
|
||||
auto skipq = [&] (size_t start, char quote) {
|
||||
for (auto i = start + 1; i < names.size() ; ++i) {
|
||||
if (names[i] == quote)
|
||||
return i;
|
||||
if (names[i] == '\\')
|
||||
++i;
|
||||
}
|
||||
CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
|
||||
};
|
||||
|
||||
size_t start = 0;
|
||||
std::stack<char> openings;
|
||||
for (size_t pos = 0; pos < names.size(); ++pos) {
|
||||
char c = names[pos];
|
||||
switch (c) {
|
||||
case '[':
|
||||
case '{':
|
||||
case '(':
|
||||
// It is basically impossible to disambiguate between
|
||||
// comparison and start of template args in this context
|
||||
// case '<':
|
||||
openings.push(c);
|
||||
break;
|
||||
case ']':
|
||||
case '}':
|
||||
case ')':
|
||||
// case '>':
|
||||
openings.pop();
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
pos = skipq(pos, c);
|
||||
break;
|
||||
case ',':
|
||||
if (start != pos && openings.empty()) {
|
||||
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||
m_messages.back().message += trimmed(start, pos);
|
||||
m_messages.back().message += " := "_sr;
|
||||
start = pos;
|
||||
}
|
||||
break;
|
||||
default:; // noop
|
||||
}
|
||||
}
|
||||
assert(openings.empty() && "Mismatched openings");
|
||||
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||
m_messages.back().message += trimmed(start, names.size() - 1);
|
||||
m_messages.back().message += " := "_sr;
|
||||
}
|
||||
Capturer::~Capturer() {
|
||||
assert( m_captured == m_messages.size() );
|
||||
for (auto const& message : m_messages) {
|
||||
IResultCapture::popScopedMessage( message.sequence );
|
||||
}
|
||||
}
|
||||
|
||||
void Capturer::captureValue( size_t index, std::string const& value ) {
|
||||
assert( index < m_messages.size() );
|
||||
m_messages[index].message += value;
|
||||
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
|
||||
m_captured++;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
149
tests/catch2/src/catch2/catch_message.hpp
Normal file
149
tests/catch2/src/catch2/catch_message.hpp
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_MESSAGE_HPP_INCLUDED
|
||||
#define CATCH_MESSAGE_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_config_prefix_messages.hpp>
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_stream_end_stop.hpp>
|
||||
#include <catch2/internal/catch_message_info.hpp>
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SourceLineInfo;
|
||||
class IResultCapture;
|
||||
|
||||
struct MessageStream {
|
||||
|
||||
template<typename T>
|
||||
MessageStream& operator << ( T const& value ) {
|
||||
m_stream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReusableStringStream m_stream;
|
||||
};
|
||||
|
||||
struct MessageBuilder : MessageStream {
|
||||
MessageBuilder( StringRef macroName,
|
||||
SourceLineInfo const& lineInfo,
|
||||
ResultWas::OfType type ):
|
||||
m_info(macroName, lineInfo, type) {}
|
||||
|
||||
template<typename T>
|
||||
MessageBuilder&& operator << ( T const& value ) && {
|
||||
m_stream << value;
|
||||
return CATCH_MOVE(*this);
|
||||
}
|
||||
|
||||
MessageInfo m_info;
|
||||
};
|
||||
|
||||
class ScopedMessage {
|
||||
public:
|
||||
explicit ScopedMessage( MessageBuilder&& builder );
|
||||
ScopedMessage( ScopedMessage& duplicate ) = delete;
|
||||
ScopedMessage( ScopedMessage&& old ) noexcept;
|
||||
~ScopedMessage();
|
||||
|
||||
unsigned int m_messageId;
|
||||
bool m_moved = false;
|
||||
};
|
||||
|
||||
class Capturer {
|
||||
std::vector<MessageInfo> m_messages;
|
||||
size_t m_captured = 0;
|
||||
public:
|
||||
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||
|
||||
Capturer(Capturer const&) = delete;
|
||||
Capturer& operator=(Capturer const&) = delete;
|
||||
|
||||
~Capturer();
|
||||
|
||||
void captureValue( size_t index, std::string const& value );
|
||||
|
||||
template<typename T>
|
||||
void captureValues( size_t index, T const& value ) {
|
||||
captureValue( index, Catch::Detail::stringify( value ) );
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void captureValues( size_t index, T const& value, Ts const&... values ) {
|
||||
captureValue( index, Catch::Detail::stringify(value) );
|
||||
captureValues( index+1, values... );
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
|
||||
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
|
||||
catchAssertionHandler.complete(); \
|
||||
} while( false )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
|
||||
Catch::Capturer varName( macroName##_catch_sr, \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
Catch::ResultWas::Info, \
|
||||
#__VA_ARGS__##_catch_sr ); \
|
||||
varName.captureValues( 0, __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
||||
const Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
|
||||
Catch::IResultCapture::emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||
|
||||
|
||||
#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
||||
#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
|
||||
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ )
|
||||
|
||||
#elif defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define CATCH_INFO( msg ) (void)(0)
|
||||
#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
|
||||
#define CATCH_WARN( msg ) (void)(0)
|
||||
#define CATCH_CAPTURE( ... ) (void)(0)
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||
#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
|
||||
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ )
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define INFO( msg ) (void)(0)
|
||||
#define UNSCOPED_INFO( msg ) (void)(0)
|
||||
#define WARN( msg ) (void)(0)
|
||||
#define CAPTURE( ... ) (void)(0)
|
||||
|
||||
#endif // end of user facing macro declarations
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // CATCH_MESSAGE_HPP_INCLUDED
|
||||
105
tests/catch2/src/catch2/catch_registry_hub.cpp
Normal file
105
tests/catch2/src/catch2/catch_registry_hub.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_startup_exception_registry.hpp>
|
||||
#include <catch2/internal/catch_singletons.hpp>
|
||||
#include <catch2/internal/catch_enum_values_registry.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
|
||||
class RegistryHub : public IRegistryHub,
|
||||
public IMutableRegistryHub,
|
||||
private Detail::NonCopyable {
|
||||
|
||||
public: // IRegistryHub
|
||||
RegistryHub() = default;
|
||||
ReporterRegistry const& getReporterRegistry() const override {
|
||||
return m_reporterRegistry;
|
||||
}
|
||||
ITestCaseRegistry const& getTestCaseRegistry() const override {
|
||||
return m_testCaseRegistry;
|
||||
}
|
||||
IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
|
||||
return m_exceptionTranslatorRegistry;
|
||||
}
|
||||
ITagAliasRegistry const& getTagAliasRegistry() const override {
|
||||
return m_tagAliasRegistry;
|
||||
}
|
||||
StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
|
||||
return m_exceptionRegistry;
|
||||
}
|
||||
|
||||
public: // IMutableRegistryHub
|
||||
void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
|
||||
m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) );
|
||||
}
|
||||
void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) override {
|
||||
m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
|
||||
}
|
||||
void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker ) override {
|
||||
m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
|
||||
}
|
||||
void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) override {
|
||||
m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) );
|
||||
}
|
||||
void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
|
||||
m_tagAliasRegistry.add( alias, tag, lineInfo );
|
||||
}
|
||||
void registerStartupException() noexcept override {
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
m_exceptionRegistry.add(std::current_exception());
|
||||
#else
|
||||
CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||
#endif
|
||||
}
|
||||
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
|
||||
return m_enumValuesRegistry;
|
||||
}
|
||||
|
||||
private:
|
||||
TestRegistry m_testCaseRegistry;
|
||||
ReporterRegistry m_reporterRegistry;
|
||||
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
|
||||
TagAliasRegistry m_tagAliasRegistry;
|
||||
StartupExceptionRegistry m_exceptionRegistry;
|
||||
Detail::EnumValuesRegistry m_enumValuesRegistry;
|
||||
};
|
||||
}
|
||||
|
||||
using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
|
||||
|
||||
IRegistryHub const& getRegistryHub() {
|
||||
return RegistryHubSingleton::get();
|
||||
}
|
||||
IMutableRegistryHub& getMutableRegistryHub() {
|
||||
return RegistryHubSingleton::getMutable();
|
||||
}
|
||||
void cleanUp() {
|
||||
cleanupSingletons();
|
||||
}
|
||||
std::string translateActiveException() {
|
||||
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
42
tests/catch2/src/catch2/catch_section_info.hpp
Normal file
42
tests/catch2/src/catch2/catch_section_info.hpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_SECTION_INFO_HPP_INCLUDED
|
||||
#define CATCH_SECTION_INFO_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/catch_totals.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SectionInfo {
|
||||
// The last argument is ignored, so that people can write
|
||||
// SECTION("ShortName", "Proper description that is long") and
|
||||
// still use the `-c` flag comfortably.
|
||||
SectionInfo( SourceLineInfo const& _lineInfo, std::string _name,
|
||||
const char* const = nullptr ):
|
||||
name(CATCH_MOVE(_name)),
|
||||
lineInfo(_lineInfo)
|
||||
{}
|
||||
|
||||
std::string name;
|
||||
SourceLineInfo lineInfo;
|
||||
};
|
||||
|
||||
struct SectionEndInfo {
|
||||
SectionInfo sectionInfo;
|
||||
Counts prevAssertions;
|
||||
double durationInSeconds;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_SECTION_INFO_HPP_INCLUDED
|
||||
413
tests/catch2/src/catch2/catch_session.cpp
Normal file
413
tests/catch2/src/catch2/catch_session.cpp
Normal file
|
|
@ -0,0 +1,413 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_session.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
#include <catch2/catch_version.hpp>
|
||||
#include <catch2/internal/catch_startup_exception_registry.hpp>
|
||||
#include <catch2/internal/catch_sharding.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_textflow.hpp>
|
||||
#include <catch2/internal/catch_windows_h_proxy.hpp>
|
||||
#include <catch2/reporters/catch_reporter_multi.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_stdstreams.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
IEventListenerPtr createReporter(std::string const& reporterName, ReporterConfig&& config) {
|
||||
auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config));
|
||||
CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\'');
|
||||
|
||||
return reporter;
|
||||
}
|
||||
|
||||
IEventListenerPtr prepareReporters(Config const* config) {
|
||||
if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()
|
||||
&& config->getProcessedReporterSpecs().size() == 1) {
|
||||
auto const& spec = config->getProcessedReporterSpecs()[0];
|
||||
return createReporter(
|
||||
spec.name,
|
||||
ReporterConfig( config,
|
||||
makeStream( spec.outputFilename ),
|
||||
spec.colourMode,
|
||||
spec.customOptions ) );
|
||||
}
|
||||
|
||||
auto multi = Detail::make_unique<MultiReporter>(config);
|
||||
|
||||
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
|
||||
for (auto const& listener : listeners) {
|
||||
multi->addListener(listener->create(config));
|
||||
}
|
||||
|
||||
for ( auto const& reporterSpec : config->getProcessedReporterSpecs() ) {
|
||||
multi->addReporter( createReporter(
|
||||
reporterSpec.name,
|
||||
ReporterConfig( config,
|
||||
makeStream( reporterSpec.outputFilename ),
|
||||
reporterSpec.colourMode,
|
||||
reporterSpec.customOptions ) ) );
|
||||
}
|
||||
|
||||
return multi;
|
||||
}
|
||||
|
||||
class TestGroup {
|
||||
public:
|
||||
explicit TestGroup(IEventListenerPtr&& reporter, Config const* config):
|
||||
m_reporter(reporter.get()),
|
||||
m_config{config},
|
||||
m_context{config, CATCH_MOVE(reporter)} {
|
||||
|
||||
assert( m_config->testSpec().getInvalidSpecs().empty() &&
|
||||
"Invalid test specs should be handled before running tests" );
|
||||
|
||||
auto const& allTestCases = getAllTestCasesSorted(*m_config);
|
||||
auto const& testSpec = m_config->testSpec();
|
||||
if ( !testSpec.hasFilters() ) {
|
||||
for ( auto const& test : allTestCases ) {
|
||||
if ( !test.getTestCaseInfo().isHidden() ) {
|
||||
m_tests.emplace( &test );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_matches =
|
||||
testSpec.matchesByFilter( allTestCases, *m_config );
|
||||
for ( auto const& match : m_matches ) {
|
||||
m_tests.insert( match.tests.begin(),
|
||||
match.tests.end() );
|
||||
}
|
||||
}
|
||||
|
||||
m_tests = createShard(m_tests, m_config->shardCount(), m_config->shardIndex());
|
||||
}
|
||||
|
||||
Totals execute() {
|
||||
Totals totals;
|
||||
for (auto const& testCase : m_tests) {
|
||||
if (!m_context.aborting())
|
||||
totals += m_context.runTest(*testCase);
|
||||
else
|
||||
m_reporter->skipTest(testCase->getTestCaseInfo());
|
||||
}
|
||||
|
||||
for (auto const& match : m_matches) {
|
||||
if (match.tests.empty()) {
|
||||
m_unmatchedTestSpecs = true;
|
||||
m_reporter->noMatchingTestCases( match.name );
|
||||
}
|
||||
}
|
||||
|
||||
return totals;
|
||||
}
|
||||
|
||||
bool hadUnmatchedTestSpecs() const {
|
||||
return m_unmatchedTestSpecs;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
IEventListener* m_reporter;
|
||||
Config const* m_config;
|
||||
RunContext m_context;
|
||||
std::set<TestCaseHandle const*> m_tests;
|
||||
TestSpec::Matches m_matches;
|
||||
bool m_unmatchedTestSpecs = false;
|
||||
};
|
||||
|
||||
void applyFilenamesAsTags() {
|
||||
for (auto const& testInfo : getRegistryHub().getTestCaseRegistry().getAllInfos()) {
|
||||
testInfo->addFilenameTag();
|
||||
}
|
||||
}
|
||||
|
||||
// Creates empty file at path. The path must be writable, we do not
|
||||
// try to create directories in path because that's hard in C++14.
|
||||
void setUpGuardFile( std::string const& guardFilePath ) {
|
||||
if ( !guardFilePath.empty() ) {
|
||||
#if defined( _MSC_VER )
|
||||
std::FILE* file = nullptr;
|
||||
if ( fopen_s( &file, guardFilePath.c_str(), "w" ) ) {
|
||||
char msgBuffer[100];
|
||||
const auto err = errno;
|
||||
std::string errMsg;
|
||||
if ( !strerror_s( msgBuffer, err ) ) {
|
||||
errMsg = msgBuffer;
|
||||
} else {
|
||||
errMsg = "Could not translate errno to a string";
|
||||
}
|
||||
|
||||
#else
|
||||
std::FILE* file = std::fopen( guardFilePath.c_str(), "w" );
|
||||
if ( !file ) {
|
||||
const auto err = errno;
|
||||
const char* errMsg = std::strerror( err );
|
||||
#endif
|
||||
|
||||
CATCH_RUNTIME_ERROR( "Could not open the exit guard file '"
|
||||
<< guardFilePath << "' because '"
|
||||
<< errMsg << "' (" << err << ')' );
|
||||
}
|
||||
const int ret = std::fclose( file );
|
||||
CATCH_ENFORCE(
|
||||
ret == 0,
|
||||
"Error when closing the exit guard file: " << ret );
|
||||
}
|
||||
}
|
||||
|
||||
// Removes file at path. Assuming we created it in setUpGuardFile.
|
||||
void tearDownGuardFile( std::string const& guardFilePath ) {
|
||||
if ( !guardFilePath.empty() ) {
|
||||
const int ret = std::remove( guardFilePath.c_str() );
|
||||
CATCH_ENFORCE(
|
||||
ret == 0,
|
||||
"Error when removing the exit guard file: " << ret );
|
||||
}
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
Session::Session() {
|
||||
static bool alreadyInstantiated = false;
|
||||
if( alreadyInstantiated ) {
|
||||
CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
|
||||
CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
|
||||
}
|
||||
|
||||
// There cannot be exceptions at startup in no-exception mode.
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
|
||||
if ( !exceptions.empty() ) {
|
||||
config();
|
||||
getCurrentMutableContext().setConfig(m_config.get());
|
||||
|
||||
m_startupExceptions = true;
|
||||
auto errStream = makeStream( "%stderr" );
|
||||
auto colourImpl = makeColourImpl(
|
||||
ColourMode::PlatformDefault, errStream.get() );
|
||||
auto guard = colourImpl->guardColour( Colour::Red );
|
||||
errStream->stream() << "Errors occurred during startup!" << '\n';
|
||||
// iterate over all exceptions and notify user
|
||||
for ( const auto& ex_ptr : exceptions ) {
|
||||
try {
|
||||
std::rethrow_exception(ex_ptr);
|
||||
} catch ( std::exception const& ex ) {
|
||||
errStream->stream() << TextFlow::Column( ex.what() ).indent(2) << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
alreadyInstantiated = true;
|
||||
m_cli = makeCommandLineParser( m_configData );
|
||||
}
|
||||
Session::~Session() {
|
||||
Catch::cleanUp();
|
||||
}
|
||||
|
||||
void Session::showHelp() const {
|
||||
Catch::cout()
|
||||
<< "\nCatch2 v" << libraryVersion() << '\n'
|
||||
<< m_cli << '\n'
|
||||
<< "For more detailed usage please see the project docs\n\n" << std::flush;
|
||||
}
|
||||
void Session::libIdentify() {
|
||||
Catch::cout()
|
||||
<< std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
|
||||
<< std::left << std::setw(16) << "category: " << "testframework\n"
|
||||
<< std::left << std::setw(16) << "framework: " << "Catch2\n"
|
||||
<< std::left << std::setw(16) << "version: " << libraryVersion() << '\n' << std::flush;
|
||||
}
|
||||
|
||||
int Session::applyCommandLine( int argc, char const * const * argv ) {
|
||||
if ( m_startupExceptions ) { return UnspecifiedErrorExitCode; }
|
||||
|
||||
auto result = m_cli.parse( Clara::Args( argc, argv ) );
|
||||
|
||||
if( !result ) {
|
||||
config();
|
||||
getCurrentMutableContext().setConfig(m_config.get());
|
||||
auto errStream = makeStream( "%stderr" );
|
||||
auto colour = makeColourImpl( ColourMode::PlatformDefault, errStream.get() );
|
||||
|
||||
errStream->stream()
|
||||
<< colour->guardColour( Colour::Red )
|
||||
<< "\nError(s) in input:\n"
|
||||
<< TextFlow::Column( result.errorMessage() ).indent( 2 )
|
||||
<< "\n\n";
|
||||
errStream->stream() << "Run with -? for usage\n\n" << std::flush;
|
||||
return UnspecifiedErrorExitCode;
|
||||
}
|
||||
|
||||
if( m_configData.showHelp )
|
||||
showHelp();
|
||||
if( m_configData.libIdentify )
|
||||
libIdentify();
|
||||
|
||||
m_config.reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
|
||||
int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
|
||||
|
||||
char **utf8Argv = new char *[ argc ];
|
||||
|
||||
for ( int i = 0; i < argc; ++i ) {
|
||||
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
|
||||
|
||||
utf8Argv[ i ] = new char[ bufSize ];
|
||||
|
||||
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
|
||||
}
|
||||
|
||||
int returnCode = applyCommandLine( argc, utf8Argv );
|
||||
|
||||
for ( int i = 0; i < argc; ++i )
|
||||
delete [] utf8Argv[ i ];
|
||||
|
||||
delete [] utf8Argv;
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Session::useConfigData( ConfigData const& configData ) {
|
||||
m_configData = configData;
|
||||
m_config.reset();
|
||||
}
|
||||
|
||||
int Session::run() {
|
||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
|
||||
Catch::cout() << "...waiting for enter/ return before starting\n" << std::flush;
|
||||
static_cast<void>(std::getchar());
|
||||
}
|
||||
int exitCode = runInternal();
|
||||
|
||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
|
||||
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
|
||||
static_cast<void>(std::getchar());
|
||||
}
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
Clara::Parser const& Session::cli() const {
|
||||
return m_cli;
|
||||
}
|
||||
void Session::cli( Clara::Parser const& newParser ) {
|
||||
m_cli = newParser;
|
||||
}
|
||||
ConfigData& Session::configData() {
|
||||
return m_configData;
|
||||
}
|
||||
Config& Session::config() {
|
||||
if( !m_config )
|
||||
m_config = Detail::make_unique<Config>( m_configData );
|
||||
return *m_config;
|
||||
}
|
||||
|
||||
int Session::runInternal() {
|
||||
if ( m_startupExceptions ) { return UnspecifiedErrorExitCode; }
|
||||
|
||||
if (m_configData.showHelp || m_configData.libIdentify) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( m_configData.shardIndex >= m_configData.shardCount ) {
|
||||
Catch::cerr() << "The shard count (" << m_configData.shardCount
|
||||
<< ") must be greater than the shard index ("
|
||||
<< m_configData.shardIndex << ")\n"
|
||||
<< std::flush;
|
||||
return UnspecifiedErrorExitCode;
|
||||
}
|
||||
|
||||
CATCH_TRY {
|
||||
config(); // Force config to be constructed
|
||||
|
||||
// We need to retrieve potential Bazel config with the full Config
|
||||
// constructor, so we have to create the guard file after it is created.
|
||||
setUpGuardFile( m_config->getExitGuardFilePath() );
|
||||
|
||||
seedRng( *m_config );
|
||||
|
||||
if (m_configData.filenamesAsTags) {
|
||||
applyFilenamesAsTags();
|
||||
}
|
||||
|
||||
// Set up global config instance before we start calling into other functions
|
||||
getCurrentMutableContext().setConfig(m_config.get());
|
||||
|
||||
// Create reporter(s) so we can route listings through them
|
||||
auto reporter = prepareReporters(m_config.get());
|
||||
|
||||
auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
|
||||
if ( !invalidSpecs.empty() ) {
|
||||
for ( auto const& spec : invalidSpecs ) {
|
||||
reporter->reportInvalidTestSpec( spec );
|
||||
}
|
||||
return InvalidTestSpecExitCode;
|
||||
}
|
||||
|
||||
|
||||
// Handle list request
|
||||
if (list(*reporter, *m_config)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
|
||||
auto const totals = tests.execute();
|
||||
|
||||
// If we got here, running the tests finished normally-enough.
|
||||
// They might've failed, but that would've been reported elsewhere.
|
||||
tearDownGuardFile( m_config->getExitGuardFilePath() );
|
||||
|
||||
if ( tests.hadUnmatchedTestSpecs()
|
||||
&& m_config->warnAboutUnmatchedTestSpecs() ) {
|
||||
return UnmatchedTestSpecExitCode;
|
||||
}
|
||||
|
||||
if ( totals.testCases.total() == 0
|
||||
&& !m_config->zeroTestsCountAsSuccess() ) {
|
||||
return NoTestsRunExitCode;
|
||||
}
|
||||
|
||||
if ( totals.testCases.total() > 0 &&
|
||||
totals.testCases.total() == totals.testCases.skipped
|
||||
&& !m_config->zeroTestsCountAsSuccess() ) {
|
||||
return AllTestsSkippedExitCode;
|
||||
}
|
||||
|
||||
if ( totals.assertions.failed ) { return TestFailureExitCode; }
|
||||
return 0;
|
||||
|
||||
}
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
catch( std::exception& ex ) {
|
||||
Catch::cerr() << ex.what() << '\n' << std::flush;
|
||||
return UnspecifiedErrorExitCode;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
70
tests/catch2/src/catch2/catch_session.hpp
Normal file
70
tests/catch2/src/catch2/catch_session.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_SESSION_HPP_INCLUDED
|
||||
#define CATCH_SESSION_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_commandline.hpp>
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_config_wchar.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// TODO: Use C++17 `inline` variables
|
||||
constexpr int UnspecifiedErrorExitCode = 1;
|
||||
constexpr int NoTestsRunExitCode = 2;
|
||||
constexpr int UnmatchedTestSpecExitCode = 3;
|
||||
constexpr int AllTestsSkippedExitCode = 4;
|
||||
constexpr int InvalidTestSpecExitCode = 5;
|
||||
constexpr int TestFailureExitCode = 42;
|
||||
|
||||
class Session : Detail::NonCopyable {
|
||||
public:
|
||||
|
||||
Session();
|
||||
~Session();
|
||||
|
||||
void showHelp() const;
|
||||
void libIdentify();
|
||||
|
||||
int applyCommandLine( int argc, char const * const * argv );
|
||||
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
|
||||
int applyCommandLine( int argc, wchar_t const * const * argv );
|
||||
#endif
|
||||
|
||||
void useConfigData( ConfigData const& configData );
|
||||
|
||||
template<typename CharT>
|
||||
int run(int argc, CharT const * const argv[]) {
|
||||
if (m_startupExceptions)
|
||||
return 1;
|
||||
int returnCode = applyCommandLine(argc, argv);
|
||||
if (returnCode == 0)
|
||||
returnCode = run();
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
int run();
|
||||
|
||||
Clara::Parser const& cli() const;
|
||||
void cli( Clara::Parser const& newParser );
|
||||
ConfigData& configData();
|
||||
Config& config();
|
||||
private:
|
||||
int runInternal();
|
||||
|
||||
Clara::Parser m_cli;
|
||||
ConfigData m_configData;
|
||||
Detail::unique_ptr<Config> m_config;
|
||||
bool m_startupExceptions = false;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_SESSION_HPP_INCLUDED
|
||||
29
tests/catch2/src/catch2/catch_tag_alias.hpp
Normal file
29
tests/catch2/src/catch2/catch_tag_alias.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TAG_ALIAS_HPP_INCLUDED
|
||||
#define CATCH_TAG_ALIAS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TagAlias {
|
||||
TagAlias(std::string const& _tag, SourceLineInfo _lineInfo):
|
||||
tag(_tag),
|
||||
lineInfo(_lineInfo)
|
||||
{}
|
||||
|
||||
std::string tag;
|
||||
SourceLineInfo lineInfo;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_TAG_ALIAS_HPP_INCLUDED
|
||||
24
tests/catch2/src/catch2/catch_tag_alias_autoregistrar.cpp
Normal file
24
tests/catch2/src/catch2/catch_tag_alias_autoregistrar.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_tag_alias_autoregistrar.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
|
||||
CATCH_TRY {
|
||||
getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
|
||||
} CATCH_CATCH_ALL {
|
||||
// Do not throw when constructing global objects, instead register the exception to be processed later
|
||||
getMutableRegistryHub().registerStartupException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
29
tests/catch2/src/catch2/catch_tag_alias_autoregistrar.hpp
Normal file
29
tests/catch2/src/catch2/catch_tag_alias_autoregistrar.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
|
||||
#define CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct RegistrarForTagAliases {
|
||||
RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ const Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
#endif // CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
|
||||
124
tests/catch2/src/catch2/catch_template_test_macros.hpp
Normal file
124
tests/catch2/src/catch2/catch_template_test_macros.hpp
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
|
||||
#define CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
|
||||
|
||||
// We need this suppression to leak, because it took until GCC 10
|
||||
// for the front end to handle local suppression via _Pragma properly
|
||||
// inside templates (so `TEMPLATE_TEST_CASE` and co).
|
||||
// **THIS IS DIFFERENT FOR STANDARD TESTS, WHERE GCC 9 IS SUFFICIENT**
|
||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ < 10
|
||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||
#endif
|
||||
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_template_test_registry.hpp>
|
||||
#include <catch2/internal/catch_preprocessor.hpp>
|
||||
|
||||
|
||||
#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
|
||||
#define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
|
||||
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
|
||||
#else
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
// When disabled, these can be shared between proper preprocessor and MSVC preprocessor
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE(__VA_ARGS__)
|
||||
#define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
|
||||
#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
|
||||
#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
|
||||
#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
|
||||
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
|
||||
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
|
||||
#else
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
|
||||
#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
// When disabled, these can be shared between proper preprocessor and MSVC preprocessor
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define TEMPLATE_LIST_TEST_CASE( ... ) TEMPLATE_TEST_CASE(__VA_ARGS__)
|
||||
#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
|
||||
#endif // end of user facing macro declarations
|
||||
|
||||
|
||||
#endif // CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
|
||||
262
tests/catch2/src/catch2/catch_test_case_info.cpp
Normal file
262
tests/catch2/src/catch2/catch_test_case_info.cpp
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||
#include <catch2/internal/catch_test_registry.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
using TCP_underlying_type = uint8_t;
|
||||
static_assert(sizeof(TestCaseProperties) == sizeof(TCP_underlying_type),
|
||||
"The size of the TestCaseProperties is different from the assumed size");
|
||||
|
||||
constexpr TestCaseProperties operator|(TestCaseProperties lhs, TestCaseProperties rhs) {
|
||||
return static_cast<TestCaseProperties>(
|
||||
static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
constexpr TestCaseProperties& operator|=(TestCaseProperties& lhs, TestCaseProperties rhs) {
|
||||
lhs = static_cast<TestCaseProperties>(
|
||||
static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
|
||||
);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr TestCaseProperties operator&(TestCaseProperties lhs, TestCaseProperties rhs) {
|
||||
return static_cast<TestCaseProperties>(
|
||||
static_cast<TCP_underlying_type>(lhs) & static_cast<TCP_underlying_type>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
constexpr bool applies(TestCaseProperties tcp) {
|
||||
static_assert(static_cast<TCP_underlying_type>(TestCaseProperties::None) == 0,
|
||||
"TestCaseProperties::None must be equal to 0");
|
||||
return tcp != TestCaseProperties::None;
|
||||
}
|
||||
|
||||
TestCaseProperties parseSpecialTag( StringRef tag ) {
|
||||
if( !tag.empty() && tag[0] == '.' )
|
||||
return TestCaseProperties::IsHidden;
|
||||
else if( tag == "!throws"_sr )
|
||||
return TestCaseProperties::Throws;
|
||||
else if( tag == "!shouldfail"_sr )
|
||||
return TestCaseProperties::ShouldFail;
|
||||
else if( tag == "!mayfail"_sr )
|
||||
return TestCaseProperties::MayFail;
|
||||
else if( tag == "!nonportable"_sr )
|
||||
return TestCaseProperties::NonPortable;
|
||||
else if( tag == "!benchmark"_sr )
|
||||
return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden;
|
||||
else
|
||||
return TestCaseProperties::None;
|
||||
}
|
||||
bool isReservedTag( StringRef tag ) {
|
||||
return parseSpecialTag( tag ) == TestCaseProperties::None
|
||||
&& tag.size() > 0
|
||||
&& !std::isalnum( static_cast<unsigned char>(tag[0]) );
|
||||
}
|
||||
void enforceNotReservedTag( StringRef tag, SourceLineInfo const& _lineInfo ) {
|
||||
CATCH_ENFORCE( !isReservedTag(tag),
|
||||
"Tag name: [" << tag << "] is not allowed.\n"
|
||||
<< "Tag names starting with non alphanumeric characters are reserved\n"
|
||||
<< _lineInfo );
|
||||
}
|
||||
|
||||
std::string makeDefaultName() {
|
||||
static size_t counter = 0;
|
||||
return "Anonymous test case " + std::to_string(++counter);
|
||||
}
|
||||
|
||||
constexpr StringRef extractFilenamePart(StringRef filename) {
|
||||
size_t lastDot = filename.size();
|
||||
while (lastDot > 0 && filename[lastDot - 1] != '.') {
|
||||
--lastDot;
|
||||
}
|
||||
// In theory we could have filename without any extension in it
|
||||
if ( lastDot == 0 ) { return StringRef(); }
|
||||
|
||||
--lastDot;
|
||||
size_t nameStart = lastDot;
|
||||
while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') {
|
||||
--nameStart;
|
||||
}
|
||||
|
||||
return filename.substr(nameStart, lastDot - nameStart);
|
||||
}
|
||||
|
||||
// Returns the upper bound on size of extra tags ([#file]+[.])
|
||||
constexpr size_t sizeOfExtraTags(StringRef filepath) {
|
||||
// [.] is 3, [#] is another 3
|
||||
const size_t extras = 3 + 3;
|
||||
return extractFilenamePart(filepath).size() + extras;
|
||||
}
|
||||
} // end unnamed namespace
|
||||
|
||||
bool operator<( Tag const& lhs, Tag const& rhs ) {
|
||||
Detail::CaseInsensitiveLess cmp;
|
||||
return cmp( lhs.original, rhs.original );
|
||||
}
|
||||
bool operator==( Tag const& lhs, Tag const& rhs ) {
|
||||
Detail::CaseInsensitiveEqualTo cmp;
|
||||
return cmp( lhs.original, rhs.original );
|
||||
}
|
||||
|
||||
Detail::unique_ptr<TestCaseInfo>
|
||||
makeTestCaseInfo(StringRef _className,
|
||||
NameAndTags const& nameAndTags,
|
||||
SourceLineInfo const& _lineInfo ) {
|
||||
return Detail::make_unique<TestCaseInfo>(_className, nameAndTags, _lineInfo);
|
||||
}
|
||||
|
||||
TestCaseInfo::TestCaseInfo(StringRef _className,
|
||||
NameAndTags const& _nameAndTags,
|
||||
SourceLineInfo const& _lineInfo):
|
||||
name( _nameAndTags.name.empty() ? makeDefaultName() : _nameAndTags.name ),
|
||||
className( _className ),
|
||||
lineInfo( _lineInfo )
|
||||
{
|
||||
StringRef originalTags = _nameAndTags.tags;
|
||||
// We need to reserve enough space to store all of the tags
|
||||
// (including optional hidden tag and filename tag)
|
||||
auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file);
|
||||
backingTags.reserve(requiredSize);
|
||||
|
||||
// We cannot copy the tags directly, as we need to normalize
|
||||
// some tags, so that [.foo] is copied as [.][foo].
|
||||
size_t tagStart = 0;
|
||||
size_t tagEnd = 0;
|
||||
bool inTag = false;
|
||||
for (size_t idx = 0; idx < originalTags.size(); ++idx) {
|
||||
auto c = originalTags[idx];
|
||||
if (c == '[') {
|
||||
CATCH_ENFORCE(
|
||||
!inTag,
|
||||
"Found '[' inside a tag while registering test case '"
|
||||
<< _nameAndTags.name << "' at " << _lineInfo );
|
||||
|
||||
inTag = true;
|
||||
tagStart = idx;
|
||||
}
|
||||
if (c == ']') {
|
||||
CATCH_ENFORCE(
|
||||
inTag,
|
||||
"Found unmatched ']' while registering test case '"
|
||||
<< _nameAndTags.name << "' at " << _lineInfo );
|
||||
|
||||
inTag = false;
|
||||
tagEnd = idx;
|
||||
assert(tagStart < tagEnd);
|
||||
|
||||
// We need to check the tag for special meanings, copy
|
||||
// it over to backing storage and actually reference the
|
||||
// backing storage in the saved tags
|
||||
StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1);
|
||||
CATCH_ENFORCE( !tagStr.empty(),
|
||||
"Found an empty tag while registering test case '"
|
||||
<< _nameAndTags.name << "' at "
|
||||
<< _lineInfo );
|
||||
|
||||
enforceNotReservedTag(tagStr, lineInfo);
|
||||
properties |= parseSpecialTag(tagStr);
|
||||
// When copying a tag to the backing storage, we need to
|
||||
// check if it is a merged hide tag, such as [.foo], and
|
||||
// if it is, we need to handle it as if it was [foo].
|
||||
if (tagStr.size() > 1 && tagStr[0] == '.') {
|
||||
tagStr = tagStr.substr(1, tagStr.size() - 1);
|
||||
}
|
||||
// We skip over dealing with the [.] tag, as we will add
|
||||
// it later unconditionally and then sort and unique all
|
||||
// the tags.
|
||||
internalAppendTag(tagStr);
|
||||
}
|
||||
}
|
||||
CATCH_ENFORCE( !inTag,
|
||||
"Found an unclosed tag while registering test case '"
|
||||
<< _nameAndTags.name << "' at " << _lineInfo );
|
||||
|
||||
|
||||
// Add [.] if relevant
|
||||
if (isHidden()) {
|
||||
internalAppendTag("."_sr);
|
||||
}
|
||||
|
||||
// Sort and prepare tags
|
||||
std::sort(begin(tags), end(tags));
|
||||
tags.erase(std::unique(begin(tags), end(tags)),
|
||||
end(tags));
|
||||
}
|
||||
|
||||
bool TestCaseInfo::isHidden() const {
|
||||
return applies( properties & TestCaseProperties::IsHidden );
|
||||
}
|
||||
bool TestCaseInfo::throws() const {
|
||||
return applies( properties & TestCaseProperties::Throws );
|
||||
}
|
||||
bool TestCaseInfo::okToFail() const {
|
||||
return applies( properties & (TestCaseProperties::ShouldFail | TestCaseProperties::MayFail ) );
|
||||
}
|
||||
bool TestCaseInfo::expectedToFail() const {
|
||||
return applies( properties & (TestCaseProperties::ShouldFail) );
|
||||
}
|
||||
|
||||
void TestCaseInfo::addFilenameTag() {
|
||||
std::string combined("#");
|
||||
combined += extractFilenamePart(lineInfo.file);
|
||||
internalAppendTag(combined);
|
||||
}
|
||||
|
||||
std::string TestCaseInfo::tagsAsString() const {
|
||||
std::string ret;
|
||||
// '[' and ']' per tag
|
||||
std::size_t full_size = 2 * tags.size();
|
||||
for (const auto& tag : tags) {
|
||||
full_size += tag.original.size();
|
||||
}
|
||||
ret.reserve(full_size);
|
||||
for (const auto& tag : tags) {
|
||||
ret.push_back('[');
|
||||
ret += tag.original;
|
||||
ret.push_back(']');
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TestCaseInfo::internalAppendTag(StringRef tagStr) {
|
||||
backingTags += '[';
|
||||
const auto backingStart = backingTags.size();
|
||||
backingTags += tagStr;
|
||||
const auto backingEnd = backingTags.size();
|
||||
backingTags += ']';
|
||||
tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart));
|
||||
}
|
||||
|
||||
bool operator<( TestCaseInfo const& lhs, TestCaseInfo const& rhs ) {
|
||||
// We want to avoid redoing the string comparisons multiple times,
|
||||
// so we store the result of a three-way comparison before using
|
||||
// it in the actual comparison logic.
|
||||
const auto cmpName = lhs.name.compare( rhs.name );
|
||||
if ( cmpName != 0 ) {
|
||||
return cmpName < 0;
|
||||
}
|
||||
const auto cmpClassName = lhs.className.compare( rhs.className );
|
||||
if ( cmpClassName != 0 ) {
|
||||
return cmpClassName < 0;
|
||||
}
|
||||
return lhs.tags < rhs.tags;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
142
tests/catch2/src/catch2/catch_test_case_info.hpp
Normal file
142
tests/catch2/src/catch2/catch_test_case_info.hpp
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TEST_CASE_INFO_HPP_INCLUDED
|
||||
#define CATCH_TEST_CASE_INFO_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_test_invoker.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpadded"
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
|
||||
/**
|
||||
* A **view** of a tag string that provides case insensitive comparisons
|
||||
*
|
||||
* Note that in Catch2 internals, the square brackets around tags are
|
||||
* not a part of tag's representation, so e.g. "[cool-tag]" is represented
|
||||
* as "cool-tag" internally.
|
||||
*/
|
||||
struct Tag {
|
||||
constexpr Tag(StringRef original_):
|
||||
original(original_)
|
||||
{}
|
||||
StringRef original;
|
||||
|
||||
friend bool operator< ( Tag const& lhs, Tag const& rhs );
|
||||
friend bool operator==( Tag const& lhs, Tag const& rhs );
|
||||
};
|
||||
|
||||
class ITestInvoker;
|
||||
struct NameAndTags;
|
||||
|
||||
enum class TestCaseProperties : uint8_t {
|
||||
None = 0,
|
||||
IsHidden = 1 << 1,
|
||||
ShouldFail = 1 << 2,
|
||||
MayFail = 1 << 3,
|
||||
Throws = 1 << 4,
|
||||
NonPortable = 1 << 5,
|
||||
Benchmark = 1 << 6
|
||||
};
|
||||
|
||||
/**
|
||||
* Various metadata about the test case.
|
||||
*
|
||||
* A test case is uniquely identified by its (class)name and tags
|
||||
* combination, with source location being ignored, and other properties
|
||||
* being determined from tags.
|
||||
*
|
||||
* Tags are kept sorted.
|
||||
*/
|
||||
struct TestCaseInfo : Detail::NonCopyable {
|
||||
|
||||
TestCaseInfo(StringRef _className,
|
||||
NameAndTags const& _nameAndTags,
|
||||
SourceLineInfo const& _lineInfo);
|
||||
|
||||
bool isHidden() const;
|
||||
bool throws() const;
|
||||
bool okToFail() const;
|
||||
bool expectedToFail() const;
|
||||
|
||||
// Adds the tag(s) with test's filename (for the -# flag)
|
||||
void addFilenameTag();
|
||||
|
||||
//! Orders by name, classname and tags
|
||||
friend bool operator<( TestCaseInfo const& lhs,
|
||||
TestCaseInfo const& rhs );
|
||||
|
||||
|
||||
std::string tagsAsString() const;
|
||||
|
||||
std::string name;
|
||||
StringRef className;
|
||||
private:
|
||||
std::string backingTags;
|
||||
// Internally we copy tags to the backing storage and then add
|
||||
// refs to this storage to the tags vector.
|
||||
void internalAppendTag(StringRef tagString);
|
||||
public:
|
||||
std::vector<Tag> tags;
|
||||
SourceLineInfo lineInfo;
|
||||
TestCaseProperties properties = TestCaseProperties::None;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper over the test case information and the test case invoker
|
||||
*
|
||||
* Does not own either, and is specifically made to be cheap
|
||||
* to copy around.
|
||||
*/
|
||||
class TestCaseHandle {
|
||||
TestCaseInfo* m_info;
|
||||
ITestInvoker* m_invoker;
|
||||
public:
|
||||
constexpr TestCaseHandle(TestCaseInfo* info, ITestInvoker* invoker) :
|
||||
m_info(info), m_invoker(invoker) {}
|
||||
|
||||
void prepareTestCase() const {
|
||||
m_invoker->prepareTestCase();
|
||||
}
|
||||
|
||||
void tearDownTestCase() const {
|
||||
m_invoker->tearDownTestCase();
|
||||
}
|
||||
|
||||
void invoke() const {
|
||||
m_invoker->invoke();
|
||||
}
|
||||
|
||||
constexpr TestCaseInfo const& getTestCaseInfo() const {
|
||||
return *m_info;
|
||||
}
|
||||
};
|
||||
|
||||
Detail::unique_ptr<TestCaseInfo>
|
||||
makeTestCaseInfo( StringRef className,
|
||||
NameAndTags const& nameAndTags,
|
||||
SourceLineInfo const& lineInfo );
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // CATCH_TEST_CASE_INFO_HPP_INCLUDED
|
||||
243
tests/catch2/src/catch2/catch_test_macros.hpp
Normal file
243
tests/catch2/src/catch2/catch_test_macros.hpp
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TEST_MACROS_HPP_INCLUDED
|
||||
#define CATCH_TEST_MACROS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_test_macro_impl.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
#include <catch2/internal/catch_section.hpp>
|
||||
#include <catch2/internal/catch_test_registry.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
#include <catch2/internal/catch_unreachable.hpp>
|
||||
|
||||
|
||||
// All of our user-facing macros support configuration toggle, that
|
||||
// forces them to be defined prefixed with CATCH_. We also like to
|
||||
// support another toggle that can minimize (disable) their implementation.
|
||||
// Given this, we have 4 different configuration options below
|
||||
|
||||
#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
|
||||
#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
|
||||
#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
|
||||
#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
|
||||
#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
|
||||
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||
#define CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, __VA_ARGS__ )
|
||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||
#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||
#define CATCH_FAIL( ... ) do { \
|
||||
INTERNAL_CATCH_MSG("CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
|
||||
Catch::Detail::Unreachable(); \
|
||||
} while ( false )
|
||||
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_SKIP( ... ) do { \
|
||||
INTERNAL_CATCH_MSG( "CATCH_SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
|
||||
Catch::Detail::Unreachable(); \
|
||||
} while (false)
|
||||
|
||||
|
||||
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
|
||||
#define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||
#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||
#define CATCH_STATIC_CHECK( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||
#define CATCH_STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||
#else
|
||||
#define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )
|
||||
#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
|
||||
#define CATCH_STATIC_CHECK( ... ) CATCH_CHECK( __VA_ARGS__ )
|
||||
#define CATCH_STATIC_CHECK_FALSE( ... ) CATCH_CHECK_FALSE( __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
|
||||
// "BDD-style" convenience wrappers
|
||||
#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||
#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||
#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
|
||||
#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||
#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
|
||||
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
|
||||
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
|
||||
|
||||
#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, implemented | vv prefixed, disabled
|
||||
|
||||
#define CATCH_REQUIRE( ... ) (void)(0)
|
||||
#define CATCH_REQUIRE_FALSE( ... ) (void)(0)
|
||||
|
||||
#define CATCH_REQUIRE_THROWS( ... ) (void)(0)
|
||||
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
|
||||
#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)
|
||||
|
||||
#define CATCH_CHECK( ... ) (void)(0)
|
||||
#define CATCH_CHECK_FALSE( ... ) (void)(0)
|
||||
#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__)
|
||||
#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
|
||||
#define CATCH_CHECK_NOFAIL( ... ) (void)(0)
|
||||
|
||||
#define CATCH_CHECK_THROWS( ... ) (void)(0)
|
||||
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
|
||||
#define CATCH_CHECK_NOTHROW( ... ) (void)(0)
|
||||
|
||||
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
|
||||
#define CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||
#define CATCH_SECTION( ... )
|
||||
#define CATCH_DYNAMIC_SECTION( ... )
|
||||
#define CATCH_FAIL( ... ) (void)(0)
|
||||
#define CATCH_FAIL_CHECK( ... ) (void)(0)
|
||||
#define CATCH_SUCCEED( ... ) (void)(0)
|
||||
#define CATCH_SKIP( ... ) (void)(0)
|
||||
|
||||
#define CATCH_STATIC_REQUIRE( ... ) (void)(0)
|
||||
#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
|
||||
#define CATCH_STATIC_CHECK( ... ) (void)(0)
|
||||
#define CATCH_STATIC_CHECK_FALSE( ... ) (void)(0)
|
||||
|
||||
// "BDD-style" convenience wrappers
|
||||
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
|
||||
#define CATCH_GIVEN( desc )
|
||||
#define CATCH_AND_GIVEN( desc )
|
||||
#define CATCH_WHEN( desc )
|
||||
#define CATCH_AND_WHEN( desc )
|
||||
#define CATCH_THEN( desc )
|
||||
#define CATCH_AND_THEN( desc )
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, disabled | vv unprefixed, implemented
|
||||
|
||||
#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
|
||||
#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
|
||||
#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
|
||||
#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
|
||||
#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
|
||||
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||
#define TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, __VA_ARGS__ )
|
||||
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||
#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||
#define FAIL( ... ) do { \
|
||||
INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
|
||||
Catch::Detail::Unreachable(); \
|
||||
} while (false)
|
||||
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define SKIP( ... ) do { \
|
||||
INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
|
||||
Catch::Detail::Unreachable(); \
|
||||
} while (false)
|
||||
|
||||
|
||||
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
|
||||
#define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
|
||||
#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
|
||||
#define STATIC_CHECK( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
|
||||
#define STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
|
||||
#else
|
||||
#define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )
|
||||
#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
|
||||
#define STATIC_CHECK( ... ) CHECK( __VA_ARGS__ )
|
||||
#define STATIC_CHECK_FALSE( ... ) CHECK_FALSE( __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
// "BDD-style" convenience wrappers
|
||||
#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||
#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||
#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
|
||||
#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||
#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
|
||||
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
|
||||
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ unprefixed, implemented | vv unprefixed, disabled
|
||||
|
||||
#define REQUIRE( ... ) (void)(0)
|
||||
#define REQUIRE_FALSE( ... ) (void)(0)
|
||||
|
||||
#define REQUIRE_THROWS( ... ) (void)(0)
|
||||
#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
|
||||
#define REQUIRE_NOTHROW( ... ) (void)(0)
|
||||
|
||||
#define CHECK( ... ) (void)(0)
|
||||
#define CHECK_FALSE( ... ) (void)(0)
|
||||
#define CHECKED_IF( ... ) if (__VA_ARGS__)
|
||||
#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
|
||||
#define CHECK_NOFAIL( ... ) (void)(0)
|
||||
|
||||
#define CHECK_THROWS( ... ) (void)(0)
|
||||
#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
|
||||
#define CHECK_NOTHROW( ... ) (void)(0)
|
||||
|
||||
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
|
||||
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||
#define METHOD_AS_TEST_CASE( method, ... )
|
||||
#define TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
|
||||
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||
#define SECTION( ... )
|
||||
#define DYNAMIC_SECTION( ... )
|
||||
#define FAIL( ... ) (void)(0)
|
||||
#define FAIL_CHECK( ... ) (void)(0)
|
||||
#define SUCCEED( ... ) (void)(0)
|
||||
#define SKIP( ... ) (void)(0)
|
||||
|
||||
#define STATIC_REQUIRE( ... ) (void)(0)
|
||||
#define STATIC_REQUIRE_FALSE( ... ) (void)(0)
|
||||
#define STATIC_CHECK( ... ) (void)(0)
|
||||
#define STATIC_CHECK_FALSE( ... ) (void)(0)
|
||||
|
||||
// "BDD-style" convenience wrappers
|
||||
#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ) )
|
||||
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
|
||||
|
||||
#define GIVEN( desc )
|
||||
#define AND_GIVEN( desc )
|
||||
#define WHEN( desc )
|
||||
#define AND_WHEN( desc )
|
||||
#define THEN( desc )
|
||||
#define AND_THEN( desc )
|
||||
|
||||
#endif // ^^ unprefixed, disabled
|
||||
|
||||
// end of user facing macros
|
||||
|
||||
#endif // CATCH_TEST_MACROS_HPP_INCLUDED
|
||||
22
tests/catch2/src/catch2/catch_test_run_info.hpp
Normal file
22
tests/catch2/src/catch2/catch_test_run_info.hpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TEST_RUN_INFO_HPP_INCLUDED
|
||||
#define CATCH_TEST_RUN_INFO_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TestRunInfo {
|
||||
constexpr TestRunInfo(StringRef _name) : name(_name) {}
|
||||
StringRef name;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED
|
||||
141
tests/catch2/src/catch2/catch_test_spec.cpp
Normal file
141
tests/catch2/src/catch2/catch_test_spec.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_testcase.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ostream>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
TestSpec::Pattern::Pattern( std::string const& name )
|
||||
: m_name( name )
|
||||
{}
|
||||
|
||||
TestSpec::Pattern::~Pattern() = default;
|
||||
|
||||
std::string const& TestSpec::Pattern::name() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
|
||||
TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
|
||||
: Pattern( filterString )
|
||||
, m_wildcardPattern( toLower( name ), CaseSensitive::No )
|
||||
{}
|
||||
|
||||
bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
|
||||
return m_wildcardPattern.matches( testCase.name );
|
||||
}
|
||||
|
||||
void TestSpec::NamePattern::serializeTo( std::ostream& out ) const {
|
||||
out << '"' << name() << '"';
|
||||
}
|
||||
|
||||
|
||||
TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
|
||||
: Pattern( filterString )
|
||||
, m_tag( tag )
|
||||
{}
|
||||
|
||||
bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
|
||||
return std::find( begin( testCase.tags ),
|
||||
end( testCase.tags ),
|
||||
Tag( m_tag ) ) != end( testCase.tags );
|
||||
}
|
||||
|
||||
void TestSpec::TagPattern::serializeTo( std::ostream& out ) const {
|
||||
out << name();
|
||||
}
|
||||
|
||||
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
|
||||
bool should_use = !testCase.isHidden();
|
||||
for (auto const& pattern : m_required) {
|
||||
should_use = true;
|
||||
if (!pattern->matches(testCase)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (auto const& pattern : m_forbidden) {
|
||||
if (pattern->matches(testCase)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return should_use;
|
||||
}
|
||||
|
||||
void TestSpec::Filter::serializeTo( std::ostream& out ) const {
|
||||
bool first = true;
|
||||
for ( auto const& pattern : m_required ) {
|
||||
if ( !first ) {
|
||||
out << ' ';
|
||||
}
|
||||
out << *pattern;
|
||||
first = false;
|
||||
}
|
||||
for ( auto const& pattern : m_forbidden ) {
|
||||
if ( !first ) {
|
||||
out << ' ';
|
||||
}
|
||||
out << *pattern;
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string TestSpec::extractFilterName( Filter const& filter ) {
|
||||
Catch::ReusableStringStream sstr;
|
||||
sstr << filter;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
bool TestSpec::hasFilters() const {
|
||||
return !m_filters.empty();
|
||||
}
|
||||
|
||||
bool TestSpec::matches( TestCaseInfo const& testCase ) const {
|
||||
return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
|
||||
}
|
||||
|
||||
TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const {
|
||||
Matches matches;
|
||||
matches.reserve( m_filters.size() );
|
||||
for ( auto const& filter : m_filters ) {
|
||||
std::vector<TestCaseHandle const*> currentMatches;
|
||||
for ( auto const& test : testCases )
|
||||
if ( isThrowSafe( test, config ) &&
|
||||
filter.matches( test.getTestCaseInfo() ) )
|
||||
currentMatches.emplace_back( &test );
|
||||
matches.push_back(
|
||||
FilterMatch{ extractFilterName( filter ), currentMatches } );
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
const TestSpec::vectorStrings& TestSpec::getInvalidSpecs() const {
|
||||
return m_invalidSpecs;
|
||||
}
|
||||
|
||||
void TestSpec::serializeTo( std::ostream& out ) const {
|
||||
bool first = true;
|
||||
for ( auto const& filter : m_filters ) {
|
||||
if ( !first ) {
|
||||
out << ',';
|
||||
}
|
||||
out << filter;
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
119
tests/catch2/src/catch2/catch_test_spec.hpp
Normal file
119
tests/catch2/src/catch2/catch_test_spec.hpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TEST_SPEC_HPP_INCLUDED
|
||||
#define CATCH_TEST_SPEC_HPP_INCLUDED
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wpadded"
|
||||
#endif
|
||||
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_wildcard_pattern.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class IConfig;
|
||||
struct TestCaseInfo;
|
||||
class TestCaseHandle;
|
||||
|
||||
class TestSpec {
|
||||
|
||||
class Pattern {
|
||||
public:
|
||||
explicit Pattern( std::string const& name );
|
||||
virtual ~Pattern();
|
||||
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
|
||||
std::string const& name() const;
|
||||
private:
|
||||
virtual void serializeTo( std::ostream& out ) const = 0;
|
||||
// Writes string that would be reparsed into the pattern
|
||||
friend std::ostream& operator<<(std::ostream& out,
|
||||
Pattern const& pattern) {
|
||||
pattern.serializeTo( out );
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string const m_name;
|
||||
};
|
||||
|
||||
class NamePattern : public Pattern {
|
||||
public:
|
||||
explicit NamePattern( std::string const& name, std::string const& filterString );
|
||||
bool matches( TestCaseInfo const& testCase ) const override;
|
||||
private:
|
||||
void serializeTo( std::ostream& out ) const override;
|
||||
|
||||
WildcardPattern m_wildcardPattern;
|
||||
};
|
||||
|
||||
class TagPattern : public Pattern {
|
||||
public:
|
||||
explicit TagPattern( std::string const& tag, std::string const& filterString );
|
||||
bool matches( TestCaseInfo const& testCase ) const override;
|
||||
private:
|
||||
void serializeTo( std::ostream& out ) const override;
|
||||
|
||||
std::string m_tag;
|
||||
};
|
||||
|
||||
struct Filter {
|
||||
std::vector<Detail::unique_ptr<Pattern>> m_required;
|
||||
std::vector<Detail::unique_ptr<Pattern>> m_forbidden;
|
||||
|
||||
//! Serializes this filter into a string that would be parsed into
|
||||
//! an equivalent filter
|
||||
void serializeTo( std::ostream& out ) const;
|
||||
friend std::ostream& operator<<(std::ostream& out, Filter const& f) {
|
||||
f.serializeTo( out );
|
||||
return out;
|
||||
}
|
||||
|
||||
bool matches( TestCaseInfo const& testCase ) const;
|
||||
};
|
||||
|
||||
static std::string extractFilterName( Filter const& filter );
|
||||
|
||||
public:
|
||||
struct FilterMatch {
|
||||
std::string name;
|
||||
std::vector<TestCaseHandle const*> tests;
|
||||
};
|
||||
using Matches = std::vector<FilterMatch>;
|
||||
using vectorStrings = std::vector<std::string>;
|
||||
|
||||
bool hasFilters() const;
|
||||
bool matches( TestCaseInfo const& testCase ) const;
|
||||
Matches matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const;
|
||||
const vectorStrings & getInvalidSpecs() const;
|
||||
|
||||
private:
|
||||
std::vector<Filter> m_filters;
|
||||
std::vector<std::string> m_invalidSpecs;
|
||||
|
||||
friend class TestSpecParser;
|
||||
//! Serializes this test spec into a string that would be parsed into
|
||||
//! equivalent test spec
|
||||
void serializeTo( std::ostream& out ) const;
|
||||
friend std::ostream& operator<<(std::ostream& out,
|
||||
TestSpec const& spec) {
|
||||
spec.serializeTo( out );
|
||||
return out;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // CATCH_TEST_SPEC_HPP_INCLUDED
|
||||
37
tests/catch2/src/catch2/catch_timer.cpp
Normal file
37
tests/catch2/src/catch2/catch_timer.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_timer.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
static auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
} // end unnamed namespace
|
||||
|
||||
void Timer::start() {
|
||||
m_nanoseconds = getCurrentNanosecondsSinceEpoch();
|
||||
}
|
||||
auto Timer::getElapsedNanoseconds() const -> uint64_t {
|
||||
return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
|
||||
}
|
||||
auto Timer::getElapsedMicroseconds() const -> uint64_t {
|
||||
return getElapsedNanoseconds()/1000;
|
||||
}
|
||||
auto Timer::getElapsedMilliseconds() const -> unsigned int {
|
||||
return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
|
||||
}
|
||||
auto Timer::getElapsedSeconds() const -> double {
|
||||
return static_cast<double>(getElapsedMicroseconds())/1000000.0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Catch
|
||||
27
tests/catch2/src/catch2/catch_timer.hpp
Normal file
27
tests/catch2/src/catch2/catch_timer.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TIMER_HPP_INCLUDED
|
||||
#define CATCH_TIMER_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class Timer {
|
||||
uint64_t m_nanoseconds = 0;
|
||||
public:
|
||||
void start();
|
||||
auto getElapsedNanoseconds() const -> uint64_t;
|
||||
auto getElapsedMicroseconds() const -> uint64_t;
|
||||
auto getElapsedMilliseconds() const -> unsigned int;
|
||||
auto getElapsedSeconds() const -> double;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_TIMER_HPP_INCLUDED
|
||||
294
tests/catch2/src/catch2/catch_tostring.cpp
Normal file
294
tests/catch2/src/catch2/catch_tostring.cpp
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_polyfills.hpp>
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
namespace {
|
||||
const int hexThreshold = 255;
|
||||
|
||||
struct Endianness {
|
||||
enum Arch : uint8_t {
|
||||
Big,
|
||||
Little
|
||||
};
|
||||
|
||||
static Arch which() {
|
||||
int one = 1;
|
||||
// If the lowest byte we read is non-zero, we can assume
|
||||
// that little endian format is used.
|
||||
auto value = *reinterpret_cast<char*>(&one);
|
||||
return value ? Little : Big;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::string fpToString(T value, int precision) {
|
||||
if (Catch::isnan(value)) {
|
||||
return "nan";
|
||||
}
|
||||
|
||||
ReusableStringStream rss;
|
||||
rss << std::setprecision(precision)
|
||||
<< std::fixed
|
||||
<< value;
|
||||
std::string d = rss.str();
|
||||
std::size_t i = d.find_last_not_of('0');
|
||||
if (i != std::string::npos && i != d.size() - 1) {
|
||||
if (d[i] == '.')
|
||||
i++;
|
||||
d = d.substr(0, i + 1);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
} // end unnamed namespace
|
||||
|
||||
std::size_t catch_strnlen( const char* str, std::size_t n ) {
|
||||
auto ret = std::char_traits<char>::find( str, n, '\0' );
|
||||
if ( ret != nullptr ) { return static_cast<std::size_t>( ret - str ); }
|
||||
return n;
|
||||
}
|
||||
|
||||
std::string formatTimeT(std::time_t time) {
|
||||
#ifdef _MSC_VER
|
||||
std::tm timeInfo = {};
|
||||
const auto err = gmtime_s( &timeInfo, &time );
|
||||
if ( err ) {
|
||||
return "gmtime from provided timepoint has failed. This "
|
||||
"happens e.g. with pre-1970 dates using Microsoft libc";
|
||||
}
|
||||
#else
|
||||
std::tm* timeInfo = std::gmtime( &time );
|
||||
#endif
|
||||
|
||||
auto const timeStampSize = sizeof( "2017-01-16T17:06:45Z" );
|
||||
char timeStamp[timeStampSize];
|
||||
const char* const fmt = "%Y-%m-%dT%H:%M:%SZ";
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::strftime( timeStamp, timeStampSize, fmt, &timeInfo );
|
||||
#else
|
||||
std::strftime( timeStamp, timeStampSize, fmt, timeInfo );
|
||||
#endif
|
||||
return std::string( timeStamp, timeStampSize - 1 );
|
||||
}
|
||||
|
||||
std::string convertIntoString(StringRef string, bool escapeInvisibles) {
|
||||
std::string ret;
|
||||
// This is enough for the "don't escape invisibles" case, and a good
|
||||
// lower bound on the "escape invisibles" case.
|
||||
ret.reserve( string.size() + 2 );
|
||||
|
||||
if ( !escapeInvisibles ) {
|
||||
ret += '"';
|
||||
ret += string;
|
||||
ret += '"';
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t last_start = 0;
|
||||
auto write_to = [&]( size_t idx ) {
|
||||
if ( last_start < idx ) {
|
||||
ret += string.substr( last_start, idx - last_start );
|
||||
}
|
||||
last_start = idx + 1;
|
||||
};
|
||||
|
||||
ret += '"';
|
||||
for ( size_t i = 0; i < string.size(); ++i ) {
|
||||
const char c = string[i];
|
||||
if ( c == '\r' || c == '\n' || c == '\t' || c == '\f' ) {
|
||||
write_to( i );
|
||||
if ( c == '\r' ) { ret.append( "\\r" ); }
|
||||
if ( c == '\n' ) { ret.append( "\\n" ); }
|
||||
if ( c == '\t' ) { ret.append( "\\t" ); }
|
||||
if ( c == '\f' ) { ret.append( "\\f" ); }
|
||||
}
|
||||
}
|
||||
write_to( string.size() );
|
||||
ret += '"';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string convertIntoString(StringRef string) {
|
||||
return convertIntoString(string, getCurrentContext().getConfig()->showInvisibles());
|
||||
}
|
||||
|
||||
std::string rawMemoryToString( const void *object, std::size_t size ) {
|
||||
// Reverse order for little endian architectures
|
||||
int i = 0, end = static_cast<int>( size ), inc = 1;
|
||||
if( Endianness::which() == Endianness::Little ) {
|
||||
i = end-1;
|
||||
end = inc = -1;
|
||||
}
|
||||
|
||||
unsigned char const *bytes = static_cast<unsigned char const *>(object);
|
||||
ReusableStringStream rss;
|
||||
rss << "0x" << std::setfill('0') << std::hex;
|
||||
for( ; i != end; i += inc )
|
||||
rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
std::string makeExceptionHappenedString() {
|
||||
return "{ stringification failed with an exception: \"" +
|
||||
translateActiveException() + "\" }";
|
||||
|
||||
}
|
||||
|
||||
} // end Detail namespace
|
||||
|
||||
|
||||
|
||||
//// ======================================================= ////
|
||||
//
|
||||
// Out-of-line defs for full specialization of StringMaker
|
||||
//
|
||||
//// ======================================================= ////
|
||||
|
||||
std::string StringMaker<std::string>::convert(const std::string& str) {
|
||||
return Detail::convertIntoString( str );
|
||||
}
|
||||
|
||||
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||
std::string StringMaker<std::string_view>::convert(std::string_view str) {
|
||||
return Detail::convertIntoString( StringRef( str.data(), str.size() ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string StringMaker<char const*>::convert(char const* str) {
|
||||
if (str) {
|
||||
return Detail::convertIntoString( str );
|
||||
} else {
|
||||
return{ "{null string}" };
|
||||
}
|
||||
}
|
||||
std::string StringMaker<char*>::convert(char* str) { // NOLINT(readability-non-const-parameter)
|
||||
if (str) {
|
||||
return Detail::convertIntoString( str );
|
||||
} else {
|
||||
return{ "{null string}" };
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CATCH_CONFIG_WCHAR
|
||||
std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
|
||||
std::string s;
|
||||
s.reserve(wstr.size());
|
||||
for (auto c : wstr) {
|
||||
s += (c <= 0xff) ? static_cast<char>(c) : '?';
|
||||
}
|
||||
return ::Catch::Detail::stringify(s);
|
||||
}
|
||||
|
||||
# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||
std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
|
||||
return StringMaker<std::wstring>::convert(std::wstring(str));
|
||||
}
|
||||
# endif
|
||||
|
||||
std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
|
||||
if (str) {
|
||||
return ::Catch::Detail::stringify(std::wstring{ str });
|
||||
} else {
|
||||
return{ "{null string}" };
|
||||
}
|
||||
}
|
||||
std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
|
||||
if (str) {
|
||||
return ::Catch::Detail::stringify(std::wstring{ str });
|
||||
} else {
|
||||
return{ "{null string}" };
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP17_BYTE)
|
||||
#include <cstddef>
|
||||
std::string StringMaker<std::byte>::convert(std::byte value) {
|
||||
return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
|
||||
}
|
||||
#endif // defined(CATCH_CONFIG_CPP17_BYTE)
|
||||
|
||||
std::string StringMaker<int>::convert(int value) {
|
||||
return ::Catch::Detail::stringify(static_cast<long long>(value));
|
||||
}
|
||||
std::string StringMaker<long>::convert(long value) {
|
||||
return ::Catch::Detail::stringify(static_cast<long long>(value));
|
||||
}
|
||||
std::string StringMaker<long long>::convert(long long value) {
|
||||
ReusableStringStream rss;
|
||||
rss << value;
|
||||
if (value > Detail::hexThreshold) {
|
||||
rss << " (0x" << std::hex << value << ')';
|
||||
}
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
std::string StringMaker<unsigned int>::convert(unsigned int value) {
|
||||
return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
|
||||
}
|
||||
std::string StringMaker<unsigned long>::convert(unsigned long value) {
|
||||
return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
|
||||
}
|
||||
std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
|
||||
ReusableStringStream rss;
|
||||
rss << value;
|
||||
if (value > Detail::hexThreshold) {
|
||||
rss << " (0x" << std::hex << value << ')';
|
||||
}
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
std::string StringMaker<signed char>::convert(signed char value) {
|
||||
if (value == '\r') {
|
||||
return "'\\r'";
|
||||
} else if (value == '\f') {
|
||||
return "'\\f'";
|
||||
} else if (value == '\n') {
|
||||
return "'\\n'";
|
||||
} else if (value == '\t') {
|
||||
return "'\\t'";
|
||||
} else if ('\0' <= value && value < ' ') {
|
||||
return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
|
||||
} else {
|
||||
char chstr[] = "' '";
|
||||
chstr[1] = value;
|
||||
return chstr;
|
||||
}
|
||||
}
|
||||
std::string StringMaker<char>::convert(char c) {
|
||||
return ::Catch::Detail::stringify(static_cast<signed char>(c));
|
||||
}
|
||||
std::string StringMaker<unsigned char>::convert(unsigned char value) {
|
||||
return ::Catch::Detail::stringify(static_cast<char>(value));
|
||||
}
|
||||
|
||||
int StringMaker<float>::precision = std::numeric_limits<float>::max_digits10;
|
||||
|
||||
std::string StringMaker<float>::convert(float value) {
|
||||
return Detail::fpToString(value, precision) + 'f';
|
||||
}
|
||||
|
||||
int StringMaker<double>::precision = std::numeric_limits<double>::max_digits10;
|
||||
|
||||
std::string StringMaker<double>::convert(double value) {
|
||||
return Detail::fpToString(value, precision);
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
651
tests/catch2/src/catch2/catch_tostring.hpp
Normal file
651
tests/catch2/src/catch2/catch_tostring.hpp
Normal file
|
|
@ -0,0 +1,651 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TOSTRING_HPP_INCLUDED
|
||||
#define CATCH_TOSTRING_HPP_INCLUDED
|
||||
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_config_wchar.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_void_type.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp>
|
||||
|
||||
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
|
||||
#endif
|
||||
|
||||
// We need a dummy global operator<< so we can bring it into Catch namespace later
|
||||
struct Catch_global_namespace_dummy{};
|
||||
std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
|
||||
|
||||
namespace Catch {
|
||||
// Bring in global namespace operator<< for ADL lookup in
|
||||
// `IsStreamInsertable` below.
|
||||
using ::operator<<;
|
||||
|
||||
namespace Detail {
|
||||
|
||||
std::size_t catch_strnlen(const char *str, std::size_t n);
|
||||
|
||||
std::string formatTimeT( std::time_t time );
|
||||
|
||||
constexpr StringRef unprintableString = "{?}"_sr;
|
||||
|
||||
//! Encases `string in quotes, and optionally escapes invisibles
|
||||
std::string convertIntoString( StringRef string, bool escapeInvisibles );
|
||||
|
||||
//! Encases `string` in quotes, and escapes invisibles if user requested
|
||||
//! it via CLI
|
||||
std::string convertIntoString( StringRef string );
|
||||
|
||||
std::string rawMemoryToString( const void *object, std::size_t size );
|
||||
|
||||
template<typename T>
|
||||
std::string rawMemoryToString( const T& object ) {
|
||||
return rawMemoryToString( &object, sizeof(object) );
|
||||
}
|
||||
|
||||
template<typename T,typename = void>
|
||||
static constexpr bool IsStreamInsertable_v = false;
|
||||
|
||||
template <typename T>
|
||||
static constexpr bool IsStreamInsertable_v<
|
||||
T,
|
||||
decltype( void( std::declval<std::ostream&>() << std::declval<T>() ) )> =
|
||||
true;
|
||||
|
||||
template<typename E>
|
||||
std::string convertUnknownEnumToString( E e );
|
||||
|
||||
template<typename T>
|
||||
std::enable_if_t<
|
||||
!std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
|
||||
std::string> convertUnstreamable( T const& ) {
|
||||
return std::string(Detail::unprintableString);
|
||||
}
|
||||
template<typename T>
|
||||
std::enable_if_t<
|
||||
!std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
|
||||
std::string> convertUnstreamable(T const& ex) {
|
||||
return ex.what();
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
std::enable_if_t<
|
||||
std::is_enum<T>::value,
|
||||
std::string> convertUnstreamable( T const& value ) {
|
||||
return convertUnknownEnumToString( value );
|
||||
}
|
||||
|
||||
#if defined(_MANAGED)
|
||||
//! Convert a CLR string to a utf8 std::string
|
||||
template<typename T>
|
||||
std::string clrReferenceToString( T^ ref ) {
|
||||
if (ref == nullptr)
|
||||
return std::string("null");
|
||||
auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
|
||||
cli::pin_ptr<System::Byte> p = &bytes[0];
|
||||
return std::string(reinterpret_cast<char const *>(p), bytes->Length);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct StringMaker {
|
||||
template <typename Fake = T>
|
||||
static
|
||||
std::enable_if_t<::Catch::Detail::IsStreamInsertable_v<Fake>, std::string>
|
||||
convert(const Fake& value) {
|
||||
ReusableStringStream rss;
|
||||
// NB: call using the function-like syntax to avoid ambiguity with
|
||||
// user-defined templated operator<< under clang.
|
||||
rss.operator<<(value);
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
template <typename Fake = T>
|
||||
static
|
||||
std::enable_if_t<!::Catch::Detail::IsStreamInsertable_v<Fake>, std::string>
|
||||
convert( const Fake& value ) {
|
||||
#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
|
||||
return Detail::convertUnstreamable(value);
|
||||
#else
|
||||
return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
namespace Detail {
|
||||
|
||||
std::string makeExceptionHappenedString();
|
||||
|
||||
// This function dispatches all stringification requests inside of Catch.
|
||||
// Should be preferably called fully qualified, like ::Catch::Detail::stringify
|
||||
template <typename T>
|
||||
std::string stringify( const T& e ) {
|
||||
CATCH_TRY {
|
||||
return ::Catch::StringMaker<
|
||||
std::remove_cv_t<std::remove_reference_t<T>>>::convert( e );
|
||||
}
|
||||
CATCH_CATCH_ALL { return makeExceptionHappenedString(); }
|
||||
}
|
||||
|
||||
template<typename E>
|
||||
std::string convertUnknownEnumToString( E e ) {
|
||||
return ::Catch::Detail::stringify(static_cast<std::underlying_type_t<E>>(e));
|
||||
}
|
||||
|
||||
#if defined(_MANAGED)
|
||||
template <typename T>
|
||||
std::string stringify( T^ e ) {
|
||||
return ::Catch::StringMaker<T^>::convert(e);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
// Some predefined specializations
|
||||
|
||||
template<>
|
||||
struct StringMaker<std::string> {
|
||||
static std::string convert(const std::string& str);
|
||||
};
|
||||
|
||||
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||
template<>
|
||||
struct StringMaker<std::string_view> {
|
||||
static std::string convert(std::string_view str);
|
||||
};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct StringMaker<char const *> {
|
||||
static std::string convert(char const * str);
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<char *> {
|
||||
static std::string convert(char * str);
|
||||
};
|
||||
|
||||
#if defined(CATCH_CONFIG_WCHAR)
|
||||
template<>
|
||||
struct StringMaker<std::wstring> {
|
||||
static std::string convert(const std::wstring& wstr);
|
||||
};
|
||||
|
||||
# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||
template<>
|
||||
struct StringMaker<std::wstring_view> {
|
||||
static std::string convert(std::wstring_view str);
|
||||
};
|
||||
# endif
|
||||
|
||||
template<>
|
||||
struct StringMaker<wchar_t const *> {
|
||||
static std::string convert(wchar_t const * str);
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<wchar_t *> {
|
||||
static std::string convert(wchar_t * str);
|
||||
};
|
||||
#endif // CATCH_CONFIG_WCHAR
|
||||
|
||||
template<size_t SZ>
|
||||
struct StringMaker<char[SZ]> {
|
||||
static std::string convert(char const* str) {
|
||||
return Detail::convertIntoString(
|
||||
StringRef( str, Detail::catch_strnlen( str, SZ ) ) );
|
||||
}
|
||||
};
|
||||
template<size_t SZ>
|
||||
struct StringMaker<signed char[SZ]> {
|
||||
static std::string convert(signed char const* str) {
|
||||
auto reinterpreted = reinterpret_cast<char const*>(str);
|
||||
return Detail::convertIntoString(
|
||||
StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
|
||||
}
|
||||
};
|
||||
template<size_t SZ>
|
||||
struct StringMaker<unsigned char[SZ]> {
|
||||
static std::string convert(unsigned char const* str) {
|
||||
auto reinterpreted = reinterpret_cast<char const*>(str);
|
||||
return Detail::convertIntoString(
|
||||
StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP17_BYTE)
|
||||
template<>
|
||||
struct StringMaker<std::byte> {
|
||||
static std::string convert(std::byte value);
|
||||
};
|
||||
#endif // defined(CATCH_CONFIG_CPP17_BYTE)
|
||||
template<>
|
||||
struct StringMaker<int> {
|
||||
static std::string convert(int value);
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<long> {
|
||||
static std::string convert(long value);
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<long long> {
|
||||
static std::string convert(long long value);
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<unsigned int> {
|
||||
static std::string convert(unsigned int value);
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<unsigned long> {
|
||||
static std::string convert(unsigned long value);
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<unsigned long long> {
|
||||
static std::string convert(unsigned long long value);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct StringMaker<bool> {
|
||||
static std::string convert(bool b) {
|
||||
using namespace std::string_literals;
|
||||
return b ? "true"s : "false"s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct StringMaker<char> {
|
||||
static std::string convert(char c);
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<signed char> {
|
||||
static std::string convert(signed char value);
|
||||
};
|
||||
template<>
|
||||
struct StringMaker<unsigned char> {
|
||||
static std::string convert(unsigned char value);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct StringMaker<std::nullptr_t> {
|
||||
static std::string convert(std::nullptr_t) {
|
||||
using namespace std::string_literals;
|
||||
return "nullptr"s;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct StringMaker<float> {
|
||||
static std::string convert(float value);
|
||||
CATCH_EXPORT static int precision;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct StringMaker<double> {
|
||||
static std::string convert(double value);
|
||||
CATCH_EXPORT static int precision;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct StringMaker<T*> {
|
||||
template <typename U>
|
||||
static std::string convert(U* p) {
|
||||
if (p) {
|
||||
return ::Catch::Detail::rawMemoryToString(p);
|
||||
} else {
|
||||
return "nullptr";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename C>
|
||||
struct StringMaker<R C::*> {
|
||||
static std::string convert(R C::* p) {
|
||||
if (p) {
|
||||
return ::Catch::Detail::rawMemoryToString(p);
|
||||
} else {
|
||||
return "nullptr";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(_MANAGED)
|
||||
template <typename T>
|
||||
struct StringMaker<T^> {
|
||||
static std::string convert( T^ ref ) {
|
||||
return ::Catch::Detail::clrReferenceToString(ref);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace Detail {
|
||||
template<typename InputIterator, typename Sentinel = InputIterator>
|
||||
std::string rangeToString(InputIterator first, Sentinel last) {
|
||||
ReusableStringStream rss;
|
||||
rss << "{ ";
|
||||
if (first != last) {
|
||||
rss << ::Catch::Detail::stringify(*first);
|
||||
for (++first; first != last; ++first)
|
||||
rss << ", " << ::Catch::Detail::stringify(*first);
|
||||
}
|
||||
rss << " }";
|
||||
return rss.str();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Separate std-lib types stringification, so it can be selectively enabled
|
||||
// This means that we do not bring in their headers
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
|
||||
# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||
#endif
|
||||
|
||||
// Separate std::pair specialization
|
||||
#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
|
||||
#include <utility>
|
||||
namespace Catch {
|
||||
template<typename T1, typename T2>
|
||||
struct StringMaker<std::pair<T1, T2> > {
|
||||
static std::string convert(const std::pair<T1, T2>& pair) {
|
||||
ReusableStringStream rss;
|
||||
rss << "{ "
|
||||
<< ::Catch::Detail::stringify(pair.first)
|
||||
<< ", "
|
||||
<< ::Catch::Detail::stringify(pair.second)
|
||||
<< " }";
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
|
||||
#include <optional>
|
||||
namespace Catch {
|
||||
template<typename T>
|
||||
struct StringMaker<std::optional<T> > {
|
||||
static std::string convert(const std::optional<T>& optional) {
|
||||
if (optional.has_value()) {
|
||||
return ::Catch::Detail::stringify(*optional);
|
||||
} else {
|
||||
return "{ }";
|
||||
}
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct StringMaker<std::nullopt_t> {
|
||||
static std::string convert(const std::nullopt_t&) {
|
||||
return "{ }";
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||
|
||||
// Separate std::tuple specialization
|
||||
#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
|
||||
# include <tuple>
|
||||
# include <utility>
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
template <typename Tuple, std::size_t... Is>
|
||||
void PrintTuple( const Tuple& tuple,
|
||||
std::ostream& os,
|
||||
std::index_sequence<Is...> ) {
|
||||
// 1 + Account for when the tuple is empty
|
||||
char a[1 + sizeof...( Is )] = {
|
||||
( ( os << ( Is ? ", " : " " )
|
||||
<< ::Catch::Detail::stringify( std::get<Is>( tuple ) ) ),
|
||||
'\0' )... };
|
||||
(void)a;
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
template <typename... Types>
|
||||
struct StringMaker<std::tuple<Types...>> {
|
||||
static std::string convert( const std::tuple<Types...>& tuple ) {
|
||||
ReusableStringStream rss;
|
||||
rss << '{';
|
||||
Detail::PrintTuple(
|
||||
tuple,
|
||||
rss.get(),
|
||||
std::make_index_sequence<sizeof...( Types )>{} );
|
||||
rss << " }";
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
} // namespace Catch
|
||||
#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
|
||||
#include <variant>
|
||||
namespace Catch {
|
||||
template<>
|
||||
struct StringMaker<std::monostate> {
|
||||
static std::string convert(const std::monostate&) {
|
||||
return "{ }";
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Elements>
|
||||
struct StringMaker<std::variant<Elements...>> {
|
||||
static std::string convert(const std::variant<Elements...>& variant) {
|
||||
if (variant.valueless_by_exception()) {
|
||||
return "{valueless variant}";
|
||||
} else {
|
||||
return std::visit(
|
||||
[](const auto& value) {
|
||||
return ::Catch::Detail::stringify(value);
|
||||
},
|
||||
variant
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||
|
||||
namespace Catch {
|
||||
// Import begin/ end from std here
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
namespace Detail {
|
||||
template <typename T, typename = void>
|
||||
struct is_range_impl : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_range_impl<T, void_t<decltype(begin(std::declval<T>()))>> : std::true_type {};
|
||||
} // namespace Detail
|
||||
|
||||
template <typename T>
|
||||
struct is_range : Detail::is_range_impl<T> {};
|
||||
|
||||
#if defined(_MANAGED) // Managed types are never ranges
|
||||
template <typename T>
|
||||
struct is_range<T^> {
|
||||
static const bool value = false;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename Range>
|
||||
std::string rangeToString( Range const& range ) {
|
||||
return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
|
||||
}
|
||||
|
||||
// Handle vector<bool> specially
|
||||
template<typename Allocator>
|
||||
std::string rangeToString( std::vector<bool, Allocator> const& v ) {
|
||||
ReusableStringStream rss;
|
||||
rss << "{ ";
|
||||
bool first = true;
|
||||
for( bool b : v ) {
|
||||
if( first )
|
||||
first = false;
|
||||
else
|
||||
rss << ", ";
|
||||
rss << ::Catch::Detail::stringify( b );
|
||||
}
|
||||
rss << " }";
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
struct StringMaker<R, std::enable_if_t<is_range<R>::value && !::Catch::Detail::IsStreamInsertable_v<R>>> {
|
||||
static std::string convert( R const& range ) {
|
||||
return rangeToString( range );
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, size_t SZ>
|
||||
struct StringMaker<T[SZ]> {
|
||||
static std::string convert(T const(&arr)[SZ]) {
|
||||
return rangeToString(arr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
// Separate std::chrono::duration specialization
|
||||
#include <ctime>
|
||||
#include <ratio>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
template <class Ratio>
|
||||
struct ratio_string {
|
||||
static std::string symbol() {
|
||||
Catch::ReusableStringStream rss;
|
||||
rss << '[' << Ratio::num << '/'
|
||||
<< Ratio::den << ']';
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ratio_string<std::atto> {
|
||||
static char symbol() { return 'a'; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::femto> {
|
||||
static char symbol() { return 'f'; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::pico> {
|
||||
static char symbol() { return 'p'; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::nano> {
|
||||
static char symbol() { return 'n'; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::micro> {
|
||||
static char symbol() { return 'u'; }
|
||||
};
|
||||
template <>
|
||||
struct ratio_string<std::milli> {
|
||||
static char symbol() { return 'm'; }
|
||||
};
|
||||
|
||||
////////////
|
||||
// std::chrono::duration specializations
|
||||
template<typename Value, typename Ratio>
|
||||
struct StringMaker<std::chrono::duration<Value, Ratio>> {
|
||||
static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
|
||||
ReusableStringStream rss;
|
||||
rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
template<typename Value>
|
||||
struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
|
||||
static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
|
||||
ReusableStringStream rss;
|
||||
rss << duration.count() << " s";
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
template<typename Value>
|
||||
struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
|
||||
static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
|
||||
ReusableStringStream rss;
|
||||
rss << duration.count() << " m";
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
template<typename Value>
|
||||
struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
|
||||
static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
|
||||
ReusableStringStream rss;
|
||||
rss << duration.count() << " h";
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
|
||||
////////////
|
||||
// std::chrono::time_point specialization
|
||||
// Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
|
||||
template<typename Clock, typename Duration>
|
||||
struct StringMaker<std::chrono::time_point<Clock, Duration>> {
|
||||
static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
|
||||
return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
|
||||
}
|
||||
};
|
||||
// std::chrono::time_point<system_clock> specialization
|
||||
template<typename Duration>
|
||||
struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||
static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
|
||||
const auto systemish = std::chrono::time_point_cast<
|
||||
std::chrono::system_clock::duration>( time_point );
|
||||
const auto as_time_t = std::chrono::system_clock::to_time_t( systemish );
|
||||
return ::Catch::Detail::formatTimeT( as_time_t );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
|
||||
#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
|
||||
namespace Catch { \
|
||||
template<> struct StringMaker<enumName> { \
|
||||
static std::string convert( enumName value ) { \
|
||||
static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
|
||||
return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // CATCH_TOSTRING_HPP_INCLUDED
|
||||
65
tests/catch2/src/catch2/catch_totals.cpp
Normal file
65
tests/catch2/src/catch2/catch_totals.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_totals.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Counts Counts::operator - ( Counts const& other ) const {
|
||||
Counts diff;
|
||||
diff.passed = passed - other.passed;
|
||||
diff.failed = failed - other.failed;
|
||||
diff.failedButOk = failedButOk - other.failedButOk;
|
||||
diff.skipped = skipped - other.skipped;
|
||||
return diff;
|
||||
}
|
||||
|
||||
Counts& Counts::operator += ( Counts const& other ) {
|
||||
passed += other.passed;
|
||||
failed += other.failed;
|
||||
failedButOk += other.failedButOk;
|
||||
skipped += other.skipped;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::uint64_t Counts::total() const {
|
||||
return passed + failed + failedButOk + skipped;
|
||||
}
|
||||
bool Counts::allPassed() const {
|
||||
return failed == 0 && failedButOk == 0 && skipped == 0;
|
||||
}
|
||||
bool Counts::allOk() const {
|
||||
return failed == 0;
|
||||
}
|
||||
|
||||
Totals Totals::operator - ( Totals const& other ) const {
|
||||
Totals diff;
|
||||
diff.assertions = assertions - other.assertions;
|
||||
diff.testCases = testCases - other.testCases;
|
||||
return diff;
|
||||
}
|
||||
|
||||
Totals& Totals::operator += ( Totals const& other ) {
|
||||
assertions += other.assertions;
|
||||
testCases += other.testCases;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Totals Totals::delta( Totals const& prevTotals ) const {
|
||||
Totals diff = *this - prevTotals;
|
||||
if( diff.assertions.failed > 0 )
|
||||
++diff.testCases.failed;
|
||||
else if( diff.assertions.failedButOk > 0 )
|
||||
++diff.testCases.failedButOk;
|
||||
else if ( diff.assertions.skipped > 0 )
|
||||
++ diff.testCases.skipped;
|
||||
else
|
||||
++diff.testCases.passed;
|
||||
return diff;
|
||||
}
|
||||
|
||||
}
|
||||
41
tests/catch2/src/catch2/catch_totals.hpp
Normal file
41
tests/catch2/src/catch2/catch_totals.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TOTALS_HPP_INCLUDED
|
||||
#define CATCH_TOTALS_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct Counts {
|
||||
Counts operator - ( Counts const& other ) const;
|
||||
Counts& operator += ( Counts const& other );
|
||||
|
||||
std::uint64_t total() const;
|
||||
bool allPassed() const;
|
||||
bool allOk() const;
|
||||
|
||||
std::uint64_t passed = 0;
|
||||
std::uint64_t failed = 0;
|
||||
std::uint64_t failedButOk = 0;
|
||||
std::uint64_t skipped = 0;
|
||||
};
|
||||
|
||||
struct Totals {
|
||||
|
||||
Totals operator - ( Totals const& other ) const;
|
||||
Totals& operator += ( Totals const& other );
|
||||
|
||||
Totals delta( Totals const& prevTotals ) const;
|
||||
|
||||
Counts assertions;
|
||||
Counts testCases;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CATCH_TOTALS_HPP_INCLUDED
|
||||
20
tests/catch2/src/catch2/catch_translate_exception.cpp
Normal file
20
tests/catch2/src/catch2/catch_translate_exception.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_translate_exception.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
void registerTranslatorImpl(
|
||||
Detail::unique_ptr<IExceptionTranslator>&& translator ) {
|
||||
getMutableRegistryHub().registerTranslator(
|
||||
CATCH_MOVE( translator ) );
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Catch
|
||||
88
tests/catch2/src/catch2/catch_translate_exception.hpp
Normal file
88
tests/catch2/src/catch2/catch_translate_exception.hpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
|
||||
#define CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_exception.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
void registerTranslatorImpl(
|
||||
Detail::unique_ptr<IExceptionTranslator>&& translator );
|
||||
}
|
||||
|
||||
class ExceptionTranslatorRegistrar {
|
||||
template<typename T>
|
||||
class ExceptionTranslator : public IExceptionTranslator {
|
||||
public:
|
||||
|
||||
constexpr ExceptionTranslator( std::string(*translateFunction)( T const& ) )
|
||||
: m_translateFunction( translateFunction )
|
||||
{}
|
||||
|
||||
std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
try {
|
||||
if( it == itEnd )
|
||||
std::rethrow_exception(std::current_exception());
|
||||
else
|
||||
return (*it)->translate( it+1, itEnd );
|
||||
}
|
||||
catch( T const& ex ) {
|
||||
return m_translateFunction( ex );
|
||||
}
|
||||
#else
|
||||
return "You should never get here!";
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string(*m_translateFunction)( T const& );
|
||||
};
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) {
|
||||
Detail::registerTranslatorImpl(
|
||||
Detail::make_unique<ExceptionTranslator<T>>(
|
||||
translateFunction ) );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
|
||||
static std::string translatorName( signature ); \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ const Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
static std::string translatorName( signature )
|
||||
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
||||
|
||||
#if defined(CATCH_CONFIG_DISABLE)
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
|
||||
static std::string translatorName( signature )
|
||||
#endif
|
||||
|
||||
|
||||
// This macro is always prefixed
|
||||
#if !defined(CATCH_CONFIG_DISABLE)
|
||||
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
|
||||
#else
|
||||
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
||||
#endif
|
||||
|
||||
|
||||
#endif // CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
|
||||
247
tests/catch2/src/catch2/catch_user_config.hpp.in
Normal file
247
tests/catch2/src/catch2/catch_user_config.hpp.in
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
/**\file
|
||||
* **AUTOGENERATED FROM CMAKE CONFIGURATION**
|
||||
*
|
||||
* Contains materialized compile-time configuration provided to Catch2's
|
||||
* CMake configuration. All compile-time configuration options need to
|
||||
* be here, and also documented in `docs/configuration.md`.
|
||||
*/
|
||||
|
||||
#ifndef CATCH_USER_CONFIG_HPP_INCLUDED
|
||||
#define CATCH_USER_CONFIG_HPP_INCLUDED
|
||||
|
||||
|
||||
// ------
|
||||
// Overridable compilation flags,
|
||||
// these can have 3 "states": Force Yes, Force No, Use Default.
|
||||
// Setting both Force Yes and Force No is an error
|
||||
// ------
|
||||
|
||||
#cmakedefine CATCH_CONFIG_ANDROID_LOGWRITE
|
||||
#cmakedefine CATCH_CONFIG_NO_ANDROID_LOGWRITE
|
||||
|
||||
#if defined( CATCH_CONFIG_ANDROID_LOGWRITE ) && \
|
||||
defined( CATCH_CONFIG_NO_ANDROID_LOGWRITE )
|
||||
# error Cannot force ANDROID_LOGWRITE to both ON and OFF
|
||||
#endif
|
||||
|
||||
#cmakedefine CATCH_CONFIG_COLOUR_WIN32
|
||||
#cmakedefine CATCH_CONFIG_NO_COLOUR_WIN32
|
||||
|
||||
#if defined( CATCH_CONFIG_COLOUR_WIN32 ) && \
|
||||
defined( CATCH_CONFIG_NO_COLOUR_WIN32 )
|
||||
# error Cannot force COLOUR_WIN32 to be ON and OFF
|
||||
#endif
|
||||
|
||||
#cmakedefine CATCH_CONFIG_COUNTER
|
||||
#cmakedefine CATCH_CONFIG_NO_COUNTER
|
||||
|
||||
#if defined( CATCH_CONFIG_COUNTER ) && \
|
||||
defined( CATCH_CONFIG_NO_COUNTER )
|
||||
# error Cannot force COUNTER to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_CPP11_TO_STRING
|
||||
#cmakedefine CATCH_CONFIG_NO_CPP11_TO_STRING
|
||||
|
||||
#if defined( CATCH_CONFIG_CPP11_TO_STRING ) && \
|
||||
defined( CATCH_CONFIG_NO_CPP11_TO_STRING )
|
||||
# error Cannot force CPP11_TO_STRING to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_CPP17_BYTE
|
||||
#cmakedefine CATCH_CONFIG_NO_CPP17_BYTE
|
||||
|
||||
#if defined( CATCH_CONFIG_CPP17_BYTE ) && \
|
||||
defined( CATCH_CONFIG_NO_CPP17_BYTE )
|
||||
# error Cannot force CPP17_BYTE to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_CPP17_OPTIONAL
|
||||
#cmakedefine CATCH_CONFIG_NO_CPP17_OPTIONAL
|
||||
|
||||
#if defined( CATCH_CONFIG_CPP17_OPTIONAL ) && \
|
||||
defined( CATCH_CONFIG_NO_CPP17_OPTIONAL )
|
||||
# error Cannot force CPP17_OPTIONAL to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_CPP17_STRING_VIEW
|
||||
#cmakedefine CATCH_CONFIG_NO_CPP17_STRING_VIEW
|
||||
|
||||
#if defined( CATCH_CONFIG_CPP17_STRING_VIEW ) && \
|
||||
defined( CATCH_CONFIG_NO_CPP17_STRING_VIEW )
|
||||
# error Cannot force CPP17_STRING_VIEW to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
#cmakedefine CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
|
||||
#if defined( CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS ) && \
|
||||
defined( CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS )
|
||||
# error Cannot force CPP17_UNCAUGHT_EXCEPTIONS to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_CPP17_VARIANT
|
||||
#cmakedefine CATCH_CONFIG_NO_CPP17_VARIANT
|
||||
|
||||
#if defined( CATCH_CONFIG_CPP17_VARIANT ) && \
|
||||
defined( CATCH_CONFIG_NO_CPP17_VARIANT )
|
||||
# error Cannot force CPP17_VARIANT to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_GLOBAL_NEXTAFTER
|
||||
#cmakedefine CATCH_CONFIG_NO_GLOBAL_NEXTAFTER
|
||||
|
||||
#if defined( CATCH_CONFIG_GLOBAL_NEXTAFTER ) && \
|
||||
defined( CATCH_CONFIG_NO_GLOBAL_NEXTAFTER )
|
||||
# error Cannot force GLOBAL_NEXTAFTER to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_POSIX_SIGNALS
|
||||
#cmakedefine CATCH_CONFIG_NO_POSIX_SIGNALS
|
||||
|
||||
#if defined( CATCH_CONFIG_POSIX_SIGNALS ) && \
|
||||
defined( CATCH_CONFIG_NO_POSIX_SIGNALS )
|
||||
# error Cannot force POSIX_SIGNALS to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_GETENV
|
||||
#cmakedefine CATCH_CONFIG_NO_GETENV
|
||||
|
||||
#if defined( CATCH_CONFIG_GETENV ) && \
|
||||
defined( CATCH_CONFIG_NO_GETENV )
|
||||
# error Cannot force GETENV to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_USE_ASYNC
|
||||
#cmakedefine CATCH_CONFIG_NO_USE_ASYNC
|
||||
|
||||
#if defined( CATCH_CONFIG_USE_ASYNC ) && \
|
||||
defined( CATCH_CONFIG_NO_USE_ASYNC )
|
||||
# error Cannot force USE_ASYNC to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_WCHAR
|
||||
#cmakedefine CATCH_CONFIG_NO_WCHAR
|
||||
|
||||
#if defined( CATCH_CONFIG_WCHAR ) && \
|
||||
defined( CATCH_CONFIG_NO_WCHAR )
|
||||
# error Cannot force WCHAR to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_WINDOWS_SEH
|
||||
#cmakedefine CATCH_CONFIG_NO_WINDOWS_SEH
|
||||
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH ) && \
|
||||
defined( CATCH_CONFIG_NO_WINDOWS_SEH )
|
||||
# error Cannot force WINDOWS_SEH to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
|
||||
#cmakedefine CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
|
||||
|
||||
#if defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \
|
||||
defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT )
|
||||
# error Cannot force STATIC_ANALYSIS_SUPPORT to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_USE_BUILTIN_CONSTANT_P
|
||||
#cmakedefine CATCH_CONFIG_NO_USE_BUILTIN_CONSTANT_P
|
||||
|
||||
#if defined( CATCH_CONFIG_USE_BUILTIN_CONSTANT_P ) && \
|
||||
defined( CATCH_CONFIG_NO_USE_BUILTIN_CONSTANT_P )
|
||||
# error Cannot force USE_BUILTIN_CONSTANT_P to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_DEPRECATION_ANNOTATIONS
|
||||
#cmakedefine CATCH_CONFIG_NO_DEPRECATION_ANNOTATIONS
|
||||
|
||||
#if defined( CATCH_CONFIG_DEPRECATION_ANNOTATIONS ) && \
|
||||
defined( CATCH_CONFIG_NO_DEPRECATION_ANNOTATIONS )
|
||||
# error Cannot force DEPRECATION_ANNOTATIONS to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS
|
||||
#cmakedefine CATCH_CONFIG_NO_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS
|
||||
|
||||
#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS ) && \
|
||||
defined( CATCH_CONFIG_NO_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS )
|
||||
# error Cannot force EXPERIMENTAL_THREAD_SAFE_ASSERTIONS to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
// ------
|
||||
// Simple toggle defines
|
||||
// their value is never used and they cannot be overridden
|
||||
// ------
|
||||
|
||||
|
||||
#cmakedefine CATCH_CONFIG_BAZEL_SUPPORT
|
||||
#cmakedefine CATCH_CONFIG_DISABLE_EXCEPTIONS
|
||||
#cmakedefine CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER
|
||||
#cmakedefine CATCH_CONFIG_DISABLE
|
||||
#cmakedefine CATCH_CONFIG_DISABLE_STRINGIFICATION
|
||||
#cmakedefine CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS
|
||||
#cmakedefine CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||
#cmakedefine CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||
#cmakedefine CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||
#cmakedefine CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||
#cmakedefine CATCH_CONFIG_EXPERIMENTAL_REDIRECT
|
||||
#cmakedefine CATCH_CONFIG_FAST_COMPILE
|
||||
#cmakedefine CATCH_CONFIG_NOSTDOUT
|
||||
#cmakedefine CATCH_CONFIG_PREFIX_ALL
|
||||
#cmakedefine CATCH_CONFIG_PREFIX_MESSAGES
|
||||
#cmakedefine CATCH_CONFIG_WINDOWS_CRTDBG
|
||||
|
||||
#cmakedefine CATCH_CONFIG_SHARED_LIBRARY
|
||||
|
||||
|
||||
// ------
|
||||
// "Variable" defines, these have actual values
|
||||
// ------
|
||||
|
||||
#define CATCH_CONFIG_DEFAULT_REPORTER "@CATCH_CONFIG_DEFAULT_REPORTER@"
|
||||
#define CATCH_CONFIG_CONSOLE_WIDTH @CATCH_CONFIG_CONSOLE_WIDTH@
|
||||
|
||||
// Unlike the macros above, CATCH_CONFIG_FALLBACK_STRINGIFIER does not
|
||||
// have a good default value, so we cannot always define it, and cannot
|
||||
// even expose it as a variable in CMake. The users will have to find
|
||||
// out about it from docs and set it only if they use it.
|
||||
#cmakedefine CATCH_CONFIG_FALLBACK_STRINGIFIER @CATCH_CONFIG_FALLBACK_STRINGIFIER@
|
||||
|
||||
#endif // CATCH_USER_CONFIG_HPP_INCLUDED
|
||||
43
tests/catch2/src/catch2/catch_version.cpp
Normal file
43
tests/catch2/src/catch2/catch_version.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_version.hpp>
|
||||
#include <ostream>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Version::Version
|
||||
( unsigned int _majorVersion,
|
||||
unsigned int _minorVersion,
|
||||
unsigned int _patchNumber,
|
||||
char const * const _branchName,
|
||||
unsigned int _buildNumber )
|
||||
: majorVersion( _majorVersion ),
|
||||
minorVersion( _minorVersion ),
|
||||
patchNumber( _patchNumber ),
|
||||
branchName( _branchName ),
|
||||
buildNumber( _buildNumber )
|
||||
{}
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, Version const& version ) {
|
||||
os << version.majorVersion << '.'
|
||||
<< version.minorVersion << '.'
|
||||
<< version.patchNumber;
|
||||
// branchName is never null -> 0th char is \0 if it is empty
|
||||
if (version.branchName[0]) {
|
||||
os << '-' << version.branchName
|
||||
<< '.' << version.buildNumber;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 3, 11, 0, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
}
|
||||
39
tests/catch2/src/catch2/catch_version.hpp
Normal file
39
tests/catch2/src/catch2/catch_version.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_VERSION_HPP_INCLUDED
|
||||
#define CATCH_VERSION_HPP_INCLUDED
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Versioning information
|
||||
struct Version {
|
||||
Version( Version const& ) = delete;
|
||||
Version& operator=( Version const& ) = delete;
|
||||
Version( unsigned int _majorVersion,
|
||||
unsigned int _minorVersion,
|
||||
unsigned int _patchNumber,
|
||||
char const * const _branchName,
|
||||
unsigned int _buildNumber );
|
||||
|
||||
unsigned int const majorVersion;
|
||||
unsigned int const minorVersion;
|
||||
unsigned int const patchNumber;
|
||||
|
||||
// buildNumber is only used if branchName is not null
|
||||
char const * const branchName;
|
||||
unsigned int const buildNumber;
|
||||
|
||||
friend std::ostream& operator << ( std::ostream& os, Version const& version );
|
||||
};
|
||||
|
||||
Version const& libraryVersion();
|
||||
}
|
||||
|
||||
#endif // CATCH_VERSION_HPP_INCLUDED
|
||||
15
tests/catch2/src/catch2/catch_version_macros.hpp
Normal file
15
tests/catch2/src/catch2/catch_version_macros.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 3
|
||||
#define CATCH_VERSION_MINOR 11
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
|
||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
const char* GeneratorException::what() const noexcept {
|
||||
return m_msg;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
|
||||
#define CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Exception type to be thrown when a Generator runs into an error,
|
||||
// e.g. it cannot initialize the first return value based on
|
||||
// runtime information
|
||||
class GeneratorException : public std::exception {
|
||||
const char* const m_msg = "";
|
||||
|
||||
public:
|
||||
GeneratorException(const char* msg):
|
||||
m_msg(msg)
|
||||
{}
|
||||
|
||||
const char* what() const noexcept final;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
|
||||
42
tests/catch2/src/catch2/generators/catch_generators.cpp
Normal file
42
tests/catch2/src/catch2/generators/catch_generators.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
IGeneratorTracker::~IGeneratorTracker() = default;
|
||||
|
||||
namespace Generators {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
[[noreturn]]
|
||||
void throw_generator_exception(char const* msg) {
|
||||
Catch::throw_exception(GeneratorException{ msg });
|
||||
}
|
||||
} // end namespace Detail
|
||||
|
||||
GeneratorUntypedBase::~GeneratorUntypedBase() = default;
|
||||
|
||||
IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) {
|
||||
return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
|
||||
}
|
||||
|
||||
IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
|
||||
SourceLineInfo lineInfo,
|
||||
GeneratorBasePtr&& generator ) {
|
||||
return getResultCapture().createGeneratorTracker(
|
||||
generatorName, lineInfo, CATCH_MOVE( generator ) );
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
244
tests/catch2/src/catch2/generators/catch_generators.hpp
Normal file
244
tests/catch2/src/catch2/generators/catch_generators.hpp
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_GENERATORS_HPP_INCLUDED
|
||||
#define CATCH_GENERATORS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace Generators {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
//! Throws GeneratorException with the provided message
|
||||
[[noreturn]]
|
||||
void throw_generator_exception(char const * msg);
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template<typename T>
|
||||
class IGenerator : public GeneratorUntypedBase {
|
||||
std::string stringifyImpl() const override {
|
||||
return ::Catch::Detail::stringify( get() );
|
||||
}
|
||||
|
||||
public:
|
||||
// Returns the current element of the generator
|
||||
//
|
||||
// \Precondition The generator is either freshly constructed,
|
||||
// or the last call to `next()` returned true
|
||||
virtual T const& get() const = 0;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using GeneratorPtr = Catch::Detail::unique_ptr<IGenerator<T>>;
|
||||
|
||||
template <typename T>
|
||||
class GeneratorWrapper final {
|
||||
GeneratorPtr<T> m_generator;
|
||||
public:
|
||||
//! Takes ownership of the passed pointer.
|
||||
GeneratorWrapper(IGenerator<T>* generator):
|
||||
m_generator(generator) {}
|
||||
GeneratorWrapper(GeneratorPtr<T> generator):
|
||||
m_generator(CATCH_MOVE(generator)) {}
|
||||
|
||||
T const& get() const {
|
||||
return m_generator->get();
|
||||
}
|
||||
bool next() {
|
||||
return m_generator->countedNext();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class SingleValueGenerator final : public IGenerator<T> {
|
||||
T m_value;
|
||||
public:
|
||||
SingleValueGenerator(T const& value) :
|
||||
m_value(value)
|
||||
{}
|
||||
SingleValueGenerator(T&& value):
|
||||
m_value(CATCH_MOVE(value))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_value;
|
||||
}
|
||||
bool next() override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class FixedValuesGenerator final : public IGenerator<T> {
|
||||
static_assert(!std::is_same<T, bool>::value,
|
||||
"FixedValuesGenerator does not support bools because of std::vector<bool>"
|
||||
"specialization, use SingleValue Generator instead.");
|
||||
std::vector<T> m_values;
|
||||
size_t m_idx = 0;
|
||||
public:
|
||||
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
|
||||
|
||||
T const& get() const override {
|
||||
return m_values[m_idx];
|
||||
}
|
||||
bool next() override {
|
||||
++m_idx;
|
||||
return m_idx < m_values.size();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename DecayedT = std::decay_t<T>>
|
||||
GeneratorWrapper<DecayedT> value( T&& value ) {
|
||||
return GeneratorWrapper<DecayedT>(
|
||||
Catch::Detail::make_unique<SingleValueGenerator<DecayedT>>(
|
||||
CATCH_FORWARD( value ) ) );
|
||||
}
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> values(std::initializer_list<T> values) {
|
||||
return GeneratorWrapper<T>(Catch::Detail::make_unique<FixedValuesGenerator<T>>(values));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class Generators : public IGenerator<T> {
|
||||
std::vector<GeneratorWrapper<T>> m_generators;
|
||||
size_t m_current = 0;
|
||||
|
||||
void add_generator( GeneratorWrapper<T>&& generator ) {
|
||||
m_generators.emplace_back( CATCH_MOVE( generator ) );
|
||||
}
|
||||
void add_generator( T const& val ) {
|
||||
m_generators.emplace_back( value( val ) );
|
||||
}
|
||||
void add_generator( T&& val ) {
|
||||
m_generators.emplace_back( value( CATCH_MOVE( val ) ) );
|
||||
}
|
||||
template <typename U>
|
||||
std::enable_if_t<!std::is_same<std::decay_t<U>, T>::value>
|
||||
add_generator( U&& val ) {
|
||||
add_generator( T( CATCH_FORWARD( val ) ) );
|
||||
}
|
||||
|
||||
template <typename U> void add_generators( U&& valueOrGenerator ) {
|
||||
add_generator( CATCH_FORWARD( valueOrGenerator ) );
|
||||
}
|
||||
|
||||
template <typename U, typename... Gs>
|
||||
void add_generators( U&& valueOrGenerator, Gs&&... moreGenerators ) {
|
||||
add_generator( CATCH_FORWARD( valueOrGenerator ) );
|
||||
add_generators( CATCH_FORWARD( moreGenerators )... );
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename... Gs>
|
||||
Generators(Gs &&... moreGenerators) {
|
||||
m_generators.reserve(sizeof...(Gs));
|
||||
add_generators(CATCH_FORWARD(moreGenerators)...);
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
return m_generators[m_current].get();
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
if (m_current >= m_generators.size()) {
|
||||
return false;
|
||||
}
|
||||
const bool current_status = m_generators[m_current].next();
|
||||
if (!current_status) {
|
||||
++m_current;
|
||||
}
|
||||
return m_current < m_generators.size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename... Ts>
|
||||
GeneratorWrapper<std::tuple<std::decay_t<Ts>...>>
|
||||
table( std::initializer_list<std::tuple<std::decay_t<Ts>...>> tuples ) {
|
||||
return values<std::tuple<Ts...>>( tuples );
|
||||
}
|
||||
|
||||
// Tag type to signal that a generator sequence should convert arguments to a specific type
|
||||
template <typename T>
|
||||
struct as {};
|
||||
|
||||
template<typename T, typename... Gs>
|
||||
auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
|
||||
return Generators<T>(CATCH_MOVE(generator), CATCH_FORWARD(moreGenerators)...);
|
||||
}
|
||||
template<typename T>
|
||||
auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
|
||||
return Generators<T>(CATCH_MOVE(generator));
|
||||
}
|
||||
template<typename T, typename... Gs>
|
||||
auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<std::decay_t<T>> {
|
||||
return makeGenerators( value( CATCH_FORWARD( val ) ), CATCH_FORWARD( moreGenerators )... );
|
||||
}
|
||||
template<typename T, typename U, typename... Gs>
|
||||
auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
|
||||
return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... );
|
||||
}
|
||||
|
||||
IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName,
|
||||
SourceLineInfo const& lineInfo );
|
||||
IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
|
||||
SourceLineInfo lineInfo,
|
||||
GeneratorBasePtr&& generator );
|
||||
|
||||
template<typename L>
|
||||
auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> typename decltype(generatorExpression())::type {
|
||||
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||
|
||||
IGeneratorTracker* tracker = acquireGeneratorTracker( generatorName, lineInfo );
|
||||
// Creation of tracker is delayed after generator creation, so
|
||||
// that constructing generator can fail without breaking everything.
|
||||
if (!tracker) {
|
||||
tracker = createGeneratorTracker(
|
||||
generatorName,
|
||||
lineInfo,
|
||||
Catch::Detail::make_unique<Generators<UnderlyingType>>(
|
||||
generatorExpression() ) );
|
||||
}
|
||||
|
||||
auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker->getGenerator() );
|
||||
return generator.get();
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr
|
||||
#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__)
|
||||
|
||||
#define GENERATE( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
[ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
#define GENERATE_COPY( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
[=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
#define GENERATE_REF( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
[&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
|
||||
#endif // CATCH_GENERATORS_HPP_INCLUDED
|
||||
242
tests/catch2/src/catch2/generators/catch_generators_adapters.hpp
Normal file
242
tests/catch2/src/catch2/generators/catch_generators_adapters.hpp
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
|
||||
#define CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace Catch {
|
||||
namespace Generators {
|
||||
|
||||
template <typename T>
|
||||
class TakeGenerator final : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
size_t m_returned = 0;
|
||||
size_t m_target;
|
||||
public:
|
||||
TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
|
||||
m_generator(CATCH_MOVE(generator)),
|
||||
m_target(target)
|
||||
{
|
||||
assert(target != 0 && "Empty generators are not allowed");
|
||||
}
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
bool next() override {
|
||||
++m_returned;
|
||||
if (m_returned >= m_target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto success = m_generator.next();
|
||||
// If the underlying generator does not contain enough values
|
||||
// then we cut short as well
|
||||
if (!success) {
|
||||
m_returned = m_target;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(Catch::Detail::make_unique<TakeGenerator<T>>(target, CATCH_MOVE(generator)));
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
class FilterGenerator final : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
Predicate m_predicate;
|
||||
static_assert(!std::is_reference<Predicate>::value, "This would most likely result in a dangling reference");
|
||||
public:
|
||||
template <typename P>
|
||||
FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
|
||||
m_generator(CATCH_MOVE(generator)),
|
||||
m_predicate(CATCH_FORWARD(pred))
|
||||
{
|
||||
if (!m_predicate(m_generator.get())) {
|
||||
// It might happen that there are no values that pass the
|
||||
// filter. In that case we throw an exception.
|
||||
auto has_initial_value = next();
|
||||
if (!has_initial_value) {
|
||||
Detail::throw_generator_exception("No valid value found in filtered generator");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
bool success = m_generator.next();
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, typename std::remove_reference<Predicate>::type>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class RepeatGenerator final : public IGenerator<T> {
|
||||
static_assert(!std::is_same<T, bool>::value,
|
||||
"RepeatGenerator currently does not support bools"
|
||||
"because of std::vector<bool> specialization");
|
||||
GeneratorWrapper<T> m_generator;
|
||||
mutable std::vector<T> m_returned;
|
||||
size_t m_target_repeats;
|
||||
size_t m_current_repeat = 0;
|
||||
size_t m_repeat_index = 0;
|
||||
public:
|
||||
RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
|
||||
m_generator(CATCH_MOVE(generator)),
|
||||
m_target_repeats(repeats)
|
||||
{
|
||||
assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
if (m_current_repeat == 0) {
|
||||
m_returned.push_back(m_generator.get());
|
||||
return m_returned.back();
|
||||
}
|
||||
return m_returned[m_repeat_index];
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
// There are 2 basic cases:
|
||||
// 1) We are still reading the generator
|
||||
// 2) We are reading our own cache
|
||||
|
||||
// In the first case, we need to poke the underlying generator.
|
||||
// If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
|
||||
if (m_current_repeat == 0) {
|
||||
const auto success = m_generator.next();
|
||||
if (!success) {
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
|
||||
// In the second case, we need to move indices forward and check that we haven't run up against the end
|
||||
++m_repeat_index;
|
||||
if (m_repeat_index == m_returned.size()) {
|
||||
m_repeat_index = 0;
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(Catch::Detail::make_unique<RepeatGenerator<T>>(repeats, CATCH_MOVE(generator)));
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
class MapGenerator final : public IGenerator<T> {
|
||||
// TBD: provide static assert for mapping function, for friendly error message
|
||||
GeneratorWrapper<U> m_generator;
|
||||
Func m_function;
|
||||
// To avoid returning dangling reference, we have to save the values
|
||||
T m_cache;
|
||||
public:
|
||||
template <typename F2 = Func>
|
||||
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
|
||||
m_generator(CATCH_MOVE(generator)),
|
||||
m_function(CATCH_FORWARD(function)),
|
||||
m_cache(m_function(m_generator.get()))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_cache;
|
||||
}
|
||||
bool next() override {
|
||||
const auto success = m_generator.next();
|
||||
if (success) {
|
||||
m_cache = m_function(m_generator.get());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class ChunkGenerator final : public IGenerator<std::vector<T>> {
|
||||
std::vector<T> m_chunk;
|
||||
size_t m_chunk_size;
|
||||
GeneratorWrapper<T> m_generator;
|
||||
bool m_used_up = false;
|
||||
public:
|
||||
ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
|
||||
m_chunk_size(size), m_generator(CATCH_MOVE(generator))
|
||||
{
|
||||
m_chunk.reserve(m_chunk_size);
|
||||
if (m_chunk_size != 0) {
|
||||
m_chunk.push_back(m_generator.get());
|
||||
for (size_t i = 1; i < m_chunk_size; ++i) {
|
||||
if (!m_generator.next()) {
|
||||
Detail::throw_generator_exception("Not enough values to initialize the first chunk");
|
||||
}
|
||||
m_chunk.push_back(m_generator.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<T> const& get() const override {
|
||||
return m_chunk;
|
||||
}
|
||||
bool next() override {
|
||||
m_chunk.clear();
|
||||
for (size_t idx = 0; idx < m_chunk_size; ++idx) {
|
||||
if (!m_generator.next()) {
|
||||
return false;
|
||||
}
|
||||
m_chunk.push_back(m_generator.get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<std::vector<T>>(
|
||||
Catch::Detail::make_unique<ChunkGenerator<T>>(size, CATCH_MOVE(generator))
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
#endif // CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue