mirror of
https://github.com/Astatin3/meteorbot-old.git
synced 2026-06-09 08:38:07 -06:00
Initial commit
This commit is contained in:
@@ -0,0 +1,683 @@
|
||||
include(CatchMiscFunctions)
|
||||
|
||||
if (CATCH_BUILD_SURROGATES)
|
||||
message(STATUS "Configuring targets for surrogate TUs")
|
||||
|
||||
# If the folder does not exist before we ask for output redirect to
|
||||
# a file, it won't work.
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/surrogates)
|
||||
|
||||
# Creates target to generate the surrogate TU for provided header.
|
||||
# Returns the path to the generated file.
|
||||
function(createSurrogateFileTarget sourceHeader pathToFile)
|
||||
set(pathPrefix ${PROJECT_SOURCE_DIR}/src)
|
||||
|
||||
file(RELATIVE_PATH includePath ${pathPrefix} ${sourceHeader})
|
||||
|
||||
get_filename_component(basicFileName "${sourceHeader}" NAME_WE)
|
||||
|
||||
set(surrogateFilePath ${CMAKE_CURRENT_BINARY_DIR}/surrogates/surrogate_${basicFileName}.cpp)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${surrogateFilePath}
|
||||
COMMAND cmake -E echo "\#include <${includePath}>" > "${surrogateFilePath}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set(${pathToFile} ${surrogateFilePath} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Extracts all non-helper (e.g. catch_all.hpp) headers from the
|
||||
# Catch2 target, and returns them through the argument.
|
||||
function(ExtractCatch2Headers OutArg)
|
||||
get_target_property(targetSources Catch2 SOURCES)
|
||||
foreach(Source ${targetSources})
|
||||
string(REGEX MATCH "^.*\\.hpp$" isHeader ${Source})
|
||||
string(REGEX MATCH "_all.hpp" isAllHeader ${Source})
|
||||
if(isHeader AND NOT isAllHeader)
|
||||
list(APPEND AllHeaders ${Source})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${OutArg} ${AllHeaders} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
ExtractCatch2Headers(mainHeaders)
|
||||
|
||||
if (NOT mainHeaders)
|
||||
message(FATAL_ERROR "No headers in the main target were detected. Something is broken.")
|
||||
endif()
|
||||
|
||||
foreach(header ${mainHeaders})
|
||||
createSurrogateFileTarget(${header} pathToGeneratedFile)
|
||||
list(APPEND surrogateFiles ${pathToGeneratedFile})
|
||||
endforeach()
|
||||
|
||||
|
||||
add_executable(Catch2SurrogateTarget
|
||||
${surrogateFiles}
|
||||
)
|
||||
target_link_libraries(Catch2SurrogateTarget PRIVATE Catch2WithMain)
|
||||
|
||||
endif(CATCH_BUILD_SURROGATES)
|
||||
|
||||
####
|
||||
# Temporary workaround for VS toolset changes in 2017
|
||||
# We need to disable <UseFullPaths> property, but CMake doesn't support it
|
||||
# until 3.13 (not yet released)
|
||||
####
|
||||
if (MSVC)
|
||||
configure_file(${CATCH_DIR}/tools/misc/SelfTest.vcxproj.user
|
||||
${CMAKE_BINARY_DIR}/tests
|
||||
COPYONLY)
|
||||
endif(MSVC) #Temporary workaround
|
||||
|
||||
|
||||
# define the sources of the self test
|
||||
# Please keep these ordered alphabetically
|
||||
set(TEST_SOURCES
|
||||
${SELF_TEST_DIR}/TestRegistrations.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Algorithms.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/AssertionHandler.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Clara.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/CmdLineHelpers.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/ColourImpl.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Details.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/FloatingPoint.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/GeneratorsImpl.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Integer.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/InternalBenchmark.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Json.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Parse.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/RandomNumberGeneration.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Reporters.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Tag.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/TestCaseInfoHasher.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/TestSpec.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/TestSpecParser.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/TextFlow.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Sharding.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Stream.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/StringManip.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Traits.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/ToString.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/UniquePtr.tests.cpp
|
||||
${SELF_TEST_DIR}/helpers/parse_test_spec.cpp
|
||||
${SELF_TEST_DIR}/TimingTests/Sleep.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Class.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Compilation.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Condition.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Decomposition.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/EnumToString.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Exception.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Generators.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Message.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Skip.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringByte.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringOptional.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringPair.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringTuple.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringVariant.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringVector.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringWhich.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Tricky.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/VariadicMacros.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/MatchersRanges.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Matchers.tests.cpp
|
||||
)
|
||||
|
||||
set(TEST_HEADERS
|
||||
${SELF_TEST_DIR}/helpers/parse_test_spec.hpp
|
||||
${SELF_TEST_DIR}/helpers/range_test_helpers.hpp
|
||||
${SELF_TEST_DIR}/helpers/type_with_lit_0_comparisons.hpp
|
||||
)
|
||||
|
||||
|
||||
# Specify the headers, too, so CLion recognises them as project files
|
||||
set(HEADERS
|
||||
${TOP_LEVEL_HEADERS}
|
||||
${EXTERNAL_HEADERS}
|
||||
${INTERNAL_HEADERS}
|
||||
${REPORTER_HEADERS}
|
||||
${BENCHMARK_HEADERS}
|
||||
${BENCHMARK_SOURCES}
|
||||
)
|
||||
|
||||
# Provide some groupings for IDEs
|
||||
#SOURCE_GROUP("benchmark" FILES ${BENCHMARK_HEADERS} ${BENCHMARK_SOURCES})
|
||||
#SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
|
||||
|
||||
include(CTest)
|
||||
|
||||
add_executable(SelfTest ${TEST_SOURCES} ${TEST_HEADERS})
|
||||
target_include_directories(SelfTest PRIVATE ${SELF_TEST_DIR})
|
||||
target_link_libraries(SelfTest PRIVATE Catch2WithMain)
|
||||
if (BUILD_SHARED_LIBS AND WIN32)
|
||||
add_custom_command(TARGET SelfTest PRE_LINK
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Catch2>
|
||||
$<TARGET_FILE:Catch2WithMain> $<TARGET_FILE_DIR:SelfTest>
|
||||
)
|
||||
endif()
|
||||
|
||||
if (CATCH_ENABLE_COVERAGE)
|
||||
set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE)
|
||||
find_package(codecov)
|
||||
add_coverage(SelfTest)
|
||||
list(APPEND LCOV_REMOVE_PATTERNS "'/usr/*'")
|
||||
coverage_evaluate()
|
||||
endif()
|
||||
|
||||
# configure unit tests via CTest
|
||||
add_test(NAME RunTests COMMAND $<TARGET_FILE:SelfTest> --order rand --rng-seed time)
|
||||
set_tests_properties(RunTests PROPERTIES
|
||||
FAIL_REGULAR_EXPRESSION "Filters:"
|
||||
COST 15
|
||||
)
|
||||
|
||||
# Because CTest does not allow us to check both return code _and_ expected
|
||||
# output in one test, we run these commands twice. First time we check
|
||||
# the output, the second time we check the exit code.
|
||||
add_test(NAME List::Tests::Output COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
|
||||
set_tests_properties(List::Tests::Output PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "[0-9]+ test cases"
|
||||
FAIL_REGULAR_EXPRESSION "Hidden Test"
|
||||
)
|
||||
# This should be equivalent to the old --list-test-names-only and be usable
|
||||
# with --input-file.
|
||||
add_test(NAME List::Tests::Quiet COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity quiet)
|
||||
# Sadly we cannot ask for start-of-line and end-of-line in a ctest regex,
|
||||
# so we fail if we see space/tab at the start...
|
||||
set_tests_properties(List::Tests::Quiet PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "\"#1905 -- test spec parser properly clears internal state between compound tests\"[\r\n]"
|
||||
FAIL_REGULAR_EXPRESSION "[ \t]\"#1905 -- test spec parser properly clears internal state between compound tests\""
|
||||
)
|
||||
add_test(NAME List::Tests::ExitCode COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
|
||||
add_test(NAME List::Tests::XmlOutput COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high -r xml)
|
||||
set_tests_properties(List::Tests::XmlOutput PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "<Line>[0-9]+</Line>"
|
||||
FAIL_REGULAR_EXPRESSION "[0-9]+ test cases"
|
||||
)
|
||||
|
||||
add_test(NAME List::Tags::Output COMMAND $<TARGET_FILE:SelfTest> --list-tags)
|
||||
set_tests_properties(List::Tags::Output PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "[0-9]+ tags"
|
||||
FAIL_REGULAR_EXPRESSION "\\[\\.\\]")
|
||||
add_test(NAME List::Tags::ExitCode COMMAND $<TARGET_FILE:SelfTest> --list-tags)
|
||||
add_test(NAME List::Tags::XmlOutput COMMAND $<TARGET_FILE:SelfTest> --list-tags -r xml)
|
||||
set_tests_properties(List::Tags::XmlOutput PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "<Count>18</Count>"
|
||||
FAIL_REGULAR_EXPRESSION "[0-9]+ tags"
|
||||
)
|
||||
|
||||
|
||||
add_test(NAME List::Reporters::Output COMMAND $<TARGET_FILE:SelfTest> --list-reporters)
|
||||
set_tests_properties(List::Reporters::Output PROPERTIES PASS_REGULAR_EXPRESSION "Available reporters:")
|
||||
add_test(NAME List::Reporters::ExitCode COMMAND $<TARGET_FILE:SelfTest> --list-reporters)
|
||||
add_test(NAME List::Reporters::XmlOutput COMMAND $<TARGET_FILE:SelfTest> --list-reporters -r xml)
|
||||
set_tests_properties(List::Reporters::XmlOutput PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "<Name>compact</Name>"
|
||||
FAIL_REGULAR_EXPRESSION "Available reporters:"
|
||||
)
|
||||
|
||||
add_test(NAME List::Listeners::Output
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> --list-listeners
|
||||
)
|
||||
set_tests_properties(List::Listeners::Output
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Registered listeners:"
|
||||
)
|
||||
add_test(NAME List::Listeners::ExitCode
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> --list-listeners
|
||||
)
|
||||
add_test(NAME List::Listeners::XmlOutput
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest>
|
||||
--list-listeners
|
||||
--reporter xml
|
||||
)
|
||||
set_tests_properties(List::Listeners::XmlOutput
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "<RegisteredListeners>"
|
||||
FAIL_REGULAR_EXPRESSION "Registered listeners:"
|
||||
)
|
||||
|
||||
add_test(NAME NoAssertions COMMAND $<TARGET_FILE:SelfTest> -w NoAssertions "An empty test with no assertions")
|
||||
set_tests_properties(NoAssertions PROPERTIES PASS_REGULAR_EXPRESSION "No assertions in test case")
|
||||
|
||||
# We cannot combine a regular expression on output with return code check
|
||||
# in one test, so we register two instead of making a checking script because
|
||||
# the runtime overhead is small enough.
|
||||
add_test(NAME TestSpecs::CombiningMatchingAndNonMatchingIsOk-1 COMMAND $<TARGET_FILE:SelfTest> Tracker, "___nonexistent_test___")
|
||||
|
||||
add_test(NAME TestSpecs::CombiningMatchingAndNonMatchingIsOk-2 COMMAND $<TARGET_FILE:SelfTest> Tracker, "___nonexistent_test___")
|
||||
set_tests_properties(TestSpecs::CombiningMatchingAndNonMatchingIsOk-2 PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "No test cases matched '\"___nonexistent_test___\"'"
|
||||
FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||
)
|
||||
|
||||
add_test(NAME TestSpecs::NoMatchedTestsFail
|
||||
COMMAND $<TARGET_FILE:SelfTest> "___nonexistent_test___"
|
||||
)
|
||||
set_tests_properties(TestSpecs::NoMatchedTestsFail
|
||||
PROPERTIES
|
||||
WILL_FAIL ON
|
||||
)
|
||||
add_test(NAME TestSpecs::OverrideFailureWithNoMatchedTests
|
||||
COMMAND $<TARGET_FILE:SelfTest> "___nonexistent_test___" --allow-running-no-tests
|
||||
)
|
||||
|
||||
add_test(NAME TestSpecs::OverrideAllSkipFailure
|
||||
COMMAND $<TARGET_FILE:SelfTest> "tests can be skipped dynamically at runtime" --allow-running-no-tests
|
||||
)
|
||||
|
||||
add_test(NAME TestSpecs::NonMatchingTestSpecIsRoundTrippable
|
||||
COMMAND $<TARGET_FILE:SelfTest> Tracker, "this test does not exist" "[nor does this tag]"
|
||||
)
|
||||
set_tests_properties(TestSpecs::NonMatchingTestSpecIsRoundTrippable
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "No test cases matched '\"this test does not exist\" \\[nor does this tag\\]'"
|
||||
)
|
||||
|
||||
add_test(NAME Warnings::UnmatchedTestSpecIsAccepted
|
||||
COMMAND $<TARGET_FILE:SelfTest> Tracker --warn UnmatchedTestSpec
|
||||
)
|
||||
set_tests_properties(Warnings::UnmatchedTestSpecIsAccepted
|
||||
PROPERTIES
|
||||
FAIL_REGULAR_EXPRESSION "Unrecognised warning option: "
|
||||
)
|
||||
|
||||
add_test(NAME Warnings::MultipleWarningsCanBeSpecified
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> Tracker
|
||||
--warn NoAssertions
|
||||
--warn UnmatchedTestSpec
|
||||
)
|
||||
|
||||
add_test(NAME TestSpecs::WarnUnmatchedTestSpecFailsWithUnmatchedTestSpec
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> Tracker, "___nonexistent_test___" --warn UnmatchedTestSpec
|
||||
)
|
||||
set_tests_properties(TestSpecs::WarnUnmatchedTestSpecFailsWithUnmatchedTestSpec
|
||||
PROPERTIES
|
||||
WILL_FAIL ON
|
||||
)
|
||||
|
||||
add_test(NAME UnmatchedOutputFilter COMMAND $<TARGET_FILE:SelfTest> [this-tag-does-not-exist])
|
||||
set_tests_properties(UnmatchedOutputFilter
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "No test cases matched '\\[this-tag-does-not-exist\\]'"
|
||||
)
|
||||
|
||||
add_test(NAME FilteredSection-1 COMMAND $<TARGET_FILE:SelfTest> \#1394 -c RunSection)
|
||||
set_tests_properties(FilteredSection-1 PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran")
|
||||
add_test(NAME FilteredSection-2 COMMAND $<TARGET_FILE:SelfTest> \#1394\ nested -c NestedRunSection -c s1)
|
||||
set_tests_properties(FilteredSection-2 PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran")
|
||||
|
||||
add_test(
|
||||
NAME
|
||||
FilteredSection::GeneratorsDontCauseInfiniteLoop-1
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "#2025: original repro" -c "fov_0"
|
||||
)
|
||||
set_tests_properties(FilteredSection::GeneratorsDontCauseInfiniteLoop-1
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "inside with fov: 0" # This should happen
|
||||
FAIL_REGULAR_EXPRESSION "inside with fov: 1" # This would mean there was no filtering
|
||||
)
|
||||
|
||||
# GENERATE between filtered sections (both are selected)
|
||||
add_test(
|
||||
NAME
|
||||
FilteredSection::GeneratorsDontCauseInfiniteLoop-2
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "#2025: same-level sections"
|
||||
-c "A"
|
||||
-c "B"
|
||||
--colour-mode none
|
||||
)
|
||||
set_tests_properties(FilteredSection::GeneratorsDontCauseInfiniteLoop-2
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "All tests passed \\(4 assertions in 1 test case\\)"
|
||||
)
|
||||
|
||||
# AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable
|
||||
add_test(NAME ApprovalTests
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE}
|
||||
${CATCH_DIR}/tools/scripts/approvalTests.py
|
||||
$<TARGET_FILE:SelfTest>
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
set_tests_properties(ApprovalTests
|
||||
PROPERTIES
|
||||
FAIL_REGULAR_EXPRESSION "Results differed"
|
||||
|
||||
# This is the most expensive test in the basic test suite, so we give
|
||||
# it high cost estimate so that CI runs it as one of the first ones,
|
||||
# for better parallelization.
|
||||
COST 30
|
||||
LABELS "uses-python"
|
||||
)
|
||||
|
||||
add_test(NAME RegressionCheck-1670 COMMAND $<TARGET_FILE:SelfTest> "#1670 regression check" -c A -r compact)
|
||||
set_tests_properties(RegressionCheck-1670 PROPERTIES PASS_REGULAR_EXPRESSION "All tests passed \\(2 assertions in 1 test case\\)")
|
||||
|
||||
add_test(NAME VersionCheck COMMAND $<TARGET_FILE:SelfTest> -h)
|
||||
set_tests_properties(VersionCheck PROPERTIES PASS_REGULAR_EXPRESSION "Catch2 v${PROJECT_VERSION}")
|
||||
|
||||
add_test(NAME LibIdentityTest COMMAND $<TARGET_FILE:SelfTest> --libidentify)
|
||||
set_tests_properties(LibIdentityTest PROPERTIES PASS_REGULAR_EXPRESSION "description: A Catch2 test executable")
|
||||
|
||||
add_test(NAME FilenameAsTagsTest COMMAND $<TARGET_FILE:SelfTest> -\# --list-tags)
|
||||
set_tests_properties(FilenameAsTagsTest PROPERTIES PASS_REGULAR_EXPRESSION "\\[#Approx.tests\\]")
|
||||
|
||||
# Check that the filename tags can also be matched against (#2064)
|
||||
add_test(NAME FilenameAsTagsMatching COMMAND $<TARGET_FILE:SelfTest> -\# --list-tags [\#Approx.tests])
|
||||
set_tests_properties(FilenameAsTagsMatching
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "\\[#Approx.tests\\]"
|
||||
# Avoids false positives by looking for start of line (newline) before the 0
|
||||
FAIL_REGULAR_EXPRESSION "[\r\n]0 tag"
|
||||
)
|
||||
|
||||
add_test(NAME EscapeSpecialCharactersInTestNames COMMAND $<TARGET_FILE:SelfTest> "Test with special\\, characters \"in name")
|
||||
set_tests_properties(EscapeSpecialCharactersInTestNames PROPERTIES PASS_REGULAR_EXPRESSION "1 assertion in 1 test case")
|
||||
|
||||
add_test(NAME NegativeSpecNoHiddenTests COMMAND $<TARGET_FILE:SelfTest> --list-tests ~[approval])
|
||||
set_tests_properties(NegativeSpecNoHiddenTests PROPERTIES FAIL_REGULAR_EXPRESSION "\\[\\.\\]")
|
||||
|
||||
add_test(NAME TestsInFile::SimpleSpecs COMMAND $<TARGET_FILE:SelfTest> "-f ${SELF_TEST_DIR}/Misc/plain-old-tests.input")
|
||||
set_tests_properties(TestsInFile::SimpleSpecs PROPERTIES PASS_REGULAR_EXPRESSION "6 assertions in 2 test cases")
|
||||
|
||||
add_test(NAME TestsInFile::EscapeSpecialCharacters COMMAND $<TARGET_FILE:SelfTest> "-f ${SELF_TEST_DIR}/Misc/special-characters-in-file.input")
|
||||
set_tests_properties(TestsInFile::EscapeSpecialCharacters PROPERTIES PASS_REGULAR_EXPRESSION "1 assertion in 1 test case")
|
||||
|
||||
add_test(NAME TestsInFile::InvalidTestNames-1 COMMAND $<TARGET_FILE:SelfTest> "-f ${SELF_TEST_DIR}/Misc/invalid-test-names.input")
|
||||
set_tests_properties(TestsInFile::InvalidTestNames-1
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Invalid Filter: \"Test with special, characters in \\\\\" name\""
|
||||
FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||
)
|
||||
|
||||
add_test(NAME TagAlias COMMAND $<TARGET_FILE:SelfTest> [@tricky] --list-tests)
|
||||
set_tests_properties(TagAlias PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "[0-9]+ matching test cases"
|
||||
FAIL_REGULAR_EXPRESSION "0 matching test cases"
|
||||
)
|
||||
|
||||
add_test(NAME RandomTestOrdering COMMAND ${PYTHON_EXECUTABLE}
|
||||
${CATCH_DIR}/tests/TestScripts/testRandomOrder.py $<TARGET_FILE:SelfTest>)
|
||||
set_tests_properties(RandomTestOrdering
|
||||
PROPERTIES
|
||||
LABELS "uses-python"
|
||||
)
|
||||
|
||||
add_test(NAME CheckConvenienceHeaders
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE} ${CATCH_DIR}/tools/scripts/checkConvenienceHeaders.py
|
||||
)
|
||||
set_tests_properties(CheckConvenienceHeaders
|
||||
PROPERTIES
|
||||
LABELS "uses-python"
|
||||
)
|
||||
|
||||
add_test(NAME "Benchmarking::SkipBenchmarkMacros"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Skip benchmark macros"
|
||||
--reporter console
|
||||
--skip-benchmarks
|
||||
--colour-mode none
|
||||
)
|
||||
set_tests_properties("Benchmarking::SkipBenchmarkMacros"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "All tests passed \\(2 assertions in 1 test case\\)"
|
||||
FAIL_REGULAR_EXPRESSION "benchmark name"
|
||||
)
|
||||
|
||||
|
||||
add_test(NAME "Benchmarking::FailureReporting::OptimizedOut"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Failing benchmarks" -c "empty" -r xml
|
||||
# This test only makes sense with the optimizer being enabled when
|
||||
# the tests are being compiled.
|
||||
CONFIGURATIONS Release
|
||||
)
|
||||
set_tests_properties("Benchmarking::FailureReporting::OptimizedOut"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "could not measure benchmark\, maybe it was optimized away"
|
||||
FAIL_REGULAR_EXPRESSION "successes=\"1\""
|
||||
)
|
||||
|
||||
add_test(NAME "Benchmarking::FailureReporting::ThrowingBenchmark"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Failing benchmarks" -c "throw" -r xml
|
||||
)
|
||||
set_tests_properties("Benchmarking::FailureReporting::ThrowingBenchmark"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "<failed message=\"just a plain literal"
|
||||
FAIL_REGULAR_EXPRESSION "successes=\"1\""
|
||||
)
|
||||
|
||||
add_test(NAME "Benchmarking::FailureReporting::FailedAssertion"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Failing benchmarks" -c "assert" -r xml
|
||||
)
|
||||
set_tests_properties("Benchmarking::FailureReporting::FailedAssertion"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "<Expression success=\"false\""
|
||||
FAIL_REGULAR_EXPRESSION "successes=\"1\""
|
||||
)
|
||||
|
||||
add_test(NAME "Benchmarking::FailureReporting::FailMacro"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Failing benchmarks" -c "fail" -r xml
|
||||
)
|
||||
set_tests_properties("Benchmarking::FailureReporting::FailMacro"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "This benchmark only fails\, nothing else"
|
||||
FAIL_REGULAR_EXPRESSION "successes=\"1\""
|
||||
)
|
||||
|
||||
add_test(NAME "Benchmarking::FailureReporting::ShouldFailIsRespected"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Failing benchmark respects should-fail"
|
||||
)
|
||||
set_tests_properties("Benchmarking::FailureReporting::ShouldFailIsRespected"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "1 failed as expected"
|
||||
)
|
||||
|
||||
add_test(NAME "ErrorHandling::InvalidTestSpecExitsEarly"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "[aa,a]"
|
||||
)
|
||||
set_tests_properties("ErrorHandling::InvalidTestSpecExitsEarly"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Invalid Filter: \\[aa\,a\\]"
|
||||
FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
set(_NullFile "NUL")
|
||||
else()
|
||||
set(_NullFile "/dev/null")
|
||||
endif()
|
||||
|
||||
# This test checks that there is nothing written out from the process,
|
||||
# but if CMake is running the tests under Valgrind or similar tool, then
|
||||
# that will write its own output to stdout and the test would fail.
|
||||
if (NOT MEMORYCHECK_COMMAND)
|
||||
add_test(NAME "MultiReporter::CapturingReportersDontPropagateStdOut"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Sends stuff to stdout and stderr"
|
||||
--reporter xml::out=${_NullFile}
|
||||
--reporter junit::out=${_NullFile}
|
||||
)
|
||||
set_tests_properties("MultiReporter::CapturingReportersDontPropagateStdOut"
|
||||
PROPERTIES
|
||||
FAIL_REGULAR_EXPRESSION ".+"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_test(NAME "MultiReporter::NonCapturingReportersPropagateStdout"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Sends stuff to stdout and stderr"
|
||||
--reporter xml::out=${_NullFile}
|
||||
--reporter console::out=${_NullFile}
|
||||
)
|
||||
set_tests_properties("MultiReporter::NonCapturingReportersPropagateStdout"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "A string sent to stderr via clog"
|
||||
)
|
||||
|
||||
add_test(NAME "Outputs::DashAsOutLocationSendsOutputToStdout"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Factorials are computed"
|
||||
--out=-
|
||||
--colour-mode none
|
||||
)
|
||||
set_tests_properties("Outputs::DashAsOutLocationSendsOutputToStdout"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "All tests passed \\(5 assertions in 1 test case\\)"
|
||||
)
|
||||
|
||||
add_test(NAME "Reporters::DashAsLocationInReporterSpecSendsOutputToStdout"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Factorials are computed"
|
||||
--reporter console::out=-
|
||||
--colour-mode none
|
||||
)
|
||||
set_tests_properties("Reporters::DashAsLocationInReporterSpecSendsOutputToStdout"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "All tests passed \\(5 assertions in 1 test case\\)"
|
||||
)
|
||||
|
||||
add_test(NAME "Reporters::ReporterSpecificColourOverridesDefaultColour"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Factorials are computed"
|
||||
--reporter console::colour-mode=ansi
|
||||
--colour-mode none
|
||||
)
|
||||
set_tests_properties("Reporters::ReporterSpecificColourOverridesDefaultColour"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "\\[1\;32mAll tests passed"
|
||||
)
|
||||
|
||||
add_test(NAME "Reporters::UnrecognizedOptionInSpecCausesError"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Factorials are computed"
|
||||
--reporter console::bad-option=ansi
|
||||
)
|
||||
set_tests_properties("Reporters::UnrecognizedOptionInSpecCausesError"
|
||||
PROPERTIES
|
||||
WILL_FAIL ON
|
||||
)
|
||||
|
||||
add_test(NAME "Colours::ColourModeCanBeExplicitlySetToAnsi"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Factorials are computed"
|
||||
--reporter console
|
||||
--colour-mode ansi
|
||||
)
|
||||
set_tests_properties("Colours::ColourModeCanBeExplicitlySetToAnsi"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "\\[1\;32mAll tests passed"
|
||||
)
|
||||
|
||||
add_test(NAME "Reporters::JUnit::NamespacesAreNormalized"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest>
|
||||
--reporter junit
|
||||
"A TEST_CASE_METHOD testing junit classname normalization"
|
||||
)
|
||||
set_tests_properties("Reporters::JUnit::NamespacesAreNormalized"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "testcase classname=\"SelfTest(\.exe)?\\.A\\.B\\.TestClass\""
|
||||
)
|
||||
|
||||
if (CATCH_ENABLE_CONFIGURE_TESTS)
|
||||
foreach(testName "DefaultReporter" "Disable" "DisableStringification"
|
||||
"ExperimentalRedirect")
|
||||
|
||||
add_test(NAME "CMakeConfig::${testName}"
|
||||
COMMAND
|
||||
"${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_LIST_DIR}/TestScripts/testConfigure${testName}.py" "${CATCH_DIR}" "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
set_tests_properties("CMakeConfig::${testName}"
|
||||
PROPERTIES
|
||||
COST 240
|
||||
LABELS "uses-python"
|
||||
)
|
||||
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if (CATCH_ENABLE_CMAKE_HELPER_TESTS)
|
||||
add_test(NAME "CMakeHelper::DiscoverTests"
|
||||
COMMAND
|
||||
"${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_LIST_DIR}/TestScripts/DiscoverTests/VerifyRegistration.py" "${CATCH_DIR}" "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
set_tests_properties("CMakeHelper::DiscoverTests"
|
||||
PROPERTIES
|
||||
COST 240
|
||||
LABELS "uses-python"
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach (reporterName # "Automake" - the simple .trs format does not support any kind of comments/metadata
|
||||
"compact"
|
||||
"console"
|
||||
"JUnit"
|
||||
"SonarQube"
|
||||
"TAP"
|
||||
# "TeamCity" - does not seem to support test suite-level metadata/comments
|
||||
"XML"
|
||||
"JSON")
|
||||
|
||||
add_test(NAME "Reporters:Filters:${reporterName}"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> [comparisons][string-case] "CaseInsensitiveLess is case insensitive"
|
||||
--reporter ${reporterName}
|
||||
)
|
||||
# Different regex for these two reporters, because the commas end up xml-escaped
|
||||
if (reporterName MATCHES "JUnit|XML")
|
||||
set(testCaseNameFormat ""CaseInsensitiveLess is case insensitive"")
|
||||
elseif(reporterName MATCHES "JSON")
|
||||
set(testCaseNameFormat "\\\\\"CaseInsensitiveLess is case insensitive\\\\\"")
|
||||
else()
|
||||
set(testCaseNameFormat "\"CaseInsensitiveLess is case insensitive\"")
|
||||
endif()
|
||||
set_tests_properties("Reporters:Filters:${reporterName}"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "[fF]ilters.+\\[comparisons\\] \\[string-case\\] ${testCaseNameFormat}"
|
||||
)
|
||||
|
||||
add_test(NAME "Reporters:RngSeed:${reporterName}"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Factorials are computed"
|
||||
--reporter ${reporterName}
|
||||
--rng-seed 18181818
|
||||
)
|
||||
set_tests_properties("Reporters:RngSeed:${reporterName}"
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "18181818"
|
||||
)
|
||||
|
||||
endforeach()
|
||||
|
||||
|
||||
list(APPEND CATCH_WARNING_TARGETS SelfTest)
|
||||
set(CATCH_WARNING_TARGETS ${CATCH_WARNING_TARGETS} PARENT_SCOPE)
|
||||
@@ -0,0 +1,565 @@
|
||||
#
|
||||
# Build extra tests.
|
||||
#
|
||||
|
||||
cmake_minimum_required( VERSION 3.10 )
|
||||
|
||||
project( Catch2ExtraTests LANGUAGES CXX )
|
||||
|
||||
message( STATUS "Extra tests included" )
|
||||
|
||||
|
||||
add_test(
|
||||
NAME TestShardingIntegration
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CATCH_DIR}/tests/TestScripts/testSharding.py $<TARGET_FILE:SelfTest>
|
||||
)
|
||||
set_tests_properties(TestShardingIntegration
|
||||
PROPERTIES
|
||||
LABELS "uses-python"
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME TestSharding::OverlyLargeShardIndex
|
||||
COMMAND $<TARGET_FILE:SelfTest> --shard-index 5 --shard-count 5
|
||||
)
|
||||
set_tests_properties(
|
||||
TestSharding::OverlyLargeShardIndex
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "The shard count \\(5\\) must be greater than the shard index \\(5\\)"
|
||||
)
|
||||
|
||||
# The MinDuration reporting tests do not need separate compilation, but
|
||||
# they have non-trivial execution time, so they are categorized as
|
||||
# extra tests, so that they are run less.
|
||||
add_test(NAME MinDuration::SimpleThreshold COMMAND $<TARGET_FILE:SelfTest> --min-duration 0.950 [min_duration_test])
|
||||
set_tests_properties(
|
||||
MinDuration::SimpleThreshold
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "s: sleep_for_1000ms"
|
||||
FAIL_REGULAR_EXPRESSION "sleep_for_100ms"
|
||||
RUN_SERIAL ON # The test is timing sensitive, so we want to run it
|
||||
# serially to avoid false positives on oversubscribed machines
|
||||
)
|
||||
|
||||
# -d yes overrides the threshold, so we should see the faster test even
|
||||
# with a ridiculous high min duration threshold
|
||||
add_test(NAME MinDuration::DurationOverrideYes COMMAND $<TARGET_FILE:SelfTest> --min-duration 1.0 -d yes [min_duration_test])
|
||||
set_tests_properties(
|
||||
MinDuration::DurationOverrideYes
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "s: sleep_for_100ms"
|
||||
)
|
||||
|
||||
# -d no overrides the threshold, so we should never see any tests even
|
||||
# with ridiculously low min duration threshold
|
||||
add_test(NAME MinDuration::DurationOverrideNo COMMAND $<TARGET_FILE:SelfTest> --min-duration 0.0001 -d no [min_duration_test])
|
||||
set_tests_properties(
|
||||
MinDuration::DurationOverrideNo
|
||||
PROPERTIES
|
||||
FAIL_REGULAR_EXPRESSION "sleep_for_250ms"
|
||||
)
|
||||
|
||||
|
||||
# ------------ end of duration reporting tests
|
||||
|
||||
# define folders used:
|
||||
set( TESTS_DIR ${CATCH_DIR}/tests/ExtraTests )
|
||||
|
||||
add_executable(PrefixedMacros ${TESTS_DIR}/X01-PrefixedMacros.cpp)
|
||||
target_compile_definitions( PrefixedMacros PRIVATE CATCH_CONFIG_PREFIX_ALL CATCH_CONFIG_RUNTIME_STATIC_REQUIRE )
|
||||
# Macro configuration does not touch the compiled parts, so we can link
|
||||
# it against the main library
|
||||
target_link_libraries( PrefixedMacros Catch2WithMain )
|
||||
|
||||
add_test(NAME CATCH_CONFIG_PREFIX_ALL COMMAND PrefixedMacros -s)
|
||||
set_tests_properties(
|
||||
CATCH_CONFIG_PREFIX_ALL
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "CATCH_"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
# The spaces are important -> They disambiguate between CATCH_REQUIRE
|
||||
# and REQUIRE without prefix.
|
||||
" REQUIRE; REQUIRE_FALSE; REQUIRE_THROWS; REQUIRE_THROWS_AS; REQUIRE_THROWS_WITH; REQUIRE_THROWS_MATCHES; REQUIRE_NOTHROW; CHECK; CHECK_FALSE; CHECKED_IF; CHECKED_ELSE; CHECK_NOFAIL; CHECK_THROWS; CHECK_THROWS_AS; CHECK_THROWS_WITH; CHECK_THROWS_MATCHES; CHECK_NOTHROW; REQUIRE_THAT; CHECK_THAT"
|
||||
)
|
||||
|
||||
|
||||
add_executable(DisabledMacros ${TESTS_DIR}/X02-DisabledMacros.cpp)
|
||||
target_compile_definitions( DisabledMacros PRIVATE CATCH_CONFIG_DISABLE )
|
||||
# Macro configuration does not touch the compiled parts, so we can link
|
||||
# it against the main library
|
||||
target_link_libraries( DisabledMacros Catch2WithMain )
|
||||
|
||||
add_test(NAME CATCH_CONFIG_DISABLE-1 COMMAND DisabledMacros -s)
|
||||
set_tests_properties(
|
||||
CATCH_CONFIG_DISABLE-1
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "No tests ran"
|
||||
FAIL_REGULAR_EXPRESSION "This should not happen"
|
||||
)
|
||||
add_test(NAME CATCH_CONFIG_DISABLE-2 COMMAND DisabledMacros --list-tests)
|
||||
set_tests_properties(
|
||||
CATCH_CONFIG_DISABLE-2
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "0 test cases"
|
||||
)
|
||||
|
||||
add_executable( DisabledExceptions-DefaultHandler ${TESTS_DIR}/X03-DisabledExceptions-DefaultHandler.cpp )
|
||||
add_executable( DisabledExceptions-CustomHandler ${TESTS_DIR}/X04-DisabledExceptions-CustomHandler.cpp )
|
||||
|
||||
foreach(target DisabledExceptions-DefaultHandler DisabledExceptions-CustomHandler)
|
||||
target_compile_options( ${target}
|
||||
PUBLIC
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/EHs-c-;/D_HAS_EXCEPTIONS=0>
|
||||
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:AppleClang>>:-fno-exceptions>
|
||||
)
|
||||
target_link_libraries(${target} Catch2_buildall_interface)
|
||||
endforeach()
|
||||
target_compile_definitions( DisabledExceptions-CustomHandler PUBLIC CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER )
|
||||
|
||||
|
||||
add_test(NAME CATCH_CONFIG_DISABLE_EXCEPTIONS-1 COMMAND DisabledExceptions-DefaultHandler "Tests that run")
|
||||
set_tests_properties(
|
||||
CATCH_CONFIG_DISABLE_EXCEPTIONS-1
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "assertions: 4 \| 2 passed \| 2 failed"
|
||||
FAIL_REGULAR_EXPRESSION "abort;terminate;fatal"
|
||||
)
|
||||
|
||||
add_executable( BazelReporter ${TESTS_DIR}/X30-BazelReporter.cpp )
|
||||
target_compile_definitions( BazelReporter PRIVATE CATCH_CONFIG_BAZEL_SUPPORT )
|
||||
target_link_libraries(BazelReporter Catch2_buildall_interface)
|
||||
add_test(NAME CATCH_CONFIG_BAZEL_REPORTER-1
|
||||
COMMAND
|
||||
"${PYTHON_EXECUTABLE}" "${CATCH_DIR}/tests/TestScripts/testBazelReporter.py" $<TARGET_FILE:BazelReporter> "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
set_tests_properties(CATCH_CONFIG_BAZEL_REPORTER-1
|
||||
PROPERTIES
|
||||
LABELS "uses-python"
|
||||
)
|
||||
|
||||
# We must now test this works without the build flag.
|
||||
add_executable( BazelReporterNoCatchConfig ${TESTS_DIR}/X30-BazelReporter.cpp )
|
||||
target_link_libraries(BazelReporterNoCatchConfig Catch2WithMain)
|
||||
add_test(NAME NO_CATCH_CONFIG_BAZEL_REPORTER-1
|
||||
COMMAND
|
||||
"${PYTHON_EXECUTABLE}" "${CATCH_DIR}/tests/TestScripts/testBazelReporter.py" $<TARGET_FILE:BazelReporterNoCatchConfig> "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
set_tests_properties(NO_CATCH_CONFIG_BAZEL_REPORTER-1
|
||||
PROPERTIES
|
||||
LABELS "uses-python"
|
||||
ENVIRONMENT "BAZEL_TEST=1"
|
||||
)
|
||||
|
||||
add_test(NAME BazelEnv::TESTBRIDGE_TEST_ONLY
|
||||
COMMAND
|
||||
$<TARGET_FILE:BazelReporterNoCatchConfig>
|
||||
)
|
||||
set_tests_properties(BazelEnv::TESTBRIDGE_TEST_ONLY
|
||||
PROPERTIES
|
||||
ENVIRONMENT "BAZEL_TEST=1;TESTBRIDGE_TEST_ONLY=Passing test case"
|
||||
PASS_REGULAR_EXPRESSION "All tests passed \\(1 assertion in 1 test case\\)"
|
||||
)
|
||||
|
||||
|
||||
add_test(NAME BazelEnv::Sharding
|
||||
COMMAND
|
||||
"${PYTHON_EXECUTABLE}" "${CATCH_DIR}/tests/TestScripts/testBazelSharding.py"
|
||||
$<TARGET_FILE:BazelReporterNoCatchConfig>
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
set_tests_properties(BazelEnv::Sharding
|
||||
PROPERTIES
|
||||
LABELS "uses-python"
|
||||
)
|
||||
|
||||
|
||||
# The default handler on Windows leads to the just-in-time debugger firing,
|
||||
# which makes this test unsuitable for CI and headless runs, as it opens
|
||||
# up an interactive dialog.
|
||||
if (NOT WIN32)
|
||||
add_test(NAME CATCH_CONFIG_DISABLE_EXCEPTIONS-2 COMMAND DisabledExceptions-DefaultHandler "Tests that abort")
|
||||
set_tests_properties(
|
||||
CATCH_CONFIG_DISABLE_EXCEPTIONS-2
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Catch will terminate"
|
||||
)
|
||||
endif(NOT WIN32)
|
||||
|
||||
|
||||
add_test(NAME CATCH_CONFIG_DISABLE_EXCEPTIONS-3 COMMAND DisabledExceptions-CustomHandler "Tests that run")
|
||||
set_tests_properties(
|
||||
CATCH_CONFIG_DISABLE_EXCEPTIONS-3
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "assertions: 4 \| 2 passed \| 2 failed"
|
||||
FAIL_REGULAR_EXPRESSION "====== CUSTOM HANDLER ======"
|
||||
)
|
||||
|
||||
add_test(NAME CATCH_CONFIG_DISABLE_EXCEPTIONS-4 COMMAND DisabledExceptions-CustomHandler "Tests that abort")
|
||||
set_tests_properties(
|
||||
CATCH_CONFIG_DISABLE_EXCEPTIONS-4
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "====== CUSTOM HANDLER ======"
|
||||
)
|
||||
|
||||
|
||||
add_executable(DeferredStaticChecks ${TESTS_DIR}/X05-DeferredStaticChecks.cpp)
|
||||
target_link_libraries(DeferredStaticChecks PRIVATE Catch2WithMain)
|
||||
target_compile_definitions(DeferredStaticChecks PRIVATE "CATCH_CONFIG_RUNTIME_STATIC_REQUIRE")
|
||||
|
||||
add_test(NAME DeferredStaticChecks COMMAND DeferredStaticChecks -r compact)
|
||||
set_tests_properties(
|
||||
DeferredStaticChecks
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "test cases: 1 \\| 1 failed\nassertions: 3 \\| 3 failed"
|
||||
)
|
||||
|
||||
|
||||
add_executable(FallbackStringifier ${TESTS_DIR}/X10-FallbackStringifier.cpp)
|
||||
target_compile_definitions( FallbackStringifier PRIVATE CATCH_CONFIG_FALLBACK_STRINGIFIER=fallbackStringifier )
|
||||
target_link_libraries( FallbackStringifier Catch2WithMain )
|
||||
|
||||
add_test(NAME FallbackStringifier COMMAND FallbackStringifier -r compact -s)
|
||||
set_tests_properties(
|
||||
FallbackStringifier
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "foo{} for: { !!! }"
|
||||
)
|
||||
|
||||
|
||||
add_executable(DisableStringification ${TESTS_DIR}/X11-DisableStringification.cpp)
|
||||
target_compile_definitions( DisableStringification PRIVATE CATCH_CONFIG_DISABLE_STRINGIFICATION )
|
||||
target_link_libraries(DisableStringification Catch2WithMain)
|
||||
add_test(NAME CATCH_CONFIG_DISABLE_STRINGIFICATION COMMAND DisableStringification -r compact -s)
|
||||
set_tests_properties(
|
||||
CATCH_CONFIG_DISABLE_STRINGIFICATION
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
|
||||
FAIL_REGULAR_EXPRESSION "Hidden{} == Hidden{}"
|
||||
)
|
||||
|
||||
|
||||
# This test touches windows.h, so it should only be compiled under msvc
|
||||
if (MSVC)
|
||||
# This test fails if it does not compile and succeeds otherwise
|
||||
add_executable(WindowsHeader ${TESTS_DIR}/X90-WindowsHeaderInclusion.cpp)
|
||||
target_link_libraries( WindowsHeader Catch2WithMain )
|
||||
add_test(NAME WindowsHeader COMMAND WindowsHeader -r compact)
|
||||
list(APPEND CATCH_WARNING_TARGETS ${EXTRA_TEST_BINARIES} WindowsHeader)
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(PartialTestCaseEvents ${TESTS_DIR}/X21-PartialTestCaseEvents.cpp)
|
||||
target_link_libraries(PartialTestCaseEvents PRIVATE Catch2WithMain)
|
||||
add_test(
|
||||
NAME PartialTestCaseEvents
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CATCH_DIR}/tests/TestScripts/testPartialTestCaseEvent.py $<TARGET_FILE:PartialTestCaseEvents>
|
||||
)
|
||||
set_tests_properties(PartialTestCaseEvents
|
||||
PROPERTIES
|
||||
LABELS "uses-python"
|
||||
)
|
||||
|
||||
add_executable(BenchmarksInCumulativeReporter ${TESTS_DIR}/X22-BenchmarksInCumulativeReporter.cpp)
|
||||
target_link_libraries(BenchmarksInCumulativeReporter PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME BenchmarksInCumulativeReporter
|
||||
COMMAND BenchmarksInCumulativeReporter --reporter testReporter
|
||||
)
|
||||
set_tests_properties(
|
||||
BenchmarksInCumulativeReporter
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "1\n2\n3\n4\n5\n"
|
||||
COST 30
|
||||
)
|
||||
|
||||
|
||||
add_executable(CasingInReporterNames ${TESTS_DIR}/X23-CasingInReporterNames.cpp)
|
||||
target_link_libraries(CasingInReporterNames PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME Reporters::registration-is-case-preserving
|
||||
COMMAND CasingInReporterNames --list-reporters
|
||||
)
|
||||
set_tests_properties(
|
||||
Reporters::registration-is-case-preserving
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "testReporterCASED"
|
||||
)
|
||||
add_test(
|
||||
NAME Reporters::selection-is-case-insensitive
|
||||
COMMAND CasingInReporterNames -r testReportercased
|
||||
)
|
||||
set_tests_properties(
|
||||
Reporters::selection-is-case-insensitive
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "TestReporter constructed"
|
||||
)
|
||||
|
||||
add_executable(CapturedStdoutInTestCaseEvents ${TESTS_DIR}/X27-CapturedStdoutInTestCaseEvents.cpp)
|
||||
target_link_libraries(CapturedStdoutInTestCaseEvents PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME Reporters::CapturedStdOutInEvents
|
||||
COMMAND CapturedStdoutInTestCaseEvents
|
||||
--reporter test-reporter
|
||||
)
|
||||
set_tests_properties(
|
||||
Reporters::CapturedStdOutInEvents
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "X27 - TestReporter constructed"
|
||||
FAIL_REGULAR_EXPRESSION "X27 ERROR"
|
||||
)
|
||||
|
||||
|
||||
if (MSVC)
|
||||
set(_NullFile "NUL")
|
||||
else()
|
||||
set(_NullFile "/dev/null")
|
||||
endif()
|
||||
|
||||
add_executable(ListenerStdoutCaptureInMultireporter ${TESTS_DIR}/X24-ListenerStdoutCaptureInMultireporter.cpp)
|
||||
target_link_libraries(ListenerStdoutCaptureInMultireporter PRIVATE Catch2::Catch2WithMain)
|
||||
|
||||
# This test checks that there is nothing written out from the process,
|
||||
# but if CMake is running the tests under Valgrind or similar tool, then
|
||||
# that will write its own output to stdout and the test would fail.
|
||||
if (NOT MEMORYCHECK_COMMAND)
|
||||
add_test(
|
||||
NAME MultiReporter::NoncapturingListenerDoesntCauseStdoutPassThrough
|
||||
COMMAND ListenerStdoutCaptureInMultireporter
|
||||
--reporter xml::out=${_NullFile}
|
||||
--reporter junit::out=${_NullFile}
|
||||
)
|
||||
|
||||
set_tests_properties(
|
||||
MultiReporter::NoncapturingListenerDoesntCauseStdoutPassThrough
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "X24 - NonCapturingListener initialized"
|
||||
FAIL_REGULAR_EXPRESSION "X24 - FooBarBaz"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(ListenerCanAskForCapturedStdout ${TESTS_DIR}/X25-ListenerCanAskForCapturedStdout.cpp)
|
||||
target_link_libraries(ListenerCanAskForCapturedStdout PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME MultiReporter::CapturingListenerCausesStdoutCapture
|
||||
COMMAND ListenerCanAskForCapturedStdout
|
||||
--reporter compact::out=${_NullFile}
|
||||
--reporter console::out=${_NullFile}
|
||||
)
|
||||
set_tests_properties(
|
||||
MultiReporter::CapturingListenerCausesStdoutCapture
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "CapturingListener initialized"
|
||||
FAIL_REGULAR_EXPRESSION "X25 - ERROR"
|
||||
)
|
||||
|
||||
add_executable(ReporterPreferencesForPassingAssertionsIsRespected ${TESTS_DIR}/X26-ReporterPreferencesForPassingAssertionsIsRespected.cpp)
|
||||
target_link_libraries(ReporterPreferencesForPassingAssertionsIsRespected PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME Reporters::PreferencesForPassingAssertionsIsRespected
|
||||
COMMAND ReporterPreferencesForPassingAssertionsIsRespected
|
||||
--reporter test-reporter
|
||||
)
|
||||
set_tests_properties(
|
||||
Reporters::PreferencesForPassingAssertionsIsRespected
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "X26 - TestReporter constructed"
|
||||
FAIL_REGULAR_EXPRESSION "X26 - assertionEnded"
|
||||
)
|
||||
add_test(
|
||||
NAME MultiReporter::PreferencesForPassingAssertionsIsRespected
|
||||
COMMAND ReporterPreferencesForPassingAssertionsIsRespected
|
||||
--reporter test-reporter
|
||||
--reporter console::out=${_NullFile}
|
||||
)
|
||||
set_tests_properties(
|
||||
MultiReporter::PreferencesForPassingAssertionsIsRespected
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "X26 - TestReporter constructed"
|
||||
FAIL_REGULAR_EXPRESSION "X26 - assertionEnded"
|
||||
)
|
||||
|
||||
add_executable(ListenersGetEventsBeforeReporters ${TESTS_DIR}/X28-ListenersGetEventsBeforeReporters.cpp)
|
||||
target_link_libraries(ListenersGetEventsBeforeReporters PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME ListenersGetEventsBeforeReporters
|
||||
COMMAND ListenersGetEventsBeforeReporters --reporter test-reporter
|
||||
)
|
||||
set_tests_properties(
|
||||
ListenersGetEventsBeforeReporters
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "X28 - TestReporter constructed"
|
||||
FAIL_REGULAR_EXPRESSION "X28 - ERROR"
|
||||
)
|
||||
|
||||
add_executable(CustomArgumentsForReporters ${TESTS_DIR}/X29-CustomArgumentsForReporters.cpp)
|
||||
target_link_libraries(CustomArgumentsForReporters PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME CustomArgumentsForReporters
|
||||
COMMAND CustomArgumentsForReporters
|
||||
--reporter "test-reporter::Xa b=c 1::Xz:e = 1234"
|
||||
)
|
||||
set_tests_properties(
|
||||
CustomArgumentsForReporters
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Xa b=c 1::Xz:e = 1234"
|
||||
)
|
||||
|
||||
|
||||
add_executable(DuplicatedTestCases-SameNameAndTags ${TESTS_DIR}/X31-DuplicatedTestCases.cpp)
|
||||
target_link_libraries(DuplicatedTestCases-SameNameAndTags PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME DuplicatedTestCases::SameNameAndTags
|
||||
COMMAND $<TARGET_FILE:DuplicatedTestCases-SameNameAndTags>
|
||||
)
|
||||
set_tests_properties(
|
||||
DuplicatedTestCases::SameNameAndTags
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "error: .* already defined\\."
|
||||
)
|
||||
|
||||
add_executable(DuplicatedTestCases-SameNameDifferentTags ${TESTS_DIR}/X32-DuplicatedTestCasesDifferentTags.cpp)
|
||||
target_link_libraries(DuplicatedTestCases-SameNameDifferentTags PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME DuplicatedTestCases::SameNameDifferentTags
|
||||
COMMAND $<TARGET_FILE:DuplicatedTestCases-SameNameDifferentTags>
|
||||
)
|
||||
set_tests_properties(
|
||||
DuplicatedTestCases::SameNameDifferentTags
|
||||
PROPERTIES
|
||||
FAIL_REGULAR_EXPRESSION "error: .* already defined\\."
|
||||
)
|
||||
|
||||
add_executable(DuplicatedTestCases-DuplicatedTestCaseMethods ${TESTS_DIR}/X33-DuplicatedTestCaseMethods.cpp)
|
||||
target_link_libraries(DuplicatedTestCases-DuplicatedTestCaseMethods PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME DuplicatedTestCases::DuplicatedTestCaseMethods
|
||||
COMMAND $<TARGET_FILE:DuplicatedTestCases-DuplicatedTestCaseMethods>
|
||||
)
|
||||
set_tests_properties(
|
||||
DuplicatedTestCases::DuplicatedTestCaseMethods
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "error: .* already defined\\."
|
||||
)
|
||||
|
||||
add_executable(DuplicatedTestCases-DifferentFixtures ${TESTS_DIR}/X34-DuplicatedTestCaseMethodsDifferentFixtures.cpp)
|
||||
target_link_libraries(DuplicatedTestCases-DifferentFixtures PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME DuplicatedTestCases::DuplicatedTestCaseMethodsDifferentFixtures
|
||||
COMMAND $<TARGET_FILE:DuplicatedTestCases-DifferentFixtures>
|
||||
)
|
||||
set_tests_properties(
|
||||
DuplicatedTestCases::DuplicatedTestCaseMethodsDifferentFixtures
|
||||
PROPERTIES
|
||||
FAIL_REGULAR_EXPRESSION "error: .* already defined\\."
|
||||
)
|
||||
|
||||
|
||||
add_executable(DuplicatedReporters ${TESTS_DIR}/X35-DuplicatedReporterNames.cpp)
|
||||
target_link_libraries(DuplicatedReporters PRIVATE Catch2::Catch2WithMain)
|
||||
add_test(
|
||||
NAME Reporters::RegistrationErrorsAreCaught
|
||||
COMMAND $<TARGET_FILE:DuplicatedReporters>
|
||||
)
|
||||
set_tests_properties(
|
||||
Reporters::RegistrationErrorsAreCaught
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Errors occurred during startup!"
|
||||
)
|
||||
|
||||
|
||||
add_executable(AssertionStartingEventGoesBeforeAssertionIsEvaluated
|
||||
X20-AssertionStartingEventGoesBeforeAssertionIsEvaluated.cpp
|
||||
)
|
||||
target_link_libraries(AssertionStartingEventGoesBeforeAssertionIsEvaluated
|
||||
PRIVATE Catch2::Catch2WithMain
|
||||
)
|
||||
add_test(
|
||||
NAME ReporterEvents::AssertionStartingHappensBeforeAssertionIsEvaluated
|
||||
COMMAND $<TARGET_FILE:AssertionStartingEventGoesBeforeAssertionIsEvaluated>
|
||||
)
|
||||
|
||||
#add_executable(DebugBreakMacros ${TESTS_DIR}/X12-CustomDebugBreakMacro.cpp)
|
||||
#target_link_libraries(DebugBreakMacros Catch2)
|
||||
#add_test(NAME DebugBreakMacros COMMAND DebugBreakMacros --break)
|
||||
#set_tests_properties(
|
||||
# DebugBreakMacros
|
||||
# PROPERTIES
|
||||
# PASS_REGULAR_EXPRESSION "Pretty please, break into debugger"
|
||||
#)
|
||||
|
||||
add_executable(NoTests ${TESTS_DIR}/X92-NoTests.cpp)
|
||||
target_link_libraries(NoTests PRIVATE Catch2::Catch2WithMain)
|
||||
|
||||
add_test(
|
||||
NAME TestSpecs::EmptySpecWithNoTestsFails
|
||||
COMMAND $<TARGET_FILE:NoTests>
|
||||
)
|
||||
set_tests_properties(TestSpecs::EmptySpecWithNoTestsFails
|
||||
PROPERTIES
|
||||
WILL_FAIL ON
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME TestSpecs::OverrideFailureWithEmptySpec
|
||||
COMMAND $<TARGET_FILE:NoTests> --allow-running-no-tests
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME List::Listeners::WorksWithoutRegisteredListeners
|
||||
COMMAND $<TARGET_FILE:NoTests> --list-listeners
|
||||
)
|
||||
|
||||
|
||||
add_executable(AllSkipped ${TESTS_DIR}/X93-AllSkipped.cpp)
|
||||
target_link_libraries(AllSkipped PRIVATE Catch2::Catch2WithMain)
|
||||
|
||||
add_test(
|
||||
NAME TestSpecs::SkippingAllTestsFails
|
||||
COMMAND $<TARGET_FILE:AllSkipped>
|
||||
)
|
||||
set_tests_properties(TestSpecs::SkippingAllTestsFails
|
||||
PROPERTIES
|
||||
WILL_FAIL ON
|
||||
)
|
||||
|
||||
set( EXTRA_TEST_BINARIES
|
||||
AllSkipped
|
||||
PrefixedMacros
|
||||
DisabledMacros
|
||||
DisabledExceptions-DefaultHandler
|
||||
DisabledExceptions-CustomHandler
|
||||
FallbackStringifier
|
||||
DisableStringification
|
||||
PartialTestCaseEvents
|
||||
DuplicatedTestCases-SameNameAndTags
|
||||
DuplicatedTestCases-SameNameDifferentTags
|
||||
DuplicatedTestCases-DuplicatedTestCaseMethods
|
||||
NoTests
|
||||
ListenersGetEventsBeforeReporters
|
||||
# DebugBreakMacros
|
||||
)
|
||||
|
||||
# Notice that we are modifying EXTRA_TEST_BINARIES destructively, do not
|
||||
# use it after this point!
|
||||
list(FILTER EXTRA_TEST_BINARIES EXCLUDE REGEX "DisabledExceptions.*")
|
||||
list(APPEND CATCH_WARNING_TARGETS ${EXTRA_TEST_BINARIES})
|
||||
set(CATCH_WARNING_TARGETS ${CATCH_WARNING_TARGETS} PARENT_SCOPE)
|
||||
|
||||
|
||||
# This sets up a one-off executable that compiles against the amalgamated
|
||||
# files, and then runs it for a super simple check that the amalgamated
|
||||
# files are usable.
|
||||
add_executable(AmalgamatedTestCompilation
|
||||
${TESTS_DIR}/X91-AmalgamatedCatch.cpp
|
||||
${CATCH_DIR}/extras/catch_amalgamated.hpp
|
||||
${CATCH_DIR}/extras/catch_amalgamated.cpp
|
||||
)
|
||||
target_include_directories(AmalgamatedTestCompilation PRIVATE ${CATCH_DIR}/extras)
|
||||
|
||||
add_test(NAME AmalgamatedFileTest COMMAND AmalgamatedTestCompilation)
|
||||
set_tests_properties(
|
||||
AmalgamatedFileTest
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "All tests passed \\(14 assertions in 3 test cases\\)"
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
Configuration options that are left default and thus are not properly tested
|
||||
yet:
|
||||
|
||||
CATCH_CONFIG_COUNTER // Use __COUNTER__ to generate unique names for test cases
|
||||
CATCH_CONFIG_WINDOWS_SEH // Enable SEH handling on Windows
|
||||
CATCH_CONFIG_FAST_COMPILE // Sacrifices some (rather minor) features for compilation speed
|
||||
CATCH_CONFIG_POSIX_SIGNALS // Enable handling POSIX signals
|
||||
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
|
||||
CATCH_CONFIG_DEFAULT_REPORTER
|
||||
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
|
||||
// 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
|
||||
* Test that Catch's prefixed macros compile and run properly.
|
||||
*
|
||||
* We intentionally do not provide full coverage of all macros, but we
|
||||
* test a smattering and can add other ones as they have regressions.
|
||||
*/
|
||||
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace {
|
||||
[[noreturn]]
|
||||
void this_throws() {
|
||||
throw std::runtime_error("Some msg");
|
||||
}
|
||||
void this_doesnt_throw() {}
|
||||
}
|
||||
|
||||
CATCH_TEST_CASE("PrefixedMacros") {
|
||||
using namespace Catch::Matchers;
|
||||
|
||||
CATCH_REQUIRE( 1 == 1 );
|
||||
CATCH_REQUIRE_FALSE( 1 != 1 );
|
||||
|
||||
CATCH_REQUIRE_THROWS(this_throws());
|
||||
CATCH_REQUIRE_THROWS_AS(this_throws(), std::runtime_error);
|
||||
CATCH_REQUIRE_THROWS_WITH(this_throws(), "Some msg");
|
||||
CATCH_REQUIRE_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate<std::runtime_error>([](std::runtime_error const&) { return true; }));
|
||||
CATCH_REQUIRE_NOTHROW(this_doesnt_throw());
|
||||
|
||||
CATCH_CHECK( 1 == 1 );
|
||||
CATCH_CHECK_FALSE( 1 != 1 );
|
||||
CATCH_CHECKED_IF( 1 == 1 ) {
|
||||
CATCH_SUCCEED("don't care");
|
||||
} CATCH_CHECKED_ELSE ( 1 == 1 ) {
|
||||
CATCH_SUCCEED("don't care");
|
||||
}
|
||||
|
||||
CATCH_CHECK_NOFAIL(1 == 2);
|
||||
|
||||
CATCH_CHECK_THROWS(this_throws());
|
||||
CATCH_CHECK_THROWS_AS(this_throws(), std::runtime_error);
|
||||
CATCH_CHECK_THROWS_WITH(this_throws(), "Some msg");
|
||||
CATCH_CHECK_THROWS_MATCHES(this_throws(), std::runtime_error, Predicate<std::runtime_error>([](std::runtime_error const&) { return true; }));
|
||||
CATCH_CHECK_NOTHROW(this_doesnt_throw());
|
||||
|
||||
CATCH_REQUIRE_THAT("abcd", Equals("abcd"));
|
||||
CATCH_CHECK_THAT("bdef", Equals("bdef"));
|
||||
|
||||
CATCH_INFO( "some info" );
|
||||
CATCH_UNSCOPED_INFO( "some info" );
|
||||
CATCH_WARN( "some warn" );
|
||||
CATCH_SECTION("some section") {
|
||||
int i = 1;
|
||||
CATCH_CAPTURE( i );
|
||||
CATCH_CAPTURE( i, i + 1 );
|
||||
CATCH_DYNAMIC_SECTION("Dynamic section: " << i) {
|
||||
CATCH_FAIL_CHECK( "failure" );
|
||||
}
|
||||
}
|
||||
|
||||
CATCH_STATIC_REQUIRE( std::is_void<void>::value );
|
||||
CATCH_STATIC_REQUIRE_FALSE( std::is_void<int>::value );
|
||||
CATCH_STATIC_CHECK( std::is_void<void>::value );
|
||||
CATCH_STATIC_CHECK_FALSE( std::is_void<int>::value );
|
||||
CATCH_FAIL("");
|
||||
}
|
||||
|
||||
// Missing:
|
||||
|
||||
//
|
||||
// #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_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||
//
|
||||
// // "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_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 )
|
||||
//
|
||||
+65
@@ -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
|
||||
|
||||
/**\file
|
||||
* Test that CATCH_CONFIG_DISABLE turns off TEST_CASE autoregistration
|
||||
* and expressions in assertion macros are not run.
|
||||
*/
|
||||
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct foo {
|
||||
foo(){
|
||||
REQUIRE_NOTHROW( print() );
|
||||
}
|
||||
void print() const {
|
||||
std::cout << "This should not happen\n";
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
#endif
|
||||
// Construct foo, but `foo::print` should not be run
|
||||
static foo f;
|
||||
|
||||
|
||||
#if defined(__clang__)
|
||||
// The test is unused since the registration is disabled
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
// This test should not be run, because it won't be registered
|
||||
TEST_CASE( "Disabled Macros" ) {
|
||||
CHECK( 1 == 2 );
|
||||
REQUIRE( 1 == 2 );
|
||||
std::cout << "This should not happen\n";
|
||||
FAIL();
|
||||
|
||||
// Test that static assertions don't fire when macros are disabled
|
||||
STATIC_CHECK( 0 == 1 );
|
||||
STATIC_REQUIRE( !true );
|
||||
|
||||
CAPTURE( 1 );
|
||||
CAPTURE( 1, "captured" );
|
||||
|
||||
REQUIRE_THAT( 1,
|
||||
Catch::Matchers::Predicate( []( int ) { return false; } ) );
|
||||
BENCHMARK( "Disabled benchmark" ) { REQUIRE( 1 == 2 ); };
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
Vendored
+39
@@ -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
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
|
||||
TEST_CASE("Tests that run") {
|
||||
// All of these should be run and be reported
|
||||
CHECK(1 == 2);
|
||||
CHECK(1 == 1);
|
||||
CHECK(1 != 3);
|
||||
CHECK(1 == 4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("Tests that abort") {
|
||||
// Avoid abort and other exceptional exits -- there is no way
|
||||
// to tell CMake that abort is the desired outcome of a test.
|
||||
std::set_terminate([](){exit(1);});
|
||||
REQUIRE(1 == 1);
|
||||
REQUIRE(1 != 2);
|
||||
REQUIRE(1 == 3);
|
||||
// We should not get here, because the test above aborts
|
||||
REQUIRE(1 != 4);
|
||||
}
|
||||
|
||||
TEST_CASE( "Misc. macros to check that they compile without exceptions" ) {
|
||||
BENCHMARK( "simple benchmark" ) { return 1 * 2 + 3; };
|
||||
REQUIRE_THAT( 1,
|
||||
Catch::Matchers::Predicate<int>( []( int i ) { return i == 1; } ) );
|
||||
}
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace Catch {
|
||||
[[noreturn]]
|
||||
void throw_exception(std::exception const& e) {
|
||||
std::cerr << "====== CUSTOM HANDLER ====== run terminates because an exception was thrown.\n"
|
||||
<< "The message was: " << e.what() << '\n';
|
||||
// Avoid abort and other exceptional exits -- there is no way
|
||||
// to tell CMake that abort is the desired outcome of a test.
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Tests that run") {
|
||||
// All of these should be run and be reported
|
||||
CHECK(1 == 2);
|
||||
CHECK(1 == 1);
|
||||
CHECK(1 != 3);
|
||||
CHECK(1 == 4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("Tests that abort") {
|
||||
REQUIRE(1 == 1);
|
||||
REQUIRE(1 != 2);
|
||||
REQUIRE(1 == 3);
|
||||
// We should not get here, because the test above aborts
|
||||
REQUIRE(1 != 4);
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
// 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
|
||||
* Checks that when `STATIC_CHECK` is deferred to runtime and fails, it
|
||||
* does not abort the test case.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE("Deferred static checks") {
|
||||
STATIC_CHECK(1 == 2);
|
||||
STATIC_CHECK_FALSE(1 != 2);
|
||||
// This last assertion must be executed too
|
||||
CHECK(1 == 2);
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
|
||||
// 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
|
||||
* Test that the user can define custom fallbackStringifier
|
||||
*
|
||||
* This is done by defining a custom fallback stringifier that prints
|
||||
* out a specific string, and then asserting (to cause stringification)
|
||||
* over a type without stringification support.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
// A catch-all stringifier
|
||||
template <typename T>
|
||||
std::string fallbackStringifier(T const&) {
|
||||
return "{ !!! }";
|
||||
}
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
struct foo {
|
||||
explicit operator bool() const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("aa") {
|
||||
REQUIRE(foo{});
|
||||
}
|
||||
+27
@@ -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
|
||||
|
||||
/**\file
|
||||
* Test that stringification of original expression can be disabled.
|
||||
*
|
||||
* This is a workaround for VS 2017, 2019 issue with Raw String literals
|
||||
* and preprocessor token pasting.
|
||||
*/
|
||||
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
namespace {
|
||||
struct Hidden {};
|
||||
|
||||
bool operator==(Hidden, Hidden) { return true; }
|
||||
}
|
||||
|
||||
TEST_CASE("DisableStringification") {
|
||||
REQUIRE( Hidden{} == Hidden{} );
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
|
||||
// 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
|
||||
* Test that user-defined `CATCH_BREAK_INTO_DEBUGGER` is respected and used.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void custom_debug_break() {
|
||||
std::cerr << "Pretty please, break into debugger\n";
|
||||
}
|
||||
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() custom_debug_break()
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
TEST_CASE("Failing test that breaks into debugger", "[macros]") {
|
||||
REQUIRE(1 == 2);
|
||||
}
|
||||
+77
@@ -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
|
||||
|
||||
/**\file
|
||||
* Registers an event listener to increments counter of assertionStarting events.
|
||||
*
|
||||
* Different assertion macros then check that the counter is at expected
|
||||
* value when they are evaluated.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/reporters/catch_reporter_event_listener.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
static size_t assertion_starting_events_seen = 0;
|
||||
|
||||
class AssertionStartingListener : public Catch::EventListenerBase {
|
||||
public:
|
||||
AssertionStartingListener( Catch::IConfig const* config ):
|
||||
EventListenerBase( config ) {}
|
||||
|
||||
void assertionStarting( Catch::AssertionInfo const& ) override {
|
||||
++assertion_starting_events_seen;
|
||||
}
|
||||
};
|
||||
|
||||
static bool f1() {
|
||||
return assertion_starting_events_seen == 1;
|
||||
}
|
||||
|
||||
static void f2() {
|
||||
if ( assertion_starting_events_seen != 2 ) { throw 1; }
|
||||
}
|
||||
|
||||
static void f3() {
|
||||
if ( assertion_starting_events_seen == 3 ) { throw 1; }
|
||||
}
|
||||
|
||||
static bool f4() { return assertion_starting_events_seen == 4; }
|
||||
|
||||
static void f5() { throw assertion_starting_events_seen; }
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
CATCH_REGISTER_LISTENER( AssertionStartingListener )
|
||||
|
||||
TEST_CASE() {
|
||||
// **IMPORTANT**
|
||||
// The order of assertions below matters.
|
||||
REQUIRE( f1() );
|
||||
REQUIRE_NOTHROW( f2() );
|
||||
REQUIRE_THROWS( f3() );
|
||||
REQUIRE_THAT( f4(),
|
||||
Catch::Matchers::Predicate<bool>( []( bool b ) { return b; } ) );
|
||||
REQUIRE_THROWS_MATCHES(
|
||||
f5(), size_t, Catch::Matchers::Predicate<size_t>( []( size_t i ) {
|
||||
return i == 5;
|
||||
} ) );
|
||||
|
||||
CAPTURE( assertion_starting_events_seen ); // **not** an assertion
|
||||
INFO( "some info msg" ); // **not** an assertion
|
||||
WARN( "warning! warning!" ); // assertion-like message
|
||||
SUCCEED(); // assertion-like message
|
||||
|
||||
// We skip FAIL/SKIP and so on, which fail the test.
|
||||
|
||||
// This require will also increment the count once
|
||||
REQUIRE( assertion_starting_events_seen == 8 );
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
|
||||
// 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
|
||||
* Registers custom reporter that reports testCase* events
|
||||
*
|
||||
* The resulting executable can then be used by an external Python script
|
||||
* to verify that testCase{Starting,Ended} and testCasePartial{Starting,Ended}
|
||||
* events are properly nested.
|
||||
*/
|
||||
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/reporters/catch_reporter_streaming_base.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using Catch::TestCaseInfo;
|
||||
using Catch::TestCaseStats;
|
||||
|
||||
class PartialReporter : public Catch::StreamingReporterBase {
|
||||
public:
|
||||
using StreamingReporterBase::StreamingReporterBase;
|
||||
|
||||
~PartialReporter() override; // = default
|
||||
|
||||
static std::string getDescription() {
|
||||
return "Special reporter for testing TestCasePartialStarting/Ended events";
|
||||
}
|
||||
|
||||
//! Called _once_ for each TEST_CASE, no matter how many times it is entered
|
||||
void testCaseStarting(TestCaseInfo const& testInfo) override {
|
||||
std::cout << "TestCaseStarting: " << testInfo.name << '\n';
|
||||
}
|
||||
//! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
|
||||
void testCasePartialStarting(TestCaseInfo const& testInfo, uint64_t partNumber) override {
|
||||
std::cout << "TestCaseStartingPartial: " << testInfo.name << '#' << partNumber << '\n';
|
||||
}
|
||||
|
||||
|
||||
//! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
|
||||
void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber) override {
|
||||
std::cout << "TestCasePartialEnded: " << testCaseStats.testInfo->name << '#' << partNumber << '\n';
|
||||
}
|
||||
//! Called _once_ for each TEST_CASE, no matter how many times it is entered
|
||||
void testCaseEnded(TestCaseStats const& testCaseStats) override {
|
||||
std::cout << "TestCaseEnded: " << testCaseStats.testInfo->name << '\n';
|
||||
}
|
||||
};
|
||||
PartialReporter::~PartialReporter() = default;
|
||||
|
||||
|
||||
CATCH_REGISTER_REPORTER("partial", PartialReporter)
|
||||
|
||||
TEST_CASE("section") {
|
||||
SECTION("A") {}
|
||||
SECTION("B") {}
|
||||
SECTION("C") {}
|
||||
SECTION("D") {}
|
||||
}
|
||||
|
||||
TEST_CASE("generator") {
|
||||
auto _ = GENERATE(1, 2, 3, 4);
|
||||
(void)_;
|
||||
}
|
||||
Vendored
+79
@@ -0,0 +1,79 @@
|
||||
|
||||
// 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
|
||||
* Test that the cumulative reporter base stores both assertions and
|
||||
* benchmarks, and stores them in the right order.
|
||||
*
|
||||
* This is done through a custom reporter that writes out the assertions
|
||||
* and benchmarks and checking that the output is in right order.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/reporters/catch_reporter_cumulative_base.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
class CumulativeBenchmarkReporter final : public Catch::CumulativeReporterBase {
|
||||
|
||||
public:
|
||||
CumulativeBenchmarkReporter(Catch::ReporterConfig&& _config) :
|
||||
CumulativeReporterBase(std::move(_config)) {
|
||||
m_preferences.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
static std::string getDescription() {
|
||||
return "Custom reporter for testing cumulative reporter base";
|
||||
}
|
||||
|
||||
virtual void testRunEndedCumulative() override;
|
||||
};
|
||||
|
||||
CATCH_REGISTER_REPORTER("testReporter", CumulativeBenchmarkReporter)
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
TEST_CASE("Some assertions and benchmarks") {
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
REQUIRE(1);
|
||||
BENCHMARK("2") {
|
||||
std::this_thread::sleep_for(1ms);
|
||||
};
|
||||
REQUIRE(3);
|
||||
BENCHMARK("4") {
|
||||
std::this_thread::sleep_for(1ms);
|
||||
};
|
||||
REQUIRE(5);
|
||||
}
|
||||
|
||||
void CumulativeBenchmarkReporter::testRunEndedCumulative() {
|
||||
auto const& testCases = m_testRun->children;
|
||||
assert(testCases.size() == 1);
|
||||
|
||||
auto const& testCase = *testCases.front();
|
||||
auto const& sections = testCase.children;
|
||||
assert(sections.size() == 1);
|
||||
|
||||
auto const& section = *sections.front();
|
||||
assert(section.childSections.empty());
|
||||
for (auto const& aob : section.assertionsAndBenchmarks) {
|
||||
if (aob.isAssertion()) {
|
||||
auto const& assertion = aob.asAssertion();
|
||||
std::cout << assertion.assertionResult.getExpandedExpression() << '\n';
|
||||
}
|
||||
if (aob.isBenchmark()) {
|
||||
auto const& bench = aob.asBenchmark();
|
||||
std::cout << bench.info.name << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -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
|
||||
|
||||
/**\file
|
||||
* Test that reporter registration is case-preserving, selection is
|
||||
* case-insensitive.
|
||||
*
|
||||
* This is done by registering a custom reporter that prints out a marker
|
||||
* string upon construction and then invoking the binary with different
|
||||
* casings of the name.
|
||||
*/
|
||||
|
||||
#include <catch2/reporters/catch_reporter_streaming_base.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
class TestReporter : public Catch::StreamingReporterBase {
|
||||
public:
|
||||
TestReporter(Catch::ReporterConfig&& _config):
|
||||
StreamingReporterBase(std::move(_config)) {
|
||||
std::cout << "TestReporter constructed\n";
|
||||
}
|
||||
|
||||
static std::string getDescription() {
|
||||
return "Reporter for testing casing handling in reporter registration/selection";
|
||||
}
|
||||
|
||||
~TestReporter() override;
|
||||
};
|
||||
|
||||
TestReporter::~TestReporter() = default;
|
||||
|
||||
CATCH_REGISTER_REPORTER("testReporterCASED", TestReporter)
|
||||
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
|
||||
// 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
|
||||
* Registers custom listener that does not ask for captured stdout/err
|
||||
*
|
||||
* Running the binary with this listener, and asking for multiple _capturing_
|
||||
* reporters (one would be sufficient, but that would also mean depending on
|
||||
* implementation details inside Catch2's handling of listeners), we check that
|
||||
* nothing is written to stdout, because listeners should not be considered in
|
||||
* whether the stdout should be passed-through or not.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/reporters/catch_reporter_event_listener.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
class NonCapturingListener : public Catch::EventListenerBase {
|
||||
public:
|
||||
NonCapturingListener( Catch::IConfig const* config ):
|
||||
EventListenerBase( config ) {
|
||||
m_preferences.shouldRedirectStdOut = false;
|
||||
std::cerr << "X24 - NonCapturingListener initialized.\n";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CATCH_REGISTER_LISTENER( NonCapturingListener )
|
||||
|
||||
TEST_CASE( "Writes to stdout" ) {
|
||||
std::cout << "X24 - FooBarBaz\n";
|
||||
}
|
||||
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
|
||||
// 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
|
||||
* Registers custom listener that asks for captured stdout/err
|
||||
*
|
||||
* Running the binary with this listener, and asking for multiple _noncapturing_
|
||||
* reporters (one would be sufficient, but that would also mean depending on
|
||||
* implementation details inside Catch2's handling of listeners), we check that
|
||||
* the listener gets redirected stdout, even though the reporters didn't ask for
|
||||
* it.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/reporters/catch_reporter_event_listener.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
class CapturingListener : public Catch::EventListenerBase {
|
||||
public:
|
||||
CapturingListener( Catch::IConfig const* config ):
|
||||
EventListenerBase( config ) {
|
||||
m_preferences.shouldRedirectStdOut = true;
|
||||
std::cerr << "CapturingListener initialized\n";
|
||||
}
|
||||
|
||||
void
|
||||
testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override {
|
||||
if ( testCaseStats.stdOut.empty() ) {
|
||||
std::cerr << "X25 - ERROR: empty stdout\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CATCH_REGISTER_LISTENER( CapturingListener )
|
||||
|
||||
TEST_CASE( "Writes to stdout" ) {
|
||||
std::cout << "X25 - FooBarBaz\n";
|
||||
}
|
||||
+52
@@ -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
|
||||
|
||||
/**\file
|
||||
* Test that reporter is not passed passing assertions when it
|
||||
* doesn't ask for it.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/reporters/catch_reporter_streaming_base.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
|
||||
class TestReporter : public Catch::StreamingReporterBase {
|
||||
public:
|
||||
TestReporter(Catch::ReporterConfig&& _config):
|
||||
StreamingReporterBase(std::move(_config)) {
|
||||
m_preferences.shouldReportAllAssertions = false;
|
||||
std::cout << "X26 - TestReporter constructed\n";
|
||||
}
|
||||
|
||||
static std::string getDescription() {
|
||||
return "X26 - test reporter that opts out of passing assertions";
|
||||
}
|
||||
|
||||
void
|
||||
assertionEnded( Catch::AssertionStats const& ) override {
|
||||
std::cerr << "X26 - assertionEnded\n";
|
||||
}
|
||||
|
||||
~TestReporter() override;
|
||||
};
|
||||
|
||||
TestReporter::~TestReporter() = default;
|
||||
|
||||
}
|
||||
|
||||
CATCH_REGISTER_REPORTER("test-reporter", TestReporter)
|
||||
|
||||
TEST_CASE( "Test with only passing assertions" ) {
|
||||
REQUIRE( 1 == 1 );
|
||||
REQUIRE( 2 == 2 );
|
||||
}
|
||||
Vendored
+82
@@ -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
|
||||
|
||||
/**\file
|
||||
* Test that the captured stdout/err in (partial) testCaseEnded events
|
||||
* is correct (e.g. that the partial test case event does not get accumulated
|
||||
* output).
|
||||
*
|
||||
* This is done by having a single test case that is entered multiple
|
||||
* times through generator, and a custom capturing reporter that knows
|
||||
* what it should expect captured from the test case.
|
||||
*/
|
||||
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
#include <catch2/reporters/catch_reporter_streaming_base.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
class TestReporter : public Catch::StreamingReporterBase {
|
||||
std::string stdOutString( uint64_t iter ){
|
||||
return "stdout " + std::to_string( iter ) + '\n';
|
||||
}
|
||||
std::string stdErrString(uint64_t iter) {
|
||||
return "stderr " + std::to_string( iter ) + '\n';
|
||||
}
|
||||
|
||||
public:
|
||||
TestReporter( Catch::ReporterConfig&& _config ):
|
||||
StreamingReporterBase( std::move(_config) ) {
|
||||
m_preferences.shouldRedirectStdOut = true;
|
||||
std::cout << "X27 - TestReporter constructed\n";
|
||||
}
|
||||
|
||||
static std::string getDescription() {
|
||||
return "X27 test reporter";
|
||||
}
|
||||
|
||||
void testCasePartialEnded( Catch::TestCaseStats const& stats,
|
||||
uint64_t iter ) override {
|
||||
if ( stats.stdOut != stdOutString( iter ) ) {
|
||||
std::cerr << "X27 ERROR in partial stdout\n" << stats.stdOut;
|
||||
}
|
||||
if ( stats.stdErr != stdErrString( iter ) ) {
|
||||
std::cerr << "X27 ERROR in partial stderr\n" << stats.stdErr;
|
||||
}
|
||||
}
|
||||
|
||||
void testCaseEnded( Catch::TestCaseStats const& stats ) override {
|
||||
if ( stats.stdOut != "stdout 0\nstdout 1\nstdout 2\nstdout 3\nstdout 4\nstdout 5\n" ) {
|
||||
std::cerr << "X27 ERROR in full stdout\n" << stats.stdOut;
|
||||
}
|
||||
if ( stats.stdErr != "stderr 0\nstderr 1\nstderr 2\nstderr 3\nstderr 4\nstderr 5\n" ) {
|
||||
std::cerr << "X27 ERROR in full stderr\n" << stats.stdErr;
|
||||
}
|
||||
}
|
||||
|
||||
~TestReporter() override;
|
||||
};
|
||||
|
||||
TestReporter::~TestReporter() = default;
|
||||
|
||||
CATCH_REGISTER_REPORTER( "test-reporter", TestReporter )
|
||||
|
||||
TEST_CASE( "repeatedly entered test case" ) {
|
||||
auto i = GENERATE( range(0, 6) );
|
||||
std::cout << "stdout " << i << '\n';
|
||||
// Switch between writing to std::cerr and std::clog just to make sure
|
||||
// both are properly captured and redirected.
|
||||
( ( i % 2 == 0 ) ? std::cerr : std::clog ) << "stderr " << i << '\n';
|
||||
}
|
||||
Vendored
+99
@@ -0,0 +1,99 @@
|
||||
|
||||
// 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
|
||||
* Test that the different events are sent to listeners before they are
|
||||
* sent to the reporters.
|
||||
*
|
||||
* We only do this for a subset of the events, as doing all of them would
|
||||
* be annoying, and we can assume that their implementation is roughly
|
||||
* the same, and thus if few work, all work.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/reporters/catch_reporter_event_listener.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
#include <catch2/reporters/catch_reporter_streaming_base.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
|
||||
static bool testRunStartingReceivedByListener = false;
|
||||
static bool testRunEndedReceivedByListener = false;
|
||||
static bool assertionStartingReceivedByListener = false;
|
||||
static bool assertionEndedReceivedByListener = false;
|
||||
|
||||
class TestListener : public Catch::EventListenerBase {
|
||||
public:
|
||||
TestListener( Catch::IConfig const* config ):
|
||||
EventListenerBase( config ) {
|
||||
std::cout << "X28 - TestListener constructed.\n";
|
||||
}
|
||||
|
||||
void testRunStarting( Catch::TestRunInfo const& ) override {
|
||||
testRunStartingReceivedByListener = true;
|
||||
}
|
||||
|
||||
void testRunEnded( Catch::TestRunStats const& ) override {
|
||||
testRunEndedReceivedByListener = true;
|
||||
}
|
||||
|
||||
void assertionStarting( Catch::AssertionInfo const& ) override {
|
||||
assertionStartingReceivedByListener = true;
|
||||
}
|
||||
|
||||
void assertionEnded( Catch::AssertionStats const& ) override {
|
||||
assertionEndedReceivedByListener = true;
|
||||
}
|
||||
};
|
||||
|
||||
class TestReporter : public Catch::StreamingReporterBase {
|
||||
public:
|
||||
TestReporter( Catch::ReporterConfig&& _config ):
|
||||
StreamingReporterBase( std::move(_config) ) {
|
||||
std::cout << "X28 - TestReporter constructed\n";
|
||||
}
|
||||
|
||||
void testRunStarting( Catch::TestRunInfo const& ) override {
|
||||
if ( !testRunStartingReceivedByListener ) {
|
||||
std::cout << "X28 - ERROR\n";
|
||||
}
|
||||
}
|
||||
|
||||
void testRunEnded( Catch::TestRunStats const& ) override {
|
||||
if ( !testRunEndedReceivedByListener ) {
|
||||
std::cout << "X28 - ERROR\n";
|
||||
}
|
||||
}
|
||||
|
||||
void assertionStarting( Catch::AssertionInfo const& ) override {
|
||||
if ( !assertionStartingReceivedByListener ) {
|
||||
std::cout << "X28 - ERROR\n";
|
||||
}
|
||||
}
|
||||
|
||||
void assertionEnded( Catch::AssertionStats const& ) override {
|
||||
if ( !assertionEndedReceivedByListener ) {
|
||||
std::cout << "X28 - ERROR\n";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getDescription() { return "X28 test reporter"; }
|
||||
~TestReporter() override;
|
||||
};
|
||||
|
||||
TestReporter::~TestReporter() = default;
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
CATCH_REGISTER_REPORTER( "test-reporter", TestReporter )
|
||||
CATCH_REGISTER_LISTENER( TestListener )
|
||||
|
||||
TEST_CASE( "Dummy test case" ) { REQUIRE( 1 == 1 ); }
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
|
||||
// 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
|
||||
* Test that custom options are properly passed down to the reporter.
|
||||
*
|
||||
* We print out the arguments sorted by key, to have a stable expected
|
||||
* output.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/reporters/catch_reporter_streaming_base.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class TestReporter : public Catch::StreamingReporterBase {
|
||||
public:
|
||||
TestReporter( Catch::ReporterConfig&& _config ):
|
||||
StreamingReporterBase( std::move(_config) ) {
|
||||
std::cout << "X29 - TestReporter constructed\n";
|
||||
}
|
||||
|
||||
static std::string getDescription() {
|
||||
return "X29 test reporter";
|
||||
}
|
||||
|
||||
void testRunStarting( Catch::TestRunInfo const& ) override {
|
||||
std::vector<std::pair<std::string, std::string>> options;
|
||||
for ( auto const& kv : m_customOptions ) {
|
||||
options.push_back( kv );
|
||||
}
|
||||
std::sort( options.begin(), options.end() );
|
||||
bool first = true;
|
||||
for ( auto const& kv : options ) {
|
||||
if ( !first ) { std::cout << "::"; }
|
||||
std::cout << kv.first << "=" << kv.second;
|
||||
first = false;
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
~TestReporter() override;
|
||||
};
|
||||
|
||||
TestReporter::~TestReporter() = default;
|
||||
|
||||
CATCH_REGISTER_REPORTER( "test-reporter", TestReporter )
|
||||
|
||||
TEST_CASE( "Just a test case to run things" ) {}
|
||||
@@ -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
|
||||
|
||||
/**\file
|
||||
* Test the Bazel report functionality with a simple set
|
||||
* of dummy test cases.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE( "Passing test case" ) { REQUIRE( 1 == 1 ); }
|
||||
TEST_CASE( "Failing test case" ) { REQUIRE( 2 == 1 ); }
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
|
||||
// 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
|
||||
* Checks that test cases with identical name and tags are reported as error
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE("A test case with duplicated name and tags", "[tag1][tag2]") {}
|
||||
TEST_CASE("A test case with duplicated name and tags", "[tag1][tag2]") {}
|
||||
Vendored
+17
@@ -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
|
||||
|
||||
/**\file
|
||||
* Checks that test cases with identical name but different tags are
|
||||
* not reported as an error.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE("A test case with duplicated name but different tags", "[tag1]") {}
|
||||
TEST_CASE("A test case with duplicated name but different tags", "[tag2]") {}
|
||||
+22
@@ -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
|
||||
|
||||
/**\file
|
||||
* Checks that test case methods with identical class, name and tags are
|
||||
* reported as error.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
class TestCaseFixture {
|
||||
public:
|
||||
int m_a;
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TestCaseFixture, "A test case with duplicated name and tags", "[tag1]") {}
|
||||
TEST_CASE_METHOD(TestCaseFixture, "A test case with duplicated name and tags", "[tag1]") {}
|
||||
+27
@@ -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
|
||||
|
||||
/**\file
|
||||
* Checks that test case methods with different class, but same name and
|
||||
* tags name and tags are not reported as error.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
class TestCaseFixture1 {
|
||||
public:
|
||||
int m_a;
|
||||
};
|
||||
|
||||
class TestCaseFixture2 {
|
||||
public:
|
||||
int m_a;
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(TestCaseFixture1, "A test case with duplicated name and tags", "[tag1]") {}
|
||||
TEST_CASE_METHOD(TestCaseFixture2, "A test case with duplicated name and tags", "[tag1]") {}
|
||||
+31
@@ -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
|
||||
|
||||
/**\file
|
||||
* Checks that reporter registration errors are caught and handled as
|
||||
* startup errors, by causing a registration error by registering multiple
|
||||
* reporters with the same name.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
#include <catch2/reporters/catch_reporter_streaming_base.hpp>
|
||||
|
||||
namespace {
|
||||
//! Trivial custom reporter for registration
|
||||
class TestReporter : public Catch::StreamingReporterBase {
|
||||
public:
|
||||
using StreamingReporterBase::StreamingReporterBase;
|
||||
|
||||
static std::string getDescription() { return "X35 test reporter"; }
|
||||
};
|
||||
}
|
||||
|
||||
CATCH_REGISTER_REPORTER( "test-reporter", TestReporter )
|
||||
CATCH_REGISTER_REPORTER( "test-reporter", TestReporter )
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
// 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
|
||||
* Test that the Catch2 header compiles even after including windows.h
|
||||
* without defining NOMINMAX first.
|
||||
*
|
||||
* As an FYI, if you do that, you are wrong.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE("Catch2 did survive compilation with windows.h", "[compile-test]") {
|
||||
SUCCEED();
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
|
||||
// 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 file serves as a simple compilation test against the amalgamated
|
||||
* version of Catch2.
|
||||
*/
|
||||
|
||||
#include "catch_amalgamated.hpp"
|
||||
|
||||
TEST_CASE("Just a dummy test") {
|
||||
auto i = GENERATE(1, 2, 3);
|
||||
SECTION("a") {
|
||||
REQUIRE(1 != 4);
|
||||
}
|
||||
SECTION("b") {
|
||||
CHECK(1 != 5);
|
||||
}
|
||||
REQUIRE_THAT(1,
|
||||
Catch::Matchers::Predicate<int>([](int i) {
|
||||
return i % 2 == 1;
|
||||
}));
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE("Trivial template test case", "", char, short) {
|
||||
STATIC_REQUIRE(sizeof(TestType) <= sizeof(int));
|
||||
}
|
||||
|
||||
TEST_CASE("Benchmark test", "[!benchmark]") {
|
||||
BENCHMARK("Allocation benchmark") {
|
||||
return std::vector<int>(10);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
// 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
|
||||
* Links into executable with no tests which should fail when run
|
||||
*/
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
|
||||
TEST_CASE( "this test case is being skipped" ) { SKIP(); }
|
||||
|
||||
TEST_CASE( "all sections in this test case are being skipped" ) {
|
||||
SECTION( "A" ) { SKIP(); }
|
||||
SECTION( "B" ) { SKIP(); }
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
:test-result: PASS # A test name that starts with a #
|
||||
:test-result: PASS #542
|
||||
:test-result: PASS #809
|
||||
:test-result: FAIL 'Not' checks that should fail
|
||||
:test-result: PASS 'Not' checks that should succeed
|
||||
:test-result: PASS (unimplemented) static bools can be evaluated
|
||||
:test-result: FAIL A METHOD_AS_TEST_CASE based test run that fails
|
||||
:test-result: PASS A METHOD_AS_TEST_CASE based test run that succeeds
|
||||
:test-result: FAIL A TEST_CASE_METHOD based test run that fails
|
||||
:test-result: PASS A TEST_CASE_METHOD based test run that succeeds
|
||||
:test-result: FAIL A couple of nested sections followed by a failure
|
||||
:test-result: FAIL A failing expression with a non streamable type is still captured
|
||||
:test-result: PASS AllOf matcher
|
||||
:test-result: PASS An empty test with no assertions
|
||||
:test-result: PASS An expression with side-effects should only be evaluated once
|
||||
:test-result: FAIL An unchecked exception reports the line of the last assertion
|
||||
:test-result: PASS Anonymous test case 1
|
||||
:test-result: PASS AnyOf matcher
|
||||
:test-result: PASS Approximate PI
|
||||
:test-result: PASS Approximate comparisons with different epsilons
|
||||
:test-result: PASS Approximate comparisons with floats
|
||||
:test-result: PASS Approximate comparisons with ints
|
||||
:test-result: PASS Approximate comparisons with mixed numeric types
|
||||
:test-result: PASS Assertions then sections
|
||||
:test-result: PASS Character pretty printing
|
||||
:test-result: PASS Comparing function pointers
|
||||
:test-result: PASS Comparing member function pointers
|
||||
:test-result: PASS Comparisons between ints where one side is computed
|
||||
:test-result: PASS Comparisons between unsigned ints and negative signed ints match c++ standard behaviour
|
||||
:test-result: PASS Comparisons with int literals don't warn when mixing signed/ unsigned
|
||||
:test-result: FAIL Contains string matcher
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for nothrow
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for throwing as something else
|
||||
:test-result: FAIL Custom std-exceptions can be custom translated
|
||||
:test-result: PASS Demonstrate that a non-const == is not used
|
||||
:test-result: FAIL EndsWith string matcher
|
||||
:test-result: XFAIL Equality checks that should fail
|
||||
:test-result: PASS Equality checks that should succeed
|
||||
:test-result: PASS Equals
|
||||
:test-result: FAIL Equals string matcher
|
||||
:test-result: PASS Exception messages can be tested for
|
||||
:test-result: FAIL Expected exceptions that don't throw or unexpected exceptions fail the test
|
||||
:test-result: FAIL FAIL aborts the test
|
||||
:test-result: FAIL FAIL does not require an argument
|
||||
:test-result: PASS Factorials are computed
|
||||
:test-result: PASS Generator over a range of pairs
|
||||
:test-result: PASS Generators over two ranges
|
||||
:test-result: PASS Greater-than inequalities with different epsilons
|
||||
:test-result: PASS INFO and WARN do not abort tests
|
||||
:test-result: FAIL INFO gets logged on failure
|
||||
:test-result: FAIL INFO gets logged on failure, even if captured before successful assertions
|
||||
:test-result: XFAIL Inequality checks that should fail
|
||||
:test-result: PASS Inequality checks that should succeed
|
||||
:test-result: PASS Less-than inequalities with different epsilons
|
||||
:test-result: PASS Long strings can be wrapped
|
||||
:test-result: PASS Long text is truncated
|
||||
:test-result: PASS ManuallyRegistered
|
||||
:test-result: PASS Matchers can be (AllOf) composed with the && operator
|
||||
:test-result: PASS Matchers can be (AnyOf) composed with the || operator
|
||||
:test-result: PASS Matchers can be composed with both && and ||
|
||||
:test-result: FAIL Matchers can be composed with both && and || - failing
|
||||
:test-result: PASS Matchers can be negated (Not) with the ! operator
|
||||
:test-result: FAIL Matchers can be negated (Not) with the ! operator - failing
|
||||
:test-result: FAIL Mismatching exception messages failing the test
|
||||
:test-result: PASS Nice descriptive name
|
||||
:test-result: FAIL Non-std exceptions can be translated
|
||||
:test-result: PASS NotImplemented exception
|
||||
:test-result: PASS Objects that evaluated in boolean contexts can be checked
|
||||
:test-result: PASS Operators at different namespace levels not hijacked by Koenig lookup
|
||||
:test-result: FAIL Ordering comparison checks that should fail
|
||||
:test-result: PASS Ordering comparison checks that should succeed
|
||||
:test-result: FAIL Output from all sections is reported
|
||||
:test-result: PASS Parse test names and tags
|
||||
:test-result: PASS Parsing a std::pair
|
||||
:test-result: PASS Pointers can be compared to null
|
||||
:test-result: PASS Pointers can be converted to strings
|
||||
:test-result: PASS Process can be configured on command line
|
||||
:test-result: FAIL SCOPED_INFO is reset for each loop
|
||||
:test-result: PASS SUCCEED counts as a test pass
|
||||
:test-result: PASS SUCCESS does not require an argument
|
||||
:test-result: PASS Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods
|
||||
:test-result: PASS Scenario: Do that thing with the thing
|
||||
:test-result: PASS Scenario: This is a really long scenario name to see how the list command deals with wrapping
|
||||
:test-result: PASS Scenario: Vector resizing affects size and capacity
|
||||
A string sent directly to stdout
|
||||
A string sent directly to stderr
|
||||
:test-result: PASS Sends stuff to stdout and stderr
|
||||
:test-result: PASS Some simple comparisons between doubles
|
||||
Message from section one
|
||||
Message from section two
|
||||
:test-result: PASS Standard output from all sections is reported
|
||||
:test-result: FAIL StartsWith string matcher
|
||||
:test-result: PASS String matchers
|
||||
hello
|
||||
hello
|
||||
:test-result: PASS Strings can be rendered with colour
|
||||
:test-result: FAIL Tabs and newlines show in output
|
||||
:test-result: PASS Tag alias can be registered against tag patterns
|
||||
:test-result: PASS Test case with one argument
|
||||
:test-result: PASS Test enum bit values
|
||||
:test-result: PASS Text can be formatted using the Text class
|
||||
:test-result: PASS The NO_FAIL macro reports a failure but does not fail the test
|
||||
:test-result: FAIL This test 'should' fail but doesn't
|
||||
:test-result: PASS Tracker
|
||||
:test-result: FAIL Unexpected exceptions can be translated
|
||||
:test-result: PASS Use a custom approx
|
||||
:test-result: PASS Variadic macros
|
||||
:test-result: PASS When checked exceptions are thrown they can be expected or unexpected
|
||||
:test-result: FAIL When unchecked exceptions are thrown directly they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a CHECK the test should continue
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a REQUIRE the test should abort fail
|
||||
:test-result: FAIL When unchecked exceptions are thrown from functions they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown from sections they are always failures
|
||||
:test-result: PASS When unchecked exceptions are thrown, but caught, they do not affect the test
|
||||
:test-result: PASS Where the LHS is not a simple value
|
||||
:test-result: PASS Where there is more to the expression after the RHS
|
||||
:test-result: PASS X/level/0/a
|
||||
:test-result: PASS X/level/0/b
|
||||
:test-result: PASS X/level/1/a
|
||||
:test-result: PASS X/level/1/b
|
||||
:test-result: PASS XmlEncode
|
||||
:test-result: PASS atomic if
|
||||
:test-result: PASS boolean member
|
||||
:test-result: PASS checkedElse
|
||||
:test-result: FAIL checkedElse, failing
|
||||
:test-result: PASS checkedIf
|
||||
:test-result: FAIL checkedIf, failing
|
||||
:test-result: PASS comparisons between const int variables
|
||||
:test-result: PASS comparisons between int variables
|
||||
:test-result: PASS even more nested SECTION tests
|
||||
:test-result: PASS first tag
|
||||
spanner:test-result: PASS has printf
|
||||
:test-result: FAIL just failure
|
||||
:test-result: PASS just info
|
||||
:test-result: FAIL looped SECTION tests
|
||||
:test-result: FAIL looped tests
|
||||
:test-result: FAIL more nested SECTION tests
|
||||
:test-result: PASS nested SECTION tests
|
||||
:test-result: PASS non streamable - with conv. op
|
||||
:test-result: PASS not allowed
|
||||
:test-result: PASS null strings
|
||||
:test-result: PASS pair<pair<int,const char *,pair<std::string,int> > -> toString
|
||||
:test-result: PASS pointer to class
|
||||
:test-result: PASS random SECTION tests
|
||||
:test-result: PASS replaceInPlace
|
||||
:test-result: PASS second tag
|
||||
:test-result: FAIL send a single char to INFO
|
||||
:test-result: FAIL sends information to INFO
|
||||
:test-result: PASS std::pair<int,const std::string> -> toString
|
||||
:test-result: PASS std::pair<int,std::string> -> toString
|
||||
:test-result: PASS std::vector<std::pair<std::string,int> > -> toString
|
||||
:test-result: FAIL string literals of different sizes can be compared
|
||||
:test-result: PASS toString on const wchar_t const pointer returns the string contents
|
||||
:test-result: PASS toString on const wchar_t pointer returns the string contents
|
||||
:test-result: PASS toString on wchar_t const pointer returns the string contents
|
||||
:test-result: PASS toString on wchar_t returns the string contents
|
||||
:test-result: PASS toString( has_maker )
|
||||
:test-result: PASS toString( has_maker_and_toString )
|
||||
:test-result: PASS toString( has_toString )
|
||||
:test-result: PASS toString( vectors<has_maker )
|
||||
:test-result: SKIP toString( vectors<has_maker_and_toString )
|
||||
:test-result: SKIP toString( vectors<has_toString )
|
||||
:test-result: PASS toString(enum w/operator<<)
|
||||
:test-result: PASS toString(enum)
|
||||
:test-result: PASS vector<int> -> toString
|
||||
:test-result: PASS vector<string> -> toString
|
||||
:test-result: PASS vectors can be sized and resized
|
||||
:test-result: PASS xmlentitycheck
|
||||
+428
@@ -0,0 +1,428 @@
|
||||
:test-result: PASS # A test name that starts with a #
|
||||
:test-result: PASS #1027: Bitfields can be captured
|
||||
:test-result: PASS #1147
|
||||
:test-result: PASS #1175 - Hidden Test
|
||||
:test-result: PASS #1238
|
||||
:test-result: PASS #1245
|
||||
:test-result: PASS #1319: Sections can have description (even if it is not saved
|
||||
:test-result: PASS #1403
|
||||
:test-result: FAIL #1455 - INFO and WARN can start with a linebreak
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
:test-result: FAIL #1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
:test-result: PASS #1548
|
||||
:test-result: PASS #1905 -- test spec parser properly clears internal state between compound tests
|
||||
:test-result: PASS #1912 -- test spec parser handles escaping
|
||||
:test-result: PASS #1913 - GENERATE inside a for loop should not keep recreating the generator
|
||||
:test-result: PASS #1913 - GENERATEs can share a line
|
||||
:test-result: PASS #1938 - GENERATE after a section
|
||||
:test-result: PASS #1938 - Section followed by flat generate
|
||||
:test-result: PASS #1938 - flat generate
|
||||
:test-result: PASS #1938 - mixed sections and generates
|
||||
:test-result: PASS #1938 - nested generate
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0
|
||||
:test-result: PASS #2152 - ULP checks between differently signed values were wrong - double
|
||||
:test-result: PASS #2152 - ULP checks between differently signed values were wrong - float
|
||||
:test-result: XFAIL #2615 - Throwing in constructor generator fails test case but does not abort
|
||||
:test-result: XFAIL #748 - captures with unexpected exceptions
|
||||
:test-result: PASS #809
|
||||
:test-result: PASS #833
|
||||
:test-result: XFAIL #835 -- errno should not be touched by Catch2
|
||||
:test-result: PASS #872
|
||||
:test-result: PASS #961 -- Dynamically created sections should all be reported
|
||||
:test-result: FAIL 'Not' checks that should fail
|
||||
:test-result: PASS 'Not' checks that should succeed
|
||||
:test-result: PASS (unimplemented) static bools can be evaluated
|
||||
:test-result: PASS 3x3x3 ints
|
||||
:test-result: FAIL A METHOD_AS_TEST_CASE based test run that fails
|
||||
:test-result: PASS A METHOD_AS_TEST_CASE based test run that succeeds
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<float>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<int>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<float>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<int>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<float>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<int>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<float>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<int>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2<float, 6>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2<int, 2>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array<float, 6>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array<int, 2>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2<float,6>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2<int,2>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array<float,6>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array<int,2>
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - double
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - float
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - int
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - float
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - int
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6
|
||||
:test-result: FAIL A TEST_CASE_METHOD based test run that fails
|
||||
:test-result: PASS A TEST_CASE_METHOD based test run that succeeds
|
||||
:test-result: PASS A Template product test case - Foo<float>
|
||||
:test-result: PASS A Template product test case - Foo<int>
|
||||
:test-result: PASS A Template product test case - std::vector<float>
|
||||
:test-result: PASS A Template product test case - std::vector<int>
|
||||
:test-result: PASS A Template product test case with array signature - Bar<float, 42>
|
||||
:test-result: PASS A Template product test case with array signature - Bar<int, 9>
|
||||
:test-result: PASS A Template product test case with array signature - std::array<float, 42>
|
||||
:test-result: PASS A Template product test case with array signature - std::array<int, 9>
|
||||
:test-result: PASS A comparison that uses literals instead of the normal constructor
|
||||
:test-result: FAIL A couple of nested sections followed by a failure
|
||||
:test-result: FAIL A failing expression with a non streamable type is still captured
|
||||
:test-result: PASS Absolute margin
|
||||
:test-result: FAIL An empty test with no assertions
|
||||
:test-result: PASS An expression with side-effects should only be evaluated once
|
||||
:test-result: FAIL An unchecked exception reports the line of the last assertion
|
||||
:test-result: PASS Anonymous test case 1
|
||||
:test-result: PASS Approx setters validate their arguments
|
||||
:test-result: PASS Approx with exactly-representable margin
|
||||
:test-result: PASS Approximate PI
|
||||
:test-result: PASS Approximate comparisons with different epsilons
|
||||
:test-result: PASS Approximate comparisons with floats
|
||||
:test-result: PASS Approximate comparisons with ints
|
||||
:test-result: PASS Approximate comparisons with mixed numeric types
|
||||
:test-result: PASS Arbitrary predicate matcher
|
||||
:test-result: PASS Assertion macros support bit operators and bool conversions
|
||||
:test-result: PASS Assertions then sections
|
||||
:test-result: PASS Basic use of the Contains range matcher
|
||||
:test-result: PASS Basic use of the Empty range matcher
|
||||
:test-result: PASS CAPTURE can deal with complex expressions
|
||||
:test-result: PASS CAPTURE can deal with complex expressions involving commas
|
||||
:test-result: PASS CAPTURE parses string and character constants
|
||||
:test-result: PASS Capture and info messages
|
||||
:test-result: PASS CaseInsensitiveEqualsTo is case insensitive
|
||||
:test-result: PASS CaseInsensitiveLess is case insensitive
|
||||
:test-result: PASS Character pretty printing
|
||||
:test-result: PASS Clara::Arg supports single-arg parse the way Opt does
|
||||
:test-result: PASS Clara::Opt supports accept-many lambdas
|
||||
:test-result: PASS ColourGuard behaviour
|
||||
:test-result: PASS Combining MatchAllOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchAnyOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchNotOfGeneric does not nest
|
||||
:test-result: PASS Combining concrete matchers does not use templated matchers
|
||||
:test-result: PASS Combining only templated matchers
|
||||
:test-result: PASS Combining templated and concrete matchers
|
||||
:test-result: PASS Combining templated matchers
|
||||
:test-result: PASS Commas in various macros are allowed
|
||||
:test-result: PASS Comparing function pointers
|
||||
:test-result: PASS Comparison ops
|
||||
:test-result: PASS Comparison with explicitly convertible types
|
||||
:test-result: PASS Comparisons between ints where one side is computed
|
||||
:test-result: PASS Comparisons between unsigned ints and negative signed ints match c++ standard behaviour
|
||||
:test-result: PASS Comparisons with int literals don't warn when mixing signed/ unsigned
|
||||
:test-result: PASS Composed generic matchers shortcircuit
|
||||
:test-result: PASS Composed matchers shortcircuit
|
||||
:test-result: FAIL Contains string matcher
|
||||
:test-result: PASS Copy and then generate a range
|
||||
:test-result: PASS Cout stream properly declares it writes to stdout
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for nothrow
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for throwing as something else
|
||||
:test-result: FAIL Custom std-exceptions can be custom translated
|
||||
:test-result: PASS Default scale is invisible to comparison
|
||||
:test-result: PASS Directly creating an EnumInfo
|
||||
:test-result: SKIP Empty generators can SKIP in constructor
|
||||
:test-result: PASS Empty stream name opens cout stream
|
||||
:test-result: FAIL EndsWith string matcher
|
||||
:test-result: PASS Enums can quickly have stringification enabled using REGISTER_ENUM
|
||||
:test-result: PASS Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM
|
||||
:test-result: PASS Epsilon only applies to Approx's value
|
||||
:test-result: XFAIL Equality checks that should fail
|
||||
:test-result: PASS Equality checks that should succeed
|
||||
:test-result: PASS Equals
|
||||
:test-result: FAIL Equals string matcher
|
||||
:test-result: PASS Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified
|
||||
:test-result: FAIL Exception matchers that fail
|
||||
:test-result: PASS Exception matchers that succeed
|
||||
:test-result: PASS Exception message can be matched
|
||||
:test-result: PASS Exception messages can be tested for
|
||||
:test-result: PASS Exceptions matchers
|
||||
:test-result: FAIL Expected exceptions that don't throw or unexpected exceptions fail the test
|
||||
:test-result: FAIL FAIL aborts the test
|
||||
:test-result: FAIL FAIL does not require an argument
|
||||
:test-result: FAIL FAIL_CHECK does not abort the test
|
||||
:test-result: PASS Factorials are computed
|
||||
:test-result: PASS Filter generator throws exception for empty generator
|
||||
:test-result: PASS Floating point matchers: double
|
||||
:test-result: PASS Floating point matchers: float
|
||||
:test-result: PASS GENERATE can combine literals and generators
|
||||
:test-result: PASS Generators -- adapters
|
||||
:test-result: PASS Generators -- simple
|
||||
:test-result: PASS Generators internals
|
||||
:test-result: PASS Greater-than inequalities with different epsilons
|
||||
:test-result: PASS Hashers with different seed produce different hash with same test case
|
||||
:test-result: PASS Hashers with same seed produce same hash
|
||||
:test-result: PASS Hashing different test cases produces different result
|
||||
:test-result: PASS Hashing test case produces same hash across multiple calls
|
||||
:test-result: FAIL INFO and UNSCOPED_INFO can stream multiple arguments
|
||||
:test-result: FAIL INFO and WARN do not abort tests
|
||||
:test-result: FAIL INFO gets logged on failure
|
||||
:test-result: FAIL INFO gets logged on failure, even if captured before successful assertions
|
||||
:test-result: FAIL INFO is reset for each loop
|
||||
:test-result: XFAIL Incomplete AssertionHandler
|
||||
:test-result: XFAIL Inequality checks that should fail
|
||||
:test-result: PASS Inequality checks that should succeed
|
||||
:test-result: PASS JsonWriter
|
||||
:test-result: PASS JsonWriter escapes charaters in strings properly
|
||||
:test-result: PASS Lambdas in assertions
|
||||
:test-result: PASS Less-than inequalities with different epsilons
|
||||
:test-result: PASS ManuallyRegistered
|
||||
:test-result: PASS Matchers can be (AllOf) composed with the && operator
|
||||
:test-result: PASS Matchers can be (AnyOf) composed with the || operator
|
||||
:test-result: PASS Matchers can be composed with both && and ||
|
||||
:test-result: FAIL Matchers can be composed with both && and || - failing
|
||||
:test-result: PASS Matchers can be negated (Not) with the ! operator
|
||||
:test-result: FAIL Matchers can be negated (Not) with the ! operator - failing
|
||||
:test-result: XFAIL Mayfail test case with nested sections
|
||||
:test-result: FAIL Mismatching exception messages failing the test
|
||||
:test-result: PASS Multireporter calls reporters and listeners in correct order
|
||||
:test-result: PASS Multireporter updates ReporterPreferences properly
|
||||
:test-result: PASS Nested generators and captured variables
|
||||
:test-result: FAIL Nice descriptive name
|
||||
:test-result: FAIL Non-std exceptions can be translated
|
||||
:test-result: PASS Objects that evaluated in boolean contexts can be checked
|
||||
:test-result: PASS Optionally static assertions
|
||||
:test-result: FAIL Ordering comparison checks that should fail
|
||||
:test-result: PASS Ordering comparison checks that should succeed
|
||||
:test-result: PASS Our PCG implementation provides expected results for known seeds
|
||||
:test-result: FAIL Output from all sections is reported
|
||||
:test-result: PASS Overloaded comma or address-of operators are not used
|
||||
:test-result: PASS Parse uints
|
||||
:test-result: PASS Parsed tags are matched case insensitive
|
||||
:test-result: PASS Parsing sharding-related cli flags
|
||||
:test-result: PASS Parsing tags with non-alphabetical characters is pass-through
|
||||
:test-result: PASS Parsing warnings
|
||||
:test-result: PASS Pointers can be compared to null
|
||||
:test-result: PASS Precision of floating point stringification can be set
|
||||
:test-result: PASS Predicate matcher can accept const char*
|
||||
:test-result: PASS Process can be configured on command line
|
||||
:test-result: PASS Product with differing arities - std::tuple<int, double, float>
|
||||
:test-result: PASS Product with differing arities - std::tuple<int, double>
|
||||
:test-result: PASS Product with differing arities - std::tuple<int>
|
||||
:test-result: PASS Random seed generation accepts known methods
|
||||
:test-result: PASS Random seed generation reports unknown methods
|
||||
:test-result: PASS Range type with sentinel
|
||||
:test-result: FAIL Reconstruction should be based on stringification: #914
|
||||
:test-result: FAIL Regex string matcher
|
||||
:test-result: PASS Registering reporter with '::' in name fails
|
||||
:test-result: PASS Regression test #1
|
||||
:test-result: PASS Reporter's write listings to provided stream
|
||||
:test-result: PASS Reproducer for #2309 - a very long description past 80 chars (default console width) with a late colon : blablabla
|
||||
:test-result: PASS SUCCEED counts as a test pass
|
||||
:test-result: PASS SUCCEED does not require an argument
|
||||
:test-result: PASS Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods
|
||||
:test-result: PASS Scenario: Do that thing with the thing
|
||||
:test-result: PASS Scenario: This is a really long scenario name to see how the list command deals with wrapping
|
||||
:test-result: PASS Scenario: Vector resizing affects size and capacity
|
||||
A string sent directly to stdout
|
||||
A string sent directly to stderr
|
||||
A string sent to stderr via clog
|
||||
:test-result: FAIL Sends stuff to stdout and stderr
|
||||
:test-result: PASS Some simple comparisons between doubles
|
||||
Message from section one
|
||||
Message from section two
|
||||
:test-result: FAIL Standard output from all sections is reported
|
||||
:test-result: FAIL StartsWith string matcher
|
||||
:test-result: PASS Static arrays are convertible to string
|
||||
:test-result: PASS String matchers
|
||||
:test-result: PASS StringRef
|
||||
:test-result: PASS StringRef at compilation time
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - char
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - signed char
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - unsigned char
|
||||
:test-result: PASS Stringifying std::chrono::duration helpers
|
||||
:test-result: PASS Stringifying std::chrono::duration with weird ratios
|
||||
:test-result: PASS Stringifying std::chrono::time_point<system_clock>
|
||||
:test-result: FAIL Tabs and newlines show in output
|
||||
:test-result: PASS Tag alias can be registered against tag patterns
|
||||
:test-result: PASS Tags with spaces and non-alphanumerical characters are accepted
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 0
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 1
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 2
|
||||
:test-result: PASS Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 2
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - float
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - int
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - std::string
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - std::tuple<int,float>
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - float,4
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - int,5
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - std::string,15
|
||||
:test-result: PASS Test case with identical tags keeps just one
|
||||
:test-result: PASS Test case with one argument
|
||||
:test-result: PASS Test enum bit values
|
||||
:test-result: PASS Test with special, characters "in name
|
||||
:test-result: PASS Testing checked-if
|
||||
:test-result: XFAIL Testing checked-if 2
|
||||
:test-result: XFAIL Testing checked-if 3
|
||||
:test-result: XFAIL Testing checked-if 4
|
||||
:test-result: XFAIL Testing checked-if 5
|
||||
:test-result: FAIL The NO_FAIL macro reports a failure but does not fail the test
|
||||
:test-result: PASS The default listing implementation write to provided stream
|
||||
:test-result: FAIL This test 'should' fail but doesn't
|
||||
:test-result: FAIL Thrown string literals are translated
|
||||
:test-result: PASS Tracker
|
||||
:test-result: PASS Trim strings
|
||||
:test-result: PASS Type conversions of RangeEquals and similar
|
||||
:test-result: FAIL Unexpected exceptions can be translated
|
||||
:test-result: PASS Upcasting special member functions
|
||||
:test-result: PASS Usage of AllMatch range matcher
|
||||
:test-result: PASS Usage of AllTrue range matcher
|
||||
:test-result: PASS Usage of AnyMatch range matcher
|
||||
:test-result: PASS Usage of AnyTrue range matcher
|
||||
:test-result: PASS Usage of NoneMatch range matcher
|
||||
:test-result: PASS Usage of NoneTrue range matcher
|
||||
:test-result: PASS Usage of RangeEquals range matcher
|
||||
:test-result: PASS Usage of UnorderedRangeEquals range matcher
|
||||
:test-result: PASS Usage of the SizeIs range matcher
|
||||
:test-result: PASS Use a custom approx
|
||||
:test-result: PASS Variadic macros
|
||||
:test-result: PASS Vector Approx matcher
|
||||
:test-result: FAIL Vector Approx matcher -- failing
|
||||
:test-result: PASS Vector matchers
|
||||
:test-result: FAIL Vector matchers that fail
|
||||
:test-result: PASS When checked exceptions are thrown they can be expected or unexpected
|
||||
:test-result: FAIL When unchecked exceptions are thrown directly they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a CHECK the test should continue
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a REQUIRE the test should abort fail
|
||||
:test-result: FAIL When unchecked exceptions are thrown from functions they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown from sections they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown, but caught, they do not affect the test
|
||||
:test-result: PASS X/level/0/a
|
||||
:test-result: PASS X/level/0/b
|
||||
:test-result: PASS X/level/1/a
|
||||
:test-result: PASS X/level/1/b
|
||||
:test-result: PASS XmlEncode
|
||||
:test-result: PASS XmlWriter writes boolean attributes as true/false
|
||||
:test-result: SKIP a succeeding test can still be skipped
|
||||
:test-result: PASS analyse no analysis
|
||||
:test-result: PASS array<int, N> -> toString
|
||||
:test-result: PASS benchmark function call
|
||||
:test-result: PASS boolean member
|
||||
:test-result: PASS checkedElse
|
||||
:test-result: FAIL checkedElse, failing
|
||||
:test-result: PASS checkedIf
|
||||
:test-result: FAIL checkedIf, failing
|
||||
:test-result: PASS classify_outliers
|
||||
:test-result: PASS comparisons between const int variables
|
||||
:test-result: PASS comparisons between int variables
|
||||
:test-result: PASS convertToBits
|
||||
:test-result: SKIP dynamic skipping works with generators
|
||||
:test-result: PASS empty tags are not allowed
|
||||
:test-result: PASS erfc_inv
|
||||
:test-result: PASS estimate_clock_resolution
|
||||
:test-result: PASS even more nested SECTION tests
|
||||
:test-result: XFAIL failed assertions before SKIP cause test case to fail
|
||||
:test-result: XFAIL failing for some generator values causes entire test case to fail
|
||||
:test-result: XFAIL failing in some unskipped sections causes entire test case to fail
|
||||
:test-result: FAIL first tag
|
||||
loose text artifact
|
||||
:test-result: FAIL has printf
|
||||
:test-result: PASS is_unary_function
|
||||
:test-result: FAIL just failure
|
||||
:test-result: FAIL just failure after unscoped info
|
||||
:test-result: FAIL just info
|
||||
:test-result: FAIL just unscoped info
|
||||
:test-result: PASS long long
|
||||
:test-result: FAIL looped SECTION tests
|
||||
:test-result: FAIL looped tests
|
||||
:test-result: PASS makeStream recognizes %debug stream name
|
||||
:test-result: PASS make_unique reimplementation
|
||||
:test-result: PASS mean
|
||||
:test-result: PASS measure
|
||||
:test-result: FAIL mix info, unscoped info and warning
|
||||
:test-result: FAIL more nested SECTION tests
|
||||
:test-result: PASS nested SECTION tests
|
||||
a!
|
||||
b1!
|
||||
!
|
||||
:test-result: FAIL nested sections can be skipped dynamically at runtime
|
||||
:test-result: PASS non streamable - with conv. op
|
||||
:test-result: PASS non-copyable objects
|
||||
:test-result: PASS normal_cdf
|
||||
:test-result: PASS normal_quantile
|
||||
:test-result: PASS not allowed
|
||||
:test-result: FAIL not prints unscoped info from previous failures
|
||||
:test-result: PASS null strings
|
||||
:test-result: PASS null_ptr
|
||||
:test-result: PASS pair<pair<int,const char *,pair<std::string,int> > -> toString
|
||||
:test-result: PASS parseEnums
|
||||
:test-result: PASS pointer to class
|
||||
:test-result: PASS print unscoped info if passing unscoped info is printed
|
||||
:test-result: FAIL prints unscoped info on failure
|
||||
:test-result: FAIL prints unscoped info only for the first assertion
|
||||
:test-result: PASS random SECTION tests
|
||||
:test-result: PASS replaceInPlace
|
||||
:test-result: PASS request an unknown %-starting stream fails
|
||||
:test-result: PASS resolution
|
||||
:test-result: PASS run_for_at_least, chronometer
|
||||
:test-result: PASS run_for_at_least, int
|
||||
:test-result: FAIL second tag
|
||||
:test-result: SKIP sections can be skipped dynamically at runtime
|
||||
:test-result: FAIL send a single char to INFO
|
||||
:test-result: FAIL sends information to INFO
|
||||
:test-result: PASS shortened hide tags are split apart
|
||||
:test-result: SKIP skipped tests can optionally provide a reason
|
||||
:test-result: PASS splitString
|
||||
:test-result: FAIL stacks unscoped info in loops
|
||||
:test-result: PASS startsWith
|
||||
:test-result: PASS std::map is convertible string
|
||||
:test-result: PASS std::pair<int,const std::string> -> toString
|
||||
:test-result: PASS std::pair<int,std::string> -> toString
|
||||
:test-result: PASS std::set is convertible string
|
||||
:test-result: PASS std::vector<std::pair<std::string,int> > -> toString
|
||||
:test-result: PASS stdout and stderr streams have %-starting name
|
||||
:test-result: PASS stringify ranges
|
||||
:test-result: PASS stringify( has_maker )
|
||||
:test-result: PASS stringify( has_maker_and_operator )
|
||||
:test-result: PASS stringify( has_neither )
|
||||
:test-result: PASS stringify( has_operator )
|
||||
:test-result: PASS stringify( has_template_operator )
|
||||
:test-result: PASS stringify( vectors<has_maker> )
|
||||
:test-result: PASS stringify( vectors<has_maker_and_operator> )
|
||||
:test-result: PASS stringify( vectors<has_operator> )
|
||||
:test-result: PASS strlen3
|
||||
:test-result: PASS tables
|
||||
:test-result: PASS tags with dots in later positions are not parsed as hidden
|
||||
:test-result: SKIP tests can be skipped dynamically at runtime
|
||||
:test-result: FAIL thrown std::strings are translated
|
||||
:test-result: PASS toString on const wchar_t const pointer returns the string contents
|
||||
:test-result: PASS toString on const wchar_t pointer returns the string contents
|
||||
:test-result: PASS toString on wchar_t const pointer returns the string contents
|
||||
:test-result: PASS toString on wchar_t returns the string contents
|
||||
:test-result: PASS toString(enum class w/operator<<)
|
||||
:test-result: PASS toString(enum class)
|
||||
:test-result: PASS toString(enum w/operator<<)
|
||||
:test-result: PASS toString(enum)
|
||||
:test-result: PASS tuple<>
|
||||
:test-result: PASS tuple<float,int>
|
||||
:test-result: PASS tuple<int>
|
||||
:test-result: PASS tuple<string,string>
|
||||
:test-result: PASS tuple<tuple<int>,tuple<>,float>
|
||||
:test-result: PASS uniform samples
|
||||
:test-result: PASS uniform_integer_distribution can return the bounds
|
||||
:test-result: PASS unique_ptr reimplementation: basic functionality
|
||||
:test-result: PASS vec<vec<string,alloc>> -> toString
|
||||
:test-result: PASS vector<bool> -> toString
|
||||
:test-result: PASS vector<int,allocator> -> toString
|
||||
:test-result: PASS vector<int> -> toString
|
||||
:test-result: PASS vector<string> -> toString
|
||||
:test-result: PASS vectors can be sized and resized
|
||||
:test-result: PASS warmup
|
||||
:test-result: PASS weighted_average_quantile
|
||||
:test-result: PASS xmlentitycheck
|
||||
Vendored
+417
@@ -0,0 +1,417 @@
|
||||
:test-result: PASS # A test name that starts with a #
|
||||
:test-result: PASS #1027: Bitfields can be captured
|
||||
:test-result: PASS #1147
|
||||
:test-result: PASS #1175 - Hidden Test
|
||||
:test-result: PASS #1238
|
||||
:test-result: PASS #1245
|
||||
:test-result: PASS #1319: Sections can have description (even if it is not saved
|
||||
:test-result: PASS #1403
|
||||
:test-result: FAIL #1455 - INFO and WARN can start with a linebreak
|
||||
:test-result: FAIL #1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
:test-result: PASS #1548
|
||||
:test-result: PASS #1905 -- test spec parser properly clears internal state between compound tests
|
||||
:test-result: PASS #1912 -- test spec parser handles escaping
|
||||
:test-result: PASS #1913 - GENERATE inside a for loop should not keep recreating the generator
|
||||
:test-result: PASS #1913 - GENERATEs can share a line
|
||||
:test-result: PASS #1938 - GENERATE after a section
|
||||
:test-result: PASS #1938 - Section followed by flat generate
|
||||
:test-result: PASS #1938 - flat generate
|
||||
:test-result: PASS #1938 - mixed sections and generates
|
||||
:test-result: PASS #1938 - nested generate
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0
|
||||
:test-result: PASS #1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0
|
||||
:test-result: PASS #2152 - ULP checks between differently signed values were wrong - double
|
||||
:test-result: PASS #2152 - ULP checks between differently signed values were wrong - float
|
||||
:test-result: XFAIL #2615 - Throwing in constructor generator fails test case but does not abort
|
||||
:test-result: XFAIL #748 - captures with unexpected exceptions
|
||||
:test-result: PASS #809
|
||||
:test-result: PASS #833
|
||||
:test-result: XFAIL #835 -- errno should not be touched by Catch2
|
||||
:test-result: PASS #872
|
||||
:test-result: PASS #961 -- Dynamically created sections should all be reported
|
||||
:test-result: FAIL 'Not' checks that should fail
|
||||
:test-result: PASS 'Not' checks that should succeed
|
||||
:test-result: PASS (unimplemented) static bools can be evaluated
|
||||
:test-result: PASS 3x3x3 ints
|
||||
:test-result: FAIL A METHOD_AS_TEST_CASE based test run that fails
|
||||
:test-result: PASS A METHOD_AS_TEST_CASE based test run that succeeds
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<float>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<int>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<float>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<int>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<float>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<int>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<float>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<int>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2<float, 6>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2<int, 2>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array<float, 6>
|
||||
:test-result: FAIL A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array<int, 2>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2<float,6>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2<int,2>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array<float,6>
|
||||
:test-result: PASS A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array<int,2>
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - double
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - float
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD based test run that fails - int
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - float
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - int
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3
|
||||
:test-result: FAIL A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3
|
||||
:test-result: PASS A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6
|
||||
:test-result: FAIL A TEST_CASE_METHOD based test run that fails
|
||||
:test-result: PASS A TEST_CASE_METHOD based test run that succeeds
|
||||
:test-result: PASS A Template product test case - Foo<float>
|
||||
:test-result: PASS A Template product test case - Foo<int>
|
||||
:test-result: PASS A Template product test case - std::vector<float>
|
||||
:test-result: PASS A Template product test case - std::vector<int>
|
||||
:test-result: PASS A Template product test case with array signature - Bar<float, 42>
|
||||
:test-result: PASS A Template product test case with array signature - Bar<int, 9>
|
||||
:test-result: PASS A Template product test case with array signature - std::array<float, 42>
|
||||
:test-result: PASS A Template product test case with array signature - std::array<int, 9>
|
||||
:test-result: PASS A comparison that uses literals instead of the normal constructor
|
||||
:test-result: FAIL A couple of nested sections followed by a failure
|
||||
:test-result: FAIL A failing expression with a non streamable type is still captured
|
||||
:test-result: PASS Absolute margin
|
||||
:test-result: FAIL An empty test with no assertions
|
||||
:test-result: PASS An expression with side-effects should only be evaluated once
|
||||
:test-result: FAIL An unchecked exception reports the line of the last assertion
|
||||
:test-result: PASS Anonymous test case 1
|
||||
:test-result: PASS Approx setters validate their arguments
|
||||
:test-result: PASS Approx with exactly-representable margin
|
||||
:test-result: PASS Approximate PI
|
||||
:test-result: PASS Approximate comparisons with different epsilons
|
||||
:test-result: PASS Approximate comparisons with floats
|
||||
:test-result: PASS Approximate comparisons with ints
|
||||
:test-result: PASS Approximate comparisons with mixed numeric types
|
||||
:test-result: PASS Arbitrary predicate matcher
|
||||
:test-result: PASS Assertion macros support bit operators and bool conversions
|
||||
:test-result: PASS Assertions then sections
|
||||
:test-result: PASS Basic use of the Contains range matcher
|
||||
:test-result: PASS Basic use of the Empty range matcher
|
||||
:test-result: PASS CAPTURE can deal with complex expressions
|
||||
:test-result: PASS CAPTURE can deal with complex expressions involving commas
|
||||
:test-result: PASS CAPTURE parses string and character constants
|
||||
:test-result: PASS Capture and info messages
|
||||
:test-result: PASS CaseInsensitiveEqualsTo is case insensitive
|
||||
:test-result: PASS CaseInsensitiveLess is case insensitive
|
||||
:test-result: PASS Character pretty printing
|
||||
:test-result: PASS Clara::Arg supports single-arg parse the way Opt does
|
||||
:test-result: PASS Clara::Opt supports accept-many lambdas
|
||||
:test-result: PASS ColourGuard behaviour
|
||||
:test-result: PASS Combining MatchAllOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchAnyOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchNotOfGeneric does not nest
|
||||
:test-result: PASS Combining concrete matchers does not use templated matchers
|
||||
:test-result: PASS Combining only templated matchers
|
||||
:test-result: PASS Combining templated and concrete matchers
|
||||
:test-result: PASS Combining templated matchers
|
||||
:test-result: PASS Commas in various macros are allowed
|
||||
:test-result: PASS Comparing function pointers
|
||||
:test-result: PASS Comparison ops
|
||||
:test-result: PASS Comparison with explicitly convertible types
|
||||
:test-result: PASS Comparisons between ints where one side is computed
|
||||
:test-result: PASS Comparisons between unsigned ints and negative signed ints match c++ standard behaviour
|
||||
:test-result: PASS Comparisons with int literals don't warn when mixing signed/ unsigned
|
||||
:test-result: PASS Composed generic matchers shortcircuit
|
||||
:test-result: PASS Composed matchers shortcircuit
|
||||
:test-result: FAIL Contains string matcher
|
||||
:test-result: PASS Copy and then generate a range
|
||||
:test-result: PASS Cout stream properly declares it writes to stdout
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for nothrow
|
||||
:test-result: FAIL Custom exceptions can be translated when testing for throwing as something else
|
||||
:test-result: FAIL Custom std-exceptions can be custom translated
|
||||
:test-result: PASS Default scale is invisible to comparison
|
||||
:test-result: PASS Directly creating an EnumInfo
|
||||
:test-result: SKIP Empty generators can SKIP in constructor
|
||||
:test-result: PASS Empty stream name opens cout stream
|
||||
:test-result: FAIL EndsWith string matcher
|
||||
:test-result: PASS Enums can quickly have stringification enabled using REGISTER_ENUM
|
||||
:test-result: PASS Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM
|
||||
:test-result: PASS Epsilon only applies to Approx's value
|
||||
:test-result: XFAIL Equality checks that should fail
|
||||
:test-result: PASS Equality checks that should succeed
|
||||
:test-result: PASS Equals
|
||||
:test-result: FAIL Equals string matcher
|
||||
:test-result: PASS Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified
|
||||
:test-result: FAIL Exception matchers that fail
|
||||
:test-result: PASS Exception matchers that succeed
|
||||
:test-result: PASS Exception message can be matched
|
||||
:test-result: PASS Exception messages can be tested for
|
||||
:test-result: PASS Exceptions matchers
|
||||
:test-result: FAIL Expected exceptions that don't throw or unexpected exceptions fail the test
|
||||
:test-result: FAIL FAIL aborts the test
|
||||
:test-result: FAIL FAIL does not require an argument
|
||||
:test-result: FAIL FAIL_CHECK does not abort the test
|
||||
:test-result: PASS Factorials are computed
|
||||
:test-result: PASS Filter generator throws exception for empty generator
|
||||
:test-result: PASS Floating point matchers: double
|
||||
:test-result: PASS Floating point matchers: float
|
||||
:test-result: PASS GENERATE can combine literals and generators
|
||||
:test-result: PASS Generators -- adapters
|
||||
:test-result: PASS Generators -- simple
|
||||
:test-result: PASS Generators internals
|
||||
:test-result: PASS Greater-than inequalities with different epsilons
|
||||
:test-result: PASS Hashers with different seed produce different hash with same test case
|
||||
:test-result: PASS Hashers with same seed produce same hash
|
||||
:test-result: PASS Hashing different test cases produces different result
|
||||
:test-result: PASS Hashing test case produces same hash across multiple calls
|
||||
:test-result: FAIL INFO and UNSCOPED_INFO can stream multiple arguments
|
||||
:test-result: FAIL INFO and WARN do not abort tests
|
||||
:test-result: FAIL INFO gets logged on failure
|
||||
:test-result: FAIL INFO gets logged on failure, even if captured before successful assertions
|
||||
:test-result: FAIL INFO is reset for each loop
|
||||
:test-result: XFAIL Incomplete AssertionHandler
|
||||
:test-result: XFAIL Inequality checks that should fail
|
||||
:test-result: PASS Inequality checks that should succeed
|
||||
:test-result: PASS JsonWriter
|
||||
:test-result: PASS JsonWriter escapes charaters in strings properly
|
||||
:test-result: PASS Lambdas in assertions
|
||||
:test-result: PASS Less-than inequalities with different epsilons
|
||||
:test-result: PASS ManuallyRegistered
|
||||
:test-result: PASS Matchers can be (AllOf) composed with the && operator
|
||||
:test-result: PASS Matchers can be (AnyOf) composed with the || operator
|
||||
:test-result: PASS Matchers can be composed with both && and ||
|
||||
:test-result: FAIL Matchers can be composed with both && and || - failing
|
||||
:test-result: PASS Matchers can be negated (Not) with the ! operator
|
||||
:test-result: FAIL Matchers can be negated (Not) with the ! operator - failing
|
||||
:test-result: XFAIL Mayfail test case with nested sections
|
||||
:test-result: FAIL Mismatching exception messages failing the test
|
||||
:test-result: PASS Multireporter calls reporters and listeners in correct order
|
||||
:test-result: PASS Multireporter updates ReporterPreferences properly
|
||||
:test-result: PASS Nested generators and captured variables
|
||||
:test-result: FAIL Nice descriptive name
|
||||
:test-result: FAIL Non-std exceptions can be translated
|
||||
:test-result: PASS Objects that evaluated in boolean contexts can be checked
|
||||
:test-result: PASS Optionally static assertions
|
||||
:test-result: FAIL Ordering comparison checks that should fail
|
||||
:test-result: PASS Ordering comparison checks that should succeed
|
||||
:test-result: PASS Our PCG implementation provides expected results for known seeds
|
||||
:test-result: FAIL Output from all sections is reported
|
||||
:test-result: PASS Overloaded comma or address-of operators are not used
|
||||
:test-result: PASS Parse uints
|
||||
:test-result: PASS Parsed tags are matched case insensitive
|
||||
:test-result: PASS Parsing sharding-related cli flags
|
||||
:test-result: PASS Parsing tags with non-alphabetical characters is pass-through
|
||||
:test-result: PASS Parsing warnings
|
||||
:test-result: PASS Pointers can be compared to null
|
||||
:test-result: PASS Precision of floating point stringification can be set
|
||||
:test-result: PASS Predicate matcher can accept const char*
|
||||
:test-result: PASS Process can be configured on command line
|
||||
:test-result: PASS Product with differing arities - std::tuple<int, double, float>
|
||||
:test-result: PASS Product with differing arities - std::tuple<int, double>
|
||||
:test-result: PASS Product with differing arities - std::tuple<int>
|
||||
:test-result: PASS Random seed generation accepts known methods
|
||||
:test-result: PASS Random seed generation reports unknown methods
|
||||
:test-result: PASS Range type with sentinel
|
||||
:test-result: FAIL Reconstruction should be based on stringification: #914
|
||||
:test-result: FAIL Regex string matcher
|
||||
:test-result: PASS Registering reporter with '::' in name fails
|
||||
:test-result: PASS Regression test #1
|
||||
:test-result: PASS Reporter's write listings to provided stream
|
||||
:test-result: PASS Reproducer for #2309 - a very long description past 80 chars (default console width) with a late colon : blablabla
|
||||
:test-result: PASS SUCCEED counts as a test pass
|
||||
:test-result: PASS SUCCEED does not require an argument
|
||||
:test-result: PASS Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods
|
||||
:test-result: PASS Scenario: Do that thing with the thing
|
||||
:test-result: PASS Scenario: This is a really long scenario name to see how the list command deals with wrapping
|
||||
:test-result: PASS Scenario: Vector resizing affects size and capacity
|
||||
:test-result: FAIL Sends stuff to stdout and stderr
|
||||
:test-result: PASS Some simple comparisons between doubles
|
||||
:test-result: FAIL Standard output from all sections is reported
|
||||
:test-result: FAIL StartsWith string matcher
|
||||
:test-result: PASS Static arrays are convertible to string
|
||||
:test-result: PASS String matchers
|
||||
:test-result: PASS StringRef
|
||||
:test-result: PASS StringRef at compilation time
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - char
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - signed char
|
||||
:test-result: PASS Stringifying char arrays with statically known sizes - unsigned char
|
||||
:test-result: PASS Stringifying std::chrono::duration helpers
|
||||
:test-result: PASS Stringifying std::chrono::duration with weird ratios
|
||||
:test-result: PASS Stringifying std::chrono::time_point<system_clock>
|
||||
:test-result: FAIL Tabs and newlines show in output
|
||||
:test-result: PASS Tag alias can be registered against tag patterns
|
||||
:test-result: PASS Tags with spaces and non-alphanumerical characters are accepted
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 0
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 1
|
||||
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 2
|
||||
:test-result: PASS Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 0
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 1
|
||||
:test-result: PASS Template test case with test types specified inside std::tuple - MyTypes - 2
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - float
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - int
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - std::string
|
||||
:test-result: PASS TemplateTest: vectors can be sized and resized - std::tuple<int,float>
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - float,4
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - int,5
|
||||
:test-result: PASS TemplateTestSig: vectors can be sized and resized - std::string,15
|
||||
:test-result: PASS Test case with identical tags keeps just one
|
||||
:test-result: PASS Test case with one argument
|
||||
:test-result: PASS Test enum bit values
|
||||
:test-result: PASS Test with special, characters "in name
|
||||
:test-result: PASS Testing checked-if
|
||||
:test-result: XFAIL Testing checked-if 2
|
||||
:test-result: XFAIL Testing checked-if 3
|
||||
:test-result: XFAIL Testing checked-if 4
|
||||
:test-result: XFAIL Testing checked-if 5
|
||||
:test-result: FAIL The NO_FAIL macro reports a failure but does not fail the test
|
||||
:test-result: PASS The default listing implementation write to provided stream
|
||||
:test-result: FAIL This test 'should' fail but doesn't
|
||||
:test-result: FAIL Thrown string literals are translated
|
||||
:test-result: PASS Tracker
|
||||
:test-result: PASS Trim strings
|
||||
:test-result: PASS Type conversions of RangeEquals and similar
|
||||
:test-result: FAIL Unexpected exceptions can be translated
|
||||
:test-result: PASS Upcasting special member functions
|
||||
:test-result: PASS Usage of AllMatch range matcher
|
||||
:test-result: PASS Usage of AllTrue range matcher
|
||||
:test-result: PASS Usage of AnyMatch range matcher
|
||||
:test-result: PASS Usage of AnyTrue range matcher
|
||||
:test-result: PASS Usage of NoneMatch range matcher
|
||||
:test-result: PASS Usage of NoneTrue range matcher
|
||||
:test-result: PASS Usage of RangeEquals range matcher
|
||||
:test-result: PASS Usage of UnorderedRangeEquals range matcher
|
||||
:test-result: PASS Usage of the SizeIs range matcher
|
||||
:test-result: PASS Use a custom approx
|
||||
:test-result: PASS Variadic macros
|
||||
:test-result: PASS Vector Approx matcher
|
||||
:test-result: FAIL Vector Approx matcher -- failing
|
||||
:test-result: PASS Vector matchers
|
||||
:test-result: FAIL Vector matchers that fail
|
||||
:test-result: PASS When checked exceptions are thrown they can be expected or unexpected
|
||||
:test-result: FAIL When unchecked exceptions are thrown directly they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a CHECK the test should continue
|
||||
:test-result: FAIL When unchecked exceptions are thrown during a REQUIRE the test should abort fail
|
||||
:test-result: FAIL When unchecked exceptions are thrown from functions they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown from sections they are always failures
|
||||
:test-result: FAIL When unchecked exceptions are thrown, but caught, they do not affect the test
|
||||
:test-result: PASS X/level/0/a
|
||||
:test-result: PASS X/level/0/b
|
||||
:test-result: PASS X/level/1/a
|
||||
:test-result: PASS X/level/1/b
|
||||
:test-result: PASS XmlEncode
|
||||
:test-result: PASS XmlWriter writes boolean attributes as true/false
|
||||
:test-result: SKIP a succeeding test can still be skipped
|
||||
:test-result: PASS analyse no analysis
|
||||
:test-result: PASS array<int, N> -> toString
|
||||
:test-result: PASS benchmark function call
|
||||
:test-result: PASS boolean member
|
||||
:test-result: PASS checkedElse
|
||||
:test-result: FAIL checkedElse, failing
|
||||
:test-result: PASS checkedIf
|
||||
:test-result: FAIL checkedIf, failing
|
||||
:test-result: PASS classify_outliers
|
||||
:test-result: PASS comparisons between const int variables
|
||||
:test-result: PASS comparisons between int variables
|
||||
:test-result: PASS convertToBits
|
||||
:test-result: SKIP dynamic skipping works with generators
|
||||
:test-result: PASS empty tags are not allowed
|
||||
:test-result: PASS erfc_inv
|
||||
:test-result: PASS estimate_clock_resolution
|
||||
:test-result: PASS even more nested SECTION tests
|
||||
:test-result: XFAIL failed assertions before SKIP cause test case to fail
|
||||
:test-result: XFAIL failing for some generator values causes entire test case to fail
|
||||
:test-result: XFAIL failing in some unskipped sections causes entire test case to fail
|
||||
:test-result: FAIL first tag
|
||||
:test-result: FAIL has printf
|
||||
:test-result: PASS is_unary_function
|
||||
:test-result: FAIL just failure
|
||||
:test-result: FAIL just failure after unscoped info
|
||||
:test-result: FAIL just info
|
||||
:test-result: FAIL just unscoped info
|
||||
:test-result: PASS long long
|
||||
:test-result: FAIL looped SECTION tests
|
||||
:test-result: FAIL looped tests
|
||||
:test-result: PASS makeStream recognizes %debug stream name
|
||||
:test-result: PASS make_unique reimplementation
|
||||
:test-result: PASS mean
|
||||
:test-result: PASS measure
|
||||
:test-result: FAIL mix info, unscoped info and warning
|
||||
:test-result: FAIL more nested SECTION tests
|
||||
:test-result: PASS nested SECTION tests
|
||||
:test-result: FAIL nested sections can be skipped dynamically at runtime
|
||||
:test-result: PASS non streamable - with conv. op
|
||||
:test-result: PASS non-copyable objects
|
||||
:test-result: PASS normal_cdf
|
||||
:test-result: PASS normal_quantile
|
||||
:test-result: PASS not allowed
|
||||
:test-result: FAIL not prints unscoped info from previous failures
|
||||
:test-result: PASS null strings
|
||||
:test-result: PASS null_ptr
|
||||
:test-result: PASS pair<pair<int,const char *,pair<std::string,int> > -> toString
|
||||
:test-result: PASS parseEnums
|
||||
:test-result: PASS pointer to class
|
||||
:test-result: PASS print unscoped info if passing unscoped info is printed
|
||||
:test-result: FAIL prints unscoped info on failure
|
||||
:test-result: FAIL prints unscoped info only for the first assertion
|
||||
:test-result: PASS random SECTION tests
|
||||
:test-result: PASS replaceInPlace
|
||||
:test-result: PASS request an unknown %-starting stream fails
|
||||
:test-result: PASS resolution
|
||||
:test-result: PASS run_for_at_least, chronometer
|
||||
:test-result: PASS run_for_at_least, int
|
||||
:test-result: FAIL second tag
|
||||
:test-result: SKIP sections can be skipped dynamically at runtime
|
||||
:test-result: FAIL send a single char to INFO
|
||||
:test-result: FAIL sends information to INFO
|
||||
:test-result: PASS shortened hide tags are split apart
|
||||
:test-result: SKIP skipped tests can optionally provide a reason
|
||||
:test-result: PASS splitString
|
||||
:test-result: FAIL stacks unscoped info in loops
|
||||
:test-result: PASS startsWith
|
||||
:test-result: PASS std::map is convertible string
|
||||
:test-result: PASS std::pair<int,const std::string> -> toString
|
||||
:test-result: PASS std::pair<int,std::string> -> toString
|
||||
:test-result: PASS std::set is convertible string
|
||||
:test-result: PASS std::vector<std::pair<std::string,int> > -> toString
|
||||
:test-result: PASS stdout and stderr streams have %-starting name
|
||||
:test-result: PASS stringify ranges
|
||||
:test-result: PASS stringify( has_maker )
|
||||
:test-result: PASS stringify( has_maker_and_operator )
|
||||
:test-result: PASS stringify( has_neither )
|
||||
:test-result: PASS stringify( has_operator )
|
||||
:test-result: PASS stringify( has_template_operator )
|
||||
:test-result: PASS stringify( vectors<has_maker> )
|
||||
:test-result: PASS stringify( vectors<has_maker_and_operator> )
|
||||
:test-result: PASS stringify( vectors<has_operator> )
|
||||
:test-result: PASS strlen3
|
||||
:test-result: PASS tables
|
||||
:test-result: PASS tags with dots in later positions are not parsed as hidden
|
||||
:test-result: SKIP tests can be skipped dynamically at runtime
|
||||
:test-result: FAIL thrown std::strings are translated
|
||||
:test-result: PASS toString on const wchar_t const pointer returns the string contents
|
||||
:test-result: PASS toString on const wchar_t pointer returns the string contents
|
||||
:test-result: PASS toString on wchar_t const pointer returns the string contents
|
||||
:test-result: PASS toString on wchar_t returns the string contents
|
||||
:test-result: PASS toString(enum class w/operator<<)
|
||||
:test-result: PASS toString(enum class)
|
||||
:test-result: PASS toString(enum w/operator<<)
|
||||
:test-result: PASS toString(enum)
|
||||
:test-result: PASS tuple<>
|
||||
:test-result: PASS tuple<float,int>
|
||||
:test-result: PASS tuple<int>
|
||||
:test-result: PASS tuple<string,string>
|
||||
:test-result: PASS tuple<tuple<int>,tuple<>,float>
|
||||
:test-result: PASS uniform samples
|
||||
:test-result: PASS uniform_integer_distribution can return the bounds
|
||||
:test-result: PASS unique_ptr reimplementation: basic functionality
|
||||
:test-result: PASS vec<vec<string,alloc>> -> toString
|
||||
:test-result: PASS vector<bool> -> toString
|
||||
:test-result: PASS vector<int,allocator> -> toString
|
||||
:test-result: PASS vector<int> -> toString
|
||||
:test-result: PASS vector<string> -> toString
|
||||
:test-result: PASS vectors can be sized and resized
|
||||
:test-result: PASS warmup
|
||||
:test-result: PASS weighted_average_quantile
|
||||
:test-result: PASS xmlentitycheck
|
||||
+2695
File diff suppressed because it is too large
Load Diff
Vendored
+2684
File diff suppressed because it is too large
Load Diff
+1593
File diff suppressed because it is too large
Load Diff
+18756
File diff suppressed because it is too large
Load Diff
Vendored
+18745
File diff suppressed because it is too large
Load Diff
+956
@@ -0,0 +1,956 @@
|
||||
Filters: "*" ~[!nonportable] ~[!benchmark] ~[approvals]
|
||||
Randomness seeded to: 1
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<exe-name> is a Catch2 v<version> host application.
|
||||
Run with -? for options
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
# A test name that starts with a #
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
yay
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1027: Bitfields can be captured
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( y.v == 0 )
|
||||
with expansion:
|
||||
0 == 0
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( 0 == y.v )
|
||||
with expansion:
|
||||
0 == 0
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1147
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 == t2 )
|
||||
with expansion:
|
||||
{?} == {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 != t2 )
|
||||
with expansion:
|
||||
{?} != {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 < t2 )
|
||||
with expansion:
|
||||
{?} < {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 > t2 )
|
||||
with expansion:
|
||||
{?} > {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 <= t2 )
|
||||
with expansion:
|
||||
{?} <= {?}
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( t1 >= t2 )
|
||||
with expansion:
|
||||
{?} >= {?}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1175 - Hidden Test
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1238
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( std::memcmp(uarr, "123", sizeof(uarr)) == 0 )
|
||||
with expansion:
|
||||
0 == 0
|
||||
with messages:
|
||||
uarr := "123"
|
||||
sarr := "456"
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( std::memcmp(sarr, "456", sizeof(sarr)) == 0 )
|
||||
with expansion:
|
||||
0 == 0
|
||||
with messages:
|
||||
uarr := "123"
|
||||
sarr := "456"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1245
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1319: Sections can have description (even if it is not saved
|
||||
SectionName
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1403
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( h1 == h2 )
|
||||
with expansion:
|
||||
[1403 helper] == [1403 helper]
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1455 - INFO and WARN can start with a linebreak
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: warning:
|
||||
|
||||
This info message starts with a linebreak
|
||||
|
||||
This warning message starts with a linebreak
|
||||
|
||||
|
||||
No assertions in test case '#1455 - INFO and WARN can start with a linebreak'
|
||||
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
-------------------------------------------------------------------------------
|
||||
#1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
-------------------------------------------------------------------------------
|
||||
Tricky.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Tricky.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
1514
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1548
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( std::is_same<TypeList<int>, TypeList<int>>::value )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1905 -- test spec parser properly clears internal state between compound tests
|
||||
-------------------------------------------------------------------------------
|
||||
TestSpec.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase("spec . char")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase("spec , char")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( spec.matches(*fakeTestCase(R"(spec \, char)")) )
|
||||
with expansion:
|
||||
!false
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1912 -- test spec parser handles escaping
|
||||
Various parentheses
|
||||
-------------------------------------------------------------------------------
|
||||
TestSpec.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase(R"(spec {a} char)")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase(R"(spec [a] char)")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( spec.matches(*fakeTestCase("differs but has similar tag", "[a]")) )
|
||||
with expansion:
|
||||
!false
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1912 -- test spec parser handles escaping
|
||||
backslash in test name
|
||||
-------------------------------------------------------------------------------
|
||||
TestSpec.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
TestSpec.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( spec.matches(*fakeTestCase(R"(spec \ char)")) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATE inside a for loop should not keep recreating the generator
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( counter < 7 )
|
||||
with expansion:
|
||||
3 < 7
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATE inside a for loop should not keep recreating the generator
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( counter < 7 )
|
||||
with expansion:
|
||||
6 < 7
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATEs can share a line
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( i != j )
|
||||
with expansion:
|
||||
1 != 3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATEs can share a line
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( i != j )
|
||||
with expansion:
|
||||
1 != 4
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATEs can share a line
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( i != j )
|
||||
with expansion:
|
||||
2 != 3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1913 - GENERATEs can share a line
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( i != j )
|
||||
with expansion:
|
||||
2 != 4
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - GENERATE after a section
|
||||
A
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
A
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - GENERATE after a section
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - GENERATE after a section
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - GENERATE after a section
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - Section followed by flat generate
|
||||
A
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( 1 )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - Section followed by flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - Section followed by flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - flat generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
A
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
A
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 1
|
||||
j := 3
|
||||
k := 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
B
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 1
|
||||
j := 3
|
||||
k := 6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
B
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 1
|
||||
j := 4
|
||||
k := 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 1
|
||||
j := 4
|
||||
k := 6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
A
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
A
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 2
|
||||
j := 3
|
||||
k := 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
B
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 2
|
||||
j := 3
|
||||
k := 6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
B
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
B
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 2
|
||||
j := 4
|
||||
k := 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - mixed sections and generates
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
with messages:
|
||||
i := 2
|
||||
j := 4
|
||||
k := 6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1938 - nested generate
|
||||
-------------------------------------------------------------------------------
|
||||
PartTracker.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( m )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
PartTracker.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( n )
|
||||
with expansion:
|
||||
3
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1954 - 7 arg template test case sig compiles - 1, 1, 1, 1, 1, 0, 0
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1954 - 7 arg template test case sig compiles - 5, 1, 1, 1, 1, 0, 0
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1954 - 7 arg template test case sig compiles - 5, 3, 1, 1, 1, 0, 0
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#2152 - ULP checks between differently signed values were wrong - double
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THAT( smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) )
|
||||
with expansion:
|
||||
0.0 is within 2 ULPs of -4.9406564584124654e-324 ([-1.4821969375237396e-323,
|
||||
4.9406564584124654e-324])
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THAT( smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) )
|
||||
with expansion:
|
||||
0.0 not is within 1 ULPs of -4.9406564584124654e-324 ([-9.8813129168249309e-
|
||||
324, -0.0000000000000000e+00])
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#2152 - ULP checks between differently signed values were wrong - float
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THAT( smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) )
|
||||
with expansion:
|
||||
0.0f is within 2 ULPs of -1.40129846e-45f ([-4.20389539e-45, 1.40129846e-45])
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THAT( smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) )
|
||||
with expansion:
|
||||
0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.
|
||||
00000000e+00])
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#2615 - Throwing in constructor generator fails test case but does not abort
|
||||
-------------------------------------------------------------------------------
|
||||
Generators.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Generators.tests.cpp:<line number>: FAILED:
|
||||
due to unexpected exception with message:
|
||||
failure to init
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
outside assertions
|
||||
-------------------------------------------------------------------------------
|
||||
Exception.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Exception.tests.cpp:<line number>: FAILED:
|
||||
due to unexpected exception with messages:
|
||||
answer := 42
|
||||
expected exception
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
inside REQUIRE_NOTHROW
|
||||
-------------------------------------------------------------------------------
|
||||
Exception.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Exception.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE_NOTHROW( thisThrows() )
|
||||
due to unexpected exception with messages:
|
||||
answer := 42
|
||||
expected exception
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
inside REQUIRE_THROWS
|
||||
-------------------------------------------------------------------------------
|
||||
Exception.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Exception.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS( thisThrows() )
|
||||
with message:
|
||||
answer := 42
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#809
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( 42 == f )
|
||||
with expansion:
|
||||
42 == {?}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#833
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( a == t )
|
||||
with expansion:
|
||||
3 == 3
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
CHECK( a == t )
|
||||
with expansion:
|
||||
3 == 3
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS( throws_int(true) )
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
CHECK_THROWS_AS( throws_int(true), int )
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_NOTHROW( throws_int(false) )
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( "aaa", Catch::Matchers::EndsWith("aaa") )
|
||||
with expansion:
|
||||
"aaa" ends with: "aaa"
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( templated_tests<int>(3) )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#835 -- errno should not be touched by Catch2
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: FAILED:
|
||||
CHECK( f() == 0 )
|
||||
with expansion:
|
||||
1 == 0
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( errno_after == 1 )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#872
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( x == 4 )
|
||||
with expansion:
|
||||
{?} == 4
|
||||
with message:
|
||||
dummy := 0
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 0
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 1
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 2
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 3
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#961 -- Dynamically created sections should all be reported
|
||||
Looped section 4
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
Everything is OK
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
'Not' checks that should fail
|
||||
-------------------------------------------------------------------------------
|
||||
Condition.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Condition.tests.cpp:<line number>: FAILED:
|
||||
CHECK( false != false )
|
||||
|
||||
Condition.tests.cpp:<line number>: FAILED:
|
||||
CHECK( true != true )
|
||||
|
||||
===============================================================================
|
||||
test cases: 33 | 27 passed | 3 failed | 3 failed as expected
|
||||
assertions: 102 | 94 passed | 4 failed | 4 failed as expected
|
||||
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
A string sent directly to stdout
|
||||
A string sent directly to stderr
|
||||
A string sent to stderr via clog
|
||||
Message from section one
|
||||
Message from section two
|
||||
loose text artifact
|
||||
a!
|
||||
b1!
|
||||
!
|
||||
+2117
File diff suppressed because it is too large
Load Diff
+2116
File diff suppressed because it is too large
Load Diff
+2137
File diff suppressed because it is too large
Load Diff
Vendored
+2136
File diff suppressed because it is too large
Load Diff
+4553
File diff suppressed because it is too large
Load Diff
+4542
File diff suppressed because it is too large
Load Diff
+1019
File diff suppressed because it is too large
Load Diff
Vendored
+1018
File diff suppressed because it is too large
Load Diff
+21712
File diff suppressed because it is too large
Load Diff
+21711
File diff suppressed because it is too large
Load Diff
Vendored
+94
@@ -0,0 +1,94 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_is_permutation.hpp>
|
||||
|
||||
#include <helpers/range_test_helpers.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace {
|
||||
template <typename Range1, typename Range2>
|
||||
static bool is_permutation(Range1 const& r1, Range2 const& r2) {
|
||||
using std::begin; using std::end;
|
||||
return Catch::Detail::is_permutation(
|
||||
begin( r1 ), end( r1 ), begin( r2 ), end( r2 ), std::equal_to<>{} );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("is_permutation", "[algorithms][approvals]") {
|
||||
SECTION( "Handle empty ranges" ) {
|
||||
std::array<int, 0> empty;
|
||||
std::array<int, 2> non_empty{ { 2, 3 } };
|
||||
REQUIRE( is_permutation( empty, empty ) );
|
||||
REQUIRE_FALSE( is_permutation( empty, non_empty ) );
|
||||
REQUIRE_FALSE( is_permutation( non_empty, empty ) );
|
||||
}
|
||||
SECTION( "Different length ranges" ) {
|
||||
std::array<int, 6> arr1{ { 1, 3, 5, 7, 8, 9 } };
|
||||
// arr2 is prefix of arr1
|
||||
std::array<int, 4> arr2{ { 1, 3, 5, 7 } };
|
||||
// arr3 shares prefix with arr1 and arr2, but is not a permutation
|
||||
std::array<int, 5> arr3{ { 1, 3, 5, 9, 8 } };
|
||||
REQUIRE_FALSE( is_permutation( arr1, arr2 ) );
|
||||
REQUIRE_FALSE( is_permutation( arr1, arr3 ) );
|
||||
REQUIRE_FALSE( is_permutation( arr2, arr3 ) );
|
||||
}
|
||||
SECTION( "Same length ranges" ) {
|
||||
SECTION( "Shared elements, but different counts" ) {
|
||||
const std::array<int, 6>
|
||||
arr1{ { 1, 1, 1, 1, 2, 2 } },
|
||||
arr2{ { 1, 1, 2, 2, 2, 2 } };
|
||||
REQUIRE_FALSE( is_permutation( arr1, arr2 ) );
|
||||
}
|
||||
SECTION( "Identical ranges" ) {
|
||||
const std::array<int, 6>
|
||||
arr1{ { 1, 1, 1, 1, 2, 2 } },
|
||||
arr2{ { 1, 1, 2, 2, 2, 2 } };
|
||||
REQUIRE( is_permutation( arr1, arr1 ) );
|
||||
REQUIRE( is_permutation( arr2, arr2 ) );
|
||||
}
|
||||
SECTION( "Completely distinct elements" ) {
|
||||
// Completely distinct elements
|
||||
const std::array<int, 4>
|
||||
arr1{ { 1, 2, 3, 4 } },
|
||||
arr2{ { 10, 20, 30, 40 } };
|
||||
REQUIRE_FALSE( is_permutation( arr1, arr2 ) );
|
||||
}
|
||||
SECTION( "Reverse ranges" ) {
|
||||
const std::array<int, 5>
|
||||
arr1{ { 1, 2, 3, 4, 5 } },
|
||||
arr2{ { 5, 4, 3, 2, 1 } };
|
||||
REQUIRE( is_permutation( arr1, arr2 ) );
|
||||
}
|
||||
SECTION( "Shared prefix & permuted elements" ) {
|
||||
const std::array<int, 5>
|
||||
arr1{ { 1, 1, 2, 3, 4 } },
|
||||
arr2{ { 1, 1, 4, 2, 3 } };
|
||||
REQUIRE( is_permutation( arr1, arr2 ) );
|
||||
}
|
||||
SECTION( "Permutations with element count > 1" ) {
|
||||
const std::array<int, 7>
|
||||
arr1{ { 2, 2, 3, 3, 3, 1, 1 } },
|
||||
arr2{ { 3, 2, 1, 3, 2, 1, 3 } };
|
||||
REQUIRE( is_permutation( arr1, arr2 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("is_permutation supports iterator + sentinel pairs",
|
||||
"[algorithms][is-permutation][approvals]") {
|
||||
const has_different_begin_end_types<int>
|
||||
range_1{ 1, 2, 3, 4 },
|
||||
range_2{ 4, 3, 2, 1 };
|
||||
REQUIRE( is_permutation( range_1, range_2 ) );
|
||||
|
||||
const has_different_begin_end_types<int> range_3{ 3, 3, 2, 1 };
|
||||
REQUIRE_FALSE( is_permutation( range_1, range_3 ) );
|
||||
}
|
||||
Vendored
+17
@@ -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/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE( "Incomplete AssertionHandler", "[assertion-handler][!shouldfail]" ) {
|
||||
Catch::AssertionHandler catchAssertionHandler(
|
||||
"REQUIRE"_catch_sr,
|
||||
CATCH_INTERNAL_LINEINFO,
|
||||
"Dummy",
|
||||
Catch::ResultDisposition::Normal );
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_clara.hpp>
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
TEST_CASE("is_unary_function", "[clara][compilation]") {
|
||||
auto unary1 = [](int) {};
|
||||
auto unary2 = [](std::string const&) {};
|
||||
auto const unary3 = [](std::string const&) {};
|
||||
auto unary4 = [](int) { return 42; };
|
||||
void unary5(char);
|
||||
double unary6(long);
|
||||
|
||||
double binary1(long, int);
|
||||
auto binary2 = [](int, char) {};
|
||||
auto nullary1 = []() {};
|
||||
auto nullary2 = []() {return 42;};
|
||||
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary1)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary2)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary3)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary4)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary5)>::value);
|
||||
STATIC_REQUIRE(Catch::Clara::Detail::is_unary_function<decltype(unary6)>::value);
|
||||
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(binary1)>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(binary2)>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(nullary1)>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<decltype(nullary2)>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<int>::value);
|
||||
STATIC_REQUIRE_FALSE(Catch::Clara::Detail::is_unary_function<std::string const&>::value);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Clara::Arg supports single-arg parse the way Opt does", "[clara][arg][compilation]") {
|
||||
std::string name;
|
||||
auto p = Catch::Clara::Arg(name, "just one arg");
|
||||
|
||||
CHECK(name.empty());
|
||||
|
||||
p.parse( Catch::Clara::Args{ "UnitTest", "foo" } );
|
||||
REQUIRE(name == "foo");
|
||||
}
|
||||
|
||||
TEST_CASE("Clara::Opt supports accept-many lambdas", "[clara][opt]") {
|
||||
using namespace Catch::Clara;
|
||||
std::vector<std::string> res;
|
||||
const auto push_to_res = [&](std::string const& s) {
|
||||
res.push_back(s);
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
|
||||
SECTION("Parsing fails on multiple options without accept_many") {
|
||||
auto p = Parser() | Opt(push_to_res, "value")["-o"];
|
||||
auto parse_result = p.parse( Args{ "UnitTest", "-o", "aaa", "-o", "bbb" } );
|
||||
CHECK_FALSE(parse_result);
|
||||
}
|
||||
SECTION("Parsing succeeds on multiple options with accept_many") {
|
||||
auto p = Parser() | Opt(accept_many, push_to_res, "value")["-o"];
|
||||
auto parse_result = p.parse( Args{ "UnitTest", "-o", "aaa", "-o", "bbb" } );
|
||||
CHECK(parse_result);
|
||||
CHECK(res == std::vector<std::string>{ "aaa", "bbb" });
|
||||
}
|
||||
}
|
||||
+467
@@ -0,0 +1,467 @@
|
||||
|
||||
// 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_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_commandline.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
|
||||
|
||||
namespace {
|
||||
auto fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCaseInfo("", { name, desc }, CATCH_INTERNAL_LINEINFO); }
|
||||
}
|
||||
|
||||
TEST_CASE( "Process can be configured on command line", "[config][command-line]" ) {
|
||||
|
||||
using namespace Catch::Matchers;
|
||||
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser(config);
|
||||
|
||||
SECTION("empty args don't cause a crash") {
|
||||
auto result = cli.parse({""});
|
||||
CHECK(result);
|
||||
CHECK(config.processName == "");
|
||||
}
|
||||
|
||||
SECTION("default - no arguments") {
|
||||
auto result = cli.parse({"test"});
|
||||
CHECK(result);
|
||||
CHECK(config.processName == "test");
|
||||
CHECK(config.shouldDebugBreak == false);
|
||||
CHECK(config.abortAfter == -1);
|
||||
CHECK(config.noThrow == false);
|
||||
CHECK( config.reporterSpecifications.empty() );
|
||||
|
||||
Catch::Config cfg(config);
|
||||
CHECK_FALSE(cfg.hasTestFilters());
|
||||
|
||||
// The Config is responsible for mixing in the default reporter
|
||||
auto expectedReporter =
|
||||
#if defined( CATCH_CONFIG_DEFAULT_REPORTER )
|
||||
CATCH_CONFIG_DEFAULT_REPORTER
|
||||
#else
|
||||
"console"
|
||||
#endif
|
||||
;
|
||||
|
||||
CHECK( cfg.getReporterSpecs().size() == 1 );
|
||||
CHECK( cfg.getReporterSpecs()[0] ==
|
||||
Catch::ReporterSpec{ expectedReporter, {}, {}, {} } );
|
||||
CHECK( cfg.getProcessedReporterSpecs().size() == 1 );
|
||||
CHECK( cfg.getProcessedReporterSpecs()[0] ==
|
||||
Catch::ProcessedReporterSpec{ expectedReporter,
|
||||
std::string{},
|
||||
Catch::ColourMode::PlatformDefault,
|
||||
{} } );
|
||||
}
|
||||
|
||||
SECTION("test lists") {
|
||||
SECTION("Specify one test case using") {
|
||||
auto result = cli.parse({"test", "test1"});
|
||||
CHECK(result);
|
||||
|
||||
Catch::Config cfg(config);
|
||||
REQUIRE(cfg.hasTestFilters());
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("notIncluded")) == false);
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("test1")));
|
||||
}
|
||||
SECTION("Specify one test case exclusion using exclude:") {
|
||||
auto result = cli.parse({"test", "exclude:test1"});
|
||||
CHECK(result);
|
||||
|
||||
Catch::Config cfg(config);
|
||||
REQUIRE(cfg.hasTestFilters());
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("test1")) == false);
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")));
|
||||
}
|
||||
|
||||
SECTION("Specify one test case exclusion using ~") {
|
||||
auto result = cli.parse({"test", "~test1"});
|
||||
CHECK(result);
|
||||
|
||||
Catch::Config cfg(config);
|
||||
REQUIRE(cfg.hasTestFilters());
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("test1")) == false);
|
||||
REQUIRE(cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("reporter") {
|
||||
using vec_Specs = std::vector<Catch::ReporterSpec>;
|
||||
using namespace std::string_literals;
|
||||
SECTION("-r/console") {
|
||||
auto result = cli.parse({"test", "-r", "console"});
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "console", {}, {}, {} } } );
|
||||
}
|
||||
SECTION("-r/xml") {
|
||||
auto result = cli.parse({"test", "-r", "xml"});
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "xml", {}, {}, {} } } );
|
||||
}
|
||||
SECTION("--reporter/junit") {
|
||||
auto result = cli.parse({"test", "--reporter", "junit"});
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "junit", {}, {}, {} } } );
|
||||
}
|
||||
SECTION("must match one of the available ones") {
|
||||
auto result = cli.parse({"test", "--reporter", "unsupported"});
|
||||
CHECK(!result);
|
||||
|
||||
REQUIRE_THAT(result.errorMessage(), ContainsSubstring("Unrecognized reporter"));
|
||||
}
|
||||
SECTION("With output file") {
|
||||
auto result = cli.parse({ "test", "-r", "console::out=out.txt" });
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "console", "out.txt"s, {}, {} } } );
|
||||
}
|
||||
SECTION("With Windows-like absolute path as output file") {
|
||||
auto result = cli.parse({ "test", "-r", "console::out=C:\\Temp\\out.txt" });
|
||||
CAPTURE(result.errorMessage());
|
||||
CHECK(result);
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } );
|
||||
}
|
||||
SECTION("Multiple reporters") {
|
||||
SECTION("All with output files") {
|
||||
CHECK(cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "junit::out=output-junit.xml" }));
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "xml", "output.xml"s, {}, {} },
|
||||
{ "junit", "output-junit.xml"s, {}, {} } } );
|
||||
}
|
||||
SECTION("Mixed output files and default output") {
|
||||
CHECK(cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "console" }));
|
||||
REQUIRE( config.reporterSpecifications ==
|
||||
vec_Specs{ { "xml", "output.xml"s, {}, {} },
|
||||
{ "console", {}, {}, {} } } );
|
||||
}
|
||||
SECTION("cannot have multiple reporters with default output") {
|
||||
auto result = cli.parse({ "test", "-r", "console", "-r", "xml::out=output.xml", "-r", "junit" });
|
||||
CHECK(!result);
|
||||
REQUIRE_THAT(result.errorMessage(), ContainsSubstring("Only one reporter may have unspecified output file."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("debugger") {
|
||||
SECTION("-b") {
|
||||
CHECK(cli.parse({"test", "-b"}));
|
||||
|
||||
REQUIRE(config.shouldDebugBreak == true);
|
||||
}
|
||||
SECTION("--break") {
|
||||
CHECK(cli.parse({"test", "--break"}));
|
||||
|
||||
REQUIRE(config.shouldDebugBreak);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SECTION("abort") {
|
||||
SECTION("-a aborts after first failure") {
|
||||
CHECK(cli.parse({"test", "-a"}));
|
||||
|
||||
REQUIRE(config.abortAfter == 1);
|
||||
}
|
||||
SECTION("-x 2 aborts after two failures") {
|
||||
CHECK(cli.parse({"test", "-x", "2"}));
|
||||
|
||||
REQUIRE(config.abortAfter == 2);
|
||||
}
|
||||
SECTION("-x must be numeric") {
|
||||
auto result = cli.parse({"test", "-x", "oops"});
|
||||
CHECK(!result);
|
||||
REQUIRE_THAT(result.errorMessage(), ContainsSubstring("convert") && ContainsSubstring("oops"));
|
||||
}
|
||||
|
||||
SECTION("wait-for-keypress") {
|
||||
SECTION("Accepted options") {
|
||||
using tuple_type = std::tuple<char const*, Catch::WaitForKeypress::When>;
|
||||
auto input = GENERATE(table<char const*, Catch::WaitForKeypress::When>({
|
||||
tuple_type{"never", Catch::WaitForKeypress::Never},
|
||||
tuple_type{"start", Catch::WaitForKeypress::BeforeStart},
|
||||
tuple_type{"exit", Catch::WaitForKeypress::BeforeExit},
|
||||
tuple_type{"both", Catch::WaitForKeypress::BeforeStartAndExit},
|
||||
}));
|
||||
CHECK(cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}));
|
||||
|
||||
REQUIRE(config.waitForKeypress == std::get<1>(input));
|
||||
}
|
||||
|
||||
SECTION("invalid options are reported") {
|
||||
auto result = cli.parse({"test", "--wait-for-keypress", "sometimes"});
|
||||
CHECK(!result);
|
||||
|
||||
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
|
||||
REQUIRE_THAT(result.errorMessage(), ContainsSubstring("never") && ContainsSubstring("both"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("nothrow") {
|
||||
SECTION("-e") {
|
||||
CHECK(cli.parse({"test", "-e"}));
|
||||
|
||||
REQUIRE(config.noThrow);
|
||||
}
|
||||
SECTION("--nothrow") {
|
||||
CHECK(cli.parse({"test", "--nothrow"}));
|
||||
|
||||
REQUIRE(config.noThrow);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("output filename") {
|
||||
SECTION("-o filename") {
|
||||
CHECK(cli.parse({"test", "-o", "filename.ext"}));
|
||||
|
||||
REQUIRE(config.defaultOutputFilename == "filename.ext");
|
||||
}
|
||||
SECTION("--out") {
|
||||
CHECK(cli.parse({"test", "--out", "filename.ext"}));
|
||||
|
||||
REQUIRE(config.defaultOutputFilename == "filename.ext");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("combinations") {
|
||||
SECTION("Single character flags can be combined") {
|
||||
CHECK(cli.parse({"test", "-abe"}));
|
||||
|
||||
CHECK(config.abortAfter == 1);
|
||||
CHECK(config.shouldDebugBreak);
|
||||
CHECK(config.noThrow == true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SECTION( "use-colour") {
|
||||
|
||||
using Catch::ColourMode;
|
||||
|
||||
SECTION( "without option" ) {
|
||||
CHECK(cli.parse({"test"}));
|
||||
|
||||
REQUIRE( config.defaultColourMode == ColourMode::PlatformDefault );
|
||||
}
|
||||
|
||||
SECTION( "auto" ) {
|
||||
CHECK( cli.parse( { "test", "--colour-mode", "default" } ) );
|
||||
|
||||
REQUIRE( config.defaultColourMode == ColourMode::PlatformDefault );
|
||||
}
|
||||
|
||||
SECTION( "yes" ) {
|
||||
CHECK(cli.parse({"test", "--colour-mode", "ansi"}));
|
||||
|
||||
REQUIRE( config.defaultColourMode == ColourMode::ANSI );
|
||||
}
|
||||
|
||||
SECTION( "no" ) {
|
||||
CHECK(cli.parse({"test", "--colour-mode", "none"}));
|
||||
|
||||
REQUIRE( config.defaultColourMode == ColourMode::None );
|
||||
}
|
||||
|
||||
SECTION( "error" ) {
|
||||
auto result = cli.parse({"test", "--colour-mode", "wrong"});
|
||||
CHECK( !result );
|
||||
CHECK_THAT( result.errorMessage(), ContainsSubstring( "colour mode must be one of" ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Benchmark options") {
|
||||
SECTION("samples") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-samples=200" }));
|
||||
|
||||
REQUIRE(config.benchmarkSamples == 200);
|
||||
}
|
||||
|
||||
SECTION("resamples") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-resamples=20000" }));
|
||||
|
||||
REQUIRE(config.benchmarkResamples == 20000);
|
||||
}
|
||||
|
||||
SECTION("confidence-interval") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-confidence-interval=0.99" }));
|
||||
|
||||
REQUIRE(config.benchmarkConfidenceInterval == Catch::Approx(0.99));
|
||||
}
|
||||
|
||||
SECTION("no-analysis") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-no-analysis" }));
|
||||
|
||||
REQUIRE(config.benchmarkNoAnalysis);
|
||||
}
|
||||
|
||||
SECTION("warmup-time") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-warmup-time=10" }));
|
||||
|
||||
REQUIRE(config.benchmarkWarmupTime == 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parsing sharding-related cli flags", "[sharding]") {
|
||||
using namespace Catch::Matchers;
|
||||
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser(config);
|
||||
|
||||
SECTION("shard-count") {
|
||||
CHECK(cli.parse({ "test", "--shard-count=8" }));
|
||||
|
||||
REQUIRE(config.shardCount == 8);
|
||||
}
|
||||
|
||||
SECTION("Negative shard count reports error") {
|
||||
auto result = cli.parse({ "test", "--shard-count=-1" });
|
||||
|
||||
CHECK_FALSE(result);
|
||||
REQUIRE_THAT(
|
||||
result.errorMessage(),
|
||||
ContainsSubstring( "Could not parse '-1' as shard count" ) );
|
||||
}
|
||||
|
||||
SECTION("Zero shard count reports error") {
|
||||
auto result = cli.parse({ "test", "--shard-count=0" });
|
||||
|
||||
CHECK_FALSE(result);
|
||||
REQUIRE_THAT(
|
||||
result.errorMessage(),
|
||||
ContainsSubstring( "Shard count must be positive" ) );
|
||||
}
|
||||
|
||||
SECTION("shard-index") {
|
||||
CHECK(cli.parse({ "test", "--shard-index=2" }));
|
||||
|
||||
REQUIRE(config.shardIndex == 2);
|
||||
}
|
||||
|
||||
SECTION("Negative shard index reports error") {
|
||||
auto result = cli.parse({ "test", "--shard-index=-12" });
|
||||
|
||||
CHECK_FALSE(result);
|
||||
REQUIRE_THAT(
|
||||
result.errorMessage(),
|
||||
ContainsSubstring( "Could not parse '-12' as shard index" ) );
|
||||
}
|
||||
|
||||
SECTION("Shard index 0 is accepted") {
|
||||
CHECK(cli.parse({ "test", "--shard-index=0" }));
|
||||
|
||||
REQUIRE(config.shardIndex == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Parsing warnings", "[cli][warnings]" ) {
|
||||
using Catch::WarnAbout;
|
||||
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser( config );
|
||||
|
||||
SECTION( "NoAssertions" ) {
|
||||
REQUIRE(cli.parse( { "test", "-w", "NoAssertions" } ));
|
||||
REQUIRE( config.warnings == WarnAbout::NoAssertions );
|
||||
}
|
||||
SECTION( "NoTests is no longer supported" ) {
|
||||
REQUIRE_FALSE(cli.parse( { "test", "-w", "NoTests" } ));
|
||||
}
|
||||
SECTION( "Combining multiple warnings" ) {
|
||||
REQUIRE( cli.parse( { "test",
|
||||
"--warn", "NoAssertions",
|
||||
"--warn", "UnmatchedTestSpec" } ) );
|
||||
|
||||
REQUIRE( config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test with special, characters \"in name", "[cli][regression]") {
|
||||
// This test case succeeds if we can invoke it from the CLI
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("Various suspicious reporter specs are rejected",
|
||||
"[cli][reporter-spec][approvals]") {
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser( config );
|
||||
|
||||
auto spec = GENERATE( as<std::string>{},
|
||||
"",
|
||||
"::console",
|
||||
"console::",
|
||||
"console::some-file::",
|
||||
"::console::some-file::" );
|
||||
CAPTURE( spec );
|
||||
|
||||
auto result = cli.parse( { "test", "--reporter", spec } );
|
||||
REQUIRE_FALSE( result );
|
||||
}
|
||||
|
||||
TEST_CASE("Win32 colour implementation is compile-time optional",
|
||||
"[approvals][cli][colours]") {
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser( config );
|
||||
|
||||
auto result = cli.parse( { "test", "--colour-mode", "win32" } );
|
||||
|
||||
#if defined( CATCH_CONFIG_COLOUR_WIN32 )
|
||||
REQUIRE( result );
|
||||
#else
|
||||
REQUIRE_FALSE( result );
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE( "Parse rng seed in different formats", "[approvals][cli][rng-seed]" ) {
|
||||
Catch::ConfigData config;
|
||||
auto cli = Catch::makeCommandLineParser( config );
|
||||
|
||||
SECTION("well formed cases") {
|
||||
char const* seed_string;
|
||||
uint32_t seed_value;
|
||||
// GCC-5 workaround
|
||||
using gen_type = std::tuple<char const*, uint32_t>;
|
||||
std::tie( seed_string, seed_value ) = GENERATE( table<char const*, uint32_t>({
|
||||
gen_type{ "0xBEEF", 0xBEEF },
|
||||
gen_type{ "12345678", 12345678 }
|
||||
} ) );
|
||||
CAPTURE( seed_string );
|
||||
|
||||
auto result = cli.parse( { "tests", "--rng-seed", seed_string } );
|
||||
|
||||
REQUIRE( result );
|
||||
REQUIRE( config.rngSeed == seed_value );
|
||||
}
|
||||
SECTION( "Error cases" ) {
|
||||
auto seed_string =
|
||||
GENERATE( "0xSEED", "999999999999", "08888", "BEEF", "123 456" );
|
||||
CAPTURE( seed_string );
|
||||
REQUIRE_FALSE( cli.parse( { "tests", "--rng-seed", seed_string } ) );
|
||||
}
|
||||
}
|
||||
Vendored
+111
@@ -0,0 +1,111 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_reporter_spec_parser.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
|
||||
TEST_CASE("Reporter spec splitting", "[reporter-spec][cli][approvals]") {
|
||||
using Catch::Detail::splitReporterSpec;
|
||||
using Catch::Matchers::Equals;
|
||||
using namespace std::string_literals;
|
||||
|
||||
SECTION("Various edge cases") {
|
||||
REQUIRE_THAT( splitReporterSpec( "" ),
|
||||
Equals( std::vector<std::string>{ ""s } ) );
|
||||
REQUIRE_THAT( splitReporterSpec( "::" ),
|
||||
Equals( std::vector<std::string>{ "", "" } ) );
|
||||
REQUIRE_THAT( splitReporterSpec( "::rep" ),
|
||||
Equals( std::vector<std::string>{ "", "rep" } ) );
|
||||
REQUIRE_THAT( splitReporterSpec( "rep::" ),
|
||||
Equals( std::vector<std::string>{ "rep", "" } ) );
|
||||
|
||||
}
|
||||
|
||||
SECTION("Validish specs") {
|
||||
REQUIRE_THAT( splitReporterSpec( "newReporter" ),
|
||||
Equals( std::vector<std::string>{ "newReporter"s } ) );
|
||||
REQUIRE_THAT(
|
||||
splitReporterSpec( "foo-reporter::key1=value1::key2=value with "
|
||||
"space::key with space=some-value" ),
|
||||
Equals(
|
||||
std::vector<std::string>{ "foo-reporter"s,
|
||||
"key1=value1"s,
|
||||
"key2=value with space"s,
|
||||
"key with space=some-value"s } ) );
|
||||
REQUIRE_THAT(
|
||||
splitReporterSpec( "spaced reporter name::key:key=value:value" ),
|
||||
Equals( std::vector<std::string>{ "spaced reporter name"s,
|
||||
"key:key=value:value"s } ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Parsing colour mode", "[cli][colour][approvals]" ) {
|
||||
using Catch::Detail::stringToColourMode;
|
||||
using Catch::ColourMode;
|
||||
SECTION("Valid strings") {
|
||||
REQUIRE( stringToColourMode( "none" ) == ColourMode::None );
|
||||
REQUIRE( stringToColourMode( "ansi" ) == ColourMode::ANSI );
|
||||
REQUIRE( stringToColourMode( "win32" ) == ColourMode::Win32 );
|
||||
REQUIRE( stringToColourMode( "default" ) ==
|
||||
ColourMode::PlatformDefault );
|
||||
}
|
||||
SECTION("Wrong strings") {
|
||||
REQUIRE_FALSE( stringToColourMode( "NONE" ) );
|
||||
REQUIRE_FALSE( stringToColourMode( "-" ) );
|
||||
REQUIRE_FALSE( stringToColourMode( "asdbjsdb kasbd" ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Parsing reporter specs", "[cli][reporter-spec][approvals]") {
|
||||
using Catch::parseReporterSpec;
|
||||
using Catch::ReporterSpec;
|
||||
using namespace std::string_literals;
|
||||
|
||||
SECTION( "Correct specs" ) {
|
||||
REQUIRE( parseReporterSpec( "someReporter" ) ==
|
||||
ReporterSpec( "someReporter"s, {}, {}, {} ) );
|
||||
REQUIRE( parseReporterSpec( "otherReporter::Xk=v::out=c:\\blah" ) ==
|
||||
ReporterSpec(
|
||||
"otherReporter"s, "c:\\blah"s, {}, { { "Xk"s, "v"s } } ) );
|
||||
REQUIRE( parseReporterSpec( "diffReporter::Xk1=v1::Xk2==v2" ) ==
|
||||
ReporterSpec( "diffReporter",
|
||||
{},
|
||||
{},
|
||||
{ { "Xk1"s, "v1"s }, { "Xk2"s, "=v2"s } } ) );
|
||||
REQUIRE( parseReporterSpec(
|
||||
"Foo:bar:reporter::colour-mode=ansi::Xk 1=v 1::Xk2=v:3" ) ==
|
||||
ReporterSpec( "Foo:bar:reporter",
|
||||
{},
|
||||
Catch::ColourMode::ANSI,
|
||||
{ { "Xk 1"s, "v 1"s }, { "Xk2"s, "v:3"s } } ) );
|
||||
}
|
||||
|
||||
SECTION( "Bad specs" ) {
|
||||
REQUIRE_FALSE( parseReporterSpec( "::" ) );
|
||||
// Unknown Catch2 arg (should be "out")
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::output=filename" ) );
|
||||
// Wrong colour spec
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::colour-mode=custom" ) );
|
||||
// Duplicated colour spec
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::colour-mode=ansi::colour-mode=ansi" ) );
|
||||
// Duplicated out arg
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::out=f.txt::out=z.txt" ) );
|
||||
// Duplicated custom arg
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::Xa=foo::Xa=bar" ) );
|
||||
// Empty key
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::X=foo" ) );
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::=foo" ) );
|
||||
// Empty value
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::Xa=" ) );
|
||||
// non-key value later field
|
||||
REQUIRE_FALSE( parseReporterSpec( "reporter::Xab" ) );
|
||||
}
|
||||
}
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
class TestColourImpl : public Catch::ColourImpl {
|
||||
using Catch::ColourImpl::ColourImpl;
|
||||
// Inherited via ColourImpl
|
||||
void use( Catch::Colour::Code colourCode ) const override {
|
||||
m_stream->stream() << "Using code: " << colourCode << '\n';
|
||||
}
|
||||
};
|
||||
|
||||
class TestStringStream : public Catch::IStream {
|
||||
std::stringstream m_stream;
|
||||
public:
|
||||
std::ostream& stream() override {
|
||||
return m_stream;
|
||||
}
|
||||
|
||||
std::string str() const { return m_stream.str(); }
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("ColourGuard behaviour", "[console-colours]") {
|
||||
TestStringStream streamWrapper;
|
||||
TestColourImpl colourImpl( &streamWrapper );
|
||||
auto& stream = streamWrapper.stream();
|
||||
|
||||
SECTION("ColourGuard is disengaged by default") {
|
||||
{ auto guard = colourImpl.guardColour( Catch::Colour::Red ); }
|
||||
|
||||
REQUIRE( streamWrapper.str().empty() );
|
||||
}
|
||||
|
||||
SECTION("ColourGuard is engaged by op<<") {
|
||||
stream << "1\n" << colourImpl.guardColour( Catch::Colour::Red ) << "2\n";
|
||||
stream << "3\n";
|
||||
|
||||
REQUIRE( streamWrapper.str() == "1\nUsing code: 2\n2\nUsing code: 0\n3\n" );
|
||||
}
|
||||
|
||||
SECTION("ColourGuard can be engaged explicitly") {
|
||||
{
|
||||
auto guard =
|
||||
colourImpl.guardColour( Catch::Colour::Red ).engage( stream );
|
||||
stream << "A\n"
|
||||
<< "B\n";
|
||||
}
|
||||
stream << "C\n";
|
||||
REQUIRE( streamWrapper.str() ==
|
||||
"Using code: 2\nA\nB\nUsing code: 0\nC\n" );
|
||||
}
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||
#include <catch2/internal/catch_optional.hpp>
|
||||
|
||||
#include <helpers/type_with_lit_0_comparisons.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4702) // unreachable code in the macro expansions
|
||||
#endif
|
||||
|
||||
TEST_CASE("Check that our error handling macros throw the right exceptions", "[!throws][internals][approvals]") {
|
||||
REQUIRE_THROWS_AS(CATCH_INTERNAL_ERROR(""), std::logic_error);
|
||||
REQUIRE_THROWS_AS(CATCH_ERROR(""), std::domain_error);
|
||||
REQUIRE_THROWS_AS(CATCH_RUNTIME_ERROR(""), std::runtime_error);
|
||||
REQUIRE_THROWS_AS([](){CATCH_ENFORCE(false, "");}(), std::domain_error);
|
||||
REQUIRE_NOTHROW([](){CATCH_ENFORCE(true, "");}());
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop) // unreachable code in the macro expansions
|
||||
#endif
|
||||
|
||||
TEST_CASE("CaseInsensitiveLess is case insensitive", "[comparisons][string-case]") {
|
||||
Catch::Detail::CaseInsensitiveLess lt;
|
||||
SECTION( "Degenerate cases" ) {
|
||||
REQUIRE( lt( "", "a" ) );
|
||||
REQUIRE_FALSE( lt( "a", "a" ) );
|
||||
REQUIRE_FALSE( lt( "", "" ) );
|
||||
}
|
||||
SECTION("Plain comparisons") {
|
||||
REQUIRE( lt( "a", "b" ) );
|
||||
REQUIRE( lt( "a", "B" ) );
|
||||
REQUIRE( lt( "A", "b" ) );
|
||||
REQUIRE( lt( "A", "B" ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "CaseInsensitiveEqualsTo is case insensitive",
|
||||
"[comparisons][string-case]" ) {
|
||||
Catch::Detail::CaseInsensitiveEqualTo eq;
|
||||
SECTION( "Degenerate cases" ) {
|
||||
REQUIRE( eq( "", "" ) );
|
||||
REQUIRE_FALSE( eq( "", "a" ) );
|
||||
}
|
||||
SECTION( "Plain comparisons" ) {
|
||||
REQUIRE( eq( "a", "a" ) );
|
||||
REQUIRE( eq( "a", "A" ) );
|
||||
REQUIRE( eq( "A", "a" ) );
|
||||
REQUIRE( eq( "A", "A" ) );
|
||||
REQUIRE_FALSE( eq( "a", "b" ) );
|
||||
REQUIRE_FALSE( eq( "a", "B" ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Optional comparison ops", "[optional][approvals]") {
|
||||
using Catch::Optional;
|
||||
|
||||
Optional<int> a, b;
|
||||
|
||||
SECTION( "Empty optionals are equal" ) {
|
||||
REQUIRE( a == b );
|
||||
REQUIRE_FALSE( a != b );
|
||||
}
|
||||
SECTION( "Empty and non-empty optionals are never equal" ) {
|
||||
a = 1;
|
||||
REQUIRE_FALSE( a == b );
|
||||
REQUIRE( a != b );
|
||||
}
|
||||
SECTION(
|
||||
"non-empty optionals are equal if the contained elements are equal") {
|
||||
a = 1;
|
||||
b = 2;
|
||||
REQUIRE( a != b );
|
||||
REQUIRE_FALSE( a == b );
|
||||
|
||||
a = 2;
|
||||
REQUIRE( a == b );
|
||||
REQUIRE_FALSE( a != b );
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct MoveChecker {
|
||||
bool has_moved = false;
|
||||
MoveChecker() = default;
|
||||
MoveChecker( MoveChecker const& rhs ) = default;
|
||||
MoveChecker& operator=( MoveChecker const& rhs ) = default;
|
||||
MoveChecker( MoveChecker&& rhs ) noexcept { rhs.has_moved = true; }
|
||||
MoveChecker& operator=( MoveChecker&& rhs ) noexcept {
|
||||
rhs.has_moved = true;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE( "Optional supports move ops", "[optional][approvals]" ) {
|
||||
using Catch::Optional;
|
||||
MoveChecker a;
|
||||
Optional<MoveChecker> opt_A( a );
|
||||
REQUIRE_FALSE( a.has_moved );
|
||||
REQUIRE_FALSE( opt_A->has_moved );
|
||||
|
||||
SECTION( "Move construction from element" ) {
|
||||
Optional<MoveChecker> opt_B( CATCH_MOVE( a ) );
|
||||
REQUIRE( a.has_moved );
|
||||
}
|
||||
SECTION( "Move assignment from element" ) {
|
||||
opt_A = CATCH_MOVE( a );
|
||||
REQUIRE( a.has_moved );
|
||||
}
|
||||
SECTION( "Move construction from optional" ) {
|
||||
Optional<MoveChecker> opt_B( CATCH_MOVE( opt_A ) );
|
||||
REQUIRE( opt_A->has_moved );
|
||||
}
|
||||
SECTION( "Move assignment from optional" ) {
|
||||
Optional<MoveChecker> opt_B( opt_A );
|
||||
REQUIRE_FALSE( opt_A->has_moved );
|
||||
opt_B = CATCH_MOVE( opt_A );
|
||||
REQUIRE( opt_A->has_moved );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Decomposer checks that the argument is 0 when handling "
|
||||
"only-0-comparable types",
|
||||
"[decomposition][approvals]" ) {
|
||||
TypeWithLit0Comparisons t{};
|
||||
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t == 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 == t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t == 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 == t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t != 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 != t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t != 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 != t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t < 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 < t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t < 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 < t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t <= 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 <= t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t <= 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 <= t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t > 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 > t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t > 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 > t );
|
||||
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= t >= 42 );
|
||||
REQUIRE_THROWS( Catch::Decomposer{} <= 42 >= t );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= t >= 0 );
|
||||
REQUIRE_NOTHROW( Catch::Decomposer{} <= 0 >= t );
|
||||
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
}
|
||||
Vendored
+133
@@ -0,0 +1,133 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <catch2/internal/catch_floating_point_helpers.hpp>
|
||||
#include <catch2/internal/catch_random_floating_point_helpers.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
TEST_CASE("convertToBits", "[floating-point][conversion]") {
|
||||
using Catch::Detail::convertToBits;
|
||||
|
||||
CHECK( convertToBits( 0.f ) == 0 );
|
||||
CHECK( convertToBits( -0.f ) == ( 1ULL << 31 ) );
|
||||
CHECK( convertToBits( 0. ) == 0 );
|
||||
CHECK( convertToBits( -0. ) == ( 1ULL << 63 ) );
|
||||
CHECK( convertToBits( std::numeric_limits<float>::denorm_min() ) == 1 );
|
||||
CHECK( convertToBits( std::numeric_limits<double>::denorm_min() ) == 1 );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE("type-shared ulpDistance tests", "[floating-point][ulp][approvals]", float, double) {
|
||||
using FP = TestType;
|
||||
using Catch::ulpDistance;
|
||||
|
||||
// Distance between zeros is zero
|
||||
CHECK( ulpDistance( FP{}, FP{} ) == 0 );
|
||||
CHECK( ulpDistance( FP{}, -FP{} ) == 0 );
|
||||
CHECK( ulpDistance( -FP{}, -FP{} ) == 0 );
|
||||
|
||||
// Distance between same-sign infinities is zero
|
||||
static constexpr FP infinity = std::numeric_limits<FP>::infinity();
|
||||
CHECK( ulpDistance( infinity, infinity ) == 0 );
|
||||
CHECK( ulpDistance( -infinity, -infinity ) == 0 );
|
||||
|
||||
// Distance between max-finite-val and same sign infinity is 1
|
||||
static constexpr FP max_finite = std::numeric_limits<FP>::max();
|
||||
CHECK( ulpDistance( max_finite, infinity ) == 1 );
|
||||
CHECK( ulpDistance( -max_finite, -infinity ) == 1 );
|
||||
|
||||
// Distance between X and 0 is half of distance between X and -X
|
||||
CHECK( ulpDistance( -infinity, infinity ) ==
|
||||
2 * ulpDistance( infinity, FP{} ) );
|
||||
CHECK( 2 * ulpDistance( FP{ -2. }, FP{} ) ==
|
||||
ulpDistance( FP{ -2. }, FP{ 2. } ) );
|
||||
CHECK( 2 * ulpDistance( FP{ 2. }, FP{} ) ==
|
||||
ulpDistance( FP{ -2. }, FP{ 2. } ) );
|
||||
|
||||
// Denorms are supported
|
||||
CHECK( ulpDistance( std::numeric_limits<FP>::denorm_min(), FP{} ) == 1 );
|
||||
CHECK( ulpDistance( std::numeric_limits<FP>::denorm_min(), -FP{} ) == 1 );
|
||||
CHECK( ulpDistance( -std::numeric_limits<FP>::denorm_min(), FP{} ) == 1 );
|
||||
CHECK( ulpDistance( -std::numeric_limits<FP>::denorm_min(), -FP{} ) == 1 );
|
||||
CHECK( ulpDistance( std::numeric_limits<FP>::denorm_min(),
|
||||
-std::numeric_limits<FP>::denorm_min() ) == 2 );
|
||||
|
||||
// Machine epsilon
|
||||
CHECK( ulpDistance( FP{ 1. },
|
||||
FP{ 1. } + std::numeric_limits<FP>::epsilon() ) == 1 );
|
||||
CHECK( ulpDistance( -FP{ 1. },
|
||||
-FP{ 1. } - std::numeric_limits<FP>::epsilon() ) == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE("UlpDistance", "[floating-point][ulp][approvals]") {
|
||||
using Catch::ulpDistance;
|
||||
|
||||
CHECK( ulpDistance( 1., 2. ) == 0x10'00'00'00'00'00'00 );
|
||||
CHECK( ulpDistance( -2., 2. ) == 0x80'00'00'00'00'00'00'00 );
|
||||
CHECK( ulpDistance( 1.f, 2.f ) == 0x80'00'00 );
|
||||
CHECK( ulpDistance( -2.f, 2.f ) == 0x80'00'00'00 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEMPLATE_TEST_CASE("gamma", "[approvals][floating-point][ulp][gamma]", float, double) {
|
||||
using Catch::Detail::gamma;
|
||||
using Catch::Detail::directCompare;
|
||||
|
||||
// We need to butcher the equal tests with the directCompare helper,
|
||||
// because the Wfloat-equal triggers in decomposer rather than here,
|
||||
// so we cannot locally disable it. Goddamn GCC.
|
||||
CHECK( directCompare( gamma( TestType( -1. ), TestType( 1. ) ),
|
||||
gamma( TestType( 0.2332 ), TestType( 1.0 ) ) ) );
|
||||
CHECK( directCompare( gamma( TestType( -2. ), TestType( 0 ) ),
|
||||
gamma( TestType( 1. ), TestType( 1.5 ) ) ) );
|
||||
CHECK( gamma( TestType( 0. ), TestType( 1.0 ) ) <
|
||||
gamma( TestType( 1.0 ), TestType( 1.5 ) ) );
|
||||
CHECK( gamma( TestType( 0 ), TestType( 1. ) ) <
|
||||
std::numeric_limits<TestType>::epsilon() );
|
||||
CHECK( gamma( TestType( -1. ), TestType( -0. ) ) <
|
||||
std::numeric_limits<TestType>::epsilon() );
|
||||
CHECK( directCompare( gamma( TestType( 1. ), TestType( 2. ) ),
|
||||
std::numeric_limits<TestType>::epsilon() ) );
|
||||
CHECK( directCompare( gamma( TestType( -2. ), TestType( -1. ) ),
|
||||
std::numeric_limits<TestType>::epsilon() ) );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE("count_equidistant_floats",
|
||||
"[approvals][floating-point][distance]",
|
||||
float,
|
||||
double) {
|
||||
using Catch::Detail::count_equidistant_floats;
|
||||
auto count_steps = []( TestType a, TestType b ) {
|
||||
return count_equidistant_floats( a, b, Catch::Detail::gamma( a, b ) );
|
||||
};
|
||||
|
||||
CHECK( count_steps( TestType( -1. ), TestType( 1. ) ) ==
|
||||
2 * count_steps( TestType( 0. ), TestType( 1. ) ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "count_equidistant_floats",
|
||||
"[approvals][floating-point][distance]" ) {
|
||||
using Catch::Detail::count_equidistant_floats;
|
||||
auto count_floats_with_scaled_ulp = []( auto a, auto b ) {
|
||||
return count_equidistant_floats( a, b, Catch::Detail::gamma( a, b ) );
|
||||
};
|
||||
|
||||
CHECK( count_floats_with_scaled_ulp( 1., 1.5 ) == 1ull << 51 );
|
||||
CHECK( count_floats_with_scaled_ulp( 1.25, 1.5 ) == 1ull << 50 );
|
||||
CHECK( count_floats_with_scaled_ulp( 1.f, 1.5f ) == 1 << 22 );
|
||||
|
||||
STATIC_REQUIRE( std::is_same<std::uint64_t,
|
||||
decltype( count_floats_with_scaled_ulp(
|
||||
0., 1. ) )>::value );
|
||||
STATIC_REQUIRE( std::is_same<std::uint32_t,
|
||||
decltype( count_floats_with_scaled_ulp(
|
||||
0.f, 1.f ) )>::value );
|
||||
}
|
||||
Vendored
+576
@@ -0,0 +1,576 @@
|
||||
|
||||
// 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
|
||||
|
||||
#if defined( __GNUC__ ) || defined( __clang__ )
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
#include <helpers/range_test_helpers.hpp>
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
#include <catch2/generators/catch_generators_adapters.hpp>
|
||||
#include <catch2/generators/catch_generators_random.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
|
||||
// Tests of generator implementation details
|
||||
TEST_CASE("Generators internals", "[generators][internals]") {
|
||||
using namespace Catch::Generators;
|
||||
|
||||
SECTION("Single value") {
|
||||
auto gen = value(123);
|
||||
REQUIRE(gen.get() == 123);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Preset values") {
|
||||
auto gen = values({ 1, 3, 5 });
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Generator combinator") {
|
||||
auto gen = makeGenerators(1, 5, values({ 2, 4 }), 0);
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Explicitly typed generator sequence") {
|
||||
auto gen = makeGenerators(as<std::string>{}, "aa", "bb", "cc");
|
||||
// This just checks that the type is std::string:
|
||||
REQUIRE(gen.get().size() == 2);
|
||||
// Iterate over the generator
|
||||
REQUIRE(gen.get() == "aa");
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == "bb");
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == "cc");
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Filter generator") {
|
||||
// Normal usage
|
||||
SECTION("Simple filtering") {
|
||||
auto gen = filter([](int i) { return i != 2; }, values({ 2, 1, 2, 3, 2, 2 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Filter out multiple elements at the start and end") {
|
||||
auto gen = filter([](int i) { return i != 2; }, values({ 2, 2, 1, 3, 2, 2 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
|
||||
SECTION("Throws on construction if it can't get initial element") {
|
||||
REQUIRE_THROWS_AS(filter([](int) { return false; }, value(1)), Catch::GeneratorException);
|
||||
REQUIRE_THROWS_AS(
|
||||
filter([](int) { return false; }, values({ 1, 2, 3 })),
|
||||
Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
SECTION("Take generator") {
|
||||
SECTION("Take less") {
|
||||
auto gen = take(2, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Take more") {
|
||||
auto gen = take(2, value(1));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Map with explicit return type") {
|
||||
auto gen = map<double>([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 2.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 6.0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Map with deduced return type") {
|
||||
auto gen = map([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 2.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 6.0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Repeat") {
|
||||
SECTION("Singular repeat") {
|
||||
auto gen = repeat(1, value(3));
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Actual repeat") {
|
||||
auto gen = repeat(2, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Range") {
|
||||
SECTION("Positive auto step") {
|
||||
SECTION("Integer") {
|
||||
auto gen = range(-2, 2);
|
||||
REQUIRE(gen.get() == -2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Negative auto step") {
|
||||
SECTION("Integer") {
|
||||
auto gen = range(2, -2);
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Positive manual step") {
|
||||
SECTION("Integer") {
|
||||
SECTION("Exact") {
|
||||
auto gen = range(-7, 5, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
auto gen = range(-7, 4, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
auto gen = range(-7, 6, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Floating Point") {
|
||||
using Catch::Approx;
|
||||
SECTION("Exact") {
|
||||
const auto rangeStart = -1.;
|
||||
const auto rangeEnd = 1.;
|
||||
const auto step = .1;
|
||||
|
||||
auto gen = range(rangeStart, rangeEnd, step);
|
||||
auto expected = rangeStart;
|
||||
while( (rangeEnd - expected) > step ) {
|
||||
INFO( "Current expected value is " << expected );
|
||||
REQUIRE(gen.get() == Approx(expected));
|
||||
REQUIRE(gen.next());
|
||||
|
||||
expected += step;
|
||||
}
|
||||
REQUIRE(gen.get() == Approx( rangeEnd ) );
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
const auto rangeStart = -1.;
|
||||
const auto rangeEnd = 1.;
|
||||
const auto step = .3;
|
||||
|
||||
auto gen = range(rangeStart, rangeEnd, step);
|
||||
auto expected = rangeStart;
|
||||
while( (rangeEnd - expected) > step ) {
|
||||
INFO( "Current expected value is " << expected );
|
||||
REQUIRE(gen.get() == Approx(expected));
|
||||
REQUIRE(gen.next());
|
||||
|
||||
expected += step;
|
||||
}
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
const auto rangeStart = -1.;
|
||||
const auto rangeEnd = .9;
|
||||
const auto step = .3;
|
||||
|
||||
auto gen = range(rangeStart, rangeEnd, step);
|
||||
auto expected = rangeStart;
|
||||
while( (rangeEnd - expected) > step ) {
|
||||
INFO( "Current expected value is " << expected );
|
||||
REQUIRE(gen.get() == Approx(expected));
|
||||
REQUIRE(gen.next());
|
||||
|
||||
expected += step;
|
||||
}
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("Negative manual step") {
|
||||
SECTION("Integer") {
|
||||
SECTION("Exact") {
|
||||
auto gen = range(5, -7, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
auto gen = range(5, -6, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
auto gen = range(5, -8, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// todo: uncopyable type used in a generator
|
||||
// idea: uncopyable tag type for a stupid generator
|
||||
|
||||
namespace {
|
||||
struct non_copyable {
|
||||
non_copyable() = default;
|
||||
non_copyable(non_copyable const&) = delete;
|
||||
non_copyable& operator=(non_copyable const&) = delete;
|
||||
int value = -1;
|
||||
};
|
||||
|
||||
// This class shows how to implement a simple generator for Catch tests
|
||||
class TestGen : public Catch::Generators::IGenerator<int> {
|
||||
int current_number;
|
||||
public:
|
||||
|
||||
TestGen(non_copyable const& nc):
|
||||
current_number(nc.value) {}
|
||||
|
||||
int const& get() const override;
|
||||
bool next() override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
int const& TestGen::get() const {
|
||||
return current_number;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("GENERATE capture macros", "[generators][internals][approvals]") {
|
||||
auto value = GENERATE(take(10, random(0, 10)));
|
||||
|
||||
non_copyable nc; nc.value = value;
|
||||
// neither `GENERATE_COPY` nor plain `GENERATE` would compile here
|
||||
auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(Catch::Detail::make_unique<TestGen>(nc)));
|
||||
REQUIRE(value == value2);
|
||||
}
|
||||
|
||||
TEST_CASE("#1809 - GENERATE_COPY and SingleValueGenerator does not compile", "[generators][compilation][approvals]") {
|
||||
// Verify Issue #1809 fix, only needs to compile.
|
||||
auto a = GENERATE_COPY(1, 2);
|
||||
(void)a;
|
||||
auto b = GENERATE_COPY(as<long>{}, 1, 2);
|
||||
(void)b;
|
||||
int i = 1;
|
||||
int j = 2;
|
||||
auto c = GENERATE_COPY(i, j);
|
||||
(void)c;
|
||||
auto d = GENERATE_COPY(as<long>{}, i, j);
|
||||
(void)d;
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("Multiple random generators in one test case output different values", "[generators][internals][approvals]") {
|
||||
SECTION("Integer") {
|
||||
auto random1 = Catch::Generators::random(0, 1000);
|
||||
auto random2 = Catch::Generators::random(0, 1000);
|
||||
size_t same = 0;
|
||||
for (size_t i = 0; i < 1000; ++i) {
|
||||
same += random1.get() == random2.get();
|
||||
random1.next(); random2.next();
|
||||
}
|
||||
// Because the previous low bound failed CI couple of times,
|
||||
// we use a very high threshold of 20% before failure is reported.
|
||||
REQUIRE(same < 200);
|
||||
}
|
||||
SECTION("Float") {
|
||||
auto random1 = Catch::Generators::random(0., 1000.);
|
||||
auto random2 = Catch::Generators::random(0., 1000.);
|
||||
size_t same = 0;
|
||||
for (size_t i = 0; i < 1000; ++i) {
|
||||
same += random1.get() == random2.get();
|
||||
random1.next(); random2.next();
|
||||
}
|
||||
// Because the previous low bound failed CI couple of times,
|
||||
// we use a very high threshold of 20% before failure is reported.
|
||||
REQUIRE(same < 200);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("#2040 - infinite compilation recursion in GENERATE with MSVC", "[generators][compilation][approvals]") {
|
||||
int x = 42;
|
||||
auto test = GENERATE_COPY(1, x, 2 * x);
|
||||
CHECK(test < 100);
|
||||
}
|
||||
|
||||
namespace {
|
||||
static bool always_true(int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_even(int n) {
|
||||
return n % 2 == 0;
|
||||
}
|
||||
|
||||
static bool is_multiple_of_3(int n) {
|
||||
return n % 3 == 0;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("GENERATE handles function (pointers)", "[generators][compilation][approvals]") {
|
||||
auto f = GENERATE(always_true, is_even, is_multiple_of_3);
|
||||
REQUIRE(f(6));
|
||||
}
|
||||
|
||||
TEST_CASE("GENERATE decays arrays", "[generators][compilation][approvals]") {
|
||||
auto str = GENERATE("abc", "def", "gh");
|
||||
(void)str;
|
||||
STATIC_REQUIRE(std::is_same<decltype(str), const char*>::value);
|
||||
}
|
||||
|
||||
TEST_CASE("Generators count returned elements", "[generators][approvals]") {
|
||||
auto generator = Catch::Generators::FixedValuesGenerator<int>( { 1, 2, 3 } );
|
||||
REQUIRE( generator.currentElementIndex() == 0 );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementIndex() == 1 );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementIndex() == 2 );
|
||||
REQUIRE_FALSE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementIndex() == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Generators can stringify their elements",
|
||||
"[generators][approvals]" ) {
|
||||
auto generator =
|
||||
Catch::Generators::FixedValuesGenerator<int>( { 1, 2, 3 } );
|
||||
|
||||
REQUIRE( generator.currentElementAsString() == "1"_catch_sr );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementAsString() == "2"_catch_sr );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementAsString() == "3"_catch_sr );
|
||||
}
|
||||
|
||||
namespace {
|
||||
class CustomStringifyGenerator
|
||||
: public Catch::Generators::IGenerator<bool> {
|
||||
bool m_first = true;
|
||||
|
||||
std::string stringifyImpl() const override {
|
||||
return m_first ? "first" : "second";
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
if ( m_first ) {
|
||||
m_first = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
bool const& get() const override;
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
bool const& CustomStringifyGenerator::get() const { return m_first; }
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "Generators can override element stringification",
|
||||
"[generators][approvals]" ) {
|
||||
CustomStringifyGenerator generator;
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.countedNext() );
|
||||
REQUIRE( generator.currentElementAsString() == "second"_catch_sr );
|
||||
}
|
||||
|
||||
namespace {
|
||||
class StringifyCountingGenerator
|
||||
: public Catch::Generators::IGenerator<bool> {
|
||||
bool m_first = true;
|
||||
mutable size_t m_stringificationCalls = 0;
|
||||
|
||||
std::string stringifyImpl() const override {
|
||||
++m_stringificationCalls;
|
||||
return m_first ? "first" : "second";
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
if ( m_first ) {
|
||||
m_first = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool const& get() const override;
|
||||
size_t stringificationCalls() const { return m_stringificationCalls; }
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
bool const& StringifyCountingGenerator::get() const { return m_first; }
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "Generator element stringification is cached",
|
||||
"[generators][approvals]" ) {
|
||||
StringifyCountingGenerator generator;
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
REQUIRE( generator.currentElementAsString() == "first"_catch_sr );
|
||||
|
||||
REQUIRE( generator.stringificationCalls() == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Random generators can be seeded", "[generators][approvals]" ) {
|
||||
SECTION( "Integer generator" ) {
|
||||
using Catch::Generators::RandomIntegerGenerator;
|
||||
RandomIntegerGenerator<int> rng1( 0, 100, 0x1234 ),
|
||||
rng2( 0, 100, 0x1234 );
|
||||
|
||||
for ( size_t i = 0; i < 10; ++i ) {
|
||||
REQUIRE( rng1.get() == rng2.get() );
|
||||
rng1.next(); rng2.next();
|
||||
}
|
||||
}
|
||||
SECTION("Float generator") {
|
||||
using Catch::Generators::RandomFloatingGenerator;
|
||||
RandomFloatingGenerator<double> rng1( 0., 100., 0x1234 ),
|
||||
rng2( 0., 100., 0x1234 );
|
||||
for ( size_t i = 0; i < 10; ++i ) {
|
||||
REQUIRE( rng1.get() == rng2.get() );
|
||||
rng1.next();
|
||||
rng2.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Filter generator throws exception for empty generator",
|
||||
"[generators]") {
|
||||
using namespace Catch::Generators;
|
||||
|
||||
REQUIRE_THROWS_AS(
|
||||
filter( []( int ) { return false; }, value( 3 ) ),
|
||||
Catch::GeneratorException );
|
||||
}
|
||||
|
||||
TEST_CASE("from_range(container) supports ADL begin/end and arrays", "[generators][from-range][approvals]") {
|
||||
using namespace Catch::Generators;
|
||||
|
||||
SECTION("C array") {
|
||||
int arr[3]{ 5, 6, 7 };
|
||||
auto gen = from_range( arr );
|
||||
REQUIRE( gen.get() == 5 );
|
||||
REQUIRE( gen.next() );
|
||||
REQUIRE( gen.get() == 6 );
|
||||
REQUIRE( gen.next() );
|
||||
REQUIRE( gen.get() == 7 );
|
||||
REQUIRE_FALSE( gen.next() );
|
||||
}
|
||||
|
||||
SECTION( "ADL range" ) {
|
||||
unrelated::needs_ADL_begin<int> range{ 1, 2, 3 };
|
||||
auto gen = from_range( range );
|
||||
REQUIRE( gen.get() == 1 );
|
||||
REQUIRE( gen.next() );
|
||||
REQUIRE( gen.get() == 2 );
|
||||
REQUIRE( gen.next() );
|
||||
REQUIRE( gen.get() == 3 );
|
||||
REQUIRE_FALSE( gen.next() );
|
||||
}
|
||||
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_random_integer_helpers.hpp>
|
||||
|
||||
namespace {
|
||||
template <typename Int>
|
||||
static void
|
||||
CommutativeMultCheck( Int a, Int b, Int upper_result, Int lower_result ) {
|
||||
using Catch::Detail::extendedMult;
|
||||
using Catch::Detail::ExtendedMultResult;
|
||||
CHECK( extendedMult( a, b ) ==
|
||||
ExtendedMultResult<Int>{ upper_result, lower_result } );
|
||||
CHECK( extendedMult( b, a ) ==
|
||||
ExtendedMultResult<Int>{ upper_result, lower_result } );
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "extendedMult 64x64", "[Integer][approvals]" ) {
|
||||
// a x 0 == 0
|
||||
CommutativeMultCheck<uint64_t>( 0x1234'5678'9ABC'DEFF, 0, 0, 0 );
|
||||
|
||||
// bit carried from low half to upper half
|
||||
CommutativeMultCheck<uint64_t>( uint64_t( 1 ) << 63, 2, 1, 0 );
|
||||
|
||||
// bits in upper half on one side, bits in lower half on other side
|
||||
CommutativeMultCheck<uint64_t>( 0xcdcd'dcdc'0000'0000,
|
||||
0x0000'0000'aeae'aeae,
|
||||
0x0000'0000'8c6e'5a77,
|
||||
0x7391'a588'0000'0000 );
|
||||
|
||||
// Some input numbers without interesting patterns
|
||||
CommutativeMultCheck<uint64_t>( 0xaaaa'aaaa'aaaa'aaaa,
|
||||
0xbbbb'bbbb'bbbb'bbbb,
|
||||
0x7d27'd27d'27d2'7d26,
|
||||
0xd82d'82d8'2d82'd82e );
|
||||
|
||||
CommutativeMultCheck<uint64_t>( 0x7d27'd27d'27d2'7d26,
|
||||
0xd82d'82d8'2d82'd82e,
|
||||
0x69af'd991'8256'b953,
|
||||
0x8724'8909'fcb6'8cd4 );
|
||||
|
||||
CommutativeMultCheck<uint64_t>( 0xdead'beef'dead'beef,
|
||||
0xfeed'feed'feed'feef,
|
||||
0xddbf'680b'2b0c'b558,
|
||||
0x7a36'b06f'2ce9'6321 );
|
||||
|
||||
CommutativeMultCheck<uint64_t>( 0xddbf'680b'2b0c'b558,
|
||||
0x7a36'b06f'2ce9'6321,
|
||||
0x69dc'96c9'294b'fc7f,
|
||||
0xd038'39fa'a3dc'6858 );
|
||||
|
||||
CommutativeMultCheck<uint64_t>( 0x61c8'8646'80b5'83eb,
|
||||
0x61c8'8646'80b5'83eb,
|
||||
0x2559'92d3'8220'8bbe,
|
||||
0xdf44'2d22'ce48'59b9 );
|
||||
}
|
||||
|
||||
TEST_CASE( "SizedUnsignedType helpers", "[integer][approvals]" ) {
|
||||
using Catch::Detail::SizedUnsignedType_t;
|
||||
using Catch::Detail::DoubleWidthUnsignedType_t;
|
||||
|
||||
STATIC_REQUIRE( sizeof( SizedUnsignedType_t<1> ) == 1 );
|
||||
STATIC_REQUIRE( sizeof( SizedUnsignedType_t<2> ) == 2 );
|
||||
STATIC_REQUIRE( sizeof( SizedUnsignedType_t<4> ) == 4 );
|
||||
STATIC_REQUIRE( sizeof( SizedUnsignedType_t<8> ) == 8 );
|
||||
|
||||
STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t<std::uint8_t> ) == 2 );
|
||||
STATIC_REQUIRE( std::is_unsigned<DoubleWidthUnsignedType_t<std::uint8_t>>::value );
|
||||
STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t<std::uint16_t> ) == 4 );
|
||||
STATIC_REQUIRE( std::is_unsigned<DoubleWidthUnsignedType_t<std::uint16_t>>::value );
|
||||
STATIC_REQUIRE( sizeof( DoubleWidthUnsignedType_t<std::uint32_t> ) == 8 );
|
||||
STATIC_REQUIRE( std::is_unsigned<DoubleWidthUnsignedType_t<std::uint32_t>>::value );
|
||||
}
|
||||
|
||||
TEST_CASE( "extendedMult 32x32", "[integer][approvals]" ) {
|
||||
// a x 0 == 0
|
||||
CommutativeMultCheck<uint32_t>( 0x1234'5678, 0, 0, 0 );
|
||||
|
||||
// bit carried from low half to upper half
|
||||
CommutativeMultCheck<uint32_t>( uint32_t(1) << 31, 2, 1, 0 );
|
||||
|
||||
// bits in upper half on one side, bits in lower half on other side
|
||||
CommutativeMultCheck<uint32_t>( 0xdcdc'0000, 0x0000'aabb, 0x0000'934b, 0x6cb4'0000 );
|
||||
|
||||
// Some input numbers without interesting patterns
|
||||
CommutativeMultCheck<uint32_t>(
|
||||
0xaaaa'aaaa, 0xbbbb'bbbb, 0x7d27'd27c, 0x2d82'd82e );
|
||||
|
||||
CommutativeMultCheck<uint32_t>(
|
||||
0x7d27'd27c, 0x2d82'd82e, 0x163f'f7e8, 0xc5b8'7248 );
|
||||
|
||||
CommutativeMultCheck<uint32_t>(
|
||||
0xdead'beef, 0xfeed'feed, 0xddbf'6809, 0x6f8d'e543 );
|
||||
|
||||
CommutativeMultCheck<uint32_t>(
|
||||
0xddbf'6809, 0x6f8d'e543, 0x60a0'e71e, 0x751d'475b );
|
||||
}
|
||||
|
||||
TEST_CASE( "extendedMult 8x8", "[integer][approvals]" ) {
|
||||
// a x 0 == 0
|
||||
CommutativeMultCheck<uint8_t>( 0xcd, 0, 0, 0 );
|
||||
|
||||
// bit carried from low half to upper half
|
||||
CommutativeMultCheck<uint8_t>( uint8_t( 1 ) << 7, 2, 1, 0 );
|
||||
|
||||
// bits in upper half on one side, bits in lower half on other side
|
||||
CommutativeMultCheck<uint8_t>( 0x80, 0x03, 0x01, 0x80 );
|
||||
|
||||
// Some input numbers without interesting patterns
|
||||
CommutativeMultCheck<uint8_t>( 0xaa, 0xbb, 0x7c, 0x2e );
|
||||
CommutativeMultCheck<uint8_t>( 0x7c, 0x2e, 0x16, 0x48 );
|
||||
CommutativeMultCheck<uint8_t>( 0xdc, 0xcd, 0xb0, 0x2c );
|
||||
CommutativeMultCheck<uint8_t>( 0xb0, 0x2c, 0x1e, 0x40 );
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "negative and positive signed integers keep their order after transposeToNaturalOrder",
|
||||
"[integer][approvals]") {
|
||||
using Catch::Detail::transposeToNaturalOrder;
|
||||
int32_t negative( -1 );
|
||||
int32_t positive( 1 );
|
||||
uint32_t adjusted_negative =
|
||||
transposeToNaturalOrder<int32_t>( static_cast<uint32_t>( negative ) );
|
||||
uint32_t adjusted_positive =
|
||||
transposeToNaturalOrder<int32_t>( static_cast<uint32_t>( positive ) );
|
||||
REQUIRE( adjusted_negative < adjusted_positive );
|
||||
REQUIRE( adjusted_positive - adjusted_negative == 2 );
|
||||
|
||||
// Conversion has to be reversible
|
||||
REQUIRE( negative == static_cast<int32_t>( transposeToNaturalOrder<int32_t>(
|
||||
adjusted_negative ) ) );
|
||||
REQUIRE( positive == static_cast<int32_t>( transposeToNaturalOrder<int32_t>(
|
||||
adjusted_positive ) ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "unsigned integers are unchanged by transposeToNaturalOrder",
|
||||
"[integer][approvals]") {
|
||||
using Catch::Detail::transposeToNaturalOrder;
|
||||
uint32_t max = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t zero = 0;
|
||||
REQUIRE( max == transposeToNaturalOrder<uint32_t>( max ) );
|
||||
REQUIRE( zero == transposeToNaturalOrder<uint32_t>( zero ) );
|
||||
}
|
||||
Vendored
+455
@@ -0,0 +1,455 @@
|
||||
|
||||
// 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.
|
||||
|
||||
|
||||
#if defined( __GNUC__ ) || defined( __clang__ )
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
#include <catch2/benchmark/detail/catch_analyse.hpp>
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
#include <catch2/benchmark/detail/catch_estimate_clock.hpp>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
namespace {
|
||||
struct manual_clock {
|
||||
public:
|
||||
using duration = std::chrono::nanoseconds;
|
||||
using time_point = std::chrono::time_point<manual_clock, duration>;
|
||||
using rep = duration::rep;
|
||||
using period = duration::period;
|
||||
enum { is_steady = true };
|
||||
|
||||
static time_point now() {
|
||||
return time_point(duration(tick()));
|
||||
}
|
||||
|
||||
static void advance(int ticks = 1) {
|
||||
tick() += ticks;
|
||||
}
|
||||
|
||||
private:
|
||||
static rep& tick() {
|
||||
static rep the_tick = 0;
|
||||
return the_tick;
|
||||
}
|
||||
};
|
||||
|
||||
struct counting_clock {
|
||||
public:
|
||||
using duration = std::chrono::nanoseconds;
|
||||
using time_point = std::chrono::time_point<counting_clock, duration>;
|
||||
using rep = duration::rep;
|
||||
using period = duration::period;
|
||||
enum { is_steady = true };
|
||||
|
||||
static time_point now() {
|
||||
static rep ticks = 0;
|
||||
return time_point(duration(ticks += rate()));
|
||||
}
|
||||
|
||||
static void set_rate(rep new_rate) { rate() = new_rate; }
|
||||
|
||||
private:
|
||||
static rep& rate() {
|
||||
static rep the_rate = 1;
|
||||
return the_rate;
|
||||
}
|
||||
};
|
||||
|
||||
struct TestChronometerModel : Catch::Benchmark::Detail::ChronometerConcept {
|
||||
int started = 0;
|
||||
int finished = 0;
|
||||
|
||||
void start() override { ++started; }
|
||||
void finish() override { ++finished; }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("warmup", "[benchmark]") {
|
||||
auto rate = 1000;
|
||||
counting_clock::set_rate(rate);
|
||||
|
||||
auto start = counting_clock::now();
|
||||
auto iterations = Catch::Benchmark::Detail::warmup<counting_clock>();
|
||||
auto end = counting_clock::now();
|
||||
|
||||
REQUIRE((iterations * rate) > Catch::Benchmark::Detail::warmup_time.count());
|
||||
REQUIRE((end - start) > Catch::Benchmark::Detail::warmup_time);
|
||||
}
|
||||
|
||||
TEST_CASE("resolution", "[benchmark]") {
|
||||
auto rate = 1000;
|
||||
counting_clock::set_rate(rate);
|
||||
|
||||
size_t count = 10;
|
||||
auto res = Catch::Benchmark::Detail::resolution<counting_clock>(static_cast<int>(count));
|
||||
|
||||
REQUIRE(res.size() == count);
|
||||
|
||||
for (size_t i = 1; i < count; ++i) {
|
||||
REQUIRE(res[i] == rate);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("estimate_clock_resolution", "[benchmark]") {
|
||||
auto rate = 2'000;
|
||||
counting_clock::set_rate(rate);
|
||||
|
||||
int iters = 160'000;
|
||||
auto res = Catch::Benchmark::Detail::estimate_clock_resolution<counting_clock>(iters);
|
||||
|
||||
REQUIRE(res.mean.count() == rate);
|
||||
REQUIRE(res.outliers.total() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("benchmark function call", "[benchmark]") {
|
||||
SECTION("without chronometer") {
|
||||
auto called = 0;
|
||||
auto model = TestChronometerModel{};
|
||||
auto meter = Catch::Benchmark::Chronometer{ model, 1 };
|
||||
auto fn = Catch::Benchmark::Detail::BenchmarkFunction{ [&] {
|
||||
CHECK(model.started == 1);
|
||||
CHECK(model.finished == 0);
|
||||
++called;
|
||||
} };
|
||||
|
||||
fn(meter);
|
||||
|
||||
CHECK(model.started == 1);
|
||||
CHECK(model.finished == 1);
|
||||
CHECK(called == 1);
|
||||
}
|
||||
|
||||
SECTION("with chronometer") {
|
||||
auto called = 0;
|
||||
auto model = TestChronometerModel{};
|
||||
auto meter = Catch::Benchmark::Chronometer{ model, 1 };
|
||||
auto fn = Catch::Benchmark::Detail::BenchmarkFunction{ [&](Catch::Benchmark::Chronometer) {
|
||||
CHECK(model.started == 0);
|
||||
CHECK(model.finished == 0);
|
||||
++called;
|
||||
} };
|
||||
|
||||
fn(meter);
|
||||
|
||||
CHECK(model.started == 0);
|
||||
CHECK(model.finished == 0);
|
||||
CHECK(called == 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("uniform samples", "[benchmark]") {
|
||||
std::vector<double> samples(100);
|
||||
std::fill(samples.begin(), samples.end(), 23);
|
||||
|
||||
auto e = Catch::Benchmark::Detail::bootstrap(
|
||||
0.95,
|
||||
samples.data(),
|
||||
samples.data() + samples.size(),
|
||||
samples,
|
||||
[]( double const* a, double const* b ) {
|
||||
auto sum = std::accumulate(a, b, 0.);
|
||||
return sum / (b - a);
|
||||
});
|
||||
CHECK(e.point == 23);
|
||||
CHECK(e.upper_bound == 23);
|
||||
CHECK(e.lower_bound == 23);
|
||||
CHECK(e.confidence_interval == 0.95);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("normal_cdf", "[benchmark]") {
|
||||
using Catch::Benchmark::Detail::normal_cdf;
|
||||
using Catch::Approx;
|
||||
CHECK(normal_cdf(0.000000) == Approx(0.50000000000000000));
|
||||
CHECK(normal_cdf(1.000000) == Approx(0.84134474606854293));
|
||||
CHECK(normal_cdf(-1.000000) == Approx(0.15865525393145705));
|
||||
CHECK(normal_cdf(2.809729) == Approx(0.99752083845315409));
|
||||
CHECK(normal_cdf(-1.352570) == Approx(0.08809652095066035));
|
||||
}
|
||||
|
||||
TEST_CASE("erfc_inv", "[benchmark]") {
|
||||
using Catch::Benchmark::Detail::erfc_inv;
|
||||
using Catch::Approx;
|
||||
CHECK(erfc_inv(1.103560) == Approx(-0.09203687623843015));
|
||||
CHECK(erfc_inv(1.067400) == Approx(-0.05980291115763361));
|
||||
CHECK(erfc_inv(0.050000) == Approx(1.38590382434967796));
|
||||
}
|
||||
|
||||
TEST_CASE("normal_quantile", "[benchmark]") {
|
||||
using Catch::Benchmark::Detail::normal_quantile;
|
||||
using Catch::Approx;
|
||||
CHECK(normal_quantile(0.551780) == Approx(0.13015979861484198));
|
||||
CHECK(normal_quantile(0.533700) == Approx(0.08457408802851875));
|
||||
CHECK(normal_quantile(0.025000) == Approx(-1.95996398454005449));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("mean", "[benchmark]") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 30., 24. };
|
||||
|
||||
auto m = Catch::Benchmark::Detail::mean(x.data(), x.data() + x.size());
|
||||
|
||||
REQUIRE(m == 19.);
|
||||
}
|
||||
|
||||
TEST_CASE("weighted_average_quantile", "[benchmark]") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 30., 24. };
|
||||
|
||||
auto q1 = Catch::Benchmark::Detail::weighted_average_quantile(1, 4, x.data(), x.data() + x.size());
|
||||
auto med = Catch::Benchmark::Detail::weighted_average_quantile(1, 2, x.data(), x.data() + x.size());
|
||||
auto q3 = Catch::Benchmark::Detail::weighted_average_quantile(3, 4, x.data(), x.data() + x.size());
|
||||
|
||||
REQUIRE(q1 == 14.5);
|
||||
REQUIRE(med == 18.);
|
||||
REQUIRE(q3 == 23.);
|
||||
}
|
||||
|
||||
TEST_CASE("classify_outliers", "[benchmark]") {
|
||||
auto require_outliers = [](Catch::Benchmark::OutlierClassification o, int los, int lom, int him, int his) {
|
||||
REQUIRE(o.low_severe == los);
|
||||
REQUIRE(o.low_mild == lom);
|
||||
REQUIRE(o.high_mild == him);
|
||||
REQUIRE(o.high_severe == his);
|
||||
REQUIRE(o.total() == los + lom + him + his);
|
||||
};
|
||||
|
||||
SECTION("none") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 30., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 0, 0, 0, 0);
|
||||
}
|
||||
SECTION("low severe") {
|
||||
std::vector<double> x{ -12., 20., 14., 16., 30., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 1, 0, 0, 0);
|
||||
}
|
||||
SECTION("low mild") {
|
||||
std::vector<double> x{ 1., 20., 14., 16., 30., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 0, 1, 0, 0);
|
||||
}
|
||||
SECTION("high mild") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 36., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 0, 0, 1, 0);
|
||||
}
|
||||
SECTION("high severe") {
|
||||
std::vector<double> x{ 10., 20., 14., 16., 49., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 0, 0, 0, 1);
|
||||
}
|
||||
SECTION("mixed") {
|
||||
std::vector<double> x{ -20., 20., 14., 16., 39., 24. };
|
||||
|
||||
auto o = Catch::Benchmark::Detail::classify_outliers(
|
||||
x.data(), x.data() + x.size() );
|
||||
|
||||
REQUIRE(o.samples_seen == static_cast<int>(x.size()));
|
||||
require_outliers(o, 1, 0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("analyse", "[approvals][benchmark]") {
|
||||
Catch::ConfigData data{};
|
||||
data.benchmarkConfidenceInterval = 0.95;
|
||||
data.benchmarkNoAnalysis = false;
|
||||
data.benchmarkResamples = 1000;
|
||||
data.benchmarkSamples = 99;
|
||||
Catch::Config config{data};
|
||||
|
||||
using FDuration = Catch::Benchmark::FDuration;
|
||||
std::vector<FDuration> samples(99);
|
||||
for (size_t i = 0; i < samples.size(); ++i) {
|
||||
samples[i] = FDuration(23 + (i % 3 - 1));
|
||||
}
|
||||
|
||||
auto analysis = Catch::Benchmark::Detail::analyse(config, samples.data(), samples.data() + samples.size());
|
||||
CHECK( analysis.mean.point.count() == 23 );
|
||||
CHECK( analysis.mean.lower_bound.count() < 23 );
|
||||
CHECK(analysis.mean.lower_bound.count() > 22);
|
||||
CHECK(analysis.mean.upper_bound.count() > 23);
|
||||
CHECK(analysis.mean.upper_bound.count() < 24);
|
||||
|
||||
CHECK(analysis.standard_deviation.point.count() > 0.5);
|
||||
CHECK(analysis.standard_deviation.point.count() < 1);
|
||||
CHECK(analysis.standard_deviation.lower_bound.count() > 0.5);
|
||||
CHECK(analysis.standard_deviation.lower_bound.count() < 1);
|
||||
CHECK(analysis.standard_deviation.upper_bound.count() > 0.5);
|
||||
CHECK(analysis.standard_deviation.upper_bound.count() < 1);
|
||||
|
||||
CHECK(analysis.outliers.total() == 0);
|
||||
CHECK(analysis.outliers.low_mild == 0);
|
||||
CHECK(analysis.outliers.low_severe == 0);
|
||||
CHECK(analysis.outliers.high_mild == 0);
|
||||
CHECK(analysis.outliers.high_severe == 0);
|
||||
CHECK(analysis.outliers.samples_seen == static_cast<int>(samples.size()));
|
||||
|
||||
CHECK(analysis.outlier_variance < 0.5);
|
||||
CHECK(analysis.outlier_variance > 0);
|
||||
}
|
||||
|
||||
TEST_CASE("analyse no analysis", "[benchmark]") {
|
||||
Catch::ConfigData data{};
|
||||
data.benchmarkConfidenceInterval = 0.95;
|
||||
data.benchmarkNoAnalysis = true;
|
||||
data.benchmarkResamples = 1000;
|
||||
data.benchmarkSamples = 99;
|
||||
Catch::Config config{ data };
|
||||
|
||||
using FDuration = Catch::Benchmark::FDuration;
|
||||
std::vector<FDuration> samples(99);
|
||||
for (size_t i = 0; i < samples.size(); ++i) {
|
||||
samples[i] = FDuration(23 + (i % 3 - 1));
|
||||
}
|
||||
|
||||
auto analysis = Catch::Benchmark::Detail::analyse(config, samples.data(), samples.data() + samples.size());
|
||||
CHECK(analysis.mean.point.count() == 23);
|
||||
CHECK(analysis.mean.lower_bound.count() == 23);
|
||||
CHECK(analysis.mean.upper_bound.count() == 23);
|
||||
|
||||
CHECK(analysis.standard_deviation.point.count() == 0);
|
||||
CHECK(analysis.standard_deviation.lower_bound.count() == 0);
|
||||
CHECK(analysis.standard_deviation.upper_bound.count() == 0);
|
||||
|
||||
CHECK(analysis.outliers.total() == 0);
|
||||
CHECK(analysis.outliers.low_mild == 0);
|
||||
CHECK(analysis.outliers.low_severe == 0);
|
||||
CHECK(analysis.outliers.high_mild == 0);
|
||||
CHECK(analysis.outliers.high_severe == 0);
|
||||
CHECK(analysis.outliers.samples_seen == 0);
|
||||
|
||||
CHECK(analysis.outlier_variance == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("run_for_at_least, int", "[benchmark]") {
|
||||
manual_clock::duration time(100);
|
||||
|
||||
int old_x = 1;
|
||||
auto Timing = Catch::Benchmark::Detail::run_for_at_least<manual_clock>(time, 1, [&old_x](int x) -> int {
|
||||
CHECK(x >= old_x);
|
||||
manual_clock::advance(x);
|
||||
old_x = x;
|
||||
return x + 17;
|
||||
});
|
||||
|
||||
REQUIRE(Timing.elapsed >= time);
|
||||
REQUIRE(Timing.result == Timing.iterations + 17);
|
||||
REQUIRE(Timing.iterations >= time.count());
|
||||
}
|
||||
|
||||
TEST_CASE("run_for_at_least, chronometer", "[benchmark]") {
|
||||
manual_clock::duration time(100);
|
||||
|
||||
int old_runs = 1;
|
||||
auto Timing = Catch::Benchmark::Detail::run_for_at_least<manual_clock>(time, 1, [&old_runs](Catch::Benchmark::Chronometer meter) -> int {
|
||||
CHECK(meter.runs() >= old_runs);
|
||||
manual_clock::advance(100);
|
||||
meter.measure([] {
|
||||
manual_clock::advance(1);
|
||||
});
|
||||
old_runs = meter.runs();
|
||||
return meter.runs() + 17;
|
||||
});
|
||||
|
||||
REQUIRE(Timing.elapsed >= time);
|
||||
REQUIRE(Timing.result == Timing.iterations + 17);
|
||||
REQUIRE(Timing.iterations >= time.count());
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("measure", "[benchmark]") {
|
||||
auto r = Catch::Benchmark::Detail::measure<manual_clock>([](int x) -> int {
|
||||
CHECK(x == 17);
|
||||
manual_clock::advance(42);
|
||||
return 23;
|
||||
}, 17);
|
||||
auto s = Catch::Benchmark::Detail::measure<manual_clock>([](int x) -> int {
|
||||
CHECK(x == 23);
|
||||
manual_clock::advance(69);
|
||||
return 17;
|
||||
}, 23);
|
||||
|
||||
CHECK(r.elapsed.count() == 42);
|
||||
CHECK(r.result == 23);
|
||||
CHECK(r.iterations == 1);
|
||||
|
||||
CHECK(s.elapsed.count() == 69);
|
||||
CHECK(s.result == 17);
|
||||
CHECK(s.iterations == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("run benchmark", "[benchmark][approvals]") {
|
||||
counting_clock::set_rate(1000);
|
||||
auto start = counting_clock::now();
|
||||
|
||||
Catch::Benchmark::Benchmark bench{ "Test Benchmark", [](Catch::Benchmark::Chronometer meter) {
|
||||
counting_clock::set_rate(100000);
|
||||
meter.measure([] { return counting_clock::now(); });
|
||||
} };
|
||||
|
||||
bench.run<counting_clock>();
|
||||
auto end = counting_clock::now();
|
||||
|
||||
CHECK((end - start).count() == 2867251000);
|
||||
}
|
||||
|
||||
TEST_CASE("Failing benchmarks", "[!benchmark][.approvals]") {
|
||||
SECTION("empty", "Benchmark that has been optimized away (because it is empty)") {
|
||||
BENCHMARK("Empty benchmark") {};
|
||||
}
|
||||
SECTION("throw", "Benchmark that throws an exception") {
|
||||
BENCHMARK("Throwing benchmark") {
|
||||
throw "just a plain literal, bleh";
|
||||
};
|
||||
}
|
||||
SECTION("assert", "Benchmark that asserts inside") {
|
||||
BENCHMARK("Asserting benchmark") {
|
||||
REQUIRE(1 == 2);
|
||||
};
|
||||
}
|
||||
SECTION("fail", "Benchmark that fails inside") {
|
||||
BENCHMARK("FAIL'd benchmark") {
|
||||
FAIL("This benchmark only fails, nothing else");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Failing benchmark respects should-fail",
|
||||
"[!shouldfail][!benchmark][approvals]" ) {
|
||||
BENCHMARK( "Asserting benchmark" ) { REQUIRE( 1 == 2 ); };
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_jsonwriter.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
struct Custom {};
|
||||
static std::ostream& operator<<( std::ostream& os, Custom const& ) {
|
||||
return os << "custom";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "JsonWriter", "[JSON][JsonWriter]" ) {
|
||||
|
||||
std::stringstream stream;
|
||||
SECTION( "Newly constructed JsonWriter does nothing" ) {
|
||||
Catch::JsonValueWriter writer{ stream };
|
||||
REQUIRE( stream.str() == "" );
|
||||
}
|
||||
|
||||
SECTION( "Calling writeObject will create an empty pair of braces" ) {
|
||||
{ auto writer = Catch::JsonValueWriter{ stream }.writeObject(); }
|
||||
REQUIRE( stream.str() == "{\n}" );
|
||||
}
|
||||
|
||||
SECTION( "Calling writeObject with key will create an object to write the "
|
||||
"value" ) {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
{
|
||||
auto writer = Catch::JsonValueWriter{ stream }.writeObject();
|
||||
writer.write( "int" ).write( 1 );
|
||||
writer.write( "double" ).write( 1.5 );
|
||||
writer.write( "true" ).write( true );
|
||||
writer.write( "false" ).write( false );
|
||||
writer.write( "string" ).write( "this is a string" );
|
||||
writer.write( "array" ).writeArray().write( 1 ).write( 2 );
|
||||
}
|
||||
REQUIRE_THAT(
|
||||
stream.str(),
|
||||
ContainsSubstring( "\"int\": 1," ) &&
|
||||
ContainsSubstring( "\"double\": 1.5," ) &&
|
||||
ContainsSubstring( "\"true\": true," ) &&
|
||||
ContainsSubstring( "\"false\": false," ) &&
|
||||
ContainsSubstring( "\"string\": \"this is a string\"," ) &&
|
||||
ContainsSubstring( "\"array\": [\n 1,\n 2\n ]\n}" ) );
|
||||
}
|
||||
|
||||
SECTION( "nesting objects" ) {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
{
|
||||
auto writer = Catch::JsonValueWriter{ stream }.writeObject();
|
||||
writer.write( "empty_object" ).writeObject();
|
||||
writer.write( "fully_object" )
|
||||
.writeObject()
|
||||
.write( "key" )
|
||||
.write( 1 );
|
||||
}
|
||||
REQUIRE_THAT( stream.str(),
|
||||
ContainsSubstring( "\"empty_object\": {\n }," ) &&
|
||||
ContainsSubstring(
|
||||
"\"fully_object\": {\n \"key\": 1\n }" ) );
|
||||
}
|
||||
|
||||
SECTION( "Calling writeArray will create an empty pair of braces" ) {
|
||||
{ auto writer = Catch::JsonValueWriter{ stream }.writeArray(); }
|
||||
REQUIRE( stream.str() == "[\n]" );
|
||||
}
|
||||
|
||||
SECTION( "Calling writeArray creates array to write the values to" ) {
|
||||
{
|
||||
auto writer = Catch::JsonValueWriter{ stream }.writeArray();
|
||||
writer.write( 1 );
|
||||
writer.write( 1.5 );
|
||||
writer.write( true );
|
||||
writer.write( false );
|
||||
writer.write( "this is a string" );
|
||||
writer.writeObject().write( "object" ).write( 42 );
|
||||
writer.writeArray().write( "array" ).write( 42.5 );
|
||||
}
|
||||
REQUIRE( stream.str() == "[\n 1,\n 1.5,\n true,\n false,\n \"this is a string\",\n {\n \"object\": 42\n },\n [\n \"array\",\n 42.5\n ]\n]" );
|
||||
}
|
||||
|
||||
SECTION(
|
||||
"Moved from JsonObjectWriter shall not insert superfluous brace" ) {
|
||||
{
|
||||
auto writer = Catch::JsonObjectWriter{ stream };
|
||||
auto another_writer = std::move( writer );
|
||||
}
|
||||
REQUIRE( stream.str() == "{\n}" );
|
||||
}
|
||||
SECTION(
|
||||
"Moved from JsonArrayWriter shall not insert superfluous bracket" ) {
|
||||
{
|
||||
auto writer = Catch::JsonArrayWriter{ stream };
|
||||
auto another_writer = std::move( writer );
|
||||
}
|
||||
REQUIRE( stream.str() == "[\n]" );
|
||||
}
|
||||
SECTION( "Custom class shall be quoted" ) {
|
||||
Catch::JsonValueWriter{ stream }.write( Custom{} );
|
||||
REQUIRE( stream.str() == "\"custom\"" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "JsonWriter escapes charaters in strings properly", "[JsonWriter]" ) {
|
||||
std::stringstream sstream;
|
||||
SECTION( "Quote in a string is escaped" ) {
|
||||
Catch::JsonValueWriter{ sstream }.write( "\"" );
|
||||
REQUIRE( sstream.str() == "\"\\\"\"" );
|
||||
}
|
||||
SECTION("Backslash in a string is escaped") {
|
||||
Catch::JsonValueWriter{ sstream }.write( "\\" );
|
||||
REQUIRE( sstream.str() == "\"\\\\\"" );
|
||||
}
|
||||
SECTION( "Forward slash in a string is **not** escaped" ) {
|
||||
Catch::JsonValueWriter{ sstream }.write( "/" );
|
||||
REQUIRE( sstream.str() == "\"/\"" );
|
||||
}
|
||||
SECTION( "Backspace in a string is escaped" ) {
|
||||
Catch::JsonValueWriter{ sstream }.write( "\b" );
|
||||
REQUIRE( sstream.str() == "\"\\b\"" );
|
||||
}
|
||||
SECTION( "Formfeed in a string is escaped" ) {
|
||||
Catch::JsonValueWriter{ sstream }.write( "\f" );
|
||||
REQUIRE( sstream.str() == "\"\\f\"" );
|
||||
}
|
||||
SECTION( "linefeed in a string is escaped" ) {
|
||||
Catch::JsonValueWriter{ sstream }.write( "\n" );
|
||||
REQUIRE( sstream.str() == "\"\\n\"" );
|
||||
}
|
||||
SECTION( "carriage return in a string is escaped" ) {
|
||||
Catch::JsonValueWriter{ sstream }.write( "\r" );
|
||||
REQUIRE( sstream.str() == "\"\\r\"" );
|
||||
}
|
||||
SECTION( "tab in a string is escaped" ) {
|
||||
Catch::JsonValueWriter{ sstream }.write( "\t" );
|
||||
REQUIRE( sstream.str() == "\"\\t\"" );
|
||||
}
|
||||
SECTION( "combination of characters is escaped" ) {
|
||||
Catch::JsonValueWriter{ sstream }.write( "\\/\t\r\n" );
|
||||
REQUIRE( sstream.str() == "\"\\\\/\\t\\r\\n\"" );
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
|
||||
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||
|
||||
TEST_CASE("Parse uints", "[parse-numbers]") {
|
||||
using Catch::parseUInt;
|
||||
using Catch::Optional;
|
||||
|
||||
SECTION("proper inputs") {
|
||||
REQUIRE( parseUInt( "0" ) == Optional<unsigned int>{ 0 } );
|
||||
REQUIRE( parseUInt( "100" ) == Optional<unsigned int>{ 100 } );
|
||||
REQUIRE( parseUInt( "4294967295" ) ==
|
||||
Optional<unsigned int>{ 4294967295 } );
|
||||
REQUIRE( parseUInt( "0xFF", 16 ) == Optional<unsigned int>{ 255 } );
|
||||
}
|
||||
SECTION( "Bad inputs" ) {
|
||||
// empty
|
||||
REQUIRE_FALSE( parseUInt( "" ) );
|
||||
// random noise
|
||||
REQUIRE_FALSE( parseUInt( "!!KJHF*#" ) );
|
||||
// negative
|
||||
REQUIRE_FALSE( parseUInt( "-1" ) );
|
||||
// too large
|
||||
REQUIRE_FALSE( parseUInt( "4294967296" ) );
|
||||
REQUIRE_FALSE( parseUInt( "42949672964294967296429496729642949672964294967296" ) );
|
||||
REQUIRE_FALSE( parseUInt( "2 4" ) );
|
||||
// hex with base 10
|
||||
REQUIRE_FALSE( parseUInt( "0xFF", 10 ) );
|
||||
}
|
||||
}
|
||||
Vendored
+254
@@ -0,0 +1,254 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_test_case_tracker.hpp>
|
||||
|
||||
|
||||
using namespace Catch;
|
||||
|
||||
namespace {
|
||||
Catch::TestCaseTracking::NameAndLocationRef makeNAL( StringRef name ) {
|
||||
return Catch::TestCaseTracking::NameAndLocationRef( name, Catch::SourceLineInfo("",0) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Tracker" ) {
|
||||
|
||||
TrackerContext ctx;
|
||||
ctx.startRun();
|
||||
ctx.startCycle();
|
||||
|
||||
|
||||
ITracker& testCase = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase.isOpen() );
|
||||
|
||||
ITracker& s1 = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1.isOpen() );
|
||||
|
||||
SECTION( "successfully close one section" ) {
|
||||
s1.close();
|
||||
REQUIRE( s1.isSuccessfullyCompleted() );
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
REQUIRE( testCase.isSuccessfullyCompleted() );
|
||||
}
|
||||
|
||||
SECTION( "fail one section" ) {
|
||||
s1.fail();
|
||||
REQUIRE( s1.isComplete() );
|
||||
REQUIRE( s1.isSuccessfullyCompleted() == false );
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
REQUIRE( testCase.isSuccessfullyCompleted() == false );
|
||||
|
||||
SECTION( "re-enter after failed section" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() == false );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
REQUIRE( testCase.isComplete() );
|
||||
REQUIRE( testCase.isSuccessfullyCompleted() );
|
||||
}
|
||||
SECTION( "re-enter after failed section and find next section" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() == false );
|
||||
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
s2.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( testCase.isComplete() );
|
||||
REQUIRE( testCase.isSuccessfullyCompleted() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "successfully close one section, then find another" ) {
|
||||
s1.close();
|
||||
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
SECTION( "Re-enter - skips S1 and enters S2" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() == false );
|
||||
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2b.isOpen() );
|
||||
|
||||
REQUIRE( ctx.completedCycle() == false );
|
||||
|
||||
SECTION ("Successfully close S2") {
|
||||
s2b.close();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
|
||||
REQUIRE( s2b.isSuccessfullyCompleted() );
|
||||
REQUIRE( testCase2.isComplete() == false );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( testCase2.isSuccessfullyCompleted() );
|
||||
}
|
||||
SECTION ("fail S2") {
|
||||
s2b.fail();
|
||||
REQUIRE( ctx.completedCycle() );
|
||||
|
||||
REQUIRE( s2b.isComplete() );
|
||||
REQUIRE( s2b.isSuccessfullyCompleted() == false );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( testCase2.isSuccessfullyCompleted() == false );
|
||||
|
||||
// Need a final cycle
|
||||
ctx.startCycle();
|
||||
ITracker& testCase3 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase3.isOpen() );
|
||||
|
||||
ITracker& s1c = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1c.isOpen() == false );
|
||||
|
||||
ITracker& s2c = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2c.isOpen() == false );
|
||||
|
||||
testCase3.close();
|
||||
REQUIRE( testCase3.isSuccessfullyCompleted() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "open a nested section" ) {
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
s2.close();
|
||||
REQUIRE( s2.isComplete() );
|
||||
REQUIRE( s1.isComplete() == false );
|
||||
|
||||
s1.close();
|
||||
REQUIRE( s1.isComplete() );
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( testCase.isComplete() );
|
||||
}
|
||||
}
|
||||
|
||||
static bool previouslyRun = false;
|
||||
static bool previouslyRunNested = false;
|
||||
|
||||
TEST_CASE( "#1394", "[.][approvals][tracker]" ) {
|
||||
// -- Don't re-run after specified section is done
|
||||
REQUIRE(previouslyRun == false);
|
||||
|
||||
SECTION( "RunSection" ) {
|
||||
previouslyRun = true;
|
||||
}
|
||||
SECTION( "SkipSection" ) {
|
||||
// cause an error if this section is called because it shouldn't be
|
||||
REQUIRE(1 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "#1394 nested", "[.][approvals][tracker]" ) {
|
||||
REQUIRE(previouslyRunNested == false);
|
||||
|
||||
SECTION( "NestedRunSection" ) {
|
||||
SECTION( "s1" ) {
|
||||
previouslyRunNested = true;
|
||||
}
|
||||
}
|
||||
SECTION( "NestedSkipSection" ) {
|
||||
// cause an error if this section is called because it shouldn't be
|
||||
REQUIRE(1 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Selecting a "not last" section inside a test case via -c "section" would
|
||||
// previously only run the first subsection, instead of running all of them.
|
||||
// This allows us to check that `"#1670 regression check" -c A` leads to
|
||||
// 2 successful assertions.
|
||||
TEST_CASE("#1670 regression check", "[.approvals][tracker]") {
|
||||
SECTION("A") {
|
||||
SECTION("1") SUCCEED();
|
||||
SECTION("2") SUCCEED();
|
||||
}
|
||||
SECTION("B") {
|
||||
SECTION("1") SUCCEED();
|
||||
SECTION("2") SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
// #1938 required a rework on how generator tracking works, so that `GENERATE`
|
||||
// supports being sandwiched between two `SECTION`s. The following tests check
|
||||
// various other scenarios through checking output in approval tests.
|
||||
TEST_CASE("#1938 - GENERATE after a section", "[.][regression][generators]") {
|
||||
SECTION("A") {
|
||||
SUCCEED("A");
|
||||
}
|
||||
auto m = GENERATE(1, 2, 3);
|
||||
SECTION("B") {
|
||||
REQUIRE(m);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("#1938 - flat generate", "[.][regression][generators]") {
|
||||
auto m = GENERATE(1, 2, 3);
|
||||
REQUIRE(m);
|
||||
}
|
||||
|
||||
TEST_CASE("#1938 - nested generate", "[.][regression][generators]") {
|
||||
auto m = GENERATE(1, 2, 3);
|
||||
auto n = GENERATE(1, 2, 3);
|
||||
REQUIRE(m);
|
||||
REQUIRE(n);
|
||||
}
|
||||
|
||||
TEST_CASE("#1938 - mixed sections and generates", "[.][regression][generators]") {
|
||||
auto i = GENERATE(1, 2);
|
||||
SECTION("A") {
|
||||
SUCCEED("A");
|
||||
}
|
||||
auto j = GENERATE(3, 4);
|
||||
SECTION("B") {
|
||||
SUCCEED("B");
|
||||
}
|
||||
auto k = GENERATE(5, 6);
|
||||
CAPTURE(i, j, k);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("#1938 - Section followed by flat generate", "[.][regression][generators]") {
|
||||
SECTION("A") {
|
||||
REQUIRE(1);
|
||||
}
|
||||
auto m = GENERATE(2, 3);
|
||||
REQUIRE(m);
|
||||
}
|
||||
+590
@@ -0,0 +1,590 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <catch2/internal/catch_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_uniform_floating_point_distribution.hpp>
|
||||
#include <catch2/internal/catch_uniform_integer_distribution.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/matchers/catch_matchers_range_equals.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
TEST_CASE("Our PCG implementation provides expected results for known seeds", "[rng]") {
|
||||
Catch::SimplePcg32 rng;
|
||||
SECTION("Default seeded") {
|
||||
REQUIRE(rng() == 0xfcdb943b);
|
||||
REQUIRE(rng() == 0x6f55b921);
|
||||
REQUIRE(rng() == 0x4c17a916);
|
||||
REQUIRE(rng() == 0x71eae25f);
|
||||
REQUIRE(rng() == 0x6ce7909c);
|
||||
}
|
||||
SECTION("Specific seed") {
|
||||
rng.seed(0xabcd1234);
|
||||
REQUIRE(rng() == 0x57c08495);
|
||||
REQUIRE(rng() == 0x33c956ac);
|
||||
REQUIRE(rng() == 0x2206fd76);
|
||||
REQUIRE(rng() == 0x3501a35b);
|
||||
REQUIRE(rng() == 0xfdffb30f);
|
||||
|
||||
// Also check repeated output after reseeding
|
||||
rng.seed(0xabcd1234);
|
||||
REQUIRE(rng() == 0x57c08495);
|
||||
REQUIRE(rng() == 0x33c956ac);
|
||||
REQUIRE(rng() == 0x2206fd76);
|
||||
REQUIRE(rng() == 0x3501a35b);
|
||||
REQUIRE(rng() == 0xfdffb30f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Comparison ops", "[rng]") {
|
||||
using Catch::SimplePcg32;
|
||||
REQUIRE(SimplePcg32{} == SimplePcg32{});
|
||||
REQUIRE(SimplePcg32{ 0 } != SimplePcg32{});
|
||||
REQUIRE_FALSE(SimplePcg32{ 1 } == SimplePcg32{ 2 });
|
||||
REQUIRE_FALSE(SimplePcg32{ 1 } != SimplePcg32{ 1 });
|
||||
}
|
||||
|
||||
TEST_CASE("Random seed generation reports unknown methods", "[rng][seed]") {
|
||||
REQUIRE_THROWS(Catch::generateRandomSeed(static_cast<Catch::GenerateFrom>(77)));
|
||||
}
|
||||
|
||||
TEST_CASE("Random seed generation accepts known methods", "[rng][seed]") {
|
||||
using Catch::GenerateFrom;
|
||||
const auto method = GENERATE(
|
||||
GenerateFrom::Time,
|
||||
GenerateFrom::RandomDevice,
|
||||
GenerateFrom::Default
|
||||
);
|
||||
|
||||
REQUIRE_NOTHROW(Catch::generateRandomSeed(method));
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE("uniform_floating_point_distribution never returns infs from finite range",
|
||||
"[rng][distribution][floating-point][approvals]", float, double) {
|
||||
std::random_device rd{};
|
||||
Catch::SimplePcg32 pcg( rd() );
|
||||
Catch::uniform_floating_point_distribution<TestType> dist(
|
||||
-std::numeric_limits<TestType>::max(),
|
||||
std::numeric_limits<TestType>::max() );
|
||||
|
||||
for (size_t i = 0; i < 10'000; ++i) {
|
||||
auto ret = dist( pcg );
|
||||
REQUIRE_FALSE( std::isinf( ret ) );
|
||||
REQUIRE_FALSE( std::isnan( ret ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "fillBitsFrom - shortening and stretching", "[rng][approvals]" ) {
|
||||
using Catch::Detail::fillBitsFrom;
|
||||
|
||||
// The seed is not important, but the numbers below have to be repeatable.
|
||||
// They should also exhibit the same general pattern of being prefixes
|
||||
Catch::SimplePcg32 pcg( 0xaabb'ccdd );
|
||||
|
||||
SECTION( "Shorten to 8 bits" ) {
|
||||
// We cast the result to avoid dealing with char-like type in uint8_t
|
||||
auto shortened = static_cast<uint32_t>( fillBitsFrom<uint8_t>( pcg ) );
|
||||
REQUIRE( shortened == 0xcc );
|
||||
}
|
||||
SECTION( "Shorten to 16 bits" ) {
|
||||
auto shortened = fillBitsFrom<uint16_t>( pcg );
|
||||
REQUIRE( shortened == 0xccbe );
|
||||
}
|
||||
SECTION( "Keep at 32 bits" ) {
|
||||
auto n = fillBitsFrom<uint32_t>( pcg );
|
||||
REQUIRE( n == 0xccbe'5f04 );
|
||||
}
|
||||
SECTION( "Stretch to 64 bits" ) {
|
||||
auto stretched = fillBitsFrom<uint64_t>( pcg );
|
||||
REQUIRE( stretched == 0xccbe'5f04'a424'a486 );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("uniform_integer_distribution can return the bounds", "[rng][distribution]") {
|
||||
Catch::uniform_integer_distribution<int32_t> dist( -10, 10 );
|
||||
REQUIRE( dist.a() == -10 );
|
||||
REQUIRE( dist.b() == 10 );
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
static void CheckReturnValue(Catch::uniform_integer_distribution<T>& dist,
|
||||
Catch::SimplePcg32& rng,
|
||||
T target) {
|
||||
REQUIRE( dist.a() == dist.b() );
|
||||
for (int i = 0; i < 1'000; ++i) {
|
||||
REQUIRE( dist( rng ) == target );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE( "uniform_integer_distribution can handle unit ranges",
|
||||
"[rng][distribution][approvals]",
|
||||
unsigned char,
|
||||
signed char,
|
||||
char,
|
||||
uint8_t,
|
||||
int8_t,
|
||||
uint16_t,
|
||||
int16_t,
|
||||
uint32_t,
|
||||
int32_t,
|
||||
uint64_t,
|
||||
int64_t ) {
|
||||
// We want random seed to sample different parts of the rng state,
|
||||
// the output is predetermined anyway
|
||||
std::random_device rd;
|
||||
auto seed = rd();
|
||||
CAPTURE( seed );
|
||||
Catch::SimplePcg32 pcg( seed );
|
||||
|
||||
// We check unitary ranges of 3 different values, min for type, max for type,
|
||||
// some value inbetween just to make sure
|
||||
SECTION("lowest value") {
|
||||
constexpr auto lowest = std::numeric_limits<TestType>::min();
|
||||
Catch::uniform_integer_distribution<TestType> dist( lowest, lowest );
|
||||
CheckReturnValue( dist, pcg, lowest );
|
||||
}
|
||||
SECTION( "highest value" ) {
|
||||
constexpr auto highest = std::numeric_limits<TestType>::max();
|
||||
Catch::uniform_integer_distribution<TestType> dist( highest, highest );
|
||||
CheckReturnValue( dist, pcg, highest );
|
||||
}
|
||||
SECTION( "some value" ) {
|
||||
constexpr auto some = TestType( 42 );
|
||||
Catch::uniform_integer_distribution<TestType> dist( some, some );
|
||||
CheckReturnValue( dist, pcg, some );
|
||||
}
|
||||
}
|
||||
|
||||
// Bool needs its own test because it doesn't have a valid "third" value
|
||||
TEST_CASE( "uniform_integer_distribution can handle boolean unit ranges",
|
||||
"[rng][distribution][approvals]" ) {
|
||||
// We want random seed to sample different parts of the rng state,
|
||||
// the output is predetermined anyway
|
||||
std::random_device rd;
|
||||
auto seed = rd();
|
||||
CAPTURE( seed );
|
||||
Catch::SimplePcg32 pcg( seed );
|
||||
|
||||
// We check unitary ranges of 3 different values, min for type, max for
|
||||
// type, some value inbetween just to make sure
|
||||
SECTION( "lowest value" ) {
|
||||
Catch::uniform_integer_distribution<bool> dist( false, false );
|
||||
CheckReturnValue( dist, pcg, false );
|
||||
}
|
||||
SECTION( "highest value" ) {
|
||||
Catch::uniform_integer_distribution<bool> dist( true, true );
|
||||
CheckReturnValue( dist, pcg, true );
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE( "uniform_integer_distribution can handle full width ranges",
|
||||
"[rng][distribution][approvals]",
|
||||
unsigned char,
|
||||
signed char,
|
||||
char,
|
||||
uint8_t,
|
||||
int8_t,
|
||||
uint16_t,
|
||||
int16_t,
|
||||
uint32_t,
|
||||
int32_t,
|
||||
uint64_t,
|
||||
int64_t ) {
|
||||
// We want random seed to sample different parts of the rng state,
|
||||
// the output is predetermined anyway
|
||||
std::random_device rd;
|
||||
auto seed = rd();
|
||||
CAPTURE( seed );
|
||||
Catch::SimplePcg32 pcg( seed );
|
||||
|
||||
constexpr auto lowest = std::numeric_limits<TestType>::min();
|
||||
constexpr auto highest = std::numeric_limits<TestType>::max();
|
||||
Catch::uniform_integer_distribution<TestType> dist( lowest, highest );
|
||||
STATIC_REQUIRE( std::is_same<TestType, decltype( dist( pcg ) )>::value );
|
||||
|
||||
// We need to do bit operations on the results, so we will have to
|
||||
// cast them to unsigned type.
|
||||
using BitType = std::make_unsigned_t<TestType>;
|
||||
BitType ORs = 0;
|
||||
BitType ANDs = BitType(-1);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
auto bits = static_cast<BitType>( dist( pcg ) );
|
||||
ORs |= bits;
|
||||
ANDs &= bits;
|
||||
}
|
||||
// Assuming both our RNG and distribution are unbiased, asking for
|
||||
// the full range should essentially give us random bit generator.
|
||||
// Over long run, OR of all the generated values should have all
|
||||
// bits set to 1, while AND should have all bits set to 0.
|
||||
// The chance of this test failing for unbiased pipeline is
|
||||
// 1 / 2**iters, which for 100 iterations is astronomical.
|
||||
REQUIRE( ORs == BitType( -1 ) );
|
||||
REQUIRE( ANDs == 0 );
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
struct uniform_integer_test_params;
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<bool> {
|
||||
static constexpr bool lowest = false;
|
||||
static constexpr bool highest = true;
|
||||
// This seems weird, but it is an artifact of the specific seed
|
||||
static constexpr bool expected[] = { true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<char> {
|
||||
static constexpr char lowest = 32;
|
||||
static constexpr char highest = 126;
|
||||
static constexpr char expected[] = { 'k',
|
||||
'\\',
|
||||
'Z',
|
||||
'X',
|
||||
'`',
|
||||
'Q',
|
||||
';',
|
||||
'o',
|
||||
']',
|
||||
'T',
|
||||
'v',
|
||||
'p',
|
||||
':',
|
||||
'S',
|
||||
't' };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<uint8_t> {
|
||||
static constexpr uint8_t lowest = 3;
|
||||
static constexpr uint8_t highest = 123;
|
||||
static constexpr uint8_t expected[] = { 'c',
|
||||
'P',
|
||||
'M',
|
||||
'J',
|
||||
'U',
|
||||
'A',
|
||||
'%',
|
||||
'h',
|
||||
'Q',
|
||||
'F',
|
||||
'q',
|
||||
'i',
|
||||
'$',
|
||||
'E',
|
||||
'o' };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<int8_t> {
|
||||
static constexpr int8_t lowest = -27;
|
||||
static constexpr int8_t highest = 73;
|
||||
static constexpr int8_t expected[] = { '5',
|
||||
'%',
|
||||
'#',
|
||||
' ',
|
||||
'*',
|
||||
25,
|
||||
2,
|
||||
'9',
|
||||
'&',
|
||||
29,
|
||||
'A',
|
||||
':',
|
||||
1,
|
||||
28,
|
||||
'?' };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<uint16_t> {
|
||||
static constexpr uint16_t lowest = 123;
|
||||
static constexpr uint16_t highest = 33333;
|
||||
static constexpr uint16_t expected[] = { 26684,
|
||||
21417,
|
||||
20658,
|
||||
19791,
|
||||
22896,
|
||||
17433,
|
||||
9806,
|
||||
27948,
|
||||
21767,
|
||||
18588,
|
||||
30556,
|
||||
28244,
|
||||
9439,
|
||||
18293,
|
||||
29949 };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<int16_t> {
|
||||
static constexpr int16_t lowest = -17222;
|
||||
static constexpr int16_t highest = 17222;
|
||||
static constexpr int16_t expected[] = { 10326,
|
||||
4863,
|
||||
4076,
|
||||
3177,
|
||||
6397,
|
||||
731,
|
||||
-7179,
|
||||
11637,
|
||||
5226,
|
||||
1929,
|
||||
14342,
|
||||
11944,
|
||||
-7560,
|
||||
1623,
|
||||
13712 };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<uint32_t> {
|
||||
static constexpr uint32_t lowest = 17222;
|
||||
static constexpr uint32_t highest = 234234;
|
||||
static constexpr uint32_t expected[] = { 190784,
|
||||
156367,
|
||||
151409,
|
||||
145743,
|
||||
166032,
|
||||
130337,
|
||||
80501,
|
||||
199046,
|
||||
158654,
|
||||
137883,
|
||||
216091,
|
||||
200981,
|
||||
78099,
|
||||
135954,
|
||||
212120 };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<int32_t> {
|
||||
static constexpr int32_t lowest = -237272;
|
||||
static constexpr int32_t highest = 234234;
|
||||
static constexpr int32_t expected[] = { 139829,
|
||||
65050,
|
||||
54278,
|
||||
41969,
|
||||
86051,
|
||||
8494,
|
||||
-99785,
|
||||
157781,
|
||||
70021,
|
||||
24890,
|
||||
194815,
|
||||
161985,
|
||||
-105004,
|
||||
20699,
|
||||
186186 };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<uint64_t> {
|
||||
static constexpr uint64_t lowest = 1234;
|
||||
static constexpr uint64_t highest = 1234567890;
|
||||
static constexpr uint64_t expected[] = { 987382749,
|
||||
763380386,
|
||||
846572137,
|
||||
359990258,
|
||||
804599765,
|
||||
1131353566,
|
||||
346324913,
|
||||
1108760730,
|
||||
1141693933,
|
||||
856999148,
|
||||
879390623,
|
||||
1149485521,
|
||||
900556586,
|
||||
952385958,
|
||||
807916408 };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct uniform_integer_test_params<int64_t> {
|
||||
static constexpr int64_t lowest = -1234567890;
|
||||
static constexpr int64_t highest = 1234567890;
|
||||
static constexpr int64_t expected[] = { 740197113,
|
||||
292191940,
|
||||
458575608,
|
||||
-514589122,
|
||||
374630781,
|
||||
1028139036,
|
||||
-541919840,
|
||||
982953318,
|
||||
1048819790,
|
||||
479429651,
|
||||
524212647,
|
||||
1064402981,
|
||||
566544615,
|
||||
670203462,
|
||||
381264073 };
|
||||
};
|
||||
|
||||
// We need these definitions for C++14 and earlier, but
|
||||
// GCC will complain about them in newer C++ standards
|
||||
#if __cplusplus <= 201402L
|
||||
constexpr bool uniform_integer_test_params<bool>::expected[];
|
||||
constexpr char uniform_integer_test_params<char>::expected[];
|
||||
constexpr uint8_t uniform_integer_test_params<uint8_t>::expected[];
|
||||
constexpr int8_t uniform_integer_test_params<int8_t>::expected[];
|
||||
constexpr uint16_t uniform_integer_test_params<uint16_t>::expected[];
|
||||
constexpr int16_t uniform_integer_test_params<int16_t>::expected[];
|
||||
constexpr uint32_t uniform_integer_test_params<uint32_t>::expected[];
|
||||
constexpr int32_t uniform_integer_test_params<int32_t>::expected[];
|
||||
constexpr uint64_t uniform_integer_test_params<uint64_t>::expected[];
|
||||
constexpr int64_t uniform_integer_test_params<int64_t>::expected[];
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE( "uniform_integer_distribution is reproducible",
|
||||
"[rng][distribution][approvals]",
|
||||
bool,
|
||||
char,
|
||||
uint8_t,
|
||||
int8_t,
|
||||
uint16_t,
|
||||
int16_t,
|
||||
uint32_t,
|
||||
int32_t,
|
||||
uint64_t,
|
||||
int64_t) {
|
||||
Catch::SimplePcg32 pcg( 0xaabb'ccdd );
|
||||
|
||||
constexpr auto lowest = uniform_integer_test_params<TestType>::lowest;
|
||||
constexpr auto highest = uniform_integer_test_params<TestType>::highest;
|
||||
Catch::uniform_integer_distribution<TestType> dist(lowest, highest);
|
||||
|
||||
constexpr auto iters = 15;
|
||||
std::array<TestType, iters> generated;
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
generated[i] = dist( pcg );
|
||||
}
|
||||
|
||||
REQUIRE_THAT(generated, Catch::Matchers::RangeEquals(uniform_integer_test_params<TestType>::expected));
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
struct uniform_fp_test_params;
|
||||
|
||||
template<>
|
||||
struct uniform_fp_test_params<float> {
|
||||
// These are exactly representable
|
||||
static constexpr float lowest = -256.125f;
|
||||
static constexpr float highest = 385.125f;
|
||||
// These are just round-trip formatted
|
||||
static constexpr float expected[] = { 92.56961f,
|
||||
-23.170044f,
|
||||
310.81833f,
|
||||
-53.023132f,
|
||||
105.03287f,
|
||||
198.77591f,
|
||||
-172.72931f,
|
||||
51.805176f,
|
||||
-241.10156f,
|
||||
64.66101f,
|
||||
212.12509f,
|
||||
-49.24292f,
|
||||
-177.1399f,
|
||||
245.23679f,
|
||||
173.22421f };
|
||||
};
|
||||
template <>
|
||||
struct uniform_fp_test_params<double> {
|
||||
// These are exactly representable
|
||||
static constexpr double lowest = -234582.9921875;
|
||||
static constexpr double highest = 261238.015625;
|
||||
// These are just round-trip formatted
|
||||
static constexpr double expected[] = { 35031.207052832615,
|
||||
203783.3401838024,
|
||||
44667.940405848756,
|
||||
-170100.5877224467,
|
||||
-222966.7418051684,
|
||||
127472.72630072923,
|
||||
-173510.88209096913,
|
||||
97394.16172239158,
|
||||
119123.6921592663,
|
||||
22595.741022785165,
|
||||
8988.68409120926,
|
||||
136906.86520606978,
|
||||
33369.19104222473,
|
||||
60912.7615841752,
|
||||
-149060.05936760217 };
|
||||
};
|
||||
|
||||
// We need these definitions for C++14 and earlier, but
|
||||
// GCC will complain about them in newer C++ standards
|
||||
#if __cplusplus <= 201402L
|
||||
constexpr float uniform_fp_test_params<float>::expected[];
|
||||
constexpr double uniform_fp_test_params<double>::expected[];
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
TEMPLATE_TEST_CASE( "uniform_floating_point_distribution is reproducible",
|
||||
"[rng][distribution][floating-point][approvals]",
|
||||
float,
|
||||
double ) {
|
||||
Catch::SimplePcg32 pcg( 0xaabb'aabb );
|
||||
|
||||
const auto lowest = uniform_fp_test_params<TestType>::lowest;
|
||||
const auto highest = uniform_fp_test_params<TestType>::highest;
|
||||
Catch::uniform_floating_point_distribution<TestType> dist( lowest, highest );
|
||||
|
||||
constexpr auto iters = 15;
|
||||
std::array<TestType, iters> generated;
|
||||
for ( int i = 0; i < iters; ++i ) {
|
||||
generated[i] = dist( pcg );
|
||||
}
|
||||
|
||||
REQUIRE_THAT( generated, Catch::Matchers::RangeEquals( uniform_fp_test_params<TestType>::expected ) );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE( "uniform_floating_point_distribution can handle unitary ranges",
|
||||
"[rng][distribution][floating-point][approvals]",
|
||||
float,
|
||||
double ) {
|
||||
std::random_device rd;
|
||||
auto seed = rd();
|
||||
CAPTURE( seed );
|
||||
Catch::SimplePcg32 pcg( seed );
|
||||
|
||||
const auto highest = uniform_fp_test_params<TestType>::highest;
|
||||
Catch::uniform_floating_point_distribution<TestType> dist( highest,
|
||||
highest );
|
||||
|
||||
constexpr auto iters = 20;
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
REQUIRE( Catch::Detail::directCompare( dist( pcg ), highest ) );
|
||||
}
|
||||
}
|
||||
Vendored
+330
@@ -0,0 +1,330 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/reporters/catch_reporter_helpers.hpp>
|
||||
#include <catch2/reporters/catch_reporter_event_listener.hpp>
|
||||
#include <catch2/reporters/catch_reporter_streaming_base.hpp>
|
||||
#include <catch2/reporters/catch_reporter_multi.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
class StringIStream : public Catch::IStream {
|
||||
public:
|
||||
std::ostream& stream() override { return sstr; }
|
||||
std::string str() const { return sstr.str(); }
|
||||
private:
|
||||
std::stringstream sstr;
|
||||
};
|
||||
|
||||
//! config must outlive the function
|
||||
Catch::ReporterConfig makeDummyRepConfig( Catch::Config const& config ) {
|
||||
return Catch::ReporterConfig{
|
||||
&config,
|
||||
Catch::Detail::make_unique<StringIStream>(),
|
||||
Catch::ColourMode::None,
|
||||
{} };
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "The default listing implementation write to provided stream",
|
||||
"[reporters][reporter-helpers]" ) {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
using namespace std::string_literals;
|
||||
|
||||
StringIStream sstream;
|
||||
SECTION( "Listing tags" ) {
|
||||
std::vector<Catch::TagInfo> tags(1);
|
||||
tags[0].add("fakeTag"_catch_sr);
|
||||
Catch::defaultListTags(sstream.stream(), tags, false);
|
||||
|
||||
auto listingString = sstream.str();
|
||||
REQUIRE_THAT(listingString, ContainsSubstring("[fakeTag]"s));
|
||||
}
|
||||
SECTION( "Listing reporters" ) {
|
||||
std::vector<Catch::ReporterDescription> reporters(
|
||||
{ { "fake reporter", "fake description" } } );
|
||||
Catch::defaultListReporters(sstream.stream(), reporters, Catch::Verbosity::Normal);
|
||||
|
||||
auto listingString = sstream.str();
|
||||
REQUIRE_THAT( listingString,
|
||||
ContainsSubstring( "fake reporter"s ) &&
|
||||
ContainsSubstring( "fake description"s ) );
|
||||
}
|
||||
SECTION( "Listing tests" ) {
|
||||
Catch::TestCaseInfo fakeInfo{
|
||||
""s,
|
||||
{ "fake test name"_catch_sr, "[fakeTestTag]"_catch_sr },
|
||||
{ "fake-file.cpp", 123456789 } };
|
||||
std::vector<Catch::TestCaseHandle> tests({ {&fakeInfo, nullptr} });
|
||||
auto colour = Catch::makeColourImpl( Catch::ColourMode::None, &sstream);
|
||||
Catch::defaultListTests(sstream.stream(), colour.get(), tests, false, Catch::Verbosity::Normal);
|
||||
|
||||
auto listingString = sstream.str();
|
||||
REQUIRE_THAT( listingString,
|
||||
ContainsSubstring( "fake test name"s ) &&
|
||||
ContainsSubstring( "fakeTestTag"s ) );
|
||||
}
|
||||
SECTION( "Listing listeners" ) {
|
||||
std::vector<Catch::ListenerDescription> listeners(
|
||||
{ { "fakeListener"_catch_sr, "fake description" } } );
|
||||
|
||||
Catch::defaultListListeners( sstream.stream(), listeners );
|
||||
auto listingString = sstream.str();
|
||||
REQUIRE_THAT( listingString,
|
||||
ContainsSubstring( "fakeListener"s ) &&
|
||||
ContainsSubstring( "fake description"s ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Reporter's write listings to provided stream", "[reporters]" ) {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
using namespace std::string_literals;
|
||||
|
||||
auto const& factories = Catch::getRegistryHub().getReporterRegistry().getFactories();
|
||||
// If there are no reporters, the test would pass falsely
|
||||
// while there is something obviously broken
|
||||
REQUIRE_FALSE(factories.empty());
|
||||
|
||||
for (auto const& factory : factories) {
|
||||
INFO("Tested reporter: " << factory.first);
|
||||
auto sstream = Catch::Detail::make_unique<StringIStream>();
|
||||
auto& sstreamRef = *sstream.get();
|
||||
|
||||
Catch::ConfigData cfg_data;
|
||||
cfg_data.rngSeed = 1234;
|
||||
Catch::Config config( cfg_data );
|
||||
auto reporter = factory.second->create( Catch::ReporterConfig{
|
||||
&config, CATCH_MOVE( sstream ), Catch::ColourMode::None, {} } );
|
||||
|
||||
DYNAMIC_SECTION( factory.first << " reporter lists tags" ) {
|
||||
std::vector<Catch::TagInfo> tags(1);
|
||||
tags[0].add("fakeTag"_catch_sr);
|
||||
reporter->listTags(tags);
|
||||
|
||||
auto listingString = sstreamRef.str();
|
||||
REQUIRE_THAT(listingString, ContainsSubstring("fakeTag"s));
|
||||
}
|
||||
|
||||
DYNAMIC_SECTION( factory.first << " reporter lists reporters" ) {
|
||||
std::vector<Catch::ReporterDescription> reporters(
|
||||
{ { "fake reporter", "fake description" } } );
|
||||
reporter->listReporters(reporters);
|
||||
|
||||
auto listingString = sstreamRef.str();
|
||||
REQUIRE_THAT(listingString, ContainsSubstring("fake reporter"s));
|
||||
}
|
||||
|
||||
DYNAMIC_SECTION( factory.first << " reporter lists tests" ) {
|
||||
Catch::TestCaseInfo fakeInfo{
|
||||
""s,
|
||||
{ "fake test name"_catch_sr, "[fakeTestTag]"_catch_sr },
|
||||
{ "fake-file.cpp", 123456789 } };
|
||||
std::vector<Catch::TestCaseHandle> tests({ {&fakeInfo, nullptr} });
|
||||
reporter->listTests(tests);
|
||||
|
||||
auto listingString = sstreamRef.str();
|
||||
REQUIRE_THAT( listingString,
|
||||
ContainsSubstring( "fake test name"s ) &&
|
||||
ContainsSubstring( "fakeTestTag"s ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Reproducer for #2309 - a very long description past 80 chars (default console width) with a late colon : blablabla", "[console-reporter]") {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A listener that writes provided string into destination,
|
||||
// to record order of testRunStarting invocation.
|
||||
class MockListener : public Catch::EventListenerBase {
|
||||
std::string m_witness;
|
||||
std::vector<std::string>& m_recorder;
|
||||
public:
|
||||
MockListener( std::string witness,
|
||||
std::vector<std::string>& recorder,
|
||||
Catch::IConfig const* config ):
|
||||
EventListenerBase( config ),
|
||||
m_witness( CATCH_MOVE(witness) ),
|
||||
m_recorder( recorder )
|
||||
{}
|
||||
|
||||
void testRunStarting( Catch::TestRunInfo const& ) override {
|
||||
m_recorder.push_back( m_witness );
|
||||
}
|
||||
};
|
||||
// A reporter that writes provided string into destination,
|
||||
// to record order of testRunStarting invocation.
|
||||
class MockReporter : public Catch::StreamingReporterBase {
|
||||
std::string m_witness;
|
||||
std::vector<std::string>& m_recorder;
|
||||
public:
|
||||
MockReporter( std::string witness,
|
||||
std::vector<std::string>& recorder,
|
||||
Catch::ReporterConfig&& config ):
|
||||
StreamingReporterBase( CATCH_MOVE(config) ),
|
||||
m_witness( CATCH_MOVE(witness) ),
|
||||
m_recorder( recorder )
|
||||
{}
|
||||
|
||||
void testRunStarting( Catch::TestRunInfo const& ) override {
|
||||
m_recorder.push_back( m_witness );
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Multireporter calls reporters and listeners in correct order",
|
||||
"[reporters][multi-reporter]") {
|
||||
Catch::Config config( Catch::ConfigData{} );
|
||||
|
||||
// We add reporters before listeners, to check that internally they
|
||||
// get sorted properly, and listeners are called first anyway.
|
||||
Catch::MultiReporter multiReporter( &config );
|
||||
std::vector<std::string> records;
|
||||
multiReporter.addReporter( Catch::Detail::make_unique<MockReporter>(
|
||||
"Goodbye", records, makeDummyRepConfig(config) ) );
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<MockListener>( "Hello", records, &config ) );
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<MockListener>( "world", records, &config ) );
|
||||
multiReporter.addReporter( Catch::Detail::make_unique<MockReporter>(
|
||||
"world", records, makeDummyRepConfig(config) ) );
|
||||
multiReporter.testRunStarting( { "" } );
|
||||
|
||||
std::vector<std::string> expected( { "Hello", "world", "Goodbye", "world" } );
|
||||
REQUIRE( records == expected );
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A listener that sets it preferences to test that multireporter,
|
||||
// properly sets up its own preferences
|
||||
class PreferenceListener : public Catch::EventListenerBase {
|
||||
public:
|
||||
PreferenceListener( bool redirectStdout,
|
||||
bool reportAllAssertions,
|
||||
Catch::IConfig const* config ):
|
||||
EventListenerBase( config ) {
|
||||
m_preferences.shouldRedirectStdOut = redirectStdout;
|
||||
m_preferences.shouldReportAllAssertions = reportAllAssertions;
|
||||
}
|
||||
};
|
||||
// A reporter that sets it preferences to test that multireporter,
|
||||
// properly sets up its own preferences
|
||||
class PreferenceReporter : public Catch::StreamingReporterBase {
|
||||
public:
|
||||
PreferenceReporter( bool redirectStdout,
|
||||
bool reportAllAssertions,
|
||||
Catch::ReporterConfig&& config ):
|
||||
StreamingReporterBase( CATCH_MOVE(config) ) {
|
||||
m_preferences.shouldRedirectStdOut = redirectStdout;
|
||||
m_preferences.shouldReportAllAssertions = reportAllAssertions;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Multireporter updates ReporterPreferences properly",
|
||||
"[reporters][multi-reporter]") {
|
||||
|
||||
Catch::Config config( Catch::ConfigData{} );
|
||||
Catch::MultiReporter multiReporter( &config );
|
||||
|
||||
// Post init defaults
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == false );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == false );
|
||||
|
||||
SECTION( "Adding listeners" ) {
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<PreferenceListener>(
|
||||
true, false, &config ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == false );
|
||||
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<PreferenceListener>(
|
||||
false, true, &config ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == true);
|
||||
|
||||
multiReporter.addListener(
|
||||
Catch::Detail::make_unique<PreferenceListener>(
|
||||
false, false, &config ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == true );
|
||||
}
|
||||
SECTION( "Adding reporters" ) {
|
||||
multiReporter.addReporter(
|
||||
Catch::Detail::make_unique<PreferenceReporter>(
|
||||
true, false, makeDummyRepConfig(config) ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == false );
|
||||
|
||||
multiReporter.addReporter(
|
||||
Catch::Detail::make_unique<PreferenceReporter>(
|
||||
false, true, makeDummyRepConfig( config ) ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == true );
|
||||
|
||||
multiReporter.addReporter(
|
||||
Catch::Detail::make_unique<PreferenceReporter>(
|
||||
false, false, makeDummyRepConfig( config ) ) );
|
||||
REQUIRE( multiReporter.getPreferences().shouldRedirectStdOut == true );
|
||||
REQUIRE( multiReporter.getPreferences().shouldReportAllAssertions == true );
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class TestReporterFactory : public Catch::IReporterFactory {
|
||||
Catch::IEventListenerPtr create( Catch::ReporterConfig&& ) const override {
|
||||
CATCH_INTERNAL_ERROR(
|
||||
"This factory should never create a reporter" );
|
||||
}
|
||||
std::string getDescription() const override {
|
||||
return "Fake test factory";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Registering reporter with '::' in name fails",
|
||||
"[reporters][registration]") {
|
||||
Catch::ReporterRegistry registry;
|
||||
|
||||
REQUIRE_THROWS_WITH( registry.registerReporter(
|
||||
"with::doublecolons",
|
||||
Catch::Detail::make_unique<TestReporterFactory>() ),
|
||||
"'::' is not allowed in reporter name: 'with::doublecolons'" );
|
||||
}
|
||||
|
||||
TEST_CASE("Registering multiple reporters with the same name fails",
|
||||
"[reporters][registration][approvals]") {
|
||||
Catch::ReporterRegistry registry;
|
||||
|
||||
registry.registerReporter(
|
||||
"some-reporter-name",
|
||||
Catch::Detail::make_unique<TestReporterFactory>() );
|
||||
|
||||
REQUIRE_THROWS_WITH(
|
||||
registry.registerReporter(
|
||||
"some-reporter-name",
|
||||
Catch::Detail::make_unique<TestReporterFactory>() ),
|
||||
"reporter using 'some-reporter-name' as name was already registered" );
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/generators/catch_generators_all.hpp>
|
||||
|
||||
#include <catch2/internal/catch_sharding.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
TEST_CASE("Sharding Function", "[approvals]") {
|
||||
std::vector<int> testContainer = { 0, 1, 2, 3, 4, 5, 6 };
|
||||
std::unordered_map<int, std::vector<std::size_t>> expectedShardSizes = {
|
||||
{1, {7}},
|
||||
{2, {4, 3}},
|
||||
{3, {3, 2, 2}},
|
||||
{4, {2, 2, 2, 1}},
|
||||
{5, {2, 2, 1, 1, 1}},
|
||||
{6, {2, 1, 1, 1, 1, 1}},
|
||||
{7, {1, 1, 1, 1, 1, 1, 1}},
|
||||
};
|
||||
|
||||
auto shardCount = GENERATE(range(1, 7));
|
||||
auto shardIndex = GENERATE_COPY(filter([=](int i) { return i < shardCount; }, range(0, 6)));
|
||||
|
||||
std::vector<int> result = Catch::createShard(testContainer, shardCount, shardIndex);
|
||||
|
||||
auto& sizes = expectedShardSizes[shardCount];
|
||||
REQUIRE(result.size() == sizes[shardIndex]);
|
||||
|
||||
std::size_t startIndex = 0;
|
||||
for(int i = 0; i < shardIndex; i++) {
|
||||
startIndex += sizes[i];
|
||||
}
|
||||
|
||||
for(std::size_t i = 0; i < sizes[shardIndex]; i++) {
|
||||
CHECK(result[i] == testContainer[i + startIndex]);
|
||||
}
|
||||
}
|
||||
+32
@@ -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
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
TEST_CASE( "Cout stream properly declares it writes to stdout", "[streams]" ) {
|
||||
REQUIRE( Catch::makeStream( "-" )->isConsole() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Empty stream name opens cout stream", "[streams]" ) {
|
||||
REQUIRE( Catch::makeStream( "" )->isConsole() );
|
||||
}
|
||||
|
||||
TEST_CASE( "stdout and stderr streams have %-starting name", "[streams]" ) {
|
||||
REQUIRE( Catch::makeStream( "%stderr" )->isConsole() );
|
||||
REQUIRE( Catch::makeStream( "%stdout" )->isConsole() );
|
||||
}
|
||||
|
||||
TEST_CASE( "request an unknown %-starting stream fails", "[streams]" ) {
|
||||
REQUIRE_THROWS( Catch::makeStream( "%somestream" ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "makeStream recognizes %debug stream name", "[streams]" ) {
|
||||
REQUIRE_NOTHROW( Catch::makeStream( "%debug" ) );
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
|
||||
using Catch::StringRef;
|
||||
|
||||
SECTION( "Empty string" ) {
|
||||
StringRef empty;
|
||||
REQUIRE( empty.empty() );
|
||||
REQUIRE( empty.size() == 0 );
|
||||
REQUIRE( std::strcmp( empty.data(), "" ) == 0 );
|
||||
}
|
||||
|
||||
SECTION( "From string literal" ) {
|
||||
StringRef s = "hello";
|
||||
REQUIRE( s.empty() == false );
|
||||
REQUIRE( s.size() == 5 );
|
||||
|
||||
auto rawChars = s.data();
|
||||
REQUIRE( std::strcmp( rawChars, "hello" ) == 0 );
|
||||
|
||||
REQUIRE(s.data() == rawChars);
|
||||
}
|
||||
SECTION( "From sub-string" ) {
|
||||
StringRef original = StringRef( "original string" ).substr(0, 8);
|
||||
REQUIRE( original == "original" );
|
||||
|
||||
REQUIRE_NOTHROW(original.data());
|
||||
}
|
||||
SECTION( "Copy construction is shallow" ) {
|
||||
StringRef original = StringRef( "original string" );
|
||||
StringRef copy = original;
|
||||
REQUIRE(original.begin() == copy.begin());
|
||||
}
|
||||
SECTION( "Copy assignment is shallow" ) {
|
||||
StringRef original = StringRef( "original string" );
|
||||
StringRef copy;
|
||||
copy = original;
|
||||
REQUIRE(original.begin() == copy.begin());
|
||||
}
|
||||
|
||||
SECTION( "Substrings" ) {
|
||||
StringRef s = "hello world!";
|
||||
StringRef ss = s.substr(0, 5);
|
||||
|
||||
SECTION( "zero-based substring" ) {
|
||||
REQUIRE( ss.empty() == false );
|
||||
REQUIRE( ss.size() == 5 );
|
||||
REQUIRE( std::strncmp( ss.data(), "hello", 5 ) == 0 );
|
||||
REQUIRE( ss == "hello" );
|
||||
}
|
||||
|
||||
SECTION( "non-zero-based substring") {
|
||||
ss = s.substr( 6, 6 );
|
||||
REQUIRE( ss.size() == 6 );
|
||||
REQUIRE( std::strcmp( ss.data(), "world!" ) == 0 );
|
||||
}
|
||||
|
||||
SECTION( "Pointer values of full refs should match" ) {
|
||||
StringRef s2 = s;
|
||||
REQUIRE( s.data() == s2.data() );
|
||||
}
|
||||
|
||||
SECTION( "Pointer values of substring refs should also match" ) {
|
||||
REQUIRE( s.data() == ss.data() );
|
||||
}
|
||||
|
||||
SECTION("Past the end substring") {
|
||||
REQUIRE(s.substr(s.size() + 1, 123).empty());
|
||||
}
|
||||
|
||||
SECTION("Substring off the end are trimmed") {
|
||||
ss = s.substr(6, 123);
|
||||
REQUIRE(std::strcmp(ss.data(), "world!") == 0);
|
||||
}
|
||||
SECTION("substring start after the end is empty") {
|
||||
REQUIRE(s.substr(1'000'000, 1).empty());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Comparisons are deep" ) {
|
||||
char buffer1[] = "Hello";
|
||||
char buffer2[] = "Hello";
|
||||
CHECK(reinterpret_cast<char*>(buffer1) != reinterpret_cast<char*>(buffer2));
|
||||
|
||||
StringRef left(buffer1), right(buffer2);
|
||||
REQUIRE( left == right );
|
||||
REQUIRE(left != left.substr(0, 3));
|
||||
}
|
||||
|
||||
SECTION( "from std::string" ) {
|
||||
std::string stdStr = "a standard string";
|
||||
|
||||
SECTION( "implicitly constructed" ) {
|
||||
StringRef sr = stdStr;
|
||||
REQUIRE( sr == "a standard string" );
|
||||
REQUIRE( sr.size() == stdStr.size() );
|
||||
}
|
||||
SECTION( "explicitly constructed" ) {
|
||||
StringRef sr( stdStr );
|
||||
REQUIRE( sr == "a standard string" );
|
||||
REQUIRE( sr.size() == stdStr.size() );
|
||||
}
|
||||
SECTION( "assigned" ) {
|
||||
StringRef sr;
|
||||
sr = stdStr;
|
||||
REQUIRE( sr == "a standard string" );
|
||||
REQUIRE( sr.size() == stdStr.size() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "to std::string" ) {
|
||||
StringRef sr = "a stringref";
|
||||
|
||||
SECTION( "explicitly constructed" ) {
|
||||
std::string stdStr( sr );
|
||||
REQUIRE( stdStr == "a stringref" );
|
||||
REQUIRE( stdStr.size() == sr.size() );
|
||||
}
|
||||
SECTION( "assigned" ) {
|
||||
std::string stdStr;
|
||||
stdStr = static_cast<std::string>(sr);
|
||||
REQUIRE( stdStr == "a stringref" );
|
||||
REQUIRE( stdStr.size() == sr.size() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::string += StringRef") {
|
||||
StringRef sr = "the stringref contents";
|
||||
std::string lhs("some string += ");
|
||||
lhs += sr;
|
||||
REQUIRE(lhs == "some string += the stringref contents");
|
||||
}
|
||||
SECTION("StringRef + StringRef") {
|
||||
StringRef sr1 = "abraka", sr2 = "dabra";
|
||||
std::string together = sr1 + sr2;
|
||||
REQUIRE(together == "abrakadabra");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("StringRef at compilation time", "[Strings][StringRef][constexpr]") {
|
||||
using Catch::StringRef;
|
||||
SECTION("Simple constructors") {
|
||||
constexpr StringRef empty{};
|
||||
STATIC_REQUIRE(empty.size() == 0);
|
||||
STATIC_REQUIRE(empty.begin() == empty.end());
|
||||
|
||||
constexpr char const* const abc = "abc";
|
||||
|
||||
constexpr StringRef stringref(abc, 3);
|
||||
STATIC_REQUIRE(stringref.size() == 3);
|
||||
STATIC_REQUIRE(stringref.data() == abc);
|
||||
STATIC_REQUIRE(stringref.begin() == abc);
|
||||
STATIC_REQUIRE(stringref.begin() != stringref.end());
|
||||
STATIC_REQUIRE(stringref.substr(10, 0).empty());
|
||||
STATIC_REQUIRE(stringref.substr(2, 1).data() == abc + 2);
|
||||
STATIC_REQUIRE(stringref[1] == 'b');
|
||||
|
||||
|
||||
constexpr StringRef shortened(abc, 2);
|
||||
STATIC_REQUIRE(shortened.size() == 2);
|
||||
STATIC_REQUIRE(shortened.data() == abc);
|
||||
STATIC_REQUIRE(shortened.begin() != shortened.end());
|
||||
}
|
||||
SECTION("UDL construction") {
|
||||
constexpr auto sr1 = "abc"_catch_sr;
|
||||
STATIC_REQUIRE_FALSE(sr1.empty());
|
||||
STATIC_REQUIRE(sr1.size() == 3);
|
||||
|
||||
using Catch::operator""_sr;
|
||||
constexpr auto sr2 = ""_sr;
|
||||
STATIC_REQUIRE(sr2.empty());
|
||||
STATIC_REQUIRE(sr2.size() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("StringRef::compare", "[Strings][StringRef][approvals]") {
|
||||
using Catch::StringRef;
|
||||
|
||||
SECTION("Same length on both sides") {
|
||||
StringRef sr1("abcdc");
|
||||
StringRef sr2("abcdd");
|
||||
StringRef sr3("abcdc");
|
||||
|
||||
REQUIRE(sr1.compare(sr2) < 0);
|
||||
REQUIRE(sr2.compare(sr1) > 0);
|
||||
REQUIRE(sr1.compare(sr3) == 0);
|
||||
REQUIRE(sr3.compare(sr1) == 0);
|
||||
}
|
||||
SECTION("Different lengths") {
|
||||
StringRef sr1("def");
|
||||
StringRef sr2("deff");
|
||||
StringRef sr3("ab");
|
||||
|
||||
REQUIRE(sr1.compare(sr2) < 0);
|
||||
REQUIRE(sr2.compare(sr1) > 0);
|
||||
REQUIRE(sr1.compare(sr3) > 0);
|
||||
REQUIRE(sr2.compare(sr3) > 0);
|
||||
REQUIRE(sr3.compare(sr1) < 0);
|
||||
REQUIRE(sr3.compare(sr2) < 0);
|
||||
}
|
||||
}
|
||||
Vendored
+83
@@ -0,0 +1,83 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
|
||||
static const char * const no_whitespace = "There is no extra whitespace here";
|
||||
static const char * const leading_whitespace = " \r \t\n There is no extra whitespace here";
|
||||
static const char * const trailing_whitespace = "There is no extra whitespace here \t \n \r ";
|
||||
static const char * const whitespace_at_both_ends = " \r\n \t There is no extra whitespace here \t\t\t \n";
|
||||
|
||||
TEST_CASE("Trim strings", "[string-manip]") {
|
||||
using Catch::trim; using Catch::StringRef;
|
||||
static_assert(std::is_same<std::string, decltype(trim(std::string{}))>::value, "Trimming std::string should return std::string");
|
||||
static_assert(std::is_same<StringRef, decltype(trim(StringRef{}))>::value, "Trimming StringRef should return StringRef");
|
||||
|
||||
REQUIRE(trim(std::string(no_whitespace)) == no_whitespace);
|
||||
REQUIRE(trim(std::string(leading_whitespace)) == no_whitespace);
|
||||
REQUIRE(trim(std::string(trailing_whitespace)) == no_whitespace);
|
||||
REQUIRE(trim(std::string(whitespace_at_both_ends)) == no_whitespace);
|
||||
|
||||
REQUIRE(trim(StringRef(no_whitespace)) == StringRef(no_whitespace));
|
||||
REQUIRE(trim(StringRef(leading_whitespace)) == StringRef(no_whitespace));
|
||||
REQUIRE(trim(StringRef(trailing_whitespace)) == StringRef(no_whitespace));
|
||||
REQUIRE(trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace));
|
||||
}
|
||||
|
||||
TEST_CASE("replaceInPlace", "[string-manip]") {
|
||||
std::string letters = "abcdefcg";
|
||||
SECTION("replace single char") {
|
||||
CHECK(Catch::replaceInPlace(letters, "b", "z"));
|
||||
CHECK(letters == "azcdefcg");
|
||||
}
|
||||
SECTION("replace two chars") {
|
||||
CHECK(Catch::replaceInPlace(letters, "c", "z"));
|
||||
CHECK(letters == "abzdefzg");
|
||||
}
|
||||
SECTION("replace first char") {
|
||||
CHECK(Catch::replaceInPlace(letters, "a", "z"));
|
||||
CHECK(letters == "zbcdefcg");
|
||||
}
|
||||
SECTION("replace last char") {
|
||||
CHECK(Catch::replaceInPlace(letters, "g", "z"));
|
||||
CHECK(letters == "abcdefcz");
|
||||
}
|
||||
SECTION("replace all chars") {
|
||||
CHECK(Catch::replaceInPlace(letters, letters, "replaced"));
|
||||
CHECK(letters == "replaced");
|
||||
}
|
||||
SECTION("replace no chars") {
|
||||
CHECK_FALSE(Catch::replaceInPlace(letters, "x", "z"));
|
||||
CHECK(letters == letters);
|
||||
}
|
||||
SECTION("escape '") {
|
||||
std::string s = "didn't";
|
||||
CHECK(Catch::replaceInPlace(s, "'", "|'"));
|
||||
CHECK(s == "didn|'t");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("splitString", "[string-manip]") {
|
||||
using namespace Catch::Matchers;
|
||||
using Catch::splitStringRef;
|
||||
using Catch::StringRef;
|
||||
|
||||
CHECK_THAT(splitStringRef("", ','), Equals(std::vector<StringRef>()));
|
||||
CHECK_THAT(splitStringRef("abc", ','), Equals(std::vector<StringRef>{"abc"}));
|
||||
CHECK_THAT(splitStringRef("abc,def", ','), Equals(std::vector<StringRef>{"abc", "def"}));
|
||||
}
|
||||
|
||||
TEST_CASE("startsWith", "[string-manip]") {
|
||||
using Catch::startsWith;
|
||||
|
||||
CHECK_FALSE(startsWith("", 'c'));
|
||||
CHECK(startsWith(std::string("abc"), 'a'));
|
||||
CHECK(startsWith("def"_catch_sr, 'd'));
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
|
||||
// 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/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
|
||||
TEST_CASE( "Tag alias can be registered against tag patterns" ) {
|
||||
|
||||
Catch::TagAliasRegistry registry;
|
||||
|
||||
registry.add( "[@zzz]", "[one][two]", Catch::SourceLineInfo( "file", 2 ) );
|
||||
|
||||
SECTION( "The same tag alias can only be registered once" ) {
|
||||
|
||||
try {
|
||||
registry.add( "[@zzz]", "[one][two]", Catch::SourceLineInfo( "file", 10 ) );
|
||||
FAIL( "expected exception" );
|
||||
}
|
||||
catch( std::exception& ex ) {
|
||||
std::string what = ex.what();
|
||||
using namespace Catch::Matchers;
|
||||
CHECK_THAT( what, ContainsSubstring( "[@zzz]" ) );
|
||||
CHECK_THAT( what, ContainsSubstring( "file" ) );
|
||||
CHECK_THAT( what, ContainsSubstring( "2" ) );
|
||||
CHECK_THAT( what, ContainsSubstring( "10" ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Tag aliases must be of the form [@name]" ) {
|
||||
CHECK_THROWS( registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
CHECK_THROWS( registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
CHECK_THROWS( registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
CHECK_THROWS( registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Dummy line info for creating dummy test cases below
|
||||
static constexpr Catch::SourceLineInfo dummySourceLineInfo = CATCH_INTERNAL_LINEINFO;
|
||||
|
||||
TEST_CASE("shortened hide tags are split apart", "[tags]") {
|
||||
using Catch::StringRef;
|
||||
using Catch::Tag;
|
||||
using Catch::Matchers::VectorContains;
|
||||
|
||||
Catch::TestCaseInfo testcase("", {"fake test name", "[.magic-tag]"}, dummySourceLineInfo);
|
||||
REQUIRE_THAT( testcase.tags, VectorContains( Tag( "magic-tag" ) )
|
||||
&& VectorContains( Tag( "."_catch_sr ) ) );
|
||||
}
|
||||
|
||||
TEST_CASE("tags with dots in later positions are not parsed as hidden", "[tags]") {
|
||||
using Catch::StringRef;
|
||||
using Catch::Matchers::VectorContains;
|
||||
Catch::TestCaseInfo testcase("", { "fake test name", "[magic.tag]" }, dummySourceLineInfo);
|
||||
|
||||
REQUIRE(testcase.tags.size() == 1);
|
||||
REQUIRE(testcase.tags[0].original == "magic.tag"_catch_sr);
|
||||
}
|
||||
|
||||
TEST_CASE( "empty tags are not allowed", "[tags]" ) {
|
||||
REQUIRE_THROWS(
|
||||
Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo)
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE( "Tags with spaces and non-alphanumerical characters are accepted",
|
||||
"[tags]" ) {
|
||||
using Catch::Tag;
|
||||
using Catch::Matchers::VectorContains;
|
||||
|
||||
Catch::TestCaseInfo testCase(
|
||||
"",
|
||||
{ "fake test name", "[tag with spaces][I said \"good day\" sir!]" },
|
||||
dummySourceLineInfo );
|
||||
|
||||
REQUIRE( testCase.tags.size() == 2 );
|
||||
REQUIRE_THAT( testCase.tags,
|
||||
VectorContains( Tag( "tag with spaces" ) ) &&
|
||||
VectorContains( Tag( "I said \"good day\" sir!"_catch_sr ) ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "Test case with identical tags keeps just one", "[tags]" ) {
|
||||
using Catch::Tag;
|
||||
|
||||
Catch::TestCaseInfo testCase(
|
||||
"",
|
||||
{ "fake test name", "[TaG1][tAg1][TAG1][tag1]" },
|
||||
dummySourceLineInfo );
|
||||
|
||||
REQUIRE( testCase.tags.size() == 1 );
|
||||
REQUIRE( testCase.tags[0] == Tag( "tag1" ) );
|
||||
}
|
||||
|
||||
TEST_CASE("Mismatched square brackets in tags are caught and reported",
|
||||
"[tags][approvals]") {
|
||||
using Catch::TestCaseInfo;
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
REQUIRE_THROWS_WITH( TestCaseInfo( "",
|
||||
{ "test with unclosed tag", "[abc" },
|
||||
dummySourceLineInfo ),
|
||||
ContainsSubstring("registering test case 'test with unclosed tag'") );
|
||||
REQUIRE_THROWS_WITH( TestCaseInfo( "",
|
||||
{ "test with nested tags", "[abc[def]]" },
|
||||
dummySourceLineInfo ),
|
||||
ContainsSubstring("registering test case 'test with nested tags'") );
|
||||
REQUIRE_THROWS_WITH( TestCaseInfo( "",
|
||||
{ "test with superfluous close tags", "[abc][def]]" },
|
||||
dummySourceLineInfo ),
|
||||
ContainsSubstring("registering test case 'test with superfluous close tags'") );
|
||||
}
|
||||
bot/external/Botcraft/3rdparty/catch2/tests/SelfTest/IntrospectiveTests/TestCaseInfoHasher.tests.cpp
Vendored
+72
@@ -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
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_test_case_info_hasher.hpp>
|
||||
|
||||
static constexpr Catch::SourceLineInfo dummySourceLineInfo = CATCH_INTERNAL_LINEINFO;
|
||||
|
||||
using Catch::TestCaseInfo;
|
||||
using Catch::TestCaseInfoHasher;
|
||||
|
||||
TEST_CASE("Hashers with same seed produce same hash", "[test-case-hash]") {
|
||||
TestCaseInfo dummy( "", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
TestCaseInfoHasher h1( 0x12345678 );
|
||||
TestCaseInfoHasher h2( 0x12345678 );
|
||||
|
||||
REQUIRE( h1( dummy ) == h2( dummy ) );
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Hashers with different seed produce different hash with same test case",
|
||||
"[test-case-hash]") {
|
||||
TestCaseInfo dummy( "", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
TestCaseInfoHasher h1( 0x12345678 );
|
||||
TestCaseInfoHasher h2( 0x87654321 );
|
||||
|
||||
REQUIRE( h1( dummy ) != h2( dummy ) );
|
||||
}
|
||||
|
||||
TEST_CASE("Hashing test case produces same hash across multiple calls",
|
||||
"[test-case-hash]") {
|
||||
TestCaseInfo dummy( "", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
TestCaseInfoHasher h( 0x12345678 );
|
||||
|
||||
REQUIRE( h( dummy ) == h( dummy ) );
|
||||
}
|
||||
|
||||
TEST_CASE("Hashing different test cases produces different result", "[test-case-hash]") {
|
||||
TestCaseInfoHasher h( 0x12345678 );
|
||||
SECTION("Different test name") {
|
||||
TestCaseInfo dummy1( "class", { "name-1", "[a-tag]" }, dummySourceLineInfo );
|
||||
TestCaseInfo dummy2(
|
||||
"class", { "name-2", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( h( dummy1 ) != h( dummy2 ) );
|
||||
}
|
||||
SECTION("Different classname") {
|
||||
TestCaseInfo dummy1(
|
||||
"class-1", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
TestCaseInfo dummy2(
|
||||
"class-2", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( h( dummy1 ) != h( dummy2 ) );
|
||||
}
|
||||
SECTION("Different tags") {
|
||||
TestCaseInfo dummy1(
|
||||
"class", { "name", "[a-tag]" }, dummySourceLineInfo );
|
||||
TestCaseInfo dummy2(
|
||||
"class", { "name", "[b-tag]" }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( h( dummy1 ) != h( dummy2 ) );
|
||||
}
|
||||
}
|
||||
+365
@@ -0,0 +1,365 @@
|
||||
|
||||
// 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_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_commandline.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
|
||||
#include <helpers/parse_test_spec.hpp>
|
||||
|
||||
namespace {
|
||||
auto fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCaseInfo("", { name, desc }, CATCH_INTERNAL_LINEINFO); }
|
||||
}
|
||||
|
||||
TEST_CASE( "Parse test names and tags", "[command-line][test-spec][approvals]" ) {
|
||||
using Catch::parseTestSpec;
|
||||
using Catch::TestSpec;
|
||||
|
||||
auto tcA = fakeTestCase( "a" );
|
||||
auto tcB = fakeTestCase( "b", "[one][x]" );
|
||||
auto tcC = fakeTestCase( "longer name with spaces", "[two][three][.][x]" );
|
||||
auto tcD = fakeTestCase( "zlonger name with spacesz" );
|
||||
|
||||
SECTION( "Empty test spec should have no filters" ) {
|
||||
TestSpec spec;
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from empty string should have no filters" ) {
|
||||
TestSpec spec = parseTestSpec( "" );
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from just a comma should have no filters" ) {
|
||||
TestSpec spec = parseTestSpec( "," );
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from name should have one filter" ) {
|
||||
TestSpec spec = parseTestSpec( "b" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from quoted name should have one filter" ) {
|
||||
TestSpec spec = parseTestSpec( "\"b\"" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
}
|
||||
|
||||
SECTION( "Test spec from name should have one filter" ) {
|
||||
TestSpec spec = parseTestSpec( "b" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
}
|
||||
|
||||
SECTION( "Wildcard at the start" ) {
|
||||
TestSpec spec = parseTestSpec( "*spaces" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
CHECK( parseTestSpec( "*a" ).matches( *tcA ) == true );
|
||||
}
|
||||
SECTION( "Wildcard at the end" ) {
|
||||
TestSpec spec = parseTestSpec( "long*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
CHECK( parseTestSpec( "a*" ).matches( *tcA ) == true );
|
||||
}
|
||||
SECTION( "Wildcard at both ends" ) {
|
||||
TestSpec spec = parseTestSpec( "*name*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
CHECK( parseTestSpec( "*a*" ).matches( *tcA ) == true );
|
||||
}
|
||||
SECTION( "Redundant wildcard at the start" ) {
|
||||
TestSpec spec = parseTestSpec( "*a" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
SECTION( "Redundant wildcard at the end" ) {
|
||||
TestSpec spec = parseTestSpec( "a*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
SECTION( "Redundant wildcard at both ends" ) {
|
||||
TestSpec spec = parseTestSpec( "*a*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
}
|
||||
SECTION( "Wildcard at both ends, redundant at start" ) {
|
||||
TestSpec spec = parseTestSpec( "*longer*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "Just wildcard" ) {
|
||||
TestSpec spec = parseTestSpec( "*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
|
||||
SECTION( "Single tag" ) {
|
||||
TestSpec spec = parseTestSpec( "[one]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
}
|
||||
SECTION( "Single tag, two matches" ) {
|
||||
TestSpec spec = parseTestSpec( "[x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
}
|
||||
SECTION( "Two tags" ) {
|
||||
TestSpec spec = parseTestSpec( "[two][x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
}
|
||||
SECTION( "Two tags, spare separated" ) {
|
||||
TestSpec spec = parseTestSpec( "[two] [x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
}
|
||||
SECTION( "Wildcarded name and tag" ) {
|
||||
TestSpec spec = parseTestSpec( "*name*[x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "Single tag exclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~[one]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
}
|
||||
SECTION( "One tag exclusion and one tag inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~[two][x]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
}
|
||||
SECTION( "One tag exclusion and one wldcarded name inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~[two]*name*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "One tag exclusion, using exclude:, and one wldcarded name inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "exclude:[two]*name*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "name exclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~b" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "wildcarded name exclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~*name*" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "wildcarded name exclusion with tag inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "~*name*,[three]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "wildcarded name exclusion, using exclude:, with tag inclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "exclude:*name*,[three]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == true );
|
||||
CHECK( spec.matches( *tcB ) == true );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "two wildcarded names" ) {
|
||||
TestSpec spec = parseTestSpec( "\"longer*\"\"*spaces\"" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == true );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "empty tag" ) {
|
||||
TestSpec spec = parseTestSpec( "[]" );
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "empty quoted name" ) {
|
||||
TestSpec spec = parseTestSpec( "\"\"" );
|
||||
CHECK( spec.hasFilters() == false );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == false );
|
||||
}
|
||||
SECTION( "quoted string followed by tag exclusion" ) {
|
||||
TestSpec spec = parseTestSpec( "\"*name*\"~[.]" );
|
||||
CHECK( spec.hasFilters() == true );
|
||||
CHECK( spec.matches( *tcA ) == false );
|
||||
CHECK( spec.matches( *tcB ) == false );
|
||||
CHECK( spec.matches( *tcC ) == false );
|
||||
CHECK( spec.matches( *tcD ) == true );
|
||||
}
|
||||
SECTION( "Leading and trailing spaces in test spec" ) {
|
||||
TestSpec spec = parseTestSpec( "\" aardvark \"" );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark" ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( "aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( "aardvark" ) ) );
|
||||
|
||||
}
|
||||
SECTION( "Leading and trailing spaces in test name" ) {
|
||||
TestSpec spec = parseTestSpec( "aardvark" );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark" ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( "aardvark " ) ) );
|
||||
CHECK( spec.matches( *fakeTestCase( "aardvark" ) ) );
|
||||
}
|
||||
SECTION("Shortened hide tags are split apart when parsing") {
|
||||
TestSpec spec = parseTestSpec("[.foo]");
|
||||
CHECK(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")));
|
||||
CHECK_FALSE(spec.matches(*fakeTestCase("only foo", "[foo]")));
|
||||
}
|
||||
SECTION("Shortened hide tags also properly handle exclusion") {
|
||||
TestSpec spec = parseTestSpec("~[.foo]");
|
||||
CHECK_FALSE(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")));
|
||||
CHECK_FALSE(spec.matches(*fakeTestCase("only foo", "[foo]")));
|
||||
CHECK_FALSE(spec.matches(*fakeTestCase("only hidden", "[.]")));
|
||||
CHECK(spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("#1905 -- test spec parser properly clears internal state between compound tests", "[command-line][test-spec]") {
|
||||
using Catch::parseTestSpec;
|
||||
using Catch::TestSpec;
|
||||
// We ask for one of 2 different tests and the latter one of them has a , in name that needs escaping
|
||||
TestSpec spec = parseTestSpec(R"("spec . char","spec \, char")");
|
||||
|
||||
REQUIRE(spec.matches(*fakeTestCase("spec . char")));
|
||||
REQUIRE(spec.matches(*fakeTestCase("spec , char")));
|
||||
REQUIRE_FALSE(spec.matches(*fakeTestCase(R"(spec \, char)")));
|
||||
}
|
||||
|
||||
TEST_CASE("#1912 -- test spec parser handles escaping", "[command-line][test-spec]") {
|
||||
using Catch::parseTestSpec;
|
||||
using Catch::TestSpec;
|
||||
|
||||
SECTION("Various parentheses") {
|
||||
TestSpec spec = parseTestSpec(R"(spec {a} char,spec \[a] char)");
|
||||
|
||||
REQUIRE(spec.matches(*fakeTestCase(R"(spec {a} char)")));
|
||||
REQUIRE(spec.matches(*fakeTestCase(R"(spec [a] char)")));
|
||||
REQUIRE_FALSE(spec.matches(*fakeTestCase("differs but has similar tag", "[a]")));
|
||||
}
|
||||
SECTION("backslash in test name") {
|
||||
TestSpec spec = parseTestSpec(R"(spec \\ char)");
|
||||
|
||||
REQUIRE(spec.matches(*fakeTestCase(R"(spec \ char)")));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test spec serialization is round-trippable", "[test-spec][serialization][approvals]") {
|
||||
using Catch::parseTestSpec;
|
||||
using Catch::TestSpec;
|
||||
|
||||
auto serializedTestSpec = []( std::string const& spec ) {
|
||||
Catch::ReusableStringStream sstr;
|
||||
sstr << parseTestSpec( spec );
|
||||
return sstr.str();
|
||||
};
|
||||
|
||||
SECTION("Spaces are normalized") {
|
||||
CHECK( serializedTestSpec( "[abc][def]" ) == "[abc] [def]" );
|
||||
CHECK( serializedTestSpec( "[def] [abc]" ) == "[def] [abc]" );
|
||||
CHECK( serializedTestSpec( "[def] [abc]" ) == "[def] [abc]" );
|
||||
}
|
||||
SECTION("Output is order dependent") {
|
||||
CHECK( serializedTestSpec( "[abc][def]" ) == "[abc] [def]" );
|
||||
CHECK( serializedTestSpec( "[def][abc]" ) == "[def] [abc]" );
|
||||
}
|
||||
SECTION("Multiple disjunct filters") {
|
||||
CHECK( serializedTestSpec( "[abc],[def]" ) == "[abc],[def]" );
|
||||
CHECK( serializedTestSpec( "[def],[abc],[idkfa]" ) == "[def],[abc],[idkfa]" );
|
||||
}
|
||||
SECTION("Test names are enclosed in string") {
|
||||
CHECK( serializedTestSpec( "Some test" ) == "\"Some test\"" );
|
||||
CHECK( serializedTestSpec( "*Some test" ) == "\"*Some test\"" );
|
||||
CHECK( serializedTestSpec( "* Some test" ) == "\"* Some test\"" );
|
||||
CHECK( serializedTestSpec( "* Some test *" ) == "\"* Some test *\"" );
|
||||
}
|
||||
SECTION( "Mixing test names and tags" ) {
|
||||
CHECK( serializedTestSpec( "some test[abcd]" ) ==
|
||||
"\"some test\" [abcd]" );
|
||||
CHECK( serializedTestSpec( "[ab]some test[cd]" ) ==
|
||||
"[ab] \"some test\" [cd]" );
|
||||
}
|
||||
}
|
||||
Vendored
+55
@@ -0,0 +1,55 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
|
||||
namespace {
|
||||
static constexpr Catch::SourceLineInfo dummySourceLineInfo = CATCH_INTERNAL_LINEINFO;
|
||||
|
||||
static Catch::TestSpec parseAndCreateSpec(std::string const& str) {
|
||||
Catch::TagAliasRegistry registry;
|
||||
Catch::TestSpecParser parser( registry );
|
||||
|
||||
parser.parse( str );
|
||||
auto spec = parser.testSpec();
|
||||
REQUIRE( spec.hasFilters() );
|
||||
REQUIRE( spec.getInvalidSpecs().empty());
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE( "Parsing tags with non-alphabetical characters is pass-through",
|
||||
"[test-spec][test-spec-parser]" ) {
|
||||
auto const& tagString = GENERATE( as<std::string>{},
|
||||
"[tag with spaces]",
|
||||
"[I said \"good day\" sir!]" );
|
||||
CAPTURE(tagString);
|
||||
|
||||
auto spec = parseAndCreateSpec( tagString );
|
||||
|
||||
Catch::TestCaseInfo testCase(
|
||||
"", { "fake test name", tagString }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( spec.matches( testCase ) );
|
||||
}
|
||||
|
||||
TEST_CASE("Parsed tags are matched case insensitive",
|
||||
"[test-spec][test-spec-parser]") {
|
||||
auto spec = parseAndCreateSpec( "[CASED tag]" );
|
||||
|
||||
Catch::TestCaseInfo testCase(
|
||||
"", { "fake test name", "[cased TAG]" }, dummySourceLineInfo );
|
||||
|
||||
REQUIRE( spec.matches( testCase ) );
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_textflow.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using Catch::TextFlow::Column;
|
||||
|
||||
namespace {
|
||||
static std::string as_written(Column const& c) {
|
||||
std::stringstream sstr;
|
||||
sstr << c;
|
||||
return sstr.str();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column one simple line",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col( "simple short line" );
|
||||
|
||||
REQUIRE(as_written(col) == "simple short line");
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column respects already present newlines",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col( "abc\ndef" );
|
||||
REQUIRE( as_written( col ) == "abc\ndef" );
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column respects width setting",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col( "The quick brown fox jumped over the lazy dog" );
|
||||
|
||||
SECTION( "width=20" ) {
|
||||
col.width( 20 );
|
||||
REQUIRE( as_written( col ) == "The quick brown fox\n"
|
||||
"jumped over the lazy\n"
|
||||
"dog" );
|
||||
}
|
||||
SECTION("width=10") {
|
||||
col.width( 10 );
|
||||
REQUIRE( as_written( col ) == "The quick\n"
|
||||
"brown fox\n"
|
||||
"jumped\n"
|
||||
"over the\n"
|
||||
"lazy dog" );
|
||||
}
|
||||
SECTION("width=5") {
|
||||
// This is so small some words will have to be split with hyphen
|
||||
col.width(5);
|
||||
REQUIRE( as_written( col ) == "The\n"
|
||||
"quick\n"
|
||||
"brown\n"
|
||||
"fox\n"
|
||||
"jump-\n"
|
||||
"ed\n"
|
||||
"over\n"
|
||||
"the\n"
|
||||
"lazy\n"
|
||||
"dog" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column respects indentation setting",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col( "First line\nSecond line\nThird line" );
|
||||
|
||||
SECTION("Default: no indentation at all") {
|
||||
REQUIRE(as_written(col) == "First line\nSecond line\nThird line");
|
||||
}
|
||||
SECTION("Indentation on first line only") {
|
||||
col.initialIndent(3);
|
||||
REQUIRE(as_written(col) == " First line\nSecond line\nThird line");
|
||||
}
|
||||
SECTION("Indentation on all lines") {
|
||||
col.indent(3);
|
||||
REQUIRE(as_written(col) == " First line\n Second line\n Third line");
|
||||
}
|
||||
SECTION("Indentation on later lines only") {
|
||||
col.indent(5).initialIndent(0);
|
||||
REQUIRE(as_written(col) == "First line\n Second line\n Third line");
|
||||
}
|
||||
SECTION("Different indentation on first and later lines") {
|
||||
col.initialIndent(1).indent(2);
|
||||
REQUIRE(as_written(col) == " First line\n Second line\n Third line");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("TextFlow::Column indentation respects whitespace", "[TextFlow][column][approvals]") {
|
||||
Column col(" text with whitespace\n after newlines");
|
||||
|
||||
SECTION("No extra indentation") {
|
||||
col.initialIndent(0).indent(0);
|
||||
REQUIRE(as_written(col) == " text with whitespace\n after newlines");
|
||||
}
|
||||
SECTION("Different indentation on first and later lines") {
|
||||
col.initialIndent(1).indent(2);
|
||||
REQUIRE(as_written(col) == " text with whitespace\n after newlines");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column linebreaking prefers boundary characters",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
SECTION("parentheses") {
|
||||
Column col("(Hello)aaa(World)");
|
||||
SECTION("width=20") {
|
||||
col.width(20);
|
||||
REQUIRE(as_written(col) == "(Hello)aaa(World)");
|
||||
}
|
||||
SECTION("width=15") {
|
||||
col.width(15);
|
||||
REQUIRE(as_written(col) == "(Hello)aaa\n(World)");
|
||||
}
|
||||
SECTION("width=8") {
|
||||
col.width(8);
|
||||
REQUIRE(as_written(col) == "(Hello)\naaa\n(World)");
|
||||
}
|
||||
}
|
||||
SECTION("commas") {
|
||||
Column col("Hello, world");
|
||||
col.width(8);
|
||||
|
||||
REQUIRE(as_written(col) == "Hello,\nworld");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "TextFlow::Column respects indentation for empty lines",
|
||||
"[TextFlow][column][approvals][!shouldfail]" ) {
|
||||
// This is currently bugged and does not do what it should
|
||||
Column col("\n\nthird line");
|
||||
col.indent(2);
|
||||
|
||||
//auto b = col.begin();
|
||||
//auto e = col.end();
|
||||
|
||||
//auto b1 = *b;
|
||||
//++b;
|
||||
//auto b2 = *b;
|
||||
//++b;
|
||||
//auto b3 = *b;
|
||||
//++b;
|
||||
|
||||
//REQUIRE(b == e);
|
||||
|
||||
std::string written = as_written(col);
|
||||
|
||||
REQUIRE(as_written(col) == " \n \n third line");
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column leading/trailing whitespace",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
SECTION("Trailing whitespace") {
|
||||
Column col("some trailing whitespace: \t");
|
||||
REQUIRE(as_written(col) == "some trailing whitespace: \t");
|
||||
}
|
||||
SECTION("Some leading whitespace") {
|
||||
Column col("\t \t whitespace wooo");
|
||||
REQUIRE(as_written(col) == "\t \t whitespace wooo");
|
||||
}
|
||||
SECTION("both") {
|
||||
Column col(" abc ");
|
||||
REQUIRE(as_written(col) == " abc ");
|
||||
}
|
||||
SECTION("whitespace only") {
|
||||
Column col("\t \t");
|
||||
REQUIRE(as_written(col) == "\t \t");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column can handle empty string",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
Column col("");
|
||||
REQUIRE(as_written(col) == "");
|
||||
}
|
||||
|
||||
TEST_CASE( "#1400 - TextFlow::Column wrapping would sometimes duplicate words",
|
||||
"[TextFlow][column][regression][approvals]" ) {
|
||||
const auto long_string = std::string(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nisl \n"
|
||||
"massa, luctus ut ligula vitae, suscipit tempus velit. Vivamus sodales, quam in \n"
|
||||
"convallis posuere, libero nisi ultricies orci, nec lobortis.\n");
|
||||
|
||||
auto col = Column(long_string)
|
||||
.width(79)
|
||||
.indent(2);
|
||||
|
||||
REQUIRE(as_written(col) ==
|
||||
" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nisl \n"
|
||||
" massa, luctus ut ligula vitae, suscipit tempus velit. Vivamus sodales, quam\n"
|
||||
" in \n"
|
||||
" convallis posuere, libero nisi ultricies orci, nec lobortis.");
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
|
||||
// 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/internal/catch_enum_values_registry.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
|
||||
enum class EnumClass3 { Value1, Value2, Value3, Value4 };
|
||||
|
||||
struct UsesSentinel {
|
||||
using const_iterator = int const*;
|
||||
using const_sentinel = std::nullptr_t;
|
||||
|
||||
const_iterator begin() const { return nullptr; }
|
||||
const_iterator end() const { return nullptr; }
|
||||
};
|
||||
|
||||
TEST_CASE( "parseEnums", "[Strings][enums]" ) {
|
||||
using namespace Catch::Matchers;
|
||||
using Catch::Detail::parseEnums;
|
||||
|
||||
SECTION( "No enums" )
|
||||
CHECK_THAT( parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) );
|
||||
|
||||
SECTION( "One enum value" ) {
|
||||
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1" ),
|
||||
Equals(std::vector<Catch::StringRef>{"Value1"} ) );
|
||||
CHECK_THAT( parseEnums( "Value1" ),
|
||||
Equals( std::vector<Catch::StringRef>{"Value1"} ) );
|
||||
CHECK_THAT( parseEnums( "EnumName::Value1" ),
|
||||
Equals(std::vector<Catch::StringRef>{"Value1"} ) );
|
||||
}
|
||||
|
||||
SECTION( "Multiple enum values" ) {
|
||||
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ),
|
||||
Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) );
|
||||
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ),
|
||||
Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) );
|
||||
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ),
|
||||
Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Directly creating an EnumInfo" ) {
|
||||
|
||||
using namespace Catch::Detail;
|
||||
auto enumInfo = makeEnumInfo( "EnumName", "EnumName::Value1, EnumName::Value2", {0, 1} );
|
||||
|
||||
CHECK( enumInfo->lookup(0) == "Value1" );
|
||||
CHECK( enumInfo->lookup(1) == "Value2" );
|
||||
CHECK( enumInfo->lookup(3) == "{** unexpected enum value **}" );
|
||||
}
|
||||
|
||||
TEST_CASE("Range type with sentinel") {
|
||||
CHECK( Catch::Detail::stringify(UsesSentinel{}) == "{ }" );
|
||||
}
|
||||
|
||||
TEST_CASE("convertIntoString stringification helper", "[toString][approvals]") {
|
||||
using namespace std::string_literals;
|
||||
using Catch::Detail::convertIntoString;
|
||||
using namespace Catch;
|
||||
|
||||
SECTION("No escaping") {
|
||||
CHECK(convertIntoString(""_sr, false) == R"("")"s);
|
||||
CHECK(convertIntoString("abcd"_sr, false) == R"("abcd")"s);
|
||||
CHECK(convertIntoString("ab\ncd"_sr, false) == "\"ab\ncd\""s);
|
||||
CHECK(convertIntoString("ab\r\ncd"_sr, false) == "\"ab\r\ncd\""s);
|
||||
CHECK(convertIntoString("ab\"cd"_sr, false) == R"("ab"cd")"s);
|
||||
}
|
||||
SECTION("Escaping invisibles") {
|
||||
CHECK(convertIntoString(""_sr, true) == R"("")"s);
|
||||
CHECK(convertIntoString("ab\ncd"_sr, true) == R"("ab\ncd")"s);
|
||||
CHECK(convertIntoString("ab\r\ncd"_sr, true) == R"("ab\r\ncd")"s);
|
||||
CHECK(convertIntoString("ab\tcd"_sr, true) == R"("ab\tcd")"s);
|
||||
CHECK(convertIntoString("ab\fcd"_sr, true) == R"("ab\fcd")"s);
|
||||
CHECK(convertIntoString("ab\"cd"_sr, true) == R"("ab"cd")"s);
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE( "Stringifying char arrays with statically known sizes",
|
||||
"[toString]",
|
||||
char,
|
||||
signed char,
|
||||
unsigned char ) {
|
||||
using namespace std::string_literals;
|
||||
TestType with_null_terminator[10] = "abc";
|
||||
CHECK( ::Catch::Detail::stringify( with_null_terminator ) == R"("abc")"s );
|
||||
|
||||
TestType no_null_terminator[3] = { 'a', 'b', 'c' };
|
||||
CHECK( ::Catch::Detail::stringify( no_null_terminator ) == R"("abc")"s );
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_compare_traits.hpp>
|
||||
#include <helpers/type_with_lit_0_comparisons.hpp>
|
||||
|
||||
|
||||
#define ADD_TRAIT_TEST_CASE( op ) \
|
||||
TEST_CASE( "is_" #op "_comparable", \
|
||||
"[traits][is_comparable][approvals]" ) { \
|
||||
using Catch::Detail::is_##op##_0_comparable; \
|
||||
using Catch::Detail::is_##op##_comparable; \
|
||||
\
|
||||
STATIC_REQUIRE( is_##op##_comparable<int, int>::value ); \
|
||||
STATIC_REQUIRE( \
|
||||
is_##op##_comparable<std::string, std::string>::value ); \
|
||||
STATIC_REQUIRE( !is_##op##_comparable<int, std::string>::value ); \
|
||||
STATIC_REQUIRE( \
|
||||
!is_##op##_comparable<TypeWithLit0Comparisons, int>::value ); \
|
||||
STATIC_REQUIRE( \
|
||||
!is_##op##_comparable<int, TypeWithLit0Comparisons>::value ); \
|
||||
\
|
||||
STATIC_REQUIRE( is_##op##_0_comparable<int>::value ); \
|
||||
STATIC_REQUIRE( \
|
||||
is_##op##_0_comparable<TypeWithLit0Comparisons>::value ); \
|
||||
STATIC_REQUIRE( !is_##op##_0_comparable<std::string>::value ); \
|
||||
\
|
||||
/* This test fails with MSVC in permissive mode, because of course it does */ \
|
||||
/* STATIC_REQUIRE( !is_##op##_0_comparable<int*>::value ); */ \
|
||||
}
|
||||
|
||||
ADD_TRAIT_TEST_CASE(lt)
|
||||
ADD_TRAIT_TEST_CASE(gt)
|
||||
ADD_TRAIT_TEST_CASE(le)
|
||||
ADD_TRAIT_TEST_CASE(ge)
|
||||
ADD_TRAIT_TEST_CASE(eq)
|
||||
ADD_TRAIT_TEST_CASE(ne)
|
||||
|
||||
#undef ADD_TRAIT_TEST_CASE
|
||||
Vendored
+141
@@ -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_macros.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace {
|
||||
struct unique_ptr_test_helper {
|
||||
bool dummy = false;
|
||||
};
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("unique_ptr reimplementation: basic functionality", "[internals][unique-ptr]") {
|
||||
using Catch::Detail::unique_ptr;
|
||||
SECTION("Default constructed unique_ptr is empty") {
|
||||
unique_ptr<int> ptr;
|
||||
REQUIRE_FALSE(ptr);
|
||||
REQUIRE(ptr.get() == nullptr);
|
||||
}
|
||||
SECTION("Take ownership of allocation") {
|
||||
auto naked_ptr = new int{ 0 };
|
||||
unique_ptr<int> ptr(naked_ptr);
|
||||
REQUIRE(ptr);
|
||||
REQUIRE(*ptr == 0);
|
||||
REQUIRE(ptr.get() == naked_ptr);
|
||||
SECTION("Plain reset deallocates") {
|
||||
ptr.reset(); // this makes naked_ptr dangling!
|
||||
REQUIRE_FALSE(ptr);
|
||||
REQUIRE(ptr.get() == nullptr);
|
||||
}
|
||||
SECTION("Reset replaces ownership") {
|
||||
ptr.reset(new int{ 2 });
|
||||
REQUIRE(ptr);
|
||||
REQUIRE(ptr.get() != nullptr);
|
||||
REQUIRE(*ptr == 2);
|
||||
}
|
||||
}
|
||||
SECTION("Release releases ownership") {
|
||||
auto naked_ptr = new int{ 1 };
|
||||
unique_ptr<int> ptr(naked_ptr);
|
||||
ptr.release();
|
||||
CHECK_FALSE(ptr);
|
||||
CHECK(ptr.get() == nullptr);
|
||||
delete naked_ptr;
|
||||
}
|
||||
SECTION("Move constructor") {
|
||||
unique_ptr<int> ptr1(new int{ 1 });
|
||||
auto ptr2(std::move(ptr1));
|
||||
REQUIRE_FALSE(ptr1);
|
||||
REQUIRE(ptr2);
|
||||
REQUIRE(*ptr2 == 1);
|
||||
}
|
||||
SECTION("Move assignment") {
|
||||
unique_ptr<int> ptr1(new int{ 1 }), ptr2(new int{ 2 });
|
||||
ptr1 = std::move(ptr2);
|
||||
REQUIRE_FALSE(ptr2);
|
||||
REQUIRE(ptr1);
|
||||
REQUIRE(*ptr1 == 2);
|
||||
}
|
||||
SECTION("free swap") {
|
||||
unique_ptr<int> ptr1(new int{ 1 }), ptr2(new int{ 2 });
|
||||
swap(ptr1, ptr2);
|
||||
REQUIRE(*ptr1 == 2);
|
||||
REQUIRE(*ptr2 == 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
struct base {
|
||||
int i;
|
||||
base(int i_) :i(i_) {}
|
||||
};
|
||||
struct derived : base { using base::base; };
|
||||
struct unrelated {};
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
static_assert( std::is_constructible<Catch::Detail::unique_ptr<base>,
|
||||
Catch::Detail::unique_ptr<derived>>::value, "Upcasting is supported");
|
||||
static_assert(!std::is_constructible<Catch::Detail::unique_ptr<derived>,
|
||||
Catch::Detail::unique_ptr<base>>::value, "Downcasting is not supported");
|
||||
static_assert(!std::is_constructible<Catch::Detail::unique_ptr<base>,
|
||||
Catch::Detail::unique_ptr<unrelated>>::value, "Cannot just convert one ptr type to another");
|
||||
|
||||
TEST_CASE("Upcasting special member functions", "[internals][unique-ptr]") {
|
||||
using Catch::Detail::unique_ptr;
|
||||
|
||||
unique_ptr<derived> dptr(new derived{3});
|
||||
SECTION("Move constructor") {
|
||||
unique_ptr<base> bptr(std::move(dptr));
|
||||
REQUIRE(bptr->i == 3);
|
||||
}
|
||||
SECTION("move assignment") {
|
||||
unique_ptr<base> bptr(new base{ 1 });
|
||||
bptr = std::move(dptr);
|
||||
REQUIRE(bptr->i == 3);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct move_detector {
|
||||
bool has_moved = false;
|
||||
move_detector() = default;
|
||||
move_detector(move_detector const& rhs) = default;
|
||||
move_detector& operator=(move_detector const& rhs) = default;
|
||||
|
||||
move_detector(move_detector&& rhs) noexcept {
|
||||
rhs.has_moved = true;
|
||||
}
|
||||
move_detector& operator=(move_detector&& rhs) noexcept {
|
||||
rhs.has_moved = true;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("make_unique reimplementation", "[internals][unique-ptr]") {
|
||||
using Catch::Detail::make_unique;
|
||||
SECTION("From lvalue copies") {
|
||||
move_detector lval;
|
||||
auto ptr = make_unique<move_detector>(lval);
|
||||
REQUIRE_FALSE(lval.has_moved);
|
||||
}
|
||||
SECTION("From rvalue moves") {
|
||||
move_detector rval;
|
||||
auto ptr = make_unique<move_detector>(std::move(rval));
|
||||
REQUIRE(rval.has_moved);
|
||||
}
|
||||
SECTION("Variadic constructor") {
|
||||
auto ptr = make_unique<std::tuple<int, double, int>>(1, 2., 3);
|
||||
REQUIRE(*ptr == std::tuple<int, double, int>{1, 2., 3});
|
||||
}
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_xmlwriter.hpp>
|
||||
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
static std::string encode( std::string const& str, Catch::XmlEncode::ForWhat forWhat = Catch::XmlEncode::ForTextNodes ) {
|
||||
Catch::ReusableStringStream oss;
|
||||
oss << Catch::XmlEncode( str, forWhat );
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
TEST_CASE( "XmlEncode", "[XML]" ) {
|
||||
SECTION( "normal string" ) {
|
||||
REQUIRE( encode( "normal string" ) == "normal string" );
|
||||
}
|
||||
SECTION( "empty string" ) {
|
||||
REQUIRE( encode( "" ) == "" );
|
||||
}
|
||||
SECTION( "string with ampersand" ) {
|
||||
REQUIRE( encode( "smith & jones" ) == "smith & jones" );
|
||||
}
|
||||
SECTION( "string with less-than" ) {
|
||||
REQUIRE( encode( "smith < jones" ) == "smith < jones" );
|
||||
}
|
||||
SECTION( "string with greater-than" ) {
|
||||
REQUIRE( encode( "smith > jones" ) == "smith > jones" );
|
||||
REQUIRE( encode( "smith ]]> jones" ) == "smith ]]> jones" );
|
||||
}
|
||||
SECTION( "string with quotes" ) {
|
||||
std::string stringWithQuotes = "don't \"quote\" me on that";
|
||||
REQUIRE( encode( stringWithQuotes ) == stringWithQuotes );
|
||||
REQUIRE( encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't "quote" me on that" );
|
||||
}
|
||||
SECTION( "string with control char (1)" ) {
|
||||
REQUIRE( encode( "[\x01]" ) == "[\\x01]" );
|
||||
}
|
||||
SECTION( "string with control char (x7F)" ) {
|
||||
REQUIRE( encode( "[\x7F]" ) == "[\\x7F]" );
|
||||
}
|
||||
}
|
||||
|
||||
// Thanks to Peter Bindels (dascandy) for some of the tests
|
||||
TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8][approvals]") {
|
||||
SECTION("Valid utf-8 strings") {
|
||||
CHECK(encode("Here be 👾") == "Here be 👾");
|
||||
CHECK(encode("šš") == "šš");
|
||||
|
||||
CHECK(encode("\xDF\xBF") == "\xDF\xBF"); // 0x7FF
|
||||
CHECK(encode("\xE0\xA0\x80") == "\xE0\xA0\x80"); // 0x800
|
||||
CHECK(encode("\xED\x9F\xBF") == "\xED\x9F\xBF"); // 0xD7FF
|
||||
CHECK(encode("\xEE\x80\x80") == "\xEE\x80\x80"); // 0xE000
|
||||
CHECK(encode("\xEF\xBF\xBF") == "\xEF\xBF\xBF"); // 0xFFFF
|
||||
CHECK(encode("\xF0\x90\x80\x80") == "\xF0\x90\x80\x80"); // 0x10000
|
||||
CHECK(encode("\xF4\x8F\xBF\xBF") == "\xF4\x8F\xBF\xBF"); // 0x10FFFF
|
||||
}
|
||||
SECTION("Invalid utf-8 strings") {
|
||||
SECTION("Various broken strings") {
|
||||
CHECK(encode("Here \xFF be \xF0\x9F\x91\xBE") == "Here \\xFF be 👾");
|
||||
CHECK(encode("\xFF") == "\\xFF");
|
||||
CHECK(encode("\xC5\xC5\xA0") == "\\xC5Š");
|
||||
CHECK(encode("\xF4\x90\x80\x80") == "\\xF4\\x90\\x80\\x80"); // 0x110000 -- out of unicode range
|
||||
}
|
||||
|
||||
SECTION("Overlong encodings") {
|
||||
CHECK(encode("\xC0\x80") == "\\xC0\\x80"); // \0
|
||||
CHECK(encode("\xF0\x80\x80\x80") == "\\xF0\\x80\\x80\\x80"); // Super-over-long \0
|
||||
CHECK(encode("\xC1\xBF") == "\\xC1\\xBF"); // ASCII char as UTF-8 (0x7F)
|
||||
CHECK(encode("\xE0\x9F\xBF") == "\\xE0\\x9F\\xBF"); // 0x7FF
|
||||
CHECK(encode("\xF0\x8F\xBF\xBF") == "\\xF0\\x8F\\xBF\\xBF"); // 0xFFFF
|
||||
}
|
||||
|
||||
// Note that we actually don't modify surrogate pairs, as we do not do strict checking
|
||||
SECTION("Surrogate pairs") {
|
||||
CHECK(encode("\xED\xA0\x80") == "\xED\xA0\x80"); // Invalid surrogate half 0xD800
|
||||
CHECK(encode("\xED\xAF\xBF") == "\xED\xAF\xBF"); // Invalid surrogate half 0xDBFF
|
||||
CHECK(encode("\xED\xB0\x80") == "\xED\xB0\x80"); // Invalid surrogate half 0xDC00
|
||||
CHECK(encode("\xED\xBF\xBF") == "\xED\xBF\xBF"); // Invalid surrogate half 0xDFFF
|
||||
}
|
||||
|
||||
SECTION("Invalid start byte") {
|
||||
CHECK(encode("\x80") == "\\x80");
|
||||
CHECK(encode("\x81") == "\\x81");
|
||||
CHECK(encode("\xBC") == "\\xBC");
|
||||
CHECK(encode("\xBF") == "\\xBF");
|
||||
// Out of range
|
||||
CHECK(encode("\xF5\x80\x80\x80") == "\\xF5\\x80\\x80\\x80");
|
||||
CHECK(encode("\xF6\x80\x80\x80") == "\\xF6\\x80\\x80\\x80");
|
||||
CHECK(encode("\xF7\x80\x80\x80") == "\\xF7\\x80\\x80\\x80");
|
||||
}
|
||||
|
||||
SECTION("Missing continuation byte(s)") {
|
||||
// Missing first continuation byte
|
||||
CHECK(encode("\xDE") == "\\xDE");
|
||||
CHECK(encode("\xDF") == "\\xDF");
|
||||
CHECK(encode("\xE0") == "\\xE0");
|
||||
CHECK(encode("\xEF") == "\\xEF");
|
||||
CHECK(encode("\xF0") == "\\xF0");
|
||||
CHECK(encode("\xF4") == "\\xF4");
|
||||
|
||||
// Missing second continuation byte
|
||||
CHECK(encode("\xE0\x80") == "\\xE0\\x80");
|
||||
CHECK(encode("\xE0\xBF") == "\\xE0\\xBF");
|
||||
CHECK(encode("\xE1\x80") == "\\xE1\\x80");
|
||||
CHECK(encode("\xF0\x80") == "\\xF0\\x80");
|
||||
CHECK(encode("\xF4\x80") == "\\xF4\\x80");
|
||||
|
||||
// Missing third continuation byte
|
||||
CHECK(encode("\xF0\x80\x80") == "\\xF0\\x80\\x80");
|
||||
CHECK(encode("\xF4\x80\x80") == "\\xF4\\x80\\x80");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter writes boolean attributes as true/false", "[XML][XmlWriter]") {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
std::stringstream stream;
|
||||
{
|
||||
Catch::XmlWriter xml(stream);
|
||||
|
||||
xml.scopedElement("Element1")
|
||||
.writeAttribute("attr1", true)
|
||||
.writeAttribute("attr2", false);
|
||||
}
|
||||
|
||||
REQUIRE_THAT( stream.str(),
|
||||
ContainsSubstring(R"(attr1="true")") &&
|
||||
ContainsSubstring(R"(attr2="false")") );
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter does not escape comments", "[XML][XmlWriter][approvals]") {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
std::stringstream stream;
|
||||
{
|
||||
Catch::XmlWriter xml(stream);
|
||||
|
||||
xml.writeComment(R"(unescaped special chars: < > ' " &)");
|
||||
}
|
||||
REQUIRE_THAT( stream.str(),
|
||||
ContainsSubstring(R"(<!-- unescaped special chars: < > ' " & -->)"));
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter errors out when writing text without enclosing element", "[XmlWriter][approvals]") {
|
||||
std::stringstream stream;
|
||||
Catch::XmlWriter xml(stream);
|
||||
REQUIRE_THROWS(xml.writeText("some text"));
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter escapes text properly", "[XML][XmlWriter][approvals]") {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
std::stringstream stream;
|
||||
{
|
||||
Catch::XmlWriter xml(stream);
|
||||
xml.scopedElement("root")
|
||||
.writeText(R"(Special chars need escaping: < > ' " &)");
|
||||
}
|
||||
|
||||
REQUIRE_THAT( stream.str(),
|
||||
ContainsSubstring(R"(Special chars need escaping: < > ' " &)"));
|
||||
}
|
||||
|
||||
TEST_CASE("XmlWriter escapes attributes properly", "[XML][XmlWriter][approvals]") {
|
||||
using Catch::Matchers::ContainsSubstring;
|
||||
std::stringstream stream;
|
||||
{
|
||||
Catch::XmlWriter xml(stream);
|
||||
xml.scopedElement("root")
|
||||
.writeAttribute("some-attribute", R"(Special chars need escaping: < > ' " &)");
|
||||
}
|
||||
|
||||
REQUIRE_THAT(stream.str(),
|
||||
ContainsSubstring(R"(some-attribute="Special chars need escaping: < > ' " &")"));
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
Test with special, characters in \" name
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
random SECTION tests
|
||||
nested SECTION tests
|
||||
+1
@@ -0,0 +1 @@
|
||||
Test with special\, characters \"in name
|
||||
@@ -0,0 +1,181 @@
|
||||
|
||||
// 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/reporters/catch_reporter_event_listener.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
|
||||
|
||||
// Some example tag aliases
|
||||
CATCH_REGISTER_TAG_ALIAS("[@nhf]", "[failing]~[.]")
|
||||
CATCH_REGISTER_TAG_ALIAS("[@tricky]", "[tricky]~[.]")
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Wpadded"
|
||||
# pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
# pragma clang diagnostic ignored "-Wc++98-compat"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Event listener that internally counts and validates received events.
|
||||
*
|
||||
* Currently only performs validation by counting received events, rather
|
||||
* than performing full matching. This means that it won't fail if the *Ended
|
||||
* events are provided in wrong order, as long as they come in the right amount
|
||||
* and with the right nesting.
|
||||
*/
|
||||
class ValidatingTestListener : public Catch::EventListenerBase {
|
||||
struct EventCounter {
|
||||
int starting = 0;
|
||||
int ended = 0;
|
||||
|
||||
bool hasActiveEvent() const {
|
||||
return starting > ended;
|
||||
}
|
||||
bool hasSingleActiveEvent() const {
|
||||
return starting - 1 == ended;
|
||||
}
|
||||
bool allEventsEnded() const {
|
||||
return starting == ended;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static std::string getDescription() {
|
||||
return "Validates ordering of Catch2's listener events";
|
||||
}
|
||||
|
||||
ValidatingTestListener(Catch::IConfig const* config) :
|
||||
EventListenerBase(config) {
|
||||
m_preferences.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
void testRunStarting( Catch::TestRunInfo const& ) override {
|
||||
CATCH_ENFORCE( m_testRunCounter.starting == 0,
|
||||
"Test run can only start once" );
|
||||
++m_testRunCounter.starting;
|
||||
}
|
||||
void testCaseStarting(Catch::TestCaseInfo const&) override {
|
||||
CATCH_ENFORCE( m_testRunCounter.hasActiveEvent(),
|
||||
"Test case can only be started if the test run has already started" );
|
||||
CATCH_ENFORCE( m_testCaseCounter.allEventsEnded(),
|
||||
"Test case cannot start if there is an unfinished one" );
|
||||
|
||||
++m_testCaseCounter.starting;
|
||||
|
||||
// Reset the part tracking for partial test case events
|
||||
m_lastSeenPartNumber = uint64_t(-1);
|
||||
}
|
||||
|
||||
void testCasePartialStarting(Catch::TestCaseInfo const&,
|
||||
uint64_t partNumber) override {
|
||||
CATCH_ENFORCE( m_testCaseCounter.hasSingleActiveEvent(),
|
||||
"Test case can only be partially started if the test case has fully started already" );
|
||||
CATCH_ENFORCE( m_lastSeenPartNumber + 1 == partNumber,
|
||||
"Partial test case started out of order" );
|
||||
|
||||
++m_testCasePartialCounter.starting;
|
||||
m_lastSeenPartNumber = partNumber;
|
||||
}
|
||||
|
||||
void sectionStarting(Catch::SectionInfo const&) override {
|
||||
CATCH_ENFORCE( m_testCaseCounter.hasSingleActiveEvent(),
|
||||
"Section can only start in a test case" );
|
||||
CATCH_ENFORCE( m_testCasePartialCounter.hasSingleActiveEvent(),
|
||||
"Section can only start in a test case" );
|
||||
|
||||
++m_sectionCounter.starting;
|
||||
}
|
||||
|
||||
void assertionStarting(Catch::AssertionInfo const&) override {
|
||||
CATCH_ENFORCE( m_testCaseCounter.hasSingleActiveEvent(),
|
||||
"Assertion can only start if test case is started" );
|
||||
|
||||
++m_assertionCounter.starting;
|
||||
}
|
||||
void assertionEnded(Catch::AssertionStats const&) override {
|
||||
// todo:
|
||||
// * Check that assertions are balanced
|
||||
// * Check that assertions has started
|
||||
++m_assertionCounter.ended;
|
||||
}
|
||||
|
||||
void sectionEnded(Catch::SectionStats const&) override {
|
||||
CATCH_ENFORCE( m_sectionCounter.hasActiveEvent(),
|
||||
"Section ended without corresponding start" );
|
||||
// TODO: Check that all assertions ended
|
||||
|
||||
++m_sectionCounter.ended;
|
||||
}
|
||||
|
||||
|
||||
void testCasePartialEnded(Catch::TestCaseStats const&,
|
||||
uint64_t partNumber) override {
|
||||
CATCH_ENFORCE( m_lastSeenPartNumber == partNumber,
|
||||
"Partial test case ended out of order" );
|
||||
CATCH_ENFORCE( m_testCasePartialCounter.hasSingleActiveEvent(),
|
||||
"Partial test case ended without corresponding start" );
|
||||
CATCH_ENFORCE( m_sectionCounter.allEventsEnded(),
|
||||
"Partial test case ended with unbalanced sections" );
|
||||
// TODO: Check that all assertions ended
|
||||
|
||||
++m_testCasePartialCounter.ended;
|
||||
}
|
||||
|
||||
|
||||
void testCaseEnded(Catch::TestCaseStats const&) override {
|
||||
CATCH_ENFORCE( m_testCaseCounter.hasSingleActiveEvent(),
|
||||
"Test case end is not matched with test case start" );
|
||||
CATCH_ENFORCE( m_testCasePartialCounter.allEventsEnded(),
|
||||
"A partial test case has not ended" );
|
||||
CATCH_ENFORCE( m_sectionCounter.allEventsEnded(),
|
||||
"Test case ended with unbalanced sections" );
|
||||
|
||||
// TODO: Check that all assertions ended
|
||||
|
||||
++m_testCaseCounter.ended;
|
||||
}
|
||||
void testRunEnded( Catch::TestRunStats const& ) override {
|
||||
CATCH_ENFORCE( m_testRunCounter.hasSingleActiveEvent(),
|
||||
"Test run end is not matched with test run start" );
|
||||
CATCH_ENFORCE( m_testRunCounter.ended == 0,
|
||||
"Test run can only end once" );
|
||||
|
||||
++m_testRunCounter.ended;
|
||||
}
|
||||
|
||||
~ValidatingTestListener() override;
|
||||
|
||||
private:
|
||||
EventCounter m_testRunCounter;
|
||||
EventCounter m_testCaseCounter;
|
||||
EventCounter m_testCasePartialCounter;
|
||||
uint64_t m_lastSeenPartNumber = 0;
|
||||
EventCounter m_sectionCounter;
|
||||
EventCounter m_assertionCounter;
|
||||
};
|
||||
|
||||
|
||||
ValidatingTestListener::~ValidatingTestListener() {
|
||||
// Throwing from noexcept destructor terminates, but we don't mind
|
||||
// because this is test-only check and we don't need to try and recover
|
||||
// from assumption violation here.
|
||||
|
||||
CATCH_ENFORCE( m_testRunCounter.ended < 2,
|
||||
"Test run should be started at most once" );
|
||||
CATCH_ENFORCE( m_testRunCounter.allEventsEnded(),
|
||||
"The test run has not finished" );
|
||||
CATCH_ENFORCE( m_testCaseCounter.allEventsEnded(),
|
||||
"A test case did not finish" );
|
||||
|
||||
// TODO: other counters being balanced?
|
||||
}
|
||||
|
||||
CATCH_REGISTER_LISTENER( ValidatingTestListener )
|
||||
+24
@@ -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_test_macros.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
TEST_CASE( "sleep_for_100ms", "[.min_duration_test][approvals]" )
|
||||
{
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
|
||||
CHECK( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "sleep_for_1000ms", "[.min_duration_test][approvals]" )
|
||||
{
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 1'000 ) );
|
||||
CHECK( true );
|
||||
}
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using Catch::Approx;
|
||||
|
||||
namespace {
|
||||
static double divide(double a, double b) {
|
||||
return a / b;
|
||||
}
|
||||
|
||||
class StrongDoubleTypedef {
|
||||
double d_ = 0.0;
|
||||
|
||||
public:
|
||||
explicit StrongDoubleTypedef(double d) : d_(d) {}
|
||||
explicit operator double() const { return d_; }
|
||||
};
|
||||
|
||||
static std::ostream& operator<<(std::ostream& os, StrongDoubleTypedef td) {
|
||||
return os << "StrongDoubleTypedef(" << static_cast<double>(td) << ")";
|
||||
}
|
||||
} // end unnamed namespace
|
||||
|
||||
using namespace Catch::literals;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "A comparison that uses literals instead of the normal constructor", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d == 1.23_a );
|
||||
REQUIRE( d != 1.22_a );
|
||||
REQUIRE( -d == -1.23_a );
|
||||
|
||||
REQUIRE( d == 1.2_a .epsilon(.1) );
|
||||
REQUIRE( d != 1.2_a .epsilon(.001) );
|
||||
REQUIRE( d == 1_a .epsilon(.3) );
|
||||
}
|
||||
|
||||
TEST_CASE( "Some simple comparisons between doubles", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d == Approx( 1.23 ) );
|
||||
REQUIRE( d != Approx( 1.22 ) );
|
||||
REQUIRE( d != Approx( 1.24 ) );
|
||||
|
||||
REQUIRE( d == 1.23_a );
|
||||
REQUIRE( d != 1.22_a );
|
||||
|
||||
REQUIRE( Approx( d ) == 1.23 );
|
||||
REQUIRE( Approx( d ) != 1.22 );
|
||||
REQUIRE( Approx( d ) != 1.24 );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Approximate comparisons with different epsilons", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d != Approx( 1.231 ) );
|
||||
REQUIRE( d == Approx( 1.231 ).epsilon( 0.1 ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Less-than inequalities with different epsilons", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d <= Approx( 1.24 ) );
|
||||
REQUIRE( d <= Approx( 1.23 ) );
|
||||
REQUIRE_FALSE( d <= Approx( 1.22 ) );
|
||||
REQUIRE( d <= Approx( 1.22 ).epsilon(0.1) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Greater-than inequalities with different epsilons", "[Approx]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
REQUIRE( d >= Approx( 1.22 ) );
|
||||
REQUIRE( d >= Approx( 1.23 ) );
|
||||
REQUIRE_FALSE( d >= Approx( 1.24 ) );
|
||||
REQUIRE( d >= Approx( 1.24 ).epsilon(0.1) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Approximate comparisons with floats", "[Approx]" ) {
|
||||
REQUIRE( 1.23f == Approx( 1.23f ) );
|
||||
REQUIRE( 0.0f == Approx( 0.0f ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Approximate comparisons with ints", "[Approx]" ) {
|
||||
REQUIRE( 1 == Approx( 1 ) );
|
||||
REQUIRE( 0 == Approx( 0 ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Approximate comparisons with mixed numeric types", "[Approx]" ) {
|
||||
const double dZero = 0;
|
||||
const double dSmall = 0.00001;
|
||||
const double dMedium = 1.234;
|
||||
|
||||
REQUIRE( 1.0f == Approx( 1 ) );
|
||||
REQUIRE( 0 == Approx( dZero) );
|
||||
REQUIRE( 0 == Approx( dSmall ).margin( 0.001 ) );
|
||||
REQUIRE( 1.234f == Approx( dMedium ) );
|
||||
REQUIRE( dMedium == Approx( 1.234f ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE( "Use a custom approx", "[Approx][custom]" ) {
|
||||
double d = 1.23;
|
||||
|
||||
Approx approx = Approx::custom().epsilon( 0.01 );
|
||||
|
||||
REQUIRE( d == approx( 1.23 ) );
|
||||
REQUIRE( d == approx( 1.22 ) );
|
||||
REQUIRE( d == approx( 1.24 ) );
|
||||
REQUIRE( d != approx( 1.25 ) );
|
||||
|
||||
REQUIRE( approx( d ) == 1.23 );
|
||||
REQUIRE( approx( d ) == 1.22 );
|
||||
REQUIRE( approx( d ) == 1.24 );
|
||||
REQUIRE( approx( d ) != 1.25 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Approximate PI", "[Approx][PI]" ) {
|
||||
REQUIRE( divide( 22, 7 ) == Approx( 3.141 ).epsilon( 0.001 ) );
|
||||
REQUIRE( divide( 22, 7 ) != Approx( 3.141 ).epsilon( 0.0001 ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST_CASE( "Absolute margin", "[Approx]" ) {
|
||||
REQUIRE( 104.0 != Approx(100.0) );
|
||||
REQUIRE( 104.0 == Approx(100.0).margin(5) );
|
||||
REQUIRE( 104.0 == Approx(100.0).margin(4) );
|
||||
REQUIRE( 104.0 != Approx(100.0).margin(3) );
|
||||
REQUIRE( 100.3 != Approx(100.0) );
|
||||
REQUIRE( 100.3 == Approx(100.0).margin(0.5) );
|
||||
}
|
||||
|
||||
TEST_CASE("Approx with exactly-representable margin", "[Approx]") {
|
||||
CHECK( 0.25f == Approx(0.0f).margin(0.25f) );
|
||||
|
||||
CHECK( 0.0f == Approx(0.25f).margin(0.25f) );
|
||||
CHECK( 0.5f == Approx(0.25f).margin(0.25f) );
|
||||
|
||||
CHECK( 245.0f == Approx(245.25f).margin(0.25f) );
|
||||
CHECK( 245.5f == Approx(245.25f).margin(0.25f) );
|
||||
}
|
||||
|
||||
TEST_CASE("Approx setters validate their arguments", "[Approx]") {
|
||||
REQUIRE_NOTHROW(Approx(0).margin(0));
|
||||
REQUIRE_NOTHROW(Approx(0).margin(1234656));
|
||||
|
||||
REQUIRE_THROWS_AS(Approx(0).margin(-2), std::domain_error);
|
||||
|
||||
REQUIRE_NOTHROW(Approx(0).epsilon(0));
|
||||
REQUIRE_NOTHROW(Approx(0).epsilon(1));
|
||||
|
||||
REQUIRE_THROWS_AS(Approx(0).epsilon(-0.001), std::domain_error);
|
||||
REQUIRE_THROWS_AS(Approx(0).epsilon(1.0001), std::domain_error);
|
||||
}
|
||||
|
||||
TEST_CASE("Default scale is invisible to comparison", "[Approx]") {
|
||||
REQUIRE(101.000001 != Approx(100).epsilon(0.01));
|
||||
REQUIRE(std::pow(10, -5) != Approx(std::pow(10, -7)));
|
||||
}
|
||||
|
||||
TEST_CASE("Epsilon only applies to Approx's value", "[Approx]") {
|
||||
REQUIRE(101.01 != Approx(100).epsilon(0.01));
|
||||
}
|
||||
|
||||
TEST_CASE("Assorted miscellaneous tests", "[Approx][approvals]") {
|
||||
REQUIRE(INFINITY == Approx(INFINITY));
|
||||
REQUIRE(-INFINITY != Approx(INFINITY));
|
||||
REQUIRE(1 != Approx(INFINITY));
|
||||
REQUIRE(INFINITY != Approx(1));
|
||||
REQUIRE(NAN != Approx(NAN));
|
||||
REQUIRE_FALSE(NAN == Approx(NAN));
|
||||
}
|
||||
|
||||
TEST_CASE( "Comparison with explicitly convertible types", "[Approx]" )
|
||||
{
|
||||
StrongDoubleTypedef td(10.0);
|
||||
|
||||
REQUIRE(td == Approx(10.0));
|
||||
REQUIRE(Approx(10.0) == td);
|
||||
|
||||
REQUIRE(td != Approx(11.0));
|
||||
REQUIRE(Approx(11.0) != td);
|
||||
|
||||
REQUIRE(td <= Approx(10.0));
|
||||
REQUIRE(td <= Approx(11.0));
|
||||
REQUIRE(Approx(10.0) <= td);
|
||||
REQUIRE(Approx(9.0) <= td);
|
||||
|
||||
REQUIRE(td >= Approx(9.0));
|
||||
REQUIRE(td >= Approx(td));
|
||||
REQUIRE(Approx(td) >= td);
|
||||
REQUIRE(Approx(11.0) >= td);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("Approx::operator() is const correct", "[Approx][.approvals]") {
|
||||
const Approx ap = Approx(0.0).margin(0.01);
|
||||
|
||||
// As long as this compiles, the test should be considered passing
|
||||
REQUIRE(1.0 == ap(1.0));
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
static bool itDoesThis() { return true; }
|
||||
|
||||
static bool itDoesThat() { return true; }
|
||||
|
||||
// a trivial fixture example to support SCENARIO_METHOD tests
|
||||
struct Fixture {
|
||||
Fixture(): d_counter( 0 ) {}
|
||||
|
||||
int counter() { return d_counter++; }
|
||||
|
||||
int d_counter;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
SCENARIO("Do that thing with the thing", "[Tags]") {
|
||||
GIVEN("This stuff exists") {
|
||||
// make stuff exist
|
||||
AND_GIVEN("And some assumption") {
|
||||
// Validate assumption
|
||||
WHEN("I do this") {
|
||||
// do this
|
||||
THEN("it should do this") {
|
||||
REQUIRE(itDoesThis());
|
||||
AND_THEN("do that") {
|
||||
REQUIRE(itDoesThat());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO( "Vector resizing affects size and capacity",
|
||||
"[vector][bdd][size][capacity]" ) {
|
||||
GIVEN( "an empty vector" ) {
|
||||
std::vector<int> v;
|
||||
REQUIRE( v.size() == 0 );
|
||||
|
||||
WHEN( "it is made larger" ) {
|
||||
v.resize( 10 );
|
||||
THEN( "the size and capacity go up" ) {
|
||||
REQUIRE( v.size() == 10 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
|
||||
AND_WHEN( "it is made smaller again" ) {
|
||||
v.resize( 5 );
|
||||
THEN(
|
||||
"the size goes down but the capacity stays the same" ) {
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WHEN( "we reserve more space" ) {
|
||||
v.reserve( 10 );
|
||||
THEN( "The capacity is increased but the size remains the same" ) {
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
REQUIRE( v.size() == 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("This is a really long scenario name to see how the list command deals with wrapping",
|
||||
"[very long tags][lots][long][tags][verbose]"
|
||||
"[one very long tag name that should cause line wrapping writing out using the list command]"
|
||||
"[anotherReallyLongTagNameButThisOneHasNoObviousWrapPointsSoShouldSplitWithinAWordUsingADashCharacter]") {
|
||||
GIVEN("A section name that is so long that it cannot fit in a single console width") {
|
||||
WHEN("The test headers are printed as part of the normal running of the scenario") {
|
||||
THEN("The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent") {
|
||||
SUCCEED("boo!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO_METHOD(Fixture,
|
||||
"BDD tests requiring Fixtures to provide commonly-accessed data or methods",
|
||||
"[bdd][fixtures]") {
|
||||
const int before(counter());
|
||||
GIVEN("No operations precede me") {
|
||||
REQUIRE(before == 0);
|
||||
WHEN("We get the count") {
|
||||
const int after(counter());
|
||||
THEN("Subsequently values are higher") {
|
||||
REQUIRE(after > before);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
|
||||
// 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/catch_test_macros.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/benchmark/catch_constructor.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace {
|
||||
std::uint64_t Fibonacci(std::uint64_t number) {
|
||||
return number < 2 ? number : Fibonacci(number - 1) + Fibonacci(number - 2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Benchmark Fibonacci", "[!benchmark]") {
|
||||
CHECK(Fibonacci(0) == 0);
|
||||
// some more asserts..
|
||||
CHECK(Fibonacci(5) == 5);
|
||||
// some more asserts..
|
||||
|
||||
REQUIRE( Fibonacci( 20 ) == 6'765 );
|
||||
BENCHMARK( "Fibonacci 20" ) {
|
||||
return Fibonacci(20);
|
||||
};
|
||||
|
||||
REQUIRE( Fibonacci( 25 ) == 75'025 );
|
||||
BENCHMARK( "Fibonacci 25" ) {
|
||||
return Fibonacci(25);
|
||||
};
|
||||
|
||||
BENCHMARK("Fibonacci 30") {
|
||||
return Fibonacci(30);
|
||||
};
|
||||
|
||||
BENCHMARK("Fibonacci 35") {
|
||||
return Fibonacci(35);
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Benchmark containers", "[!benchmark]") {
|
||||
static const int size = 100;
|
||||
|
||||
std::vector<int> v;
|
||||
std::map<int, int> m;
|
||||
|
||||
SECTION("without generator") {
|
||||
BENCHMARK("Load up a vector") {
|
||||
v = std::vector<int>();
|
||||
for (int i = 0; i < size; ++i)
|
||||
v.push_back(i);
|
||||
};
|
||||
REQUIRE(v.size() == size);
|
||||
|
||||
// test optimizer control
|
||||
BENCHMARK("Add up a vector's content") {
|
||||
uint64_t add = 0;
|
||||
for (int i = 0; i < size; ++i)
|
||||
add += v[i];
|
||||
return add;
|
||||
};
|
||||
|
||||
BENCHMARK("Load up a map") {
|
||||
m = std::map<int, int>();
|
||||
for (int i = 0; i < size; ++i)
|
||||
m.insert({ i, i + 1 });
|
||||
};
|
||||
REQUIRE(m.size() == size);
|
||||
|
||||
BENCHMARK("Reserved vector") {
|
||||
v = std::vector<int>();
|
||||
v.reserve(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
v.push_back(i);
|
||||
};
|
||||
REQUIRE(v.size() == size);
|
||||
|
||||
BENCHMARK("Resized vector") {
|
||||
v = std::vector<int>();
|
||||
v.resize(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
v[i] = i;
|
||||
};
|
||||
REQUIRE(v.size() == size);
|
||||
|
||||
int array[size];
|
||||
BENCHMARK("A fixed size array that should require no allocations") {
|
||||
for (int i = 0; i < size; ++i)
|
||||
array[i] = i;
|
||||
};
|
||||
int sum = 0;
|
||||
for (int i = 0; i < size; ++i)
|
||||
sum += array[i];
|
||||
REQUIRE(sum > size);
|
||||
|
||||
SECTION("XYZ") {
|
||||
|
||||
BENCHMARK_ADVANCED("Load up vector with chronometer")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<int> k;
|
||||
meter.measure([&](int idx) {
|
||||
k = std::vector<int>();
|
||||
for (int i = 0; i < size; ++i)
|
||||
k.push_back(idx);
|
||||
});
|
||||
REQUIRE(k.size() == size);
|
||||
};
|
||||
|
||||
int runs = 0;
|
||||
BENCHMARK("Fill vector indexed", benchmarkIndex) {
|
||||
v = std::vector<int>();
|
||||
v.resize(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
v[i] = benchmarkIndex;
|
||||
runs = benchmarkIndex;
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
REQUIRE(v[i] == runs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("with generator") {
|
||||
auto generated = GENERATE(range(0, 10));
|
||||
BENCHMARK("Fill vector generated") {
|
||||
v = std::vector<int>();
|
||||
v.resize(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
v[i] = generated;
|
||||
};
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
REQUIRE(v[i] == generated);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("construct and destroy example") {
|
||||
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
|
||||
meter.measure([&](int i) { storage[i].construct("thing"); });
|
||||
};
|
||||
|
||||
BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
|
||||
for(auto&& o : storage)
|
||||
o.construct("thing");
|
||||
meter.measure([&](int i) { storage[i].destruct(); });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Skip benchmark macros", "[!benchmark]") {
|
||||
std::vector<int> v;
|
||||
BENCHMARK("fill vector") {
|
||||
v.emplace_back(1);
|
||||
v.emplace_back(2);
|
||||
v.emplace_back(3);
|
||||
};
|
||||
REQUIRE(v.size() == 0);
|
||||
|
||||
std::size_t counter{0};
|
||||
BENCHMARK_ADVANCED("construct vector")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
|
||||
meter.measure([&](int i) { storage[i].construct("thing"); counter++; });
|
||||
};
|
||||
REQUIRE(counter == 0);
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
|
||||
// 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
|
||||
|
||||
#if defined( __GNUC__ ) || defined( __clang__ )
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace {
|
||||
|
||||
class TestClass {
|
||||
std::string s;
|
||||
|
||||
public:
|
||||
TestClass(): s( "hello" ) {}
|
||||
|
||||
void succeedingCase() { REQUIRE( s == "hello" ); }
|
||||
void failingCase() { REQUIRE( s == "world" ); }
|
||||
};
|
||||
|
||||
struct Fixture {
|
||||
Fixture(): m_a( 1 ) {}
|
||||
|
||||
int m_a;
|
||||
};
|
||||
|
||||
template <typename T> struct Template_Fixture {
|
||||
Template_Fixture(): m_a( 1 ) {}
|
||||
|
||||
T m_a;
|
||||
};
|
||||
|
||||
template <typename T> struct Template_Fixture_2 {
|
||||
Template_Fixture_2() {}
|
||||
|
||||
T m_a;
|
||||
};
|
||||
|
||||
template <typename T> struct Template_Foo {
|
||||
size_t size() { return 0; }
|
||||
};
|
||||
|
||||
template <typename T, size_t V> struct Template_Foo_2 {
|
||||
size_t size() { return V; }
|
||||
};
|
||||
|
||||
template <int V> struct Nttp_Fixture { int value = V; };
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
METHOD_AS_TEST_CASE( TestClass::succeedingCase, "A METHOD_AS_TEST_CASE based test run that succeeds", "[class]" )
|
||||
METHOD_AS_TEST_CASE( TestClass::failingCase, "A METHOD_AS_TEST_CASE based test run that fails", "[.][class][failing]" )
|
||||
|
||||
TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that succeeds", "[class]" )
|
||||
{
|
||||
REQUIRE( m_a == 1 );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD(Template_Fixture, "A TEMPLATE_TEST_CASE_METHOD based test run that succeeds", "[class][template]", int, float, double) {
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][nttp]",((int V), V), 1, 3, 6) {
|
||||
REQUIRE(Nttp_Fixture<V>::value > 0);
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds","[class][template][product]",(std::vector,Template_Foo),(int,float))
|
||||
{
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 0 );
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][product][nttp]", ((typename T, size_t S), T, S),(std::array, Template_Foo_2), ((int,2), (float,6)))
|
||||
{
|
||||
REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() >= 2);
|
||||
}
|
||||
|
||||
using MyTypes = std::tuple<int, char, double>;
|
||||
TEMPLATE_LIST_TEST_CASE_METHOD(Template_Fixture, "Template test case method with test types specified inside std::tuple", "[class][template][list]", MyTypes)
|
||||
{
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
|
||||
}
|
||||
|
||||
// We should be able to write our tests within a different namespace
|
||||
namespace Inner
|
||||
{
|
||||
TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that fails", "[.][class][failing]" )
|
||||
{
|
||||
REQUIRE( m_a == 2 );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD(Template_Fixture,"A TEMPLATE_TEST_CASE_METHOD based test run that fails", "[.][class][template][failing]", int, float, double)
|
||||
{
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 2 );
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails", "[.][class][template][nttp][failing]", ((int V), V), 1, 3, 6) {
|
||||
REQUIRE(Nttp_Fixture<V>::value == 0);
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails","[.][class][template][product][failing]",(std::vector,Template_Foo),(int,float))
|
||||
{
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 );
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails", "[.][class][template][product][nttp][failing]", ((typename T, size_t S), T, S), (std::array, Template_Foo_2), ((int, 2), (float, 6)))
|
||||
{
|
||||
REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() < 2);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
// We want a class in nested namespace so we can test JUnit's classname normalization.
|
||||
namespace {
|
||||
namespace A {
|
||||
namespace B {
|
||||
class TestClass {};
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE_METHOD( A::B::TestClass,
|
||||
"A TEST_CASE_METHOD testing junit classname normalization",
|
||||
"[class][approvals]" ) {
|
||||
SUCCEED();
|
||||
}
|
||||
+355
@@ -0,0 +1,355 @@
|
||||
|
||||
// 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 <helpers/type_with_lit_0_comparisons.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// Setup for #1403 -- look for global overloads of operator << for classes
|
||||
// in a different namespace.
|
||||
#include <ostream>
|
||||
|
||||
namespace foo {
|
||||
struct helper_1403 {
|
||||
bool operator==(helper_1403) const { return true; }
|
||||
};
|
||||
}
|
||||
|
||||
namespace bar {
|
||||
template <typename... Ts>
|
||||
struct TypeList {};
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
||||
#endif
|
||||
static std::ostream& operator<<(std::ostream& out, foo::helper_1403 const&) {
|
||||
return out << "[1403 helper]";
|
||||
}
|
||||
///////////////////////////////
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
// Comparison operators can return non-booleans.
|
||||
// This is unusual, but should be supported.
|
||||
struct logic_t {
|
||||
logic_t operator< (logic_t) const { return {}; }
|
||||
logic_t operator<=(logic_t) const { return {}; }
|
||||
logic_t operator> (logic_t) const { return {}; }
|
||||
logic_t operator>=(logic_t) const { return {}; }
|
||||
logic_t operator==(logic_t) const { return {}; }
|
||||
logic_t operator!=(logic_t) const { return {}; }
|
||||
explicit operator bool() const { return true; }
|
||||
};
|
||||
|
||||
|
||||
static void throws_int(bool b) {
|
||||
if (b) {
|
||||
throw 1;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool templated_tests(T t) {
|
||||
int a = 3;
|
||||
REQUIRE(a == t);
|
||||
CHECK(a == t);
|
||||
REQUIRE_THROWS(throws_int(true));
|
||||
CHECK_THROWS_AS(throws_int(true), int);
|
||||
REQUIRE_NOTHROW(throws_int(false));
|
||||
REQUIRE_THAT("aaa", Catch::Matchers::EndsWith("aaa"));
|
||||
return true;
|
||||
}
|
||||
|
||||
struct A {};
|
||||
|
||||
static std::ostream &operator<<(std::ostream &o, const A &) { return o << 0; }
|
||||
|
||||
struct B : private A {
|
||||
bool operator==(int) const { return true; }
|
||||
};
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
// Note that because -~GCC~-, this warning cannot be silenced temporarily, by pushing diagnostic stack...
|
||||
// Luckily it is firing in test files and thus can be silenced for the whole file, without losing much.
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
B f();
|
||||
|
||||
std::ostream g();
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
template <typename, typename>
|
||||
struct Fixture_1245 {};
|
||||
|
||||
// This is a minimal example for an issue we have found in 1.7.0
|
||||
struct dummy_809 {
|
||||
int i;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool operator==(const T& val, dummy_809 f) {
|
||||
return val == f.i;
|
||||
}
|
||||
|
||||
TEST_CASE("#809") {
|
||||
dummy_809 f;
|
||||
f.i = 42;
|
||||
REQUIRE(42 == f);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Changes to REQUIRE_THROWS_AS made it stop working in a template in
|
||||
// an unfixable way (as long as C++03 compatibility is being kept).
|
||||
// To prevent these from happening in the future, this needs to compile
|
||||
|
||||
TEST_CASE("#833") {
|
||||
REQUIRE(templated_tests<int>(3));
|
||||
}
|
||||
|
||||
|
||||
// Test containing example where original stream insertable check breaks compilation
|
||||
TEST_CASE("#872") {
|
||||
A dummy;
|
||||
CAPTURE(dummy);
|
||||
B x;
|
||||
REQUIRE (x == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("#1027: Bitfields can be captured") {
|
||||
struct Y {
|
||||
uint32_t v : 1;
|
||||
};
|
||||
Y y{ 0 };
|
||||
REQUIRE(y.v == 0);
|
||||
REQUIRE(0 == y.v);
|
||||
}
|
||||
|
||||
// Comparison operators can return non-booleans.
|
||||
// This is unusual, but should be supported.
|
||||
TEST_CASE("#1147") {
|
||||
logic_t t1, t2;
|
||||
REQUIRE(t1 == t2);
|
||||
REQUIRE(t1 != t2);
|
||||
REQUIRE(t1 < t2);
|
||||
REQUIRE(t1 > t2);
|
||||
REQUIRE(t1 <= t2);
|
||||
REQUIRE(t1 >= t2);
|
||||
}
|
||||
|
||||
// unsigned array
|
||||
TEST_CASE("#1238") {
|
||||
unsigned char uarr[] = "123";
|
||||
CAPTURE(uarr);
|
||||
signed char sarr[] = "456";
|
||||
CAPTURE(sarr);
|
||||
|
||||
REQUIRE(std::memcmp(uarr, "123", sizeof(uarr)) == 0);
|
||||
REQUIRE(std::memcmp(sarr, "456", sizeof(sarr)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD((Fixture_1245<int, int>), "#1245", "[compilation]") {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("#1403", "[compilation]") {
|
||||
::foo::helper_1403 h1, h2;
|
||||
REQUIRE(h1 == h2);
|
||||
}
|
||||
|
||||
TEST_CASE("Optionally static assertions", "[compilation]") {
|
||||
STATIC_REQUIRE( std::is_void<void>::value );
|
||||
STATIC_REQUIRE_FALSE( std::is_void<int>::value );
|
||||
STATIC_CHECK( std::is_void<void>::value );
|
||||
STATIC_CHECK_FALSE( std::is_void<int>::value );
|
||||
}
|
||||
|
||||
TEST_CASE("#1548", "[compilation]") {
|
||||
using namespace bar;
|
||||
REQUIRE(std::is_same<TypeList<int>, TypeList<int>>::value);
|
||||
}
|
||||
|
||||
// #925
|
||||
using signal_t = void (*) (void*);
|
||||
|
||||
struct TestClass {
|
||||
signal_t testMethod_uponComplete_arg = nullptr;
|
||||
};
|
||||
|
||||
namespace utility {
|
||||
inline static void synchronizing_callback( void * ) { }
|
||||
}
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
#pragma warning(push)
|
||||
// The function pointer comparison below triggers warning because of
|
||||
// calling conventions
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
TEST_CASE("#925: comparing function pointer to function address failed to compile", "[!nonportable]" ) {
|
||||
TestClass test;
|
||||
REQUIRE(utility::synchronizing_callback != test.testMethod_uponComplete_arg);
|
||||
}
|
||||
#if defined (_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
TEST_CASE( "#1319: Sections can have description (even if it is not saved",
|
||||
"[compilation]" ) {
|
||||
SECTION( "SectionName", "This is a long form section description" ) {
|
||||
SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Lambdas in assertions") {
|
||||
REQUIRE([]() { return true; }());
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct HasBitOperators {
|
||||
int value;
|
||||
|
||||
friend HasBitOperators operator| (HasBitOperators lhs, HasBitOperators rhs) {
|
||||
return { lhs.value | rhs.value };
|
||||
}
|
||||
friend HasBitOperators operator& (HasBitOperators lhs, HasBitOperators rhs) {
|
||||
return { lhs.value & rhs.value };
|
||||
}
|
||||
friend HasBitOperators operator^ (HasBitOperators lhs, HasBitOperators rhs) {
|
||||
return { lhs.value ^ rhs.value };
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return !!value;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, HasBitOperators val) {
|
||||
out << "Val: " << val.value;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Assertion macros support bit operators and bool conversions", "[compilation][bitops]") {
|
||||
HasBitOperators lhs{ 1 }, rhs{ 2 };
|
||||
REQUIRE(lhs | rhs);
|
||||
REQUIRE_FALSE(lhs & rhs);
|
||||
REQUIRE(HasBitOperators{ 1 } & HasBitOperators{ 1 });
|
||||
REQUIRE(lhs ^ rhs);
|
||||
REQUIRE_FALSE(lhs ^ lhs);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ImmovableType {
|
||||
ImmovableType() = default;
|
||||
|
||||
ImmovableType(ImmovableType const&) = delete;
|
||||
ImmovableType& operator=(ImmovableType const&) = delete;
|
||||
ImmovableType(ImmovableType&&) = delete;
|
||||
ImmovableType& operator=(ImmovableType&&) = delete;
|
||||
|
||||
friend bool operator==(ImmovableType const&, ImmovableType const&) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("Immovable types are supported in basic assertions", "[compilation][.approvals]") {
|
||||
REQUIRE(ImmovableType{} == ImmovableType{});
|
||||
}
|
||||
|
||||
namespace adl {
|
||||
|
||||
struct always_true {
|
||||
explicit operator bool() const { return true; }
|
||||
};
|
||||
|
||||
#define COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(op) \
|
||||
template <class T, class U> \
|
||||
auto operator op (T&&, U&&) { \
|
||||
return always_true{}; \
|
||||
}
|
||||
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(==)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(!=)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(<)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(>)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(<=)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(>=)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(|)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(&)
|
||||
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(^)
|
||||
|
||||
#undef COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("ADL universal operators don't hijack expression deconstruction", "[compilation][.approvals]") {
|
||||
REQUIRE(adl::always_true{});
|
||||
REQUIRE(0 == adl::always_true{});
|
||||
REQUIRE(0 != adl::always_true{});
|
||||
REQUIRE(0 < adl::always_true{});
|
||||
REQUIRE(0 > adl::always_true{});
|
||||
REQUIRE(0 <= adl::always_true{});
|
||||
REQUIRE(0 >= adl::always_true{});
|
||||
REQUIRE(0 | adl::always_true{});
|
||||
REQUIRE(0 & adl::always_true{});
|
||||
REQUIRE(0 ^ adl::always_true{});
|
||||
}
|
||||
|
||||
TEST_CASE( "#2555 - types that can only be compared with 0 literal (not int/long) are supported", "[compilation][approvals]" ) {
|
||||
REQUIRE( TypeWithLit0Comparisons{} < 0 );
|
||||
REQUIRE_FALSE( 0 < TypeWithLit0Comparisons{} );
|
||||
REQUIRE( TypeWithLit0Comparisons{} <= 0 );
|
||||
REQUIRE_FALSE( 0 > TypeWithLit0Comparisons{} );
|
||||
|
||||
REQUIRE( TypeWithLit0Comparisons{} > 0 );
|
||||
REQUIRE_FALSE( 0 > TypeWithLit0Comparisons{} );
|
||||
REQUIRE( TypeWithLit0Comparisons{} >= 0 );
|
||||
REQUIRE_FALSE( 0 >= TypeWithLit0Comparisons{} );
|
||||
|
||||
REQUIRE( TypeWithLit0Comparisons{} == 0 );
|
||||
REQUIRE_FALSE( 0 == TypeWithLit0Comparisons{} );
|
||||
REQUIRE( TypeWithLit0Comparisons{} != 0 );
|
||||
REQUIRE_FALSE( 0 != TypeWithLit0Comparisons{} );
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct MultipleImplicitConstructors {
|
||||
MultipleImplicitConstructors( double ) {}
|
||||
MultipleImplicitConstructors( int64_t ) {}
|
||||
bool operator==( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator!=( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator<( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator<=( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator>( MultipleImplicitConstructors ) const { return true; }
|
||||
bool operator>=( MultipleImplicitConstructors ) const { return true; }
|
||||
};
|
||||
}
|
||||
TEST_CASE("#2571 - tests compile types that have multiple implicit constructors from lit 0",
|
||||
"[compilation][approvals]") {
|
||||
MultipleImplicitConstructors mic1( 0.0 );
|
||||
MultipleImplicitConstructors mic2( 0.0 );
|
||||
REQUIRE( mic1 == mic2 );
|
||||
REQUIRE( mic1 != mic2 );
|
||||
REQUIRE( mic1 < mic2 );
|
||||
REQUIRE( mic1 <= mic2 );
|
||||
REQUIRE( mic1 > mic2 );
|
||||
REQUIRE( mic1 >= mic2 );
|
||||
}
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
|
||||
// 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
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wpadded"
|
||||
// Wdouble-promotion is not supported until 3.8
|
||||
# if (__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ > 7)
|
||||
# pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
using Catch::Approx;
|
||||
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestData {
|
||||
int int_seven = 7;
|
||||
std::string str_hello = "hello";
|
||||
float float_nine_point_one = 9.1f;
|
||||
double double_pi = 3.1415926535;
|
||||
};
|
||||
|
||||
static const char* returnsConstNull() { return nullptr; }
|
||||
static char* returnsNull() { return nullptr; }
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
// The "failing" tests all use the CHECK macro, which continues if the specific test fails.
|
||||
// This allows us to see all results, even if an earlier check fails
|
||||
|
||||
// Equality tests
|
||||
TEST_CASE( "Equality checks that should succeed" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
REQUIRE( data.int_seven == 7 );
|
||||
REQUIRE( data.float_nine_point_one == Approx( 9.1f ) );
|
||||
REQUIRE( data.double_pi == Approx( 3.1415926535 ) );
|
||||
REQUIRE( data.str_hello == "hello" );
|
||||
REQUIRE( "hello" == data.str_hello );
|
||||
REQUIRE( data.str_hello.size() == 5 );
|
||||
|
||||
double x = 1.1 + 0.1 + 0.1;
|
||||
REQUIRE( x == Approx( 1.3 ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "Equality checks that should fail", "[.][failing][!mayfail]" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
CHECK( data.int_seven == 6 );
|
||||
CHECK( data.int_seven == 8 );
|
||||
CHECK( data.int_seven == 0 );
|
||||
CHECK( data.float_nine_point_one == Approx( 9.11f ) );
|
||||
CHECK( data.float_nine_point_one == Approx( 9.0f ) );
|
||||
CHECK( data.float_nine_point_one == Approx( 1 ) );
|
||||
CHECK( data.float_nine_point_one == Approx( 0 ) );
|
||||
CHECK( data.double_pi == Approx( 3.1415 ) );
|
||||
CHECK( data.str_hello == "goodbye" );
|
||||
CHECK( data.str_hello == "hell" );
|
||||
CHECK( data.str_hello == "hello1" );
|
||||
CHECK( data.str_hello.size() == 6 );
|
||||
|
||||
double x = 1.1 + 0.1 + 0.1;
|
||||
CHECK( x == Approx( 1.301 ) );
|
||||
}
|
||||
|
||||
// Needed to test junit reporter's handling of mayfail test cases and sections
|
||||
TEST_CASE("Mayfail test case with nested sections", "[!mayfail]") {
|
||||
SECTION("A") {
|
||||
SECTION("1") { FAIL(); }
|
||||
SECTION("2") { FAIL(); }
|
||||
}
|
||||
SECTION("B") {
|
||||
SECTION("1") { FAIL(); }
|
||||
SECTION("2") { FAIL(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "Inequality checks that should succeed" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
REQUIRE( data.int_seven != 6 );
|
||||
REQUIRE( data.int_seven != 8 );
|
||||
REQUIRE( data.float_nine_point_one != Approx( 9.11f ) );
|
||||
REQUIRE( data.float_nine_point_one != Approx( 9.0f ) );
|
||||
REQUIRE( data.float_nine_point_one != Approx( 1 ) );
|
||||
REQUIRE( data.float_nine_point_one != Approx( 0 ) );
|
||||
REQUIRE( data.double_pi != Approx( 3.1415 ) );
|
||||
REQUIRE( data.str_hello != "goodbye" );
|
||||
REQUIRE( data.str_hello != "hell" );
|
||||
REQUIRE( data.str_hello != "hello1" );
|
||||
REQUIRE( data.str_hello.size() != 6 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Inequality checks that should fail", "[.][failing][!shouldfail]" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
CHECK( data.int_seven != 7 );
|
||||
CHECK( data.float_nine_point_one != Approx( 9.1f ) );
|
||||
CHECK( data.double_pi != Approx( 3.1415926535 ) );
|
||||
CHECK( data.str_hello != "hello" );
|
||||
CHECK( data.str_hello.size() != 5 );
|
||||
}
|
||||
|
||||
// Ordering comparison tests
|
||||
TEST_CASE( "Ordering comparison checks that should succeed" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
REQUIRE( data.int_seven < 8 );
|
||||
REQUIRE( data.int_seven > 6 );
|
||||
REQUIRE( data.int_seven > 0 );
|
||||
REQUIRE( data.int_seven > -1 );
|
||||
|
||||
REQUIRE( data.int_seven >= 7 );
|
||||
REQUIRE( data.int_seven >= 6 );
|
||||
REQUIRE( data.int_seven <= 7 );
|
||||
REQUIRE( data.int_seven <= 8 );
|
||||
|
||||
REQUIRE( data.float_nine_point_one > 9 );
|
||||
REQUIRE( data.float_nine_point_one < 10 );
|
||||
REQUIRE( data.float_nine_point_one < 9.2 );
|
||||
|
||||
REQUIRE( data.str_hello <= "hello" );
|
||||
REQUIRE( data.str_hello >= "hello" );
|
||||
|
||||
REQUIRE( data.str_hello < "hellp" );
|
||||
REQUIRE( data.str_hello < "zebra" );
|
||||
REQUIRE( data.str_hello > "hellm" );
|
||||
REQUIRE( data.str_hello > "a" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Ordering comparison checks that should fail", "[.][failing]" )
|
||||
{
|
||||
TestData data;
|
||||
|
||||
CHECK( data.int_seven > 7 );
|
||||
CHECK( data.int_seven < 7 );
|
||||
CHECK( data.int_seven > 8 );
|
||||
CHECK( data.int_seven < 6 );
|
||||
CHECK( data.int_seven < 0 );
|
||||
CHECK( data.int_seven < -1 );
|
||||
|
||||
CHECK( data.int_seven >= 8 );
|
||||
CHECK( data.int_seven <= 6 );
|
||||
|
||||
CHECK( data.float_nine_point_one < 9 );
|
||||
CHECK( data.float_nine_point_one > 10 );
|
||||
CHECK( data.float_nine_point_one > 9.2 );
|
||||
|
||||
CHECK( data.str_hello > "hello" );
|
||||
CHECK( data.str_hello < "hello" );
|
||||
CHECK( data.str_hello > "hellp" );
|
||||
CHECK( data.str_hello > "z" );
|
||||
CHECK( data.str_hello < "hellm" );
|
||||
CHECK( data.str_hello < "a" );
|
||||
|
||||
CHECK( data.str_hello >= "z" );
|
||||
CHECK( data.str_hello <= "a" );
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
// Comparisons with int literals
|
||||
TEST_CASE( "Comparisons with int literals don't warn when mixing signed/ unsigned" )
|
||||
{
|
||||
int i = 1;
|
||||
unsigned int ui = 2;
|
||||
long l = 3;
|
||||
unsigned long ul = 4;
|
||||
char c = 5;
|
||||
unsigned char uc = 6;
|
||||
|
||||
REQUIRE( i == 1 );
|
||||
REQUIRE( ui == 2 );
|
||||
REQUIRE( l == 3 );
|
||||
REQUIRE( ul == 4 );
|
||||
REQUIRE( c == 5 );
|
||||
REQUIRE( uc == 6 );
|
||||
|
||||
REQUIRE( 1 == i );
|
||||
REQUIRE( 2 == ui );
|
||||
REQUIRE( 3 == l );
|
||||
REQUIRE( 4 == ul );
|
||||
REQUIRE( 5 == c );
|
||||
REQUIRE( 6 == uc );
|
||||
|
||||
REQUIRE( (std::numeric_limits<uint32_t>::max)() > ul );
|
||||
}
|
||||
|
||||
// Disable warnings about sign conversions for the next two tests
|
||||
// (as we are deliberately invoking them)
|
||||
// - Currently only disabled for GCC/ LLVM. Should add VC++ too
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
|
||||
#endif
|
||||
|
||||
TEST_CASE( "comparisons between int variables" )
|
||||
{
|
||||
long long_var = 1L;
|
||||
unsigned char unsigned_char_var = 1;
|
||||
unsigned short unsigned_short_var = 1;
|
||||
unsigned int unsigned_int_var = 1;
|
||||
unsigned long unsigned_long_var = 1L;
|
||||
|
||||
REQUIRE( long_var == unsigned_char_var );
|
||||
REQUIRE( long_var == unsigned_short_var );
|
||||
REQUIRE( long_var == unsigned_int_var );
|
||||
REQUIRE( long_var == unsigned_long_var );
|
||||
}
|
||||
|
||||
TEST_CASE( "comparisons between const int variables" )
|
||||
{
|
||||
const unsigned char unsigned_char_var = 1;
|
||||
const unsigned short unsigned_short_var = 1;
|
||||
const unsigned int unsigned_int_var = 1;
|
||||
const unsigned long unsigned_long_var = 1L;
|
||||
|
||||
REQUIRE( unsigned_char_var == 1 );
|
||||
REQUIRE( unsigned_short_var == 1 );
|
||||
REQUIRE( unsigned_int_var == 1 );
|
||||
REQUIRE( unsigned_long_var == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Comparisons between unsigned ints and negative signed ints match c++ standard behaviour" )
|
||||
{
|
||||
CHECK( ( -1 > 2u ) );
|
||||
CHECK( -1 > 2u );
|
||||
|
||||
CHECK( ( 2u < -1 ) );
|
||||
CHECK( 2u < -1 );
|
||||
|
||||
const int minInt = (std::numeric_limits<int>::min)();
|
||||
CHECK( ( minInt > 2u ) );
|
||||
CHECK( minInt > 2u );
|
||||
}
|
||||
|
||||
TEST_CASE( "Comparisons between ints where one side is computed" )
|
||||
{
|
||||
CHECK( 54 == 6*9 );
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
TEST_CASE( "Pointers can be compared to null" )
|
||||
{
|
||||
TestData* p = nullptr;
|
||||
TestData* pNULL = nullptr;
|
||||
|
||||
REQUIRE( p == nullptr );
|
||||
REQUIRE( p == pNULL );
|
||||
|
||||
TestData data;
|
||||
p = &data;
|
||||
|
||||
REQUIRE( p != nullptr );
|
||||
|
||||
const TestData* cp = p;
|
||||
REQUIRE( cp != nullptr );
|
||||
|
||||
const TestData* const cpc = p;
|
||||
REQUIRE( cpc != nullptr );
|
||||
|
||||
REQUIRE( returnsNull() == nullptr );
|
||||
REQUIRE( returnsConstNull() == nullptr );
|
||||
|
||||
REQUIRE( nullptr != p );
|
||||
}
|
||||
|
||||
// Not (!) tests
|
||||
// The problem with the ! operator is that it has right-to-left associativity.
|
||||
// This means we can't isolate it when we decompose. The simple REQUIRE( !false ) form, therefore,
|
||||
// cannot have the operand value extracted. The test will work correctly, and the situation
|
||||
// is detected and a warning issued.
|
||||
// An alternative form of the macros (CHECK_FALSE and REQUIRE_FALSE) can be used instead to capture
|
||||
// the operand value.
|
||||
TEST_CASE( "'Not' checks that should succeed" )
|
||||
{
|
||||
bool falseValue = false;
|
||||
|
||||
REQUIRE( false == false );
|
||||
REQUIRE( true == true );
|
||||
REQUIRE( !false );
|
||||
REQUIRE_FALSE( false );
|
||||
|
||||
REQUIRE( !falseValue );
|
||||
REQUIRE_FALSE( falseValue );
|
||||
|
||||
REQUIRE( !(1 == 2) );
|
||||
REQUIRE_FALSE( 1 == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE( "'Not' checks that should fail", "[.][failing]" )
|
||||
{
|
||||
bool trueValue = true;
|
||||
|
||||
CHECK( false != false );
|
||||
CHECK( true != true );
|
||||
CHECK( !true );
|
||||
CHECK_FALSE( true );
|
||||
|
||||
CHECK( !trueValue );
|
||||
CHECK_FALSE( trueValue );
|
||||
|
||||
CHECK( !(1 == 1) );
|
||||
CHECK_FALSE( 1 == 1 );
|
||||
}
|
||||
+41
@@ -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
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
|
||||
namespace {
|
||||
|
||||
struct truthy {
|
||||
truthy(bool b):m_value(b){}
|
||||
operator bool() const {
|
||||
return false;
|
||||
}
|
||||
bool m_value;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, truthy) {
|
||||
o << "Hey, its truthy!";
|
||||
return o;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
TEST_CASE( "Reconstruction should be based on stringification: #914" , "[Decomposition][failing][.]") {
|
||||
CHECK(truthy(false));
|
||||
}
|
||||
|
||||
TEST_CASE("#1005: Comparing pointer to int and long (NULL can be either on various systems)", "[Decomposition][approvals]") {
|
||||
FILE* fptr = nullptr;
|
||||
REQUIRE( fptr == 0 );
|
||||
REQUIRE_FALSE( fptr != 0 );
|
||||
REQUIRE( fptr == 0l );
|
||||
REQUIRE_FALSE( fptr != 0l );
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/internal/catch_enum_values_registry.hpp>
|
||||
|
||||
|
||||
namespace {
|
||||
// Enum without user-provided stream operator
|
||||
enum Enum1 { Enum1Value0, Enum1Value1 };
|
||||
|
||||
// Enum with user-provided stream operator
|
||||
enum Enum2 { Enum2Value0, Enum2Value1 };
|
||||
|
||||
std::ostream& operator<<( std::ostream& os, Enum2 v ) {
|
||||
return os << "E2{" << static_cast<int>(v) << "}";
|
||||
}
|
||||
} // end anonymous namespace
|
||||
|
||||
TEST_CASE( "toString(enum)", "[toString][enum]" ) {
|
||||
Enum1 e0 = Enum1Value0;
|
||||
CHECK( ::Catch::Detail::stringify(e0) == "0" );
|
||||
Enum1 e1 = Enum1Value1;
|
||||
CHECK( ::Catch::Detail::stringify(e1) == "1" );
|
||||
}
|
||||
|
||||
TEST_CASE( "toString(enum w/operator<<)", "[toString][enum]" ) {
|
||||
Enum2 e0 = Enum2Value0;
|
||||
CHECK( ::Catch::Detail::stringify(e0) == "E2{0}" );
|
||||
Enum2 e1 = Enum2Value1;
|
||||
CHECK( ::Catch::Detail::stringify(e1) == "E2{1}" );
|
||||
}
|
||||
|
||||
// Enum class without user-provided stream operator
|
||||
namespace {
|
||||
enum class EnumClass1 { EnumClass1Value0, EnumClass1Value1 };
|
||||
|
||||
// Enum class with user-provided stream operator
|
||||
enum class EnumClass2 { EnumClass2Value0, EnumClass2Value1 };
|
||||
|
||||
std::ostream& operator<<( std::ostream& os, EnumClass2 e2 ) {
|
||||
switch( static_cast<int>( e2 ) ) {
|
||||
case static_cast<int>( EnumClass2::EnumClass2Value0 ):
|
||||
return os << "E2/V0";
|
||||
case static_cast<int>( EnumClass2::EnumClass2Value1 ):
|
||||
return os << "E2/V1";
|
||||
default:
|
||||
return os << "Unknown enum value " << static_cast<int>( e2 );
|
||||
}
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
TEST_CASE( "toString(enum class)", "[toString][enum][enumClass]" ) {
|
||||
EnumClass1 e0 = EnumClass1::EnumClass1Value0;
|
||||
CHECK( ::Catch::Detail::stringify(e0) == "0" );
|
||||
EnumClass1 e1 = EnumClass1::EnumClass1Value1;
|
||||
CHECK( ::Catch::Detail::stringify(e1) == "1" );
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "toString(enum class w/operator<<)", "[toString][enum][enumClass]" ) {
|
||||
EnumClass2 e0 = EnumClass2::EnumClass2Value0;
|
||||
CHECK( ::Catch::Detail::stringify(e0) == "E2/V0" );
|
||||
EnumClass2 e1 = EnumClass2::EnumClass2Value1;
|
||||
CHECK( ::Catch::Detail::stringify(e1) == "E2/V1" );
|
||||
|
||||
auto e3 = static_cast<EnumClass2>(10);
|
||||
CHECK( ::Catch::Detail::stringify(e3) == "Unknown enum value 10" );
|
||||
}
|
||||
|
||||
enum class EnumClass3 { Value1, Value2, Value3, Value4 };
|
||||
|
||||
CATCH_REGISTER_ENUM( EnumClass3, EnumClass3::Value1, EnumClass3::Value2, EnumClass3::Value3 )
|
||||
|
||||
|
||||
TEST_CASE( "Enums can quickly have stringification enabled using REGISTER_ENUM" ) {
|
||||
using Catch::Detail::stringify;
|
||||
REQUIRE( stringify( EnumClass3::Value1 ) == "Value1" );
|
||||
REQUIRE( stringify( EnumClass3::Value2 ) == "Value2" );
|
||||
REQUIRE( stringify( EnumClass3::Value3 ) == "Value3" );
|
||||
REQUIRE( stringify( EnumClass3::Value4 ) == "{** unexpected enum value **}" );
|
||||
|
||||
EnumClass3 ec3 = EnumClass3::Value2;
|
||||
REQUIRE( stringify( ec3 ) == "Value2" );
|
||||
}
|
||||
|
||||
namespace Bikeshed {
|
||||
enum class Colours { Red, Green, Blue };
|
||||
}
|
||||
|
||||
// Important!: This macro must appear at top level scope - not inside a namespace
|
||||
// You can fully qualify the names, or use a using if you prefer
|
||||
CATCH_REGISTER_ENUM( Bikeshed::Colours,
|
||||
Bikeshed::Colours::Red,
|
||||
Bikeshed::Colours::Green,
|
||||
Bikeshed::Colours::Blue )
|
||||
|
||||
TEST_CASE( "Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM" ) {
|
||||
using Catch::Detail::stringify;
|
||||
REQUIRE( stringify( Bikeshed::Colours::Red ) == "Red" );
|
||||
REQUIRE( stringify( Bikeshed::Colours::Blue ) == "Blue" );
|
||||
}
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/catch_translate_exception.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4702) // Unreachable code -- unconditional throws and so on
|
||||
#endif
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#pragma clang diagnostic ignored "-Wmissing-noreturn"
|
||||
#pragma clang diagnostic ignored "-Wunreachable-code-return"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
int thisThrows() {
|
||||
throw std::domain_error("expected exception");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int thisDoesntThrow() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
class CustomException {
|
||||
public:
|
||||
explicit CustomException(const std::string& msg)
|
||||
: m_msg(msg) {}
|
||||
|
||||
std::string const& getMessage() const {
|
||||
return m_msg;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_msg;
|
||||
};
|
||||
|
||||
class CustomStdException : public std::exception {
|
||||
public:
|
||||
explicit CustomStdException(const std::string& msg)
|
||||
: m_msg(msg) {}
|
||||
~CustomStdException() noexcept override = default;
|
||||
|
||||
CustomStdException( CustomStdException const& ) = default;
|
||||
CustomStdException& operator=( CustomStdException const& ) = default;
|
||||
|
||||
std::string const& getMessage() const {
|
||||
return m_msg;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_msg;
|
||||
};
|
||||
|
||||
[[noreturn]] void throwCustom() {
|
||||
throw CustomException("custom exception - not std");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE( "When checked exceptions are thrown they can be expected or unexpected", "[!throws]" ) {
|
||||
REQUIRE_THROWS_AS( thisThrows(), std::domain_error );
|
||||
REQUIRE_NOTHROW( thisDoesntThrow() );
|
||||
REQUIRE_THROWS( thisThrows() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Expected exceptions that don't throw or unexpected exceptions fail the test", "[.][failing][!throws]" ) {
|
||||
CHECK_THROWS_AS( thisThrows(), std::string );
|
||||
CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error );
|
||||
CHECK_NOTHROW( thisThrows() );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown directly they are always failures", "[.][failing][!throws]" ) {
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "An unchecked exception reports the line of the last assertion", "[.][failing][!throws]" ) {
|
||||
CHECK( 1 == 1 );
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown from sections they are always failures", "[.][failing][!throws]" ) {
|
||||
SECTION( "section name" ) {
|
||||
throw std::domain_error("unexpected exception");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown from functions they are always failures", "[.][failing][!throws]" ) {
|
||||
CHECK( thisThrows() == 0 );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown during a REQUIRE the test should abort fail", "[.][failing][!throws]" ) {
|
||||
REQUIRE( thisThrows() == 0 );
|
||||
FAIL( "This should never happen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown during a CHECK the test should continue", "[.][failing][!throws]" ) {
|
||||
try {
|
||||
CHECK(thisThrows() == 0);
|
||||
}
|
||||
catch(...) {
|
||||
FAIL( "This should never happen" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown, but caught, they do not affect the test", "[!throws]" ) {
|
||||
try {
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
}
|
||||
catch(...) {}
|
||||
}
|
||||
|
||||
|
||||
CATCH_TRANSLATE_EXCEPTION( CustomException const& ex ) {
|
||||
return ex.getMessage();
|
||||
}
|
||||
|
||||
CATCH_TRANSLATE_EXCEPTION( CustomStdException const& ex ) {
|
||||
return ex.getMessage();
|
||||
}
|
||||
|
||||
CATCH_TRANSLATE_EXCEPTION( double const& ex ) {
|
||||
return Catch::Detail::stringify( ex );
|
||||
}
|
||||
|
||||
TEST_CASE("Non-std exceptions can be translated", "[.][failing][!throws]" ) {
|
||||
throw CustomException( "custom exception" );
|
||||
}
|
||||
|
||||
TEST_CASE("Custom std-exceptions can be custom translated", "[.][failing][!throws]" ) {
|
||||
throw CustomStdException( "custom std exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Custom exceptions can be translated when testing for nothrow", "[.][failing][!throws]" ) {
|
||||
REQUIRE_NOTHROW( throwCustom() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Custom exceptions can be translated when testing for throwing as something else", "[.][failing][!throws]" ) {
|
||||
REQUIRE_THROWS_AS( throwCustom(), std::exception );
|
||||
}
|
||||
|
||||
TEST_CASE( "Unexpected exceptions can be translated", "[.][failing][!throws]" ) {
|
||||
throw double( 3.14 );
|
||||
}
|
||||
|
||||
TEST_CASE("Thrown string literals are translated", "[.][failing][!throws]") {
|
||||
throw "For some reason someone is throwing a string literal!";
|
||||
}
|
||||
|
||||
TEST_CASE("thrown std::strings are translated", "[.][failing][!throws]") {
|
||||
throw std::string{ "Why would you throw a std::string?" };
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "Exception messages can be tested for", "[!throws]" ) {
|
||||
using namespace Catch::Matchers;
|
||||
SECTION( "exact match" )
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
|
||||
SECTION( "different case" )
|
||||
REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) );
|
||||
SECTION( "wildcarded" ) {
|
||||
REQUIRE_THROWS_WITH( thisThrows(), StartsWith( "expected" ) );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), EndsWith( "exception" ) );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), ContainsSubstring( "except" ) );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Mismatching exception messages failing the test", "[.][failing][!throws]" ) {
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "should fail" );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "#748 - captures with unexpected exceptions", "[.][failing][!throws][!shouldfail]" ) {
|
||||
int answer = 42;
|
||||
CAPTURE( answer );
|
||||
// the message should be printed on the first two sections but not on the third
|
||||
SECTION( "outside assertions" ) {
|
||||
thisThrows();
|
||||
}
|
||||
SECTION( "inside REQUIRE_NOTHROW" ) {
|
||||
REQUIRE_NOTHROW( thisThrows() );
|
||||
}
|
||||
SECTION( "inside REQUIRE_THROWS" ) {
|
||||
REQUIRE_THROWS( thisThrows() );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
#include <catch2/generators/catch_generators_adapters.hpp>
|
||||
#include <catch2/generators/catch_generators_random.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
// Generators and sections can be nested freely
|
||||
TEST_CASE("Generators -- simple", "[generators]") {
|
||||
auto i = GENERATE(1, 2, 3);
|
||||
SECTION("one") {
|
||||
auto j = GENERATE(values({ -3, -2, -1 }));
|
||||
REQUIRE(j < i);
|
||||
}
|
||||
|
||||
SECTION("two") {
|
||||
// You can also explicitly set type for generators via Catch::Generators::as
|
||||
auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");
|
||||
REQUIRE(4u * i > str.size());
|
||||
}
|
||||
}
|
||||
|
||||
// You can create a cartesian-product of generators by creating multiple ones
|
||||
TEST_CASE("3x3x3 ints", "[generators]") {
|
||||
auto x = GENERATE(1, 2, 3);
|
||||
auto y = GENERATE(4, 5, 6);
|
||||
auto z = GENERATE(7, 8, 9);
|
||||
// These assertions will be run 27 times (3x3x3)
|
||||
CHECK(x < y);
|
||||
CHECK(y < z);
|
||||
REQUIRE(x < z);
|
||||
}
|
||||
|
||||
// You can also create data tuples
|
||||
TEST_CASE("tables", "[generators]") {
|
||||
// Note that this will not compile with libstdc++ older than libstdc++6
|
||||
// See https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list
|
||||
// for possible workarounds
|
||||
// auto data = GENERATE(table<char const*, int>({
|
||||
// {"first", 5},
|
||||
// {"second", 6},
|
||||
// {"third", 5},
|
||||
// {"etc...", 6}
|
||||
// }));
|
||||
|
||||
// Workaround for the libstdc++ bug mentioned above
|
||||
using tuple_type = std::tuple<char const*, int>;
|
||||
auto data = GENERATE(table<char const*, int>({
|
||||
tuple_type{"first", 5},
|
||||
tuple_type{"second", 6},
|
||||
tuple_type{"third", 5},
|
||||
tuple_type{"etc...", 6}
|
||||
}));
|
||||
|
||||
REQUIRE(strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)));
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cpp_structured_bindings
|
||||
|
||||
// Structured bindings make the table utility much nicer to use
|
||||
TEST_CASE( "strlen2", "[approvals][generators]" ) {
|
||||
using tuple_type = std::tuple<std::string, int>; // see above workaround
|
||||
auto [test_input, expected] =
|
||||
GENERATE( table<std::string, size_t>( { tuple_type{ "one", 3 },
|
||||
tuple_type{ "two", 3 },
|
||||
tuple_type{ "three", 5 },
|
||||
tuple_type{ "four", 4 } } ) );
|
||||
|
||||
REQUIRE( test_input.size() == expected );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// An alternate way of doing data tables without structured bindings
|
||||
struct Data { std::string str; size_t len; };
|
||||
|
||||
TEST_CASE( "strlen3", "[generators]" ) {
|
||||
auto data = GENERATE( values<Data>({
|
||||
{"one", 3},
|
||||
{"two", 3},
|
||||
{"three", 5},
|
||||
{"four", 4}
|
||||
}));
|
||||
|
||||
REQUIRE( data.str.size() == data.len );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef __cpp_structured_bindings
|
||||
|
||||
// Based on example from https://docs.cucumber.io/gherkin/reference/#scenario-outline
|
||||
// (thanks to https://github.com/catchorg/Catch2/issues/850#issuecomment-399504851)
|
||||
|
||||
// Note that GIVEN, WHEN, and THEN now forward onto DYNAMIC_SECTION instead of SECTION.
|
||||
// DYNAMIC_SECTION takes its name as a stringstream-style expression, so can be formatted using
|
||||
// variables in scope - such as the generated variables here. This reads quite nicely in the
|
||||
// test name output (the full scenario description).
|
||||
|
||||
static auto eatCucumbers( int start, int eat ) -> int { return start-eat; }
|
||||
|
||||
SCENARIO("Eating cucumbers", "[generators][approvals]") {
|
||||
using tuple_type = std::tuple<int, int, int>;
|
||||
auto [start, eat, left] = GENERATE( table<int, int, int>(
|
||||
{ tuple_type{ 12, 5, 7 }, tuple_type{ 20, 5, 15 } } ) );
|
||||
|
||||
GIVEN( "there are " << start << " cucumbers" )
|
||||
WHEN( "I eat " << eat << " cucumbers" )
|
||||
THEN( "I should have " << left << " cucumbers" ) {
|
||||
REQUIRE( eatCucumbers( start, eat ) == left );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// There are also some generic generator manipulators
|
||||
TEST_CASE("Generators -- adapters", "[generators][generic]") {
|
||||
// TODO: This won't work yet, introduce GENERATE_VAR?
|
||||
//auto numbers = Catch::Generators::values({ 1, 2, 3, 4, 5, 6 });
|
||||
SECTION("Filtering by predicate") {
|
||||
SECTION("Basic usage") {
|
||||
// This filters out all odd (false) numbers, giving [2, 4, 6]
|
||||
auto i = GENERATE(filter([] (int val) { return val % 2 == 0; }, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
}
|
||||
SECTION("Throws if there are no matching values") {
|
||||
using namespace Catch::Generators;
|
||||
REQUIRE_THROWS_AS(filter([] (int) {return false; }, value(1)), Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
SECTION("Shortening a range") {
|
||||
// This takes the first 3 elements from the values, giving back [1, 2, 3]
|
||||
auto i = GENERATE(take(3, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i < 4);
|
||||
}
|
||||
SECTION("Transforming elements") {
|
||||
SECTION("Same type") {
|
||||
// This doubles values [1, 2, 3] into [2, 4, 6]
|
||||
auto i = GENERATE(map([] (int val) { return val * 2; }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
}
|
||||
SECTION("Different type") {
|
||||
// This takes a generator that returns ints and maps them into strings
|
||||
auto i = GENERATE(map<std::string>([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i.size() == 1);
|
||||
}
|
||||
SECTION("Different deduced type") {
|
||||
// This takes a generator that returns ints and maps them into strings
|
||||
auto i = GENERATE(map([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i.size() == 1);
|
||||
}
|
||||
}
|
||||
SECTION("Repeating a generator") {
|
||||
// This will return values [1, 2, 3, 1, 2, 3]
|
||||
auto j = GENERATE(repeat(2, values({ 1, 2, 3 })));
|
||||
REQUIRE(j > 0);
|
||||
}
|
||||
SECTION("Chunking a generator into sized pieces") {
|
||||
SECTION("Number of elements in source is divisible by chunk size") {
|
||||
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3, 3 })));
|
||||
REQUIRE(chunk2.size() == 2);
|
||||
REQUIRE(chunk2.front() == chunk2.back());
|
||||
}
|
||||
SECTION("Number of elements in source is not divisible by chunk size") {
|
||||
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3 })));
|
||||
REQUIRE(chunk2.size() == 2);
|
||||
REQUIRE(chunk2.front() == chunk2.back());
|
||||
REQUIRE(chunk2.front() < 3);
|
||||
}
|
||||
SECTION("Chunk size of zero") {
|
||||
auto chunk2 = GENERATE(take(3, chunk(0, value(1))));
|
||||
REQUIRE(chunk2.size() == 0);
|
||||
}
|
||||
SECTION("Throws on too small generators") {
|
||||
using namespace Catch::Generators;
|
||||
REQUIRE_THROWS_AS(chunk(2, value(1)), Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that because of the non-reproducibility of distributions,
|
||||
// anything involving the random generators cannot be part of approvals
|
||||
TEST_CASE("Random generator", "[generators][approvals]") {
|
||||
SECTION("Infer int from integral arguments") {
|
||||
auto val = GENERATE(take(4, random(0, 1)));
|
||||
STATIC_REQUIRE(std::is_same<decltype(val), int>::value);
|
||||
REQUIRE(0 <= val);
|
||||
REQUIRE(val <= 1);
|
||||
}
|
||||
SECTION("Infer double from double arguments") {
|
||||
auto val = GENERATE(take(4, random(0., 1.)));
|
||||
STATIC_REQUIRE(std::is_same<decltype(val), double>::value);
|
||||
REQUIRE(0. <= val);
|
||||
REQUIRE(val < 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Nested generators and captured variables", "[generators]") {
|
||||
// Workaround for old libstdc++
|
||||
using record = std::tuple<int, int>;
|
||||
// Set up 3 ranges to generate numbers from
|
||||
auto extent = GENERATE(table<int, int>({
|
||||
record{3, 7},
|
||||
record{-5, -3},
|
||||
record{90, 100}
|
||||
}));
|
||||
|
||||
auto from = std::get<0>(extent);
|
||||
auto to = std::get<1>(extent);
|
||||
|
||||
auto values = GENERATE_COPY(range(from, to));
|
||||
REQUIRE(values > -6);
|
||||
}
|
||||
|
||||
namespace {
|
||||
size_t call_count = 0;
|
||||
size_t test_count = 0;
|
||||
std::vector<int> make_data() {
|
||||
return { 1, 3, 5, 7, 9, 11 };
|
||||
}
|
||||
std::vector<int> make_data_counted() {
|
||||
++call_count;
|
||||
return make_data();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#endif
|
||||
|
||||
TEST_CASE("Copy and then generate a range", "[generators]") {
|
||||
SECTION("from var and iterators") {
|
||||
static auto data = make_data();
|
||||
|
||||
// It is important to notice that a generator is only initialized
|
||||
// **once** per run. What this means is that modifying data will not
|
||||
// modify the underlying generator.
|
||||
auto elem = GENERATE_REF(from_range(data.begin(), data.end()));
|
||||
REQUIRE(elem % 2 == 1);
|
||||
}
|
||||
SECTION("From a temporary container") {
|
||||
auto elem = GENERATE(from_range(make_data_counted()));
|
||||
++test_count;
|
||||
REQUIRE(elem % 2 == 1);
|
||||
}
|
||||
SECTION("Final validation") {
|
||||
REQUIRE(call_count == 1);
|
||||
REQUIRE(make_data().size() == test_count);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined( __clang__ )
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
TEST_CASE("#1913 - GENERATE inside a for loop should not keep recreating the generator", "[regression][generators]") {
|
||||
static int counter = 0;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int _ = GENERATE(1, 2);
|
||||
(void)_;
|
||||
++counter;
|
||||
}
|
||||
// There should be at most 6 (3 * 2) counter increments
|
||||
REQUIRE(counter < 7);
|
||||
}
|
||||
|
||||
TEST_CASE("#1913 - GENERATEs can share a line", "[regression][generators]") {
|
||||
int i = GENERATE(1, 2); int j = GENERATE(3, 4);
|
||||
REQUIRE(i != j);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class test_generator : public Catch::Generators::IGenerator<int> {
|
||||
public:
|
||||
[[noreturn]] explicit test_generator() {
|
||||
// removing the following line will cause the program to terminate
|
||||
// gracefully.
|
||||
throw Catch::GeneratorException( "failure to init" );
|
||||
}
|
||||
|
||||
auto get() const -> int const& override {
|
||||
static constexpr int value = 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
auto next() -> bool override { return false; }
|
||||
};
|
||||
|
||||
static auto make_test_generator()
|
||||
-> Catch::Generators::GeneratorWrapper<int> {
|
||||
return { new test_generator() };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "#2615 - Throwing in constructor generator fails test case but does not abort",
|
||||
"[!shouldfail][regression][generators]" ) {
|
||||
// this should fail the test case, but not abort the application
|
||||
auto sample = GENERATE( make_test_generator() );
|
||||
// this assertion shouldn't trigger
|
||||
REQUIRE( sample == 0 );
|
||||
}
|
||||
|
||||
TEST_CASE( "GENERATE can combine literals and generators", "[generators]" ) {
|
||||
auto i = GENERATE( 2,
|
||||
4,
|
||||
take( 2,
|
||||
filter( []( int val ) { return val % 2 == 0; },
|
||||
random( -100, 100 ) ) ) );
|
||||
REQUIRE( i % 2 == 0 );
|
||||
}
|
||||
+1144
File diff suppressed because it is too large
Load Diff
+917
@@ -0,0 +1,917 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_container_properties.hpp>
|
||||
#include <catch2/matchers/catch_matchers_contains.hpp>
|
||||
#include <catch2/matchers/catch_matchers_range_equals.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/matchers/catch_matchers_quantifiers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <helpers/range_test_helpers.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
struct MoveOnlyTestElement {
|
||||
int num = 0;
|
||||
MoveOnlyTestElement(int n) :num(n) {}
|
||||
|
||||
MoveOnlyTestElement(MoveOnlyTestElement&& rhs) = default;
|
||||
MoveOnlyTestElement& operator=(MoveOnlyTestElement&& rhs) = default;
|
||||
|
||||
friend bool operator==(MoveOnlyTestElement const& lhs, MoveOnlyTestElement const& rhs) {
|
||||
return lhs.num == rhs.num;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, MoveOnlyTestElement const& elem) {
|
||||
out << elem.num;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Basic use of the Contains range matcher", "[matchers][templated][contains]") {
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
SECTION("Different argument ranges, same element type, default comparison") {
|
||||
std::array<int, 3> a{ { 1,2,3 } };
|
||||
std::vector<int> b{ 0,1,2 };
|
||||
std::list<int> c{ 4,5,6 };
|
||||
|
||||
// A contains 1
|
||||
REQUIRE_THAT(a, Contains(1));
|
||||
// B contains 1
|
||||
REQUIRE_THAT(b, Contains(1));
|
||||
// C does not contain 1
|
||||
REQUIRE_THAT(c, !Contains(1));
|
||||
}
|
||||
|
||||
SECTION("Different argument ranges, same element type, custom comparison") {
|
||||
std::array<int, 3> a{ { 1,2,3 } };
|
||||
std::vector<int> b{ 0,1,2 };
|
||||
std::list<int> c{ 4,5,6 };
|
||||
|
||||
auto close_enough = [](int lhs, int rhs) { return std::abs(lhs - rhs) <= 1; };
|
||||
|
||||
// A contains 1, which is "close enough" to 0
|
||||
REQUIRE_THAT(a, Contains(0, close_enough));
|
||||
// B contains 0 directly
|
||||
REQUIRE_THAT(b, Contains(0, close_enough));
|
||||
// C does not contain anything "close enough" to 0
|
||||
REQUIRE_THAT(c, !Contains(0, close_enough));
|
||||
}
|
||||
|
||||
SECTION("Different element type, custom comparisons") {
|
||||
std::array<std::string, 3> a{ { "abc", "abcd" , "abcde" } };
|
||||
|
||||
REQUIRE_THAT(a, Contains(4, [](auto&& lhs, size_t sz) {
|
||||
return lhs.size() == sz;
|
||||
}));
|
||||
}
|
||||
|
||||
SECTION("Can handle type that requires ADL-found free function begin and end") {
|
||||
unrelated::needs_ADL_begin<int> in{1, 2, 3, 4, 5};
|
||||
|
||||
REQUIRE_THAT(in, Contains(1));
|
||||
REQUIRE_THAT(in, !Contains(8));
|
||||
}
|
||||
|
||||
SECTION("Initialization with move only types") {
|
||||
std::array<MoveOnlyTestElement, 3> in{ { MoveOnlyTestElement{ 1 }, MoveOnlyTestElement{ 2 }, MoveOnlyTestElement{ 3 } } };
|
||||
|
||||
REQUIRE_THAT(in, Contains(MoveOnlyTestElement{ 2 }));
|
||||
REQUIRE_THAT(in, !Contains(MoveOnlyTestElement{ 9 }));
|
||||
}
|
||||
|
||||
SECTION("Matching using matcher") {
|
||||
std::array<double, 4> in{ {1, 2, 3} };
|
||||
|
||||
REQUIRE_THAT(in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)));
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct has_empty {
|
||||
bool empty() const { return false; }
|
||||
};
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("Basic use of the Empty range matcher", "[matchers][templated][empty]") {
|
||||
using Catch::Matchers::IsEmpty;
|
||||
SECTION("Simple, std-provided containers") {
|
||||
std::array<int, 0> empty_array{};
|
||||
std::array<double, 1> non_empty_array{};
|
||||
REQUIRE_THAT(empty_array, IsEmpty());
|
||||
REQUIRE_THAT(non_empty_array, !IsEmpty());
|
||||
|
||||
std::vector<std::string> empty_vec;
|
||||
std::vector<char> non_empty_vec{ 'a', 'b', 'c' };
|
||||
REQUIRE_THAT(empty_vec, IsEmpty());
|
||||
REQUIRE_THAT(non_empty_vec, !IsEmpty());
|
||||
|
||||
std::list<std::list<std::list<int>>> inner_lists_are_empty;
|
||||
inner_lists_are_empty.push_back({});
|
||||
REQUIRE_THAT(inner_lists_are_empty, !IsEmpty());
|
||||
REQUIRE_THAT(inner_lists_are_empty.front(), IsEmpty());
|
||||
}
|
||||
SECTION("Type with empty") {
|
||||
REQUIRE_THAT(has_empty{}, !IsEmpty());
|
||||
}
|
||||
SECTION("Type requires ADL found empty free function") {
|
||||
REQUIRE_THAT(unrelated::ADL_empty{}, IsEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class LessThanMatcher final : public Catch::Matchers::MatcherBase<size_t> {
|
||||
size_t m_target;
|
||||
public:
|
||||
explicit LessThanMatcher(size_t target):
|
||||
m_target(target)
|
||||
{}
|
||||
|
||||
bool match(size_t const& size) const override {
|
||||
return size < m_target;
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "is less than " + std::to_string(m_target);
|
||||
}
|
||||
};
|
||||
|
||||
LessThanMatcher Lt(size_t sz) {
|
||||
return LessThanMatcher{ sz };
|
||||
}
|
||||
|
||||
struct has_size {
|
||||
size_t size() const {
|
||||
return 13;
|
||||
}
|
||||
};
|
||||
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("Usage of the SizeIs range matcher", "[matchers][templated][size]") {
|
||||
using Catch::Matchers::SizeIs;
|
||||
SECTION("Some with stdlib containers") {
|
||||
std::vector<int> empty_vec;
|
||||
REQUIRE_THAT(empty_vec, SizeIs(0));
|
||||
REQUIRE_THAT(empty_vec, !SizeIs(2));
|
||||
REQUIRE_THAT(empty_vec, SizeIs(Lt(2)));
|
||||
|
||||
std::array<int, 2> arr{};
|
||||
REQUIRE_THAT(arr, SizeIs(2));
|
||||
REQUIRE_THAT(arr, SizeIs( Lt(3)));
|
||||
REQUIRE_THAT(arr, !SizeIs(!Lt(3)));
|
||||
|
||||
std::map<int, int> map{ {1, 1}, {2, 2}, {3, 3} };
|
||||
REQUIRE_THAT(map, SizeIs(3));
|
||||
}
|
||||
SECTION("Type requires ADL found size free function") {
|
||||
REQUIRE_THAT(unrelated::ADL_size{}, SizeIs(12));
|
||||
}
|
||||
SECTION("Type has size member") {
|
||||
REQUIRE_THAT(has_size{}, SizeIs(13));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Usage of AllMatch range matcher", "[matchers][templated][quantifiers]") {
|
||||
using Catch::Matchers::AllMatch;
|
||||
using Catch::Matchers::Predicate;
|
||||
|
||||
SECTION("Basic usage") {
|
||||
using Catch::Matchers::Contains;
|
||||
using Catch::Matchers::SizeIs;
|
||||
|
||||
std::array<std::array<int, 5>, 5> data{{
|
||||
{{ 0, 1, 2, 3, 5 }},
|
||||
{{ 4,-3,-2, 5, 0 }},
|
||||
{{ 0, 0, 0, 5, 0 }},
|
||||
{{ 0,-5, 0, 5, 0 }},
|
||||
{{ 1, 0, 0,-1, 5 }}
|
||||
}};
|
||||
|
||||
REQUIRE_THAT(data, AllMatch(SizeIs(5)));
|
||||
REQUIRE_THAT(data, !AllMatch(Contains(0) && Contains(1)));
|
||||
}
|
||||
|
||||
SECTION("Type requires ADL found begin and end") {
|
||||
unrelated::needs_ADL_begin<int> needs_adl{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( needs_adl, AllMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 6;
|
||||
} ) ) );
|
||||
}
|
||||
|
||||
SECTION("Shortcircuiting") {
|
||||
with_mocked_iterator_access<int> mocked{ 1, 2, 3, 4, 5 };
|
||||
SECTION("All are read") {
|
||||
auto allMatch = AllMatch(Predicate<int>([](int elem) {
|
||||
return elem < 10;
|
||||
}));
|
||||
REQUIRE_THAT(mocked, allMatch);
|
||||
REQUIRE(mocked.m_derefed[0]);
|
||||
REQUIRE(mocked.m_derefed[1]);
|
||||
REQUIRE(mocked.m_derefed[2]);
|
||||
REQUIRE(mocked.m_derefed[3]);
|
||||
REQUIRE(mocked.m_derefed[4]);
|
||||
}
|
||||
SECTION("Short-circuited") {
|
||||
auto allMatch = AllMatch(Predicate<int>([](int elem) {
|
||||
return elem < 3;
|
||||
}));
|
||||
REQUIRE_THAT(mocked, !allMatch);
|
||||
REQUIRE(mocked.m_derefed[0]);
|
||||
REQUIRE(mocked.m_derefed[1]);
|
||||
REQUIRE(mocked.m_derefed[2]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[3]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Usage of AnyMatch range matcher", "[matchers][templated][quantifiers]") {
|
||||
using Catch::Matchers::AnyMatch;
|
||||
using Catch::Matchers::Predicate;
|
||||
|
||||
SECTION("Basic usage") {
|
||||
using Catch::Matchers::Contains;
|
||||
using Catch::Matchers::SizeIs;
|
||||
|
||||
std::array<std::array<int, 5>, 5> data{ {
|
||||
{{ 0, 1, 2, 3, 5 }},
|
||||
{{ 4,-3,-2, 5, 0 }},
|
||||
{{ 0, 0, 0, 5, 0 }},
|
||||
{{ 0,-5, 0, 5, 0 }},
|
||||
{{ 1, 0, 0,-1, 5 }}
|
||||
} };
|
||||
|
||||
REQUIRE_THAT(data, AnyMatch(SizeIs(5)));
|
||||
REQUIRE_THAT(data, !AnyMatch(Contains(0) && Contains(10)));
|
||||
}
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<int> needs_adl{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( needs_adl, AnyMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 3;
|
||||
} ) ) );
|
||||
}
|
||||
|
||||
SECTION("Shortcircuiting") {
|
||||
with_mocked_iterator_access<int> mocked{ 1, 2, 3, 4, 5 };
|
||||
SECTION("All are read") {
|
||||
auto anyMatch = AnyMatch(
|
||||
Predicate<int>( []( int elem ) { return elem > 10; } ) );
|
||||
REQUIRE_THAT( mocked, !anyMatch );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE( mocked.m_derefed[3] );
|
||||
REQUIRE( mocked.m_derefed[4] );
|
||||
}
|
||||
SECTION("Short-circuited") {
|
||||
auto anyMatch = AnyMatch(
|
||||
Predicate<int>( []( int elem ) { return elem < 3; } ) );
|
||||
REQUIRE_THAT( mocked, anyMatch );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[1] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[3] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Usage of NoneMatch range matcher", "[matchers][templated][quantifiers]") {
|
||||
using Catch::Matchers::NoneMatch;
|
||||
using Catch::Matchers::Predicate;
|
||||
|
||||
SECTION("Basic usage") {
|
||||
using Catch::Matchers::Contains;
|
||||
using Catch::Matchers::SizeIs;
|
||||
|
||||
std::array<std::array<int, 5>, 5> data{ {
|
||||
{{ 0, 1, 2, 3, 5 }},
|
||||
{{ 4,-3,-2, 5, 0 }},
|
||||
{{ 0, 0, 0, 5, 0 }},
|
||||
{{ 0,-5, 0, 5, 0 }},
|
||||
{{ 1, 0, 0,-1, 5 }}
|
||||
} };
|
||||
|
||||
REQUIRE_THAT(data, NoneMatch(SizeIs(6)));
|
||||
REQUIRE_THAT(data, !NoneMatch(Contains(0) && Contains(1)));
|
||||
}
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<int> needs_adl{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( needs_adl, NoneMatch( Predicate<int>( []( int elem ) {
|
||||
return elem > 6;
|
||||
} ) ) );
|
||||
}
|
||||
|
||||
SECTION("Shortcircuiting") {
|
||||
with_mocked_iterator_access<int> mocked{ 1, 2, 3, 4, 5 };
|
||||
SECTION("All are read") {
|
||||
auto noneMatch = NoneMatch(
|
||||
Predicate<int>([](int elem) { return elem > 10; }));
|
||||
REQUIRE_THAT(mocked, noneMatch);
|
||||
REQUIRE(mocked.m_derefed[0]);
|
||||
REQUIRE(mocked.m_derefed[1]);
|
||||
REQUIRE(mocked.m_derefed[2]);
|
||||
REQUIRE(mocked.m_derefed[3]);
|
||||
REQUIRE(mocked.m_derefed[4]);
|
||||
}
|
||||
SECTION("Short-circuited") {
|
||||
auto noneMatch = NoneMatch(
|
||||
Predicate<int>([](int elem) { return elem < 3; }));
|
||||
REQUIRE_THAT(mocked, !noneMatch);
|
||||
REQUIRE(mocked.m_derefed[0]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[1]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[2]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[3]);
|
||||
REQUIRE_FALSE(mocked.m_derefed[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ConvertibleToBool
|
||||
{
|
||||
bool v;
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace Catch {
|
||||
template <>
|
||||
struct StringMaker<ConvertibleToBool> {
|
||||
static std::string
|
||||
convert( ConvertibleToBool const& convertible_to_bool ) {
|
||||
return ::Catch::Detail::stringify( convertible_to_bool.v );
|
||||
}
|
||||
};
|
||||
} // namespace Catch
|
||||
|
||||
TEST_CASE("Usage of AllTrue range matcher", "[matchers][templated][quantifiers]") {
|
||||
using Catch::Matchers::AllTrue;
|
||||
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "All true evaluates to true" ) {
|
||||
std::array<bool, 5> const data{ { true, true, true, true, true } };
|
||||
REQUIRE_THAT( data, AllTrue() );
|
||||
}
|
||||
SECTION( "Empty evaluates to true" ) {
|
||||
std::array<bool, 0> const data{};
|
||||
REQUIRE_THAT( data, AllTrue() );
|
||||
}
|
||||
SECTION( "One false evaluates to false" ) {
|
||||
std::array<bool, 5> const data{ { true, true, false, true, true } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to false" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, false, false, false } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Contained type is convertible to bool" ) {
|
||||
SECTION( "All true evaluates to true" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { true }, { true }, { true }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, AllTrue() );
|
||||
}
|
||||
SECTION( "One false evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { true }, { true }, { false }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { false }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Shortcircuiting" ) {
|
||||
SECTION( "All are read" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
true, true, true, true, true };
|
||||
REQUIRE_THAT( mocked, AllTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE( mocked.m_derefed[3] );
|
||||
REQUIRE( mocked.m_derefed[4] );
|
||||
}
|
||||
SECTION( "Short-circuited" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
true, true, false, true, true };
|
||||
REQUIRE_THAT( mocked, !AllTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[3] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Usage of NoneTrue range matcher", "[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::NoneTrue;
|
||||
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "All true evaluates to false" ) {
|
||||
std::array<bool, 5> const data{ { true, true, true, true, true } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
}
|
||||
SECTION( "Empty evaluates to true" ) {
|
||||
std::array<bool, 0> const data{};
|
||||
REQUIRE_THAT( data, NoneTrue() );
|
||||
}
|
||||
SECTION( "One true evaluates to false" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, true, false, false } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to true" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, false, false, false } };
|
||||
REQUIRE_THAT( data, NoneTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Contained type is convertible to bool" ) {
|
||||
SECTION( "All true evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { true }, { true }, { true }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
}
|
||||
SECTION( "One true evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { true }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to true" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { false }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, NoneTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Shortcircuiting" ) {
|
||||
SECTION( "All are read" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
false, false, false, false, false };
|
||||
REQUIRE_THAT( mocked, NoneTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE( mocked.m_derefed[3] );
|
||||
REQUIRE( mocked.m_derefed[4] );
|
||||
}
|
||||
SECTION( "Short-circuited" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
false, false, true, true, true };
|
||||
REQUIRE_THAT( mocked, !NoneTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[3] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Usage of AnyTrue range matcher", "[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::AnyTrue;
|
||||
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "All true evaluates to true" ) {
|
||||
std::array<bool, 5> const data{ { true, true, true, true, true } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
}
|
||||
SECTION( "Empty evaluates to false" ) {
|
||||
std::array<bool, 0> const data{};
|
||||
REQUIRE_THAT( data, !AnyTrue() );
|
||||
}
|
||||
SECTION( "One true evaluates to true" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, true, false, false } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to false" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, false, false, false } };
|
||||
REQUIRE_THAT( data, !AnyTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Contained type is convertible to bool" ) {
|
||||
SECTION( "All true evaluates to true" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { true }, { true }, { true }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
}
|
||||
SECTION( "One true evaluates to true" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { true }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
}
|
||||
SECTION( "All false evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { false }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, !AnyTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Shortcircuiting" ) {
|
||||
SECTION( "All are read" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
false, false, false, false, true };
|
||||
REQUIRE_THAT( mocked, AnyTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE( mocked.m_derefed[3] );
|
||||
REQUIRE( mocked.m_derefed[4] );
|
||||
}
|
||||
SECTION( "Short-circuited" ) {
|
||||
with_mocked_iterator_access<bool> const mocked{
|
||||
false, false, true, true, true };
|
||||
REQUIRE_THAT( mocked, AnyTrue() );
|
||||
REQUIRE( mocked.m_derefed[0] );
|
||||
REQUIRE( mocked.m_derefed[1] );
|
||||
REQUIRE( mocked.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[3] );
|
||||
REQUIRE_FALSE( mocked.m_derefed[4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("All/Any/None True matchers support types with ADL begin",
|
||||
"[approvals][matchers][quantifiers][templated]") {
|
||||
using Catch::Matchers::AllTrue;
|
||||
using Catch::Matchers::NoneTrue;
|
||||
using Catch::Matchers::AnyTrue;
|
||||
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<bool> const needs_adl{
|
||||
true, true, true, true, true };
|
||||
REQUIRE_THAT( needs_adl, AllTrue() );
|
||||
}
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<bool> const needs_adl{
|
||||
false, false, false, false, false };
|
||||
REQUIRE_THAT( needs_adl, NoneTrue() );
|
||||
}
|
||||
|
||||
SECTION( "Type requires ADL found begin and end" ) {
|
||||
unrelated::needs_ADL_begin<bool> const needs_adl{
|
||||
false, false, true, false, false };
|
||||
REQUIRE_THAT( needs_adl, AnyTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
// Range loop iterating over range with different types for begin and end is a
|
||||
// C++17 feature, and GCC refuses to compile such code unless the lang mode is
|
||||
// set to C++17 or later.
|
||||
#if defined(CATCH_CPP17_OR_GREATER)
|
||||
|
||||
TEST_CASE( "The quantifier range matchers support types with different types returned from begin and end",
|
||||
"[matchers][templated][quantifiers][approvals]" ) {
|
||||
using Catch::Matchers::AllMatch;
|
||||
using Catch::Matchers::AllTrue;
|
||||
using Catch::Matchers::AnyMatch;
|
||||
using Catch::Matchers::AnyTrue;
|
||||
using Catch::Matchers::NoneMatch;
|
||||
using Catch::Matchers::NoneTrue;
|
||||
|
||||
using Catch::Matchers::Predicate;
|
||||
|
||||
SECTION( "AllAnyNoneMatch" ) {
|
||||
has_different_begin_end_types<int> diff_types{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( diff_types, !AllMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 3;
|
||||
} ) ) );
|
||||
|
||||
REQUIRE_THAT( diff_types, AnyMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 2;
|
||||
} ) ) );
|
||||
|
||||
REQUIRE_THAT( diff_types, !NoneMatch( Predicate<int>( []( int elem ) {
|
||||
return elem < 3;
|
||||
} ) ) );
|
||||
}
|
||||
SECTION( "AllAnyNoneTrue" ) {
|
||||
has_different_begin_end_types<bool> diff_types{ false, false, true, false, false };
|
||||
|
||||
REQUIRE_THAT( diff_types, !AllTrue() );
|
||||
REQUIRE_THAT( diff_types, AnyTrue() );
|
||||
REQUIRE_THAT( diff_types, !NoneTrue() );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "RangeEquals supports ranges with different types returned from begin and end",
|
||||
"[matchers][templated][range][approvals] ") {
|
||||
using Catch::Matchers::RangeEquals;
|
||||
using Catch::Matchers::UnorderedRangeEquals;
|
||||
|
||||
has_different_begin_end_types<int> diff_types{ 1, 2, 3, 4, 5 };
|
||||
std::array<int, 5> arr1{ { 1, 2, 3, 4, 5 } }, arr2{ { 2, 3, 4, 5, 6 } };
|
||||
|
||||
REQUIRE_THAT( diff_types, RangeEquals( arr1 ) );
|
||||
REQUIRE_THAT( diff_types, RangeEquals( arr2, []( int l, int r ) {
|
||||
return l + 1 == r;
|
||||
} ) );
|
||||
REQUIRE_THAT( diff_types, UnorderedRangeEquals( diff_types ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "RangeContains supports ranges with different types returned from "
|
||||
"begin and end",
|
||||
"[matchers][templated][range][approvals]" ) {
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
has_different_begin_end_types<size_t> diff_types{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( diff_types, Contains( size_t( 3 ) ) );
|
||||
REQUIRE_THAT( diff_types, Contains( LessThanMatcher( size_t( 4 ) ) ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_CASE( "Usage of RangeEquals range matcher", "[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::RangeEquals;
|
||||
|
||||
// In these tests, the types are always the same - type conversion is in the next section
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "Empty container matches empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
CHECK_THAT( empty_vector, RangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Empty container does not match non-empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
const std::vector<int> non_empty_vector{ 1 };
|
||||
CHECK_THAT( empty_vector, !RangeEquals( non_empty_vector ) );
|
||||
// ...and in reverse
|
||||
CHECK_THAT( non_empty_vector, !RangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Two equal 1-length non-empty containers" ) {
|
||||
const std::array<int, 1> non_empty_array{ { 1 } };
|
||||
CHECK_THAT( non_empty_array, RangeEquals( non_empty_array ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
CHECK_THAT( array_a, RangeEquals( array_a ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
const std::array<int, 3> array_b{ { 2, 2, 3 } };
|
||||
const std::array<int, 3> array_c{ { 1, 2, 2 } };
|
||||
CHECK_THAT( array_a, !RangeEquals( array_b ) );
|
||||
CHECK_THAT( array_a, !RangeEquals( array_c ) );
|
||||
}
|
||||
SECTION( "Two non-equal-sized, non-empty containers (with same first "
|
||||
"elements)" ) {
|
||||
const std::vector<int> vector_a{ 1, 2, 3 };
|
||||
const std::vector<int> vector_b{ 1, 2, 3, 4 };
|
||||
CHECK_THAT( vector_a, !RangeEquals( vector_b ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Custom predicate" ) {
|
||||
|
||||
auto close_enough = []( int lhs, int rhs ) {
|
||||
return std::abs( lhs - rhs ) <= 1;
|
||||
};
|
||||
|
||||
SECTION( "Two equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 2, 3 } };
|
||||
const std::vector<int> vector_a_plus_1{ { 2, 3, 4 } };
|
||||
CHECK_THAT( vector_a, RangeEquals( vector_a_plus_1, close_enough ) );
|
||||
}
|
||||
SECTION( "Two non-equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 2, 3 } };
|
||||
const std::vector<int> vector_b{ { 3, 3, 4 } };
|
||||
CHECK_THAT( vector_a, !RangeEquals( vector_b, close_enough ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Ranges that need ADL begin/end" ) {
|
||||
unrelated::needs_ADL_begin<int> const
|
||||
needs_adl1{ 1, 2, 3, 4, 5 },
|
||||
needs_adl2{ 1, 2, 3, 4, 5 },
|
||||
needs_adl3{ 2, 3, 4, 5, 6 };
|
||||
|
||||
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl2 ) );
|
||||
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) {
|
||||
return l + 1 == r;
|
||||
} ) );
|
||||
}
|
||||
|
||||
SECTION("Check short-circuiting behaviour") {
|
||||
with_mocked_iterator_access<int> const mocked1{ 1, 2, 3, 4 };
|
||||
|
||||
SECTION( "Check short-circuits on failure" ) {
|
||||
std::array<int, 4> arr{ { 1, 2, 4, 4 } };
|
||||
|
||||
REQUIRE_THAT( mocked1, !RangeEquals( arr ) );
|
||||
REQUIRE( mocked1.m_derefed[0] );
|
||||
REQUIRE( mocked1.m_derefed[1] );
|
||||
REQUIRE( mocked1.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked1.m_derefed[3] );
|
||||
}
|
||||
SECTION("All elements are checked on success") {
|
||||
std::array<int, 4> arr{ { 1, 2, 3, 4 } };
|
||||
|
||||
REQUIRE_THAT( mocked1, RangeEquals( arr ) );
|
||||
REQUIRE( mocked1.m_derefed[0] );
|
||||
REQUIRE( mocked1.m_derefed[1] );
|
||||
REQUIRE( mocked1.m_derefed[2] );
|
||||
REQUIRE( mocked1.m_derefed[3] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Usage of UnorderedRangeEquals range matcher",
|
||||
"[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::UnorderedRangeEquals;
|
||||
|
||||
// In these tests, the types are always the same - type conversion is in the
|
||||
// next section
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "Empty container matches empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
CHECK_THAT( empty_vector, UnorderedRangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Empty container does not match non-empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
const std::vector<int> non_empty_vector{ 1 };
|
||||
CHECK_THAT( empty_vector,
|
||||
!UnorderedRangeEquals( non_empty_vector ) );
|
||||
// ...and in reverse
|
||||
CHECK_THAT( non_empty_vector,
|
||||
!UnorderedRangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Two equal 1-length non-empty containers" ) {
|
||||
const std::array<int, 1> non_empty_array{ { 1 } };
|
||||
CHECK_THAT( non_empty_array,
|
||||
UnorderedRangeEquals( non_empty_array ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
CHECK_THAT( array_a, UnorderedRangeEquals( array_a ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
const std::array<int, 3> array_b{ { 2, 2, 3 } };
|
||||
CHECK_THAT( array_a, !UnorderedRangeEquals( array_b ) );
|
||||
}
|
||||
SECTION( "Two non-equal-sized, non-empty containers" ) {
|
||||
const std::vector<int> vector_a{ 1, 2, 3 };
|
||||
const std::vector<int> vector_b{ 1, 2, 3, 4 };
|
||||
CHECK_THAT( vector_a, !UnorderedRangeEquals( vector_b ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Custom predicate" ) {
|
||||
|
||||
auto close_enough = []( int lhs, int rhs ) {
|
||||
return std::abs( lhs - rhs ) <= 1;
|
||||
};
|
||||
|
||||
SECTION( "Two equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 10, 20 } };
|
||||
const std::vector<int> vector_a_plus_1{ { 11, 21, 2 } };
|
||||
CHECK_THAT( vector_a,
|
||||
UnorderedRangeEquals( vector_a_plus_1, close_enough ) );
|
||||
}
|
||||
SECTION( "Two non-equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 10, 21 } };
|
||||
const std::vector<int> vector_b{ { 11, 21, 3 } };
|
||||
CHECK_THAT( vector_a,
|
||||
!UnorderedRangeEquals( vector_b, close_enough ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SECTION( "Ranges that need ADL begin/end" ) {
|
||||
unrelated::needs_ADL_begin<int> const
|
||||
needs_adl1{ 1, 2, 3, 4, 5 },
|
||||
needs_adl2{ 1, 2, 3, 4, 5 };
|
||||
|
||||
REQUIRE_THAT( needs_adl1, UnorderedRangeEquals( needs_adl2 ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the type given has a random access iterator type.
|
||||
*/
|
||||
template <typename Container>
|
||||
static constexpr bool ContainerIsRandomAccess( const Container& ) {
|
||||
using array_iter_category = typename std::iterator_traits<
|
||||
typename Container::iterator>::iterator_category;
|
||||
|
||||
return std::is_base_of<std::random_access_iterator_tag,
|
||||
array_iter_category>::value;
|
||||
}
|
||||
|
||||
TEST_CASE( "Type conversions of RangeEquals and similar",
|
||||
"[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::RangeEquals;
|
||||
using Catch::Matchers::UnorderedRangeEquals;
|
||||
|
||||
// In these test, we can always test RangeEquals and
|
||||
// UnorderedRangeEquals in the same way, since we're mostly
|
||||
// testing the template type deductions (and RangeEquals
|
||||
// implies UnorderedRangeEquals)
|
||||
|
||||
SECTION( "Container conversions" ) {
|
||||
SECTION( "Two equal containers of different container types" ) {
|
||||
const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
|
||||
const int c_array[3] = { 1, 2, 3 };
|
||||
CHECK_THAT( array_int_a, RangeEquals( c_array ) );
|
||||
CHECK_THAT( array_int_a, UnorderedRangeEquals( c_array ) );
|
||||
}
|
||||
SECTION( "Two equal containers of different container types "
|
||||
"(differ in array N)" ) {
|
||||
const std::array<int, 3> array_int_3{ { 1, 2, 3 } };
|
||||
const std::array<int, 4> array_int_4{ { 1, 2, 3, 4 } };
|
||||
CHECK_THAT( array_int_3, !RangeEquals( array_int_4 ) );
|
||||
CHECK_THAT( array_int_3, !UnorderedRangeEquals( array_int_4 ) );
|
||||
}
|
||||
SECTION( "Two equal containers of different container types and value "
|
||||
"types" ) {
|
||||
const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
|
||||
const std::vector<int> vector_char_a{ 1, 2, 3 };
|
||||
CHECK_THAT( array_int_a, RangeEquals( vector_char_a ) );
|
||||
CHECK_THAT( array_int_a, UnorderedRangeEquals( vector_char_a ) );
|
||||
}
|
||||
SECTION( "Two equal containers, one random access, one not" ) {
|
||||
const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
|
||||
const std::list<int> list_char_a{ 1, 2, 3 };
|
||||
|
||||
// Verify these types really are different in random access nature
|
||||
STATIC_REQUIRE( ContainerIsRandomAccess( array_int_a ) !=
|
||||
ContainerIsRandomAccess( list_char_a ) );
|
||||
|
||||
CHECK_THAT( array_int_a, RangeEquals( list_char_a ) );
|
||||
CHECK_THAT( array_int_a, UnorderedRangeEquals( list_char_a ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Value type" ) {
|
||||
SECTION( "Two equal containers of different value types" ) {
|
||||
const std::vector<int> vector_int_a{ 1, 2, 3 };
|
||||
const std::vector<char> vector_char_a{ 1, 2, 3 };
|
||||
CHECK_THAT( vector_int_a, RangeEquals( vector_char_a ) );
|
||||
CHECK_THAT( vector_int_a, UnorderedRangeEquals( vector_char_a ) );
|
||||
}
|
||||
SECTION( "Two non-equal containers of different value types" ) {
|
||||
const std::vector<int> vector_int_a{ 1, 2, 3 };
|
||||
const std::vector<char> vector_char_b{ 1, 2, 2 };
|
||||
CHECK_THAT( vector_int_a, !RangeEquals( vector_char_b ) );
|
||||
CHECK_THAT( vector_int_a, !UnorderedRangeEquals( vector_char_b ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Ranges with begin that needs ADL" ) {
|
||||
unrelated::needs_ADL_begin<int> a{ 1, 2, 3 }, b{ 3, 2, 1 };
|
||||
REQUIRE_THAT( a, !RangeEquals( b ) );
|
||||
REQUIRE_THAT( a, UnorderedRangeEquals( b ) );
|
||||
}
|
||||
|
||||
SECTION( "Custom predicate" ) {
|
||||
|
||||
auto close_enough = []( int lhs, int rhs ) {
|
||||
return std::abs( lhs - rhs ) <= 1;
|
||||
};
|
||||
|
||||
SECTION( "Two equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 2, 3 } };
|
||||
const std::array<char, 3> array_a_plus_1{ { 2, 3, 4 } };
|
||||
CHECK_THAT( vector_a,
|
||||
RangeEquals( array_a_plus_1, close_enough ) );
|
||||
CHECK_THAT( vector_a,
|
||||
UnorderedRangeEquals( array_a_plus_1, close_enough ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE( "INFO and WARN do not abort tests", "[messages][.]" ) {
|
||||
INFO( "this is a " << "message" ); // This should output the message if a failure occurs
|
||||
WARN( "this is a " << "warning" ); // This should always output the message but then continue
|
||||
}
|
||||
|
||||
TEST_CASE( "#1455 - INFO and WARN can start with a linebreak", "[messages][.]" ) {
|
||||
// Previously these would be hidden from the console reporter output,
|
||||
// because it would fail at properly reflowing the text
|
||||
INFO( "\nThis info message starts with a linebreak" );
|
||||
WARN( "\nThis warning message starts with a linebreak" );
|
||||
}
|
||||
|
||||
TEST_CASE( "SUCCEED counts as a test pass", "[messages]" ) {
|
||||
SUCCEED( "this is a " << "success" );
|
||||
}
|
||||
|
||||
TEST_CASE( "INFO gets logged on failure", "[failing][messages][.]" ) {
|
||||
INFO( "this message should be logged" );
|
||||
INFO( "so should this" );
|
||||
int a = 2;
|
||||
REQUIRE( a == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "INFO gets logged on failure, even if captured before successful assertions", "[failing][messages][.]" ) {
|
||||
INFO( "this message may be logged later" );
|
||||
int a = 2;
|
||||
CHECK( a == 2 );
|
||||
|
||||
INFO( "this message should be logged" );
|
||||
|
||||
CHECK( a == 1 );
|
||||
|
||||
INFO( "and this, but later" );
|
||||
|
||||
CHECK( a == 0 );
|
||||
|
||||
INFO( "but not this" );
|
||||
|
||||
CHECK( a == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE( "FAIL aborts the test", "[failing][messages][.]" ) {
|
||||
FAIL( "This is a " << "failure" ); // This should output the message and abort
|
||||
WARN( "We should never see this");
|
||||
}
|
||||
|
||||
TEST_CASE( "FAIL_CHECK does not abort the test", "[failing][messages][.]" ) {
|
||||
FAIL_CHECK( "This is a " << "failure" ); // This should output the message then continue
|
||||
WARN( "This message appears in the output");
|
||||
}
|
||||
|
||||
TEST_CASE( "FAIL does not require an argument", "[failing][messages][.]" ) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
TEST_CASE( "SUCCEED does not require an argument", "[messages][.]" ) {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE( "Output from all sections is reported", "[failing][messages][.]" ) {
|
||||
SECTION( "one" ) {
|
||||
FAIL( "Message from section one" );
|
||||
}
|
||||
|
||||
SECTION( "two" ) {
|
||||
FAIL( "Message from section two" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Standard output from all sections is reported", "[messages][.]" ) {
|
||||
SECTION( "one" ) {
|
||||
std::cout << "Message from section one" << std::endl;
|
||||
}
|
||||
|
||||
SECTION( "two" ) {
|
||||
std::cout << "Message from section two" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Standard error is reported and redirected", "[messages][.][approvals]" ) {
|
||||
SECTION( "std::cerr" ) {
|
||||
std::cerr << "Write to std::cerr" << std::endl;
|
||||
}
|
||||
SECTION( "std::clog" ) {
|
||||
std::clog << "Write to std::clog" << std::endl;
|
||||
}
|
||||
SECTION( "Interleaved writes to cerr and clog" ) {
|
||||
std::cerr << "Inter";
|
||||
std::clog << "leaved";
|
||||
std::cerr << ' ';
|
||||
std::clog << "writes";
|
||||
std::cerr << " to error";
|
||||
std::clog << " streams" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "INFO is reset for each loop", "[messages][failing][.]" ) {
|
||||
for( int i=0; i<100; i++ )
|
||||
{
|
||||
INFO( "current counter " << i );
|
||||
CAPTURE( i );
|
||||
REQUIRE( i < 10 );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "The NO_FAIL macro reports a failure but does not fail the test", "[messages]" ) {
|
||||
CHECK_NOFAIL( 1 == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE( "just info", "[info][isolated info][messages]" ) {
|
||||
INFO( "this should never be seen" );
|
||||
}
|
||||
TEST_CASE( "just failure", "[fail][isolated info][.][messages]" ) {
|
||||
FAIL( "Previous info should not be seen" );
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "sends information to INFO", "[.][failing]" ) {
|
||||
INFO( "hi" );
|
||||
int i = 7;
|
||||
CAPTURE( i );
|
||||
REQUIRE( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "Pointers can be converted to strings", "[messages][.][approvals]" ) {
|
||||
int p;
|
||||
WARN( "actual address of p: " << &p );
|
||||
WARN( "toString(p): " << ::Catch::Detail::stringify( &p ) );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void unscoped_info( T msg ) {
|
||||
UNSCOPED_INFO( msg );
|
||||
}
|
||||
|
||||
TEST_CASE( "just unscoped info", "[unscoped][info]" ) {
|
||||
unscoped_info( "this should NOT be seen" );
|
||||
unscoped_info( "this also should NOT be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "just failure after unscoped info", "[failing][.][unscoped][info]" ) {
|
||||
FAIL( "previous unscoped info SHOULD not be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "print unscoped info if passing unscoped info is printed", "[unscoped][info]" ) {
|
||||
unscoped_info( "this MAY be seen IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "prints unscoped info on failure", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this SHOULD be seen" );
|
||||
unscoped_info( "this SHOULD also be seen" );
|
||||
REQUIRE( false );
|
||||
unscoped_info( "but this should NOT be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "not prints unscoped info from previous failures", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this MAY be seen only for the FIRST assertion IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
unscoped_info( "this MAY be seen only for the SECOND assertion IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
unscoped_info( "this SHOULD be seen" );
|
||||
REQUIRE( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "prints unscoped info only for the first assertion", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this SHOULD be seen only ONCE" );
|
||||
CHECK( false );
|
||||
CHECK( true );
|
||||
unscoped_info( "this MAY also be seen only ONCE IF info is printed for passing assertions" );
|
||||
CHECK( true );
|
||||
CHECK( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "stacks unscoped info in loops", "[failing][.][unscoped][info]" ) {
|
||||
UNSCOPED_INFO("Count 1 to 3...");
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
unscoped_info(i);
|
||||
}
|
||||
CHECK( false );
|
||||
|
||||
UNSCOPED_INFO("Count 4 to 6...");
|
||||
for (int i = 4; i <= 6; i++) {
|
||||
unscoped_info(i);
|
||||
}
|
||||
CHECK( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "mix info, unscoped info and warning", "[unscoped][info]" ) {
|
||||
INFO("info");
|
||||
unscoped_info("unscoped info");
|
||||
WARN("and warn may mix");
|
||||
WARN("they are not cleared after warnings");
|
||||
}
|
||||
|
||||
TEST_CASE( "CAPTURE can deal with complex expressions", "[messages][capture]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int c = 3;
|
||||
CAPTURE( a, b, c, a + b, a+b, c > b, a == 1 );
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-value" // In (1, 2), the "1" is unused ...
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-value" // All the comma operators are side-effect free
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4709) // comma in indexing operator
|
||||
#endif
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct helper_1436 {
|
||||
helper_1436(T1 t1_, T2 t2_):
|
||||
t1{ t1_ },
|
||||
t2{ t2_ }
|
||||
{}
|
||||
T1 t1;
|
||||
T2 t2;
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
std::ostream& operator<<(std::ostream& out, helper_1436<T1, T2> const& helper) {
|
||||
out << "{ " << helper.t1 << ", " << helper.t2 << " }";
|
||||
return out;
|
||||
}
|
||||
|
||||
// Clang and gcc have different names for this warning, and clang also
|
||||
// warns about an unused value. This warning must be disabled for C++20.
|
||||
#if defined(__GNUG__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas"
|
||||
#pragma GCC diagnostic ignored "-Wcomma-subscript"
|
||||
#elif defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-comma-subscript"
|
||||
#pragma clang diagnostic ignored "-Wunused-value"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
struct custom_index_op {
|
||||
constexpr custom_index_op( std::initializer_list<T> ) {}
|
||||
constexpr T operator[]( size_t ) { return T{}; }
|
||||
#if defined( __cpp_multidimensional_subscript ) && \
|
||||
__cpp_multidimensional_subscript >= 202110L
|
||||
constexpr T operator[]( size_t, size_t, size_t ) const noexcept {
|
||||
return T{};
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("CAPTURE can deal with complex expressions involving commas", "[messages][capture]") {
|
||||
CAPTURE(custom_index_op<int>{1, 2, 3}[0, 1, 2],
|
||||
custom_index_op<int>{1, 2, 3}[(0, 1)],
|
||||
custom_index_op<int>{1, 2, 3}[0]);
|
||||
CAPTURE((helper_1436<int, int>{12, -12}),
|
||||
(helper_1436<int, int>(-12, 12)));
|
||||
CAPTURE( (1, 2), (2, 3) );
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
#ifdef __GNUG__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
TEST_CASE("CAPTURE parses string and character constants", "[messages][capture]") {
|
||||
CAPTURE(("comma, in string", "escaped, \", "), "single quote in string,',", "some escapes, \\,\\\\");
|
||||
CAPTURE("some, ), unmatched, } prenheses {[<");
|
||||
CAPTURE('"', '\'', ',', '}', ')', '(', '{');
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
TEST_CASE( "INFO and UNSCOPED_INFO can stream multiple arguments",
|
||||
"[messages][info][.failing]" ) {
|
||||
INFO( "This info"
|
||||
<< " has multiple"
|
||||
<< " parts." );
|
||||
UNSCOPED_INFO( "This unscoped info"
|
||||
<< " has multiple"
|
||||
<< " parts." );
|
||||
FAIL( "Show infos!" );
|
||||
}
|
||||
+565
@@ -0,0 +1,565 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <catch2/internal/catch_config_wchar.hpp>
|
||||
#include <catch2/internal/catch_windows_h_proxy.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic ignored "-Wc++98-compat"
|
||||
# pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
||||
#endif
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <cerrno>
|
||||
#include <limits>
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
|
||||
namespace {
|
||||
|
||||
static const char* makeString(bool makeNull) {
|
||||
return makeNull ? nullptr : "valid string";
|
||||
}
|
||||
static bool testCheckedIf(bool flag) {
|
||||
CHECKED_IF(flag)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
static bool testCheckedElse(bool flag) {
|
||||
CHECKED_ELSE(flag)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned int Factorial(unsigned int number) {
|
||||
return number > 1 ? Factorial(number - 1) * number : 1;
|
||||
}
|
||||
|
||||
static int f() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void manuallyRegisteredTestFunction() {
|
||||
SUCCEED("was called");
|
||||
}
|
||||
|
||||
struct AutoTestReg {
|
||||
AutoTestReg() {
|
||||
REGISTER_TEST_CASE(manuallyRegisteredTestFunction, "ManuallyRegistered");
|
||||
}
|
||||
};
|
||||
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
static AutoTestReg autoTestReg;
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
template<typename T>
|
||||
struct Foo {
|
||||
size_t size() { return 0; }
|
||||
};
|
||||
|
||||
template<typename T, size_t S>
|
||||
struct Bar {
|
||||
size_t size() { return S; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE( "random SECTION tests", "[.][sections][failing]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
||||
SECTION( "doesn't equal" ) {
|
||||
REQUIRE( a != b );
|
||||
REQUIRE( b != a );
|
||||
}
|
||||
|
||||
SECTION( "not equal" ) {
|
||||
REQUIRE( a != b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "nested SECTION tests", "[.][sections][failing]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
||||
SECTION( "doesn't equal" ) {
|
||||
REQUIRE( a != b );
|
||||
REQUIRE( b != a );
|
||||
|
||||
SECTION( "not equal" ) {
|
||||
REQUIRE( a != b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "more nested SECTION tests", "[sections][failing][.]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
||||
SECTION( "doesn't equal" ) {
|
||||
SECTION( "equal" ) {
|
||||
REQUIRE( a == b );
|
||||
}
|
||||
|
||||
SECTION( "not equal" ) {
|
||||
REQUIRE( a != b );
|
||||
}
|
||||
SECTION( "less than" ) {
|
||||
REQUIRE( a < b );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "even more nested SECTION tests", "[sections]" ) {
|
||||
SECTION( "c" ) {
|
||||
SECTION( "d (leaf)" ) {
|
||||
SUCCEED(); // avoid failing due to no tests
|
||||
}
|
||||
|
||||
SECTION( "e (leaf)" ) {
|
||||
SUCCEED(); // avoid failing due to no tests
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "f (leaf)" ) {
|
||||
SUCCEED(); // avoid failing due to no tests
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "looped SECTION tests", "[.][failing][sections]" ) {
|
||||
int a = 1;
|
||||
|
||||
for( int b = 0; b < 10; ++b ) {
|
||||
DYNAMIC_SECTION( "b is currently: " << b ) {
|
||||
CHECK( b > a );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "looped tests", "[.][failing]" ) {
|
||||
static const int fib[] = { 1, 1, 2, 3, 5, 8, 13, 21 };
|
||||
|
||||
for( std::size_t i=0; i < sizeof(fib)/sizeof(int); ++i ) {
|
||||
INFO( "Testing if fib[" << i << "] (" << fib[i] << ") is even" );
|
||||
CHECK( ( fib[i] % 2 ) == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Sends stuff to stdout and stderr", "[.]" ) {
|
||||
std::cout << "A string sent directly to stdout" << std::endl;
|
||||
std::cerr << "A string sent directly to stderr" << std::endl;
|
||||
std::clog << "A string sent to stderr via clog" << std::endl;
|
||||
}
|
||||
|
||||
TEST_CASE( "null strings" ) {
|
||||
REQUIRE( makeString( false ) != static_cast<char*>(nullptr));
|
||||
REQUIRE( makeString( true ) == static_cast<char*>(nullptr));
|
||||
}
|
||||
|
||||
TEST_CASE( "checkedIf" ) {
|
||||
REQUIRE( testCheckedIf( true ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "checkedIf, failing", "[failing][.]" ) {
|
||||
REQUIRE( testCheckedIf( false ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "checkedElse" ) {
|
||||
REQUIRE( testCheckedElse( true ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "checkedElse, failing", "[failing][.]" ) {
|
||||
REQUIRE( testCheckedElse( false ) );
|
||||
}
|
||||
|
||||
TEST_CASE("Testing checked-if", "[checked-if]") {
|
||||
CHECKED_IF(true) {
|
||||
SUCCEED();
|
||||
}
|
||||
CHECKED_IF(false) {
|
||||
FAIL();
|
||||
}
|
||||
CHECKED_ELSE(true) {
|
||||
FAIL();
|
||||
}
|
||||
CHECKED_ELSE(false) {
|
||||
SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Testing checked-if 2", "[checked-if][!shouldfail]") {
|
||||
CHECKED_IF(true) {
|
||||
FAIL();
|
||||
}
|
||||
// If the checked if is not entered, this passes and the test
|
||||
// fails, because of the [!shouldfail] tag.
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("Testing checked-if 3", "[checked-if][!shouldfail]") {
|
||||
CHECKED_ELSE(false) {
|
||||
FAIL();
|
||||
}
|
||||
// If the checked false is not entered, this passes and the test
|
||||
// fails, because of the [!shouldfail] tag.
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
TEST_CASE("Testing checked-if 4", "[checked-if][!shouldfail]") {
|
||||
CHECKED_ELSE(true) {}
|
||||
throw std::runtime_error("Uncaught exception should fail!");
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
TEST_CASE("Testing checked-if 5", "[checked-if][!shouldfail]") {
|
||||
CHECKED_ELSE(false) {}
|
||||
throw std::runtime_error("Uncaught exception should fail!");
|
||||
}
|
||||
|
||||
TEST_CASE( "xmlentitycheck" ) {
|
||||
SECTION( "embedded xml: <test>it should be possible to embed xml characters, such as <, \" or &, or even whole <xml>documents</xml> within an attribute</test>" ) {
|
||||
SUCCEED(); // We need this here to stop it failing due to no tests
|
||||
}
|
||||
SECTION( "encoded chars: these should all be encoded: &&&\"\"\"<<<&\"<<&\"" ) {
|
||||
SUCCEED(); // We need this here to stop it failing due to no tests
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "send a single char to INFO", "[failing][.]" ) {
|
||||
INFO(3);
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
TEST_CASE( "Factorials are computed", "[factorial]" ) {
|
||||
REQUIRE( Factorial(0) == 1 );
|
||||
REQUIRE( Factorial(1) == 1 );
|
||||
REQUIRE( Factorial(2) == 2 );
|
||||
REQUIRE( Factorial(3) == 6 );
|
||||
REQUIRE( Factorial(10) == 3628800 );
|
||||
}
|
||||
|
||||
TEST_CASE( "An empty test with no assertions", "[empty]" ) {}
|
||||
|
||||
TEST_CASE( "Nice descriptive name", "[tag1][tag2][tag3][.]" ) {
|
||||
WARN( "This one ran" );
|
||||
}
|
||||
TEST_CASE( "first tag", "[tag1]" ) {}
|
||||
TEST_CASE( "second tag", "[tag2]" ) {}
|
||||
|
||||
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
|
||||
|
||||
std::vector<int> v( 5 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
SECTION( "resizing bigger changes size and capacity" ) {
|
||||
v.resize( 10 );
|
||||
|
||||
REQUIRE( v.size() == 10 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "resizing smaller changes size but not capacity" ) {
|
||||
v.resize( 0 );
|
||||
|
||||
REQUIRE( v.size() == 0 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
SECTION( "We can use the 'swap trick' to reset the capacity" ) {
|
||||
std::vector<int> empty;
|
||||
empty.swap( v );
|
||||
|
||||
REQUIRE( v.capacity() == 0 );
|
||||
}
|
||||
}
|
||||
SECTION( "reserving bigger changes capacity but not size" ) {
|
||||
v.reserve( 10 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "reserving smaller does not change size or capacity" ) {
|
||||
v.reserve( 0 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE( "TemplateTest: vectors can be sized and resized", "[vector][template]", int, float, std::string, (std::tuple<int,float>) ) {
|
||||
|
||||
std::vector<TestType> v( 5 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
SECTION( "resizing bigger changes size and capacity" ) {
|
||||
v.resize( 10 );
|
||||
|
||||
REQUIRE( v.size() == 10 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "resizing smaller changes size but not capacity" ) {
|
||||
v.resize( 0 );
|
||||
|
||||
REQUIRE( v.size() == 0 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
SECTION( "We can use the 'swap trick' to reset the capacity" ) {
|
||||
std::vector<TestType> empty;
|
||||
empty.swap( v );
|
||||
|
||||
REQUIRE( v.capacity() == 0 );
|
||||
}
|
||||
}
|
||||
SECTION( "reserving bigger changes capacity but not size" ) {
|
||||
v.reserve( 10 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "reserving smaller does not change size or capacity" ) {
|
||||
v.reserve( 0 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_SIG("TemplateTestSig: vectors can be sized and resized", "[vector][template][nttp]", ((typename TestType, int V), TestType, V), (int,5), (float,4), (std::string,15), ((std::tuple<int, float>), 6)) {
|
||||
|
||||
std::vector<TestType> v(V);
|
||||
|
||||
REQUIRE(v.size() == V);
|
||||
REQUIRE(v.capacity() >= V);
|
||||
|
||||
SECTION("resizing bigger changes size and capacity") {
|
||||
v.resize(2 * V);
|
||||
|
||||
REQUIRE(v.size() == 2 * V);
|
||||
REQUIRE(v.capacity() >= 2 * V);
|
||||
}
|
||||
SECTION("resizing smaller changes size but not capacity") {
|
||||
v.resize(0);
|
||||
|
||||
REQUIRE(v.size() == 0);
|
||||
REQUIRE(v.capacity() >= V);
|
||||
|
||||
SECTION("We can use the 'swap trick' to reset the capacity") {
|
||||
std::vector<TestType> empty;
|
||||
empty.swap(v);
|
||||
|
||||
REQUIRE(v.capacity() == 0);
|
||||
}
|
||||
}
|
||||
SECTION("reserving bigger changes capacity but not size") {
|
||||
v.reserve(2 * V);
|
||||
|
||||
REQUIRE(v.size() == V);
|
||||
REQUIRE(v.capacity() >= 2 * V);
|
||||
}
|
||||
SECTION("reserving smaller does not change size or capacity") {
|
||||
v.reserve(0);
|
||||
|
||||
REQUIRE(v.size() == V);
|
||||
REQUIRE(v.capacity() >= V);
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE("A Template product test case", "[template][product]", (std::vector, Foo), (int, float)) {
|
||||
TestType x;
|
||||
REQUIRE(x.size() == 0);
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_SIG("A Template product test case with array signature", "[template][product][nttp]", ((typename T, size_t S), T, S), (std::array, Bar), ((int, 9), (float, 42))) {
|
||||
TestType x;
|
||||
REQUIRE(x.size() > 0);
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE("Product with differing arities", "[template][product]", std::tuple, (int, (int, double), (int, double, float))) {
|
||||
REQUIRE(std::tuple_size<TestType>::value >= 1);
|
||||
}
|
||||
|
||||
using MyTypes = std::tuple<int, char, float>;
|
||||
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std::tuple", "[template][list]", MyTypes)
|
||||
{
|
||||
REQUIRE(sizeof(TestType) > 0);
|
||||
}
|
||||
|
||||
struct NonDefaultConstructibleType {
|
||||
NonDefaultConstructibleType() = delete;
|
||||
};
|
||||
|
||||
using MyNonDefaultConstructibleTypes = std::tuple<NonDefaultConstructibleType, float>;
|
||||
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside non-default-constructible std::tuple", "[template][list]", MyNonDefaultConstructibleTypes)
|
||||
{
|
||||
REQUIRE(sizeof(TestType) > 0);
|
||||
}
|
||||
|
||||
struct NonCopyableAndNonMovableType {
|
||||
NonCopyableAndNonMovableType() = default;
|
||||
|
||||
NonCopyableAndNonMovableType(NonCopyableAndNonMovableType const &) = delete;
|
||||
NonCopyableAndNonMovableType(NonCopyableAndNonMovableType &&) = delete;
|
||||
auto operator=(NonCopyableAndNonMovableType const &) -> NonCopyableAndNonMovableType & = delete;
|
||||
auto operator=(NonCopyableAndNonMovableType &&) -> NonCopyableAndNonMovableType & = delete;
|
||||
};
|
||||
|
||||
using NonCopyableAndNonMovableTypes = std::tuple<NonCopyableAndNonMovableType, float>;
|
||||
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside non-copyable and non-movable std::tuple", "[template][list]", NonCopyableAndNonMovableTypes)
|
||||
{
|
||||
REQUIRE(sizeof(TestType) > 0);
|
||||
}
|
||||
|
||||
// https://github.com/philsquared/Catch/issues/166
|
||||
TEST_CASE("A couple of nested sections followed by a failure", "[failing][.]") {
|
||||
SECTION("Outer")
|
||||
SECTION("Inner")
|
||||
SUCCEED("that's not flying - that's failing in style");
|
||||
|
||||
FAIL("to infinity and beyond");
|
||||
}
|
||||
|
||||
TEST_CASE("not allowed", "[!throws]") {
|
||||
// This test case should not be included if you run with -e on the command line
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE( "Tabs and newlines show in output", "[.][whitespace][failing]" ) {
|
||||
|
||||
// Based on issue #242
|
||||
std::string s1 = "if ($b == 10) {\n\t\t$a\t= 20;\n}";
|
||||
std::string s2 = "if ($b == 10) {\n\t$a = 20;\n}\n";
|
||||
CHECK( s1 == s2 );
|
||||
}
|
||||
|
||||
|
||||
#if defined(CATCH_CONFIG_WCHAR)
|
||||
TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) {
|
||||
const wchar_t * const s = L"wide load";
|
||||
std::string result = ::Catch::Detail::stringify( s );
|
||||
CHECK( result == "\"wide load\"" );
|
||||
}
|
||||
|
||||
TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[toString]" ) {
|
||||
const wchar_t * s = L"wide load";
|
||||
std::string result = ::Catch::Detail::stringify( s );
|
||||
CHECK( result == "\"wide load\"" );
|
||||
}
|
||||
|
||||
TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) {
|
||||
auto const s = const_cast<wchar_t*>( L"wide load" );
|
||||
std::string result = ::Catch::Detail::stringify( s );
|
||||
CHECK( result == "\"wide load\"" );
|
||||
}
|
||||
|
||||
TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
|
||||
auto s = const_cast<wchar_t*>( L"wide load" );
|
||||
std::string result = ::Catch::Detail::stringify( s );
|
||||
CHECK( result == "\"wide load\"" );
|
||||
}
|
||||
#endif // CATCH_CONFIG_WCHAR
|
||||
|
||||
TEST_CASE( "long long" ) {
|
||||
constexpr long long l = std::numeric_limits<long long>::max();
|
||||
|
||||
REQUIRE( l == std::numeric_limits<long long>::max() );
|
||||
}
|
||||
|
||||
TEST_CASE( "This test 'should' fail but doesn't", "[.][failing][!shouldfail]" ) {
|
||||
SUCCEED( "oops!" );
|
||||
}
|
||||
|
||||
TEST_CASE( "# A test name that starts with a #" ) {
|
||||
SUCCEED( "yay" );
|
||||
}
|
||||
|
||||
TEST_CASE( "#835 -- errno should not be touched by Catch2", "[.][failing][!shouldfail]" ) {
|
||||
errno = 1;
|
||||
// Check that reporting failed test doesn't change errno.
|
||||
CHECK(f() == 0);
|
||||
// We want to avoid expanding `errno` macro in assertion, because
|
||||
// we capture the expression after macro expansion, and would have
|
||||
// to normalize the ways different platforms spell `errno`.
|
||||
const auto errno_after = errno;
|
||||
REQUIRE(errno_after == 1);
|
||||
}
|
||||
|
||||
TEST_CASE( "#961 -- Dynamically created sections should all be reported", "[.]" ) {
|
||||
for (char i = '0'; i < '5'; ++i) {
|
||||
SECTION(std::string("Looped section ") + i) {
|
||||
SUCCEED( "Everything is OK" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "#1175 - Hidden Test", "[.]" ) {
|
||||
// Just for checking that hidden test is not listed by default
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE_SIG("#1954 - 7 arg template test case sig compiles", "[regression][.compilation]",
|
||||
((int Tnx, int Tnu, int Tny, int Tph, int Tch, int Tineq, int Teq), Tnx, Tnu, Tny, Tph, Tch, Tineq, Teq),
|
||||
(1, 1, 1, 1, 1, 0, 0), (5, 1, 1, 1, 1, 0, 0), (5, 3, 1, 1, 1, 0, 0)) {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE("Same test name but with different tags is fine", "[.approvals][some-tag]") {}
|
||||
TEST_CASE("Same test name but with different tags is fine", "[.approvals][other-tag]") {}
|
||||
|
||||
// MinGW doesn't support __try, and Clang has only very partial support
|
||||
#if defined(_MSC_VER)
|
||||
void throw_and_catch()
|
||||
{
|
||||
__try {
|
||||
RaiseException(0xC0000005, 0, 0, NULL);
|
||||
}
|
||||
__except (1)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Validate SEH behavior - handled", "[approvals][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]")
|
||||
{
|
||||
// Validate that Catch2 framework correctly handles tests raising and handling SEH exceptions.
|
||||
throw_and_catch();
|
||||
}
|
||||
|
||||
void throw_no_catch()
|
||||
{
|
||||
RaiseException(0xC0000005, 0, 0, NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Validate SEH behavior - unhandled", "[.approvals][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]")
|
||||
{
|
||||
// Validate that Catch2 framework correctly handles tests raising and not handling SEH exceptions.
|
||||
throw_no_catch();
|
||||
}
|
||||
|
||||
static LONG CALLBACK dummyExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
TEST_CASE("Validate SEH behavior - no crash for stack unwinding", "[approvals][!throws][!shouldfail][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]")
|
||||
{
|
||||
// Trigger stack unwinding with SEH top-level filter changed and validate the test fails expectedly with no application crash
|
||||
SetUnhandledExceptionFilter(dummyExceptionFilter);
|
||||
throw 1;
|
||||
}
|
||||
|
||||
#endif // _MSC_VER
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
|
||||
// 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_macros.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE( "tests can be skipped dynamically at runtime", "[skipping]" ) {
|
||||
SKIP();
|
||||
FAIL( "this is not reached" );
|
||||
}
|
||||
|
||||
TEST_CASE( "skipped tests can optionally provide a reason", "[skipping]" ) {
|
||||
const int answer = 43;
|
||||
SKIP( "skipping because answer = " << answer );
|
||||
FAIL( "this is not reached" );
|
||||
}
|
||||
|
||||
TEST_CASE( "sections can be skipped dynamically at runtime", "[skipping]" ) {
|
||||
SECTION( "not skipped" ) { SUCCEED(); }
|
||||
SECTION( "skipped" ) { SKIP(); }
|
||||
SECTION( "also not skipped" ) { SUCCEED(); }
|
||||
}
|
||||
|
||||
TEST_CASE( "nested sections can be skipped dynamically at runtime",
|
||||
"[skipping]" ) {
|
||||
SECTION( "A" ) { std::cout << "a"; }
|
||||
SECTION( "B" ) {
|
||||
SECTION( "B1" ) { std::cout << "b1"; }
|
||||
SECTION( "B2" ) { SKIP(); }
|
||||
}
|
||||
std::cout << "!\n";
|
||||
}
|
||||
|
||||
TEST_CASE( "dynamic skipping works with generators", "[skipping]" ) {
|
||||
const int answer = GENERATE( 41, 42, 43 );
|
||||
if ( answer != 42 ) { SKIP( "skipping because answer = " << answer ); }
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_CASE( "failed assertions before SKIP cause test case to fail",
|
||||
"[skipping][!shouldfail]" ) {
|
||||
CHECK( 3 == 4 );
|
||||
SKIP();
|
||||
}
|
||||
|
||||
TEST_CASE( "a succeeding test can still be skipped",
|
||||
"[skipping][!shouldfail]" ) {
|
||||
SUCCEED();
|
||||
SKIP();
|
||||
}
|
||||
|
||||
TEST_CASE( "failing in some unskipped sections causes entire test case to fail",
|
||||
"[skipping][!shouldfail]" ) {
|
||||
SECTION( "skipped" ) { SKIP(); }
|
||||
SECTION( "not skipped" ) { FAIL(); }
|
||||
}
|
||||
|
||||
TEST_CASE( "failing for some generator values causes entire test case to fail",
|
||||
"[skipping][!shouldfail]" ) {
|
||||
int i = GENERATE( 1, 2, 3, 4 );
|
||||
if ( i % 2 == 0 ) {
|
||||
SKIP();
|
||||
} else {
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class test_skip_generator : public Catch::Generators::IGenerator<int> {
|
||||
public:
|
||||
explicit test_skip_generator() { SKIP( "This generator is empty" ); }
|
||||
|
||||
auto get() const -> int const& override {
|
||||
static constexpr int value = 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
auto next() -> bool override { return false; }
|
||||
};
|
||||
|
||||
static auto make_test_skip_generator()
|
||||
-> Catch::Generators::GeneratorWrapper<int> {
|
||||
return { new test_skip_generator() };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "Empty generators can SKIP in constructor", "[skipping]" ) {
|
||||
// The generator signals emptiness with `SKIP`
|
||||
auto sample = GENERATE( make_test_skip_generator() );
|
||||
// This assertion would fail, but shouldn't trigger
|
||||
REQUIRE( sample == 0 );
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user