mirror of
https://github.com/catchorg/Catch2.git
synced 2026-08-06 13:44:22 +02:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 191fa38c9b | |||
| dd94b9a780 | |||
| 9f7c9f6872 | |||
| 919385f704 | |||
| 15d52830ee | |||
| 9ec44dd62b | |||
| 675f9eaeb1 | |||
| bcfb10e498 | |||
| b7e0310fbe | |||
| 6d4ea62200 | |||
| 195231c59a | |||
| 3a865e8c0f | |||
| 69e0473f6e |
+1
-1
@@ -35,7 +35,7 @@ if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
endif()
|
||||
|
||||
project(Catch2
|
||||
VERSION 3.15.0 # CML version placeholder, don't delete
|
||||
VERSION 3.15.2 # CML version placeholder, don't delete
|
||||
LANGUAGES CXX
|
||||
HOMEPAGE_URL "https://github.com/catchorg/Catch2"
|
||||
DESCRIPTION "A modern, C++-native, unit test framework."
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ The ```CHECK``` family are equivalent but execution continues in the same test c
|
||||
Evaluates the expression and records the result. If an exception is thrown, it is caught, reported, and counted as a failure. These are the macros you will use most of the time.
|
||||
|
||||
Examples:
|
||||
```
|
||||
```cpp
|
||||
CHECK( str == "string value" );
|
||||
CHECK( thisReturnsTrue() );
|
||||
REQUIRE( i == 42 );
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
[Writing documentation](#writing-documentation)<br>
|
||||
[Writing code](#writing-code)<br>
|
||||
[CoC](#coc)<br>
|
||||
[Using LLMs when contributing](#using-llms-when-contributing)<br>
|
||||
|
||||
|
||||
So you want to contribute something to Catch2? That's great! Whether it's
|
||||
a bug fix, a new feature, support for additional compilers - or just
|
||||
@@ -332,6 +334,19 @@ When adding new `CATCH_CONFIG` option, there are multiple places to edit:
|
||||
This project has a [CoC](../CODE_OF_CONDUCT.md). Please adhere to it
|
||||
while contributing to Catch2.
|
||||
|
||||
|
||||
## Using LLMs when contributing
|
||||
|
||||
I do not care whether you used LLM for your contribution. What I care
|
||||
about is the quality of the contribution, not whether you made it through
|
||||
prompting LLM, letting GAs run wild, dictated it into the computer, wrote
|
||||
it using your nose or used butterflies to flip the correct bits.
|
||||
|
||||
The flipside of this is that I am also not going to iterate your LLM for
|
||||
you. If a PR looks LLM generated and does not pass the muster to be merged
|
||||
as-is, I am going to close it.
|
||||
|
||||
|
||||
-----------
|
||||
|
||||
_This documentation will always be in-progress as new information comes
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
# Release notes
|
||||
**Contents**<br>
|
||||
[3.15.2](#3152)<br>
|
||||
[3.15.1](#3151)<br>
|
||||
[3.15.0](#3150)<br>
|
||||
[3.14.0](#3140)<br>
|
||||
[3.13.0](#3130)<br>
|
||||
@@ -75,6 +77,23 @@
|
||||
[Even Older versions](#even-older-versions)<br>
|
||||
|
||||
|
||||
## 3.15.2
|
||||
|
||||
### Fixes
|
||||
* Fixed `--warn InfiniteGenerators` triggering even if the generator was limited to specific element via path filtering.
|
||||
* Fixed `-Wunused-parameter` triggering in `-fnoexceptions` builds.
|
||||
|
||||
### Improvements
|
||||
* `catch_discover_tests` can handle cases where the binary prints out non-Catch2 output due to global constructors (#3162)
|
||||
|
||||
|
||||
## 3.15.1
|
||||
|
||||
### Fixes
|
||||
* Fixed potential OOB access when looking for start of broken UTF-8 sequence during linebreaking (#3096)
|
||||
* Fixed `TEMPLATE_LIST_TEST_CASE_METHOD` and `CATCH_TEMPLATE_PRODUCT_TEST_CASE` potentially causing ODR violations (#3161)
|
||||
|
||||
|
||||
## 3.15.0
|
||||
|
||||
### Fixes
|
||||
|
||||
@@ -36,10 +36,12 @@ Tags allow an arbitrary number of additional strings to be associated with a tes
|
||||
|
||||
As an example - given the following test cases:
|
||||
|
||||
TEST_CASE( "A", "[widget]" ) { /* ... */ }
|
||||
TEST_CASE( "B", "[widget]" ) { /* ... */ }
|
||||
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
|
||||
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
|
||||
```cpp
|
||||
TEST_CASE( "A", "[widget]" ) { /* ... */ }
|
||||
TEST_CASE( "B", "[widget]" ) { /* ... */ }
|
||||
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
|
||||
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
|
||||
```
|
||||
|
||||
The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects C & D. ```"[widget][gadget]"``` selects just D and ```"[widget],[gadget]"``` selects all four test cases.
|
||||
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||
that generates the list of tests by parsing the output from running the test
|
||||
with the ``--list-test-names-only`` argument. This ensures that the full
|
||||
with the ``--list-tests --reporter json`` argument. This ensures that the full
|
||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||
not necessary to re-run CMake when the list of tests changes.
|
||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||
@@ -67,7 +67,7 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
``TEST_SPEC arg1...``
|
||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
||||
pass to the Catch executable when listing the tests.
|
||||
|
||||
``EXTRA_ARGS arg1...``
|
||||
Any extra arguments to pass on the command line to each test case.
|
||||
|
||||
@@ -16,6 +16,42 @@ function(add_command NAME)
|
||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Generates random filename in the temp folder.
|
||||
# Temp folder is retrieved by checking env vars from various platforms.
|
||||
function(make_temp_file_path OUT_VARIABLE FALLBACK_PATH)
|
||||
set(TEMP_DIR "")
|
||||
set(ENV_VARS
|
||||
# From XDG base dir specification
|
||||
XDG_RUNTIME_DIR
|
||||
# From POSIX standard
|
||||
TMPDIR
|
||||
# From Windows
|
||||
TMP
|
||||
TEMP
|
||||
)
|
||||
|
||||
foreach(var ${ENV_VARS})
|
||||
message(NOTICE "Checking ${var} env var")
|
||||
if(DEFINED ENV{${var}} AND NOT "$ENV{${var}}" STREQUAL "")
|
||||
set(TEMP_DIR "$ENV{${var}}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# If all checks fail, we use the fallback path
|
||||
if(TEMP_DIR STREQUAL "")
|
||||
set(TEMP_DIR "${FALLBACK_PATH}")
|
||||
endif()
|
||||
|
||||
file(TO_CMAKE_PATH "${TEMP_DIR}" TEMP_DIR)
|
||||
|
||||
# Generate the random file name
|
||||
string(RANDOM LENGTH 8 RAND_ID)
|
||||
set(FINAL_TEMP_PATH "${TEMP_DIR}/Catch2-test-listing.${RAND_ID}.json")
|
||||
|
||||
set(${OUT_VARIABLE} "${FINAL_TEMP_PATH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(catch_discover_tests_impl)
|
||||
|
||||
cmake_parse_arguments(
|
||||
@@ -72,8 +108,13 @@ function(catch_discover_tests_impl)
|
||||
set(ENV{DYLD_FRAMEWORK_PATH} "${paths}")
|
||||
endif()
|
||||
|
||||
make_temp_file_path(listing_output_path "${_TEST_WORKING_DIR}")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} --list-tests --reporter json
|
||||
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec}
|
||||
--list-tests
|
||||
--reporter json
|
||||
--out "${listing_output_path}"
|
||||
OUTPUT_VARIABLE listing_output
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
||||
@@ -86,6 +127,10 @@ function(catch_discover_tests_impl)
|
||||
)
|
||||
endif()
|
||||
|
||||
# Read the JSON output back from the output file (and then get rid of the file)
|
||||
file(READ ${listing_output_path} listing_output)
|
||||
file(REMOVE ${listing_output_path})
|
||||
|
||||
# Prepare reporter
|
||||
if(reporter)
|
||||
set(reporter_arg "--reporter ${reporter}")
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
// Catch v3.15.0
|
||||
// Generated: 2026-05-12 13:08:21.086523
|
||||
// Catch v3.15.2
|
||||
// Generated: 2026-07-07 20:39:49.445081
|
||||
// ----------------------------------------------------------
|
||||
// This file is an amalgamation of multiple different files.
|
||||
// You probably shouldn't edit it directly.
|
||||
@@ -2394,7 +2394,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 3, 15, 0, "", 0 );
|
||||
static Version version( 3, 15, 2, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -6016,6 +6016,8 @@ namespace Catch {
|
||||
auto getGenerator() const -> GeneratorBasePtr const& override {
|
||||
return m_generator;
|
||||
}
|
||||
|
||||
bool isFilteredImpl() const override { return m_isFiltered; }
|
||||
};
|
||||
} // namespace
|
||||
}
|
||||
@@ -6360,17 +6362,6 @@ namespace Catch {
|
||||
SourceLineInfo lineInfo,
|
||||
Generators::GeneratorBasePtr&& generator ) {
|
||||
|
||||
// TBD: Do we want to avoid the warning if the generator is filtered?
|
||||
if ( m_config->warnAboutInfiniteGenerators() &&
|
||||
!generator->isFinite() ) {
|
||||
// We want the semantics of `FAIL()`, but we inline it
|
||||
// to avoid issues with conditionally prefixed macros
|
||||
INTERNAL_CATCH_MSG( "FAIL",
|
||||
Catch::ResultWas::ExplicitFailure,
|
||||
Catch::ResultDisposition::Normal,
|
||||
"GENERATE() would run infinitely" );
|
||||
}
|
||||
|
||||
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
|
||||
auto& currentTracker = m_trackerContext.currentTracker();
|
||||
assert(
|
||||
@@ -6383,11 +6374,24 @@ namespace Catch {
|
||||
m_trackerContext,
|
||||
¤tTracker,
|
||||
CATCH_MOVE( generator ) );
|
||||
auto ret = newTracker.get();
|
||||
|
||||
// The warning shouldn't fire if the generator is infinite, **but** filtered down.
|
||||
if ( m_config->warnAboutInfiniteGenerators() &&
|
||||
!newTracker->m_generator->isFinite() &&
|
||||
!newTracker->isFiltered() ) {
|
||||
// We want the semantics of `FAIL()`, but we inline it
|
||||
// to avoid issues with conditionally prefixed macros
|
||||
INTERNAL_CATCH_MSG( "FAIL",
|
||||
Catch::ResultWas::ExplicitFailure,
|
||||
Catch::ResultDisposition::Normal,
|
||||
"GENERATE() would run infinitely" );
|
||||
}
|
||||
|
||||
auto returnPtr = newTracker.get();
|
||||
currentTracker.addChild( CATCH_MOVE( newTracker ) );
|
||||
|
||||
ret->open();
|
||||
return ret;
|
||||
returnPtr->open();
|
||||
return returnPtr;
|
||||
}
|
||||
|
||||
bool RunContext::testForMissingAssertions(Counts& assertions) {
|
||||
@@ -7470,6 +7474,28 @@ namespace TestCaseTracking {
|
||||
m_ctx.setCurrentTracker( this );
|
||||
}
|
||||
|
||||
bool SectionTracker::isFilteredImpl() const {
|
||||
// TBD: This is currently _very_ similar to the block in `isComplete`.
|
||||
// Is this neccessarily that way, or just accident of current semantics?
|
||||
const size_t filterIndex =
|
||||
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
|
||||
|
||||
if ( filterIndex < m_filterRef->size() ) {
|
||||
// 1) New style filter must explicitly target section
|
||||
if ( m_newStyleFilters && ( *m_filterRef )[filterIndex].type !=
|
||||
PathFilter::For::Section ) {
|
||||
return true;
|
||||
}
|
||||
// 2) Both style filters must match the trimmed name exactly
|
||||
if ( m_trimmed_name !=
|
||||
StringRef( ( *m_filterRef )[filterIndex].filter ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
|
||||
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
|
||||
@@ -8016,8 +8042,8 @@ namespace Catch {
|
||||
m_it--;
|
||||
}
|
||||
// Skip back over UTF-8 continuation bytes to the leading byte
|
||||
while ( isUtf8ContinuationByte( *m_it ) ) {
|
||||
assert( m_it != m_string->begin() );
|
||||
while ( m_it != m_string->begin() &&
|
||||
isUtf8ContinuationByte( *m_it ) ) {
|
||||
m_it--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
// Catch v3.15.0
|
||||
// Generated: 2026-05-12 13:08:20.543985
|
||||
// Catch v3.15.2
|
||||
// Generated: 2026-07-07 20:39:49.020441
|
||||
// ----------------------------------------------------------
|
||||
// This file is an amalgamation of multiple different files.
|
||||
// You probably shouldn't edit it directly.
|
||||
@@ -7079,42 +7079,42 @@ namespace Catch {
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||
namespace {\
|
||||
template<typename TestType> \
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
};\
|
||||
namespace {\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
|
||||
INTERNAL_CATCH_TYPE_GEN \
|
||||
INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
void reg_tests(){\
|
||||
std::size_t index = 0;\
|
||||
using expander = std::size_t[];\
|
||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(Catch::Detail::priority_tag<1>{})), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}\
|
||||
}\
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
};\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
|
||||
INTERNAL_CATCH_TYPE_GEN \
|
||||
INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
void reg_tests(){\
|
||||
std::size_t index = 0;\
|
||||
using expander = std::size_t[];\
|
||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(Catch::Detail::priority_tag<1>{})), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}\
|
||||
}\
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
|
||||
@@ -7132,37 +7132,37 @@ namespace Catch {
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
|
||||
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
|
||||
namespace {\
|
||||
template<typename TestType> \
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
};\
|
||||
namespace {\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
|
||||
INTERNAL_CATCH_TYPE_GEN\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
void reg_tests(){\
|
||||
size_t index = 0;\
|
||||
using expander = size_t[];\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = typename convert<TestNameClass, TmplList>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}}\
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
|
||||
INTERNAL_CATCH_TYPE_GEN\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
void reg_tests(){\
|
||||
size_t index = 0;\
|
||||
using expander = size_t[];\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = typename convert<TestNameClass, TmplList>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}}\
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
|
||||
INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, TmplList )
|
||||
@@ -7484,6 +7484,8 @@ namespace Catch {
|
||||
return m_translateFunction( ex );
|
||||
}
|
||||
#else
|
||||
(void)it;
|
||||
(void)itEnd;
|
||||
return "You should never get here!";
|
||||
#endif
|
||||
}
|
||||
@@ -7570,7 +7572,7 @@ namespace Catch {
|
||||
|
||||
#define CATCH_VERSION_MAJOR 3
|
||||
#define CATCH_VERSION_MINOR 15
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
#define CATCH_VERSION_PATCH 2
|
||||
|
||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
||||
@@ -7910,8 +7912,7 @@ namespace Generators {
|
||||
|
||||
bool isFinite() const override {
|
||||
for (auto const& gen : m_generators) {
|
||||
if (!gen.isFinite()) { return false;
|
||||
}
|
||||
if (!gen.isFinite()) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -10657,6 +10658,8 @@ namespace TestCaseTracking {
|
||||
|
||||
using Children = std::vector<ITrackerPtr>;
|
||||
|
||||
virtual bool isFilteredImpl() const = 0;
|
||||
|
||||
protected:
|
||||
enum CycleState {
|
||||
NotStarted,
|
||||
@@ -10754,6 +10757,20 @@ namespace TestCaseTracking {
|
||||
* for internal debug checks.
|
||||
*/
|
||||
virtual bool isGeneratorTracker() const;
|
||||
|
||||
/**
|
||||
* Returns true if the concrete tracker instance has a filter that applies to it.
|
||||
*/
|
||||
bool isFiltered() const {
|
||||
// Fast path: are there even filters for tracker in this position?
|
||||
const size_t filter_depth =
|
||||
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
|
||||
if ( m_filterRef->size() <= filter_depth ) { return false; }
|
||||
|
||||
// Slow path: If there are filters, ask the concrete tracker.
|
||||
// This handles things like match-all filters for that tracker.
|
||||
return isFilteredImpl();
|
||||
}
|
||||
};
|
||||
|
||||
class TrackerContext {
|
||||
@@ -10809,6 +10826,8 @@ namespace TestCaseTracking {
|
||||
// to not own the name, the name still has to outlive the `ITracker` parent, so
|
||||
// this should still be safe.
|
||||
StringRef m_trimmed_name;
|
||||
|
||||
bool isFilteredImpl() const override;
|
||||
public:
|
||||
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
project(
|
||||
'catch2',
|
||||
'cpp',
|
||||
version: '3.15.0', # CML version placeholder, don't delete
|
||||
version: '3.15.2', # CML version placeholder, don't delete
|
||||
license: 'BSL-1.0',
|
||||
meson_version: '>=0.54.1',
|
||||
)
|
||||
|
||||
@@ -41,6 +41,8 @@ namespace Catch {
|
||||
return m_translateFunction( ex );
|
||||
}
|
||||
#else
|
||||
(void)it;
|
||||
(void)itEnd;
|
||||
return "You should never get here!";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 3, 15, 0, "", 0 );
|
||||
static Version version( 3, 15, 2, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
|
||||
#define CATCH_VERSION_MAJOR 3
|
||||
#define CATCH_VERSION_MINOR 15
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
#define CATCH_VERSION_PATCH 2
|
||||
|
||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
||||
@@ -179,8 +179,7 @@ namespace Generators {
|
||||
|
||||
bool isFinite() const override {
|
||||
for (auto const& gen : m_generators) {
|
||||
if (!gen.isFinite()) { return false;
|
||||
}
|
||||
if (!gen.isFinite()) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -196,6 +196,8 @@ namespace Catch {
|
||||
auto getGenerator() const -> GeneratorBasePtr const& override {
|
||||
return m_generator;
|
||||
}
|
||||
|
||||
bool isFilteredImpl() const override { return m_isFiltered; }
|
||||
};
|
||||
} // namespace
|
||||
}
|
||||
@@ -540,17 +542,6 @@ namespace Catch {
|
||||
SourceLineInfo lineInfo,
|
||||
Generators::GeneratorBasePtr&& generator ) {
|
||||
|
||||
// TBD: Do we want to avoid the warning if the generator is filtered?
|
||||
if ( m_config->warnAboutInfiniteGenerators() &&
|
||||
!generator->isFinite() ) {
|
||||
// We want the semantics of `FAIL()`, but we inline it
|
||||
// to avoid issues with conditionally prefixed macros
|
||||
INTERNAL_CATCH_MSG( "FAIL",
|
||||
Catch::ResultWas::ExplicitFailure,
|
||||
Catch::ResultDisposition::Normal,
|
||||
"GENERATE() would run infinitely" );
|
||||
}
|
||||
|
||||
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
|
||||
auto& currentTracker = m_trackerContext.currentTracker();
|
||||
assert(
|
||||
@@ -563,11 +554,24 @@ namespace Catch {
|
||||
m_trackerContext,
|
||||
¤tTracker,
|
||||
CATCH_MOVE( generator ) );
|
||||
auto ret = newTracker.get();
|
||||
|
||||
// The warning shouldn't fire if the generator is infinite, **but** filtered down.
|
||||
if ( m_config->warnAboutInfiniteGenerators() &&
|
||||
!newTracker->m_generator->isFinite() &&
|
||||
!newTracker->isFiltered() ) {
|
||||
// We want the semantics of `FAIL()`, but we inline it
|
||||
// to avoid issues with conditionally prefixed macros
|
||||
INTERNAL_CATCH_MSG( "FAIL",
|
||||
Catch::ResultWas::ExplicitFailure,
|
||||
Catch::ResultDisposition::Normal,
|
||||
"GENERATE() would run infinitely" );
|
||||
}
|
||||
|
||||
auto returnPtr = newTracker.get();
|
||||
currentTracker.addChild( CATCH_MOVE( newTracker ) );
|
||||
|
||||
ret->open();
|
||||
return ret;
|
||||
returnPtr->open();
|
||||
return returnPtr;
|
||||
}
|
||||
|
||||
bool RunContext::testForMissingAssertions(Counts& assertions) {
|
||||
|
||||
@@ -245,42 +245,42 @@
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||
namespace {\
|
||||
template<typename TestType> \
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
};\
|
||||
namespace {\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
|
||||
INTERNAL_CATCH_TYPE_GEN \
|
||||
INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
void reg_tests(){\
|
||||
std::size_t index = 0;\
|
||||
using expander = std::size_t[];\
|
||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(Catch::Detail::priority_tag<1>{})), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}\
|
||||
}\
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
};\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
|
||||
INTERNAL_CATCH_TYPE_GEN \
|
||||
INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
void reg_tests(){\
|
||||
std::size_t index = 0;\
|
||||
using expander = std::size_t[];\
|
||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(Catch::Detail::priority_tag<1>{})), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}\
|
||||
}\
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
|
||||
@@ -298,37 +298,37 @@
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
|
||||
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
|
||||
namespace {\
|
||||
template<typename TestType> \
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
};\
|
||||
namespace {\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
|
||||
INTERNAL_CATCH_TYPE_GEN\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
void reg_tests(){\
|
||||
size_t index = 0;\
|
||||
using expander = size_t[];\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = typename convert<TestNameClass, TmplList>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}}\
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
|
||||
INTERNAL_CATCH_TYPE_GEN\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
void reg_tests(){\
|
||||
size_t index = 0;\
|
||||
using expander = size_t[];\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = typename convert<TestNameClass, TmplList>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}}\
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
|
||||
INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, TmplList )
|
||||
|
||||
@@ -167,6 +167,28 @@ namespace TestCaseTracking {
|
||||
m_ctx.setCurrentTracker( this );
|
||||
}
|
||||
|
||||
bool SectionTracker::isFilteredImpl() const {
|
||||
// TBD: This is currently _very_ similar to the block in `isComplete`.
|
||||
// Is this neccessarily that way, or just accident of current semantics?
|
||||
const size_t filterIndex =
|
||||
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
|
||||
|
||||
if ( filterIndex < m_filterRef->size() ) {
|
||||
// 1) New style filter must explicitly target section
|
||||
if ( m_newStyleFilters && ( *m_filterRef )[filterIndex].type !=
|
||||
PathFilter::For::Section ) {
|
||||
return true;
|
||||
}
|
||||
// 2) Both style filters must match the trimmed name exactly
|
||||
if ( m_trimmed_name !=
|
||||
StringRef( ( *m_filterRef )[filterIndex].filter ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
|
||||
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_path_filter.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -81,6 +82,8 @@ namespace TestCaseTracking {
|
||||
|
||||
using Children = std::vector<ITrackerPtr>;
|
||||
|
||||
virtual bool isFilteredImpl() const = 0;
|
||||
|
||||
protected:
|
||||
enum CycleState {
|
||||
NotStarted,
|
||||
@@ -178,6 +181,20 @@ namespace TestCaseTracking {
|
||||
* for internal debug checks.
|
||||
*/
|
||||
virtual bool isGeneratorTracker() const;
|
||||
|
||||
/**
|
||||
* Returns true if the concrete tracker instance has a filter that applies to it.
|
||||
*/
|
||||
bool isFiltered() const {
|
||||
// Fast path: are there even filters for tracker in this position?
|
||||
const size_t filter_depth =
|
||||
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
|
||||
if ( m_filterRef->size() <= filter_depth ) { return false; }
|
||||
|
||||
// Slow path: If there are filters, ask the concrete tracker.
|
||||
// This handles things like match-all filters for that tracker.
|
||||
return isFilteredImpl();
|
||||
}
|
||||
};
|
||||
|
||||
class TrackerContext {
|
||||
@@ -233,6 +250,8 @@ namespace TestCaseTracking {
|
||||
// to not own the name, the name still has to outlive the `ITracker` parent, so
|
||||
// this should still be safe.
|
||||
StringRef m_trimmed_name;
|
||||
|
||||
bool isFilteredImpl() const override;
|
||||
public:
|
||||
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
|
||||
|
||||
|
||||
@@ -148,8 +148,8 @@ namespace Catch {
|
||||
m_it--;
|
||||
}
|
||||
// Skip back over UTF-8 continuation bytes to the leading byte
|
||||
while ( isUtf8ContinuationByte( *m_it ) ) {
|
||||
assert( m_it != m_string->begin() );
|
||||
while ( m_it != m_string->begin() &&
|
||||
isUtf8ContinuationByte( *m_it ) ) {
|
||||
m_it--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,29 +526,18 @@ set_tests_properties(TestSpecs::SkippingAllTestsFails
|
||||
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
|
||||
MixingClearedAndUnclearedMessages
|
||||
# DebugBreakMacros
|
||||
)
|
||||
add_executable(FastCompileMacros ${TESTS_DIR}/X07-FastCompileMacros.cpp)
|
||||
target_link_libraries(FastCompileMacros PRIVATE Catch2_buildall_interface)
|
||||
target_compile_definitions(FastCompileMacros PRIVATE CATCH_CONFIG_FAST_COMPILE)
|
||||
|
||||
# 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_TEST_TARGETS ${EXTRA_TEST_BINARIES})
|
||||
set(CATCH_TEST_TARGETS ${CATCH_TEST_TARGETS} PARENT_SCOPE)
|
||||
add_test(
|
||||
NAME CompileConfiguration::FastCompile
|
||||
COMMAND $<TARGET_FILE:FastCompileMacros>
|
||||
)
|
||||
set_tests_properties(CompileConfiguration::FastCompile
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "test cases: 6 \\| 1 passed \\| 1 failed \\| 4 failed as expected\nassertions: 13 \\| 6 passed \\| 2 failed \\| 5 failed as expected"
|
||||
)
|
||||
|
||||
# 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
|
||||
@@ -594,12 +583,79 @@ add_executable(InfiniteGenerators ${TESTS_DIR}/X95-InfiniteGenerators.cpp)
|
||||
target_link_libraries(InfiniteGenerators PRIVATE Catch2::Catch2WithMain)
|
||||
|
||||
add_test(
|
||||
NAME Warnings::InfiniteGenerators
|
||||
NAME Warnings::InfiniteGenerators::NoFilterWarns
|
||||
COMMAND $<TARGET_FILE:InfiniteGenerators> --warn InfiniteGenerators
|
||||
)
|
||||
set_tests_properties(Warnings::InfiniteGenerators
|
||||
set_tests_properties(Warnings::InfiniteGenerators::NoFilterWarns
|
||||
PROPERTIES
|
||||
# One test case fails with infinite generator, but the other one runs
|
||||
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME Warnings::InfiniteGenerators::MatchAllFilterWarns
|
||||
COMMAND $<TARGET_FILE:InfiniteGenerators>
|
||||
--warn InfiniteGenerators
|
||||
--path-filter g:*
|
||||
)
|
||||
set_tests_properties(Warnings::InfiniteGenerators::MatchAllFilterWarns
|
||||
PROPERTIES
|
||||
# One test case fails with infinite generator, but the other one runs
|
||||
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME Warnings::InfiniteGenerators::MatchOneFilterDoesntWarn
|
||||
COMMAND $<TARGET_FILE:InfiniteGenerators>
|
||||
--warn InfiniteGenerators
|
||||
--path-filter g:1
|
||||
)
|
||||
set_tests_properties(Warnings::InfiniteGenerators::MatchOneFilterDoesntWarn
|
||||
PROPERTIES
|
||||
# One test case fails with infinite generator, but the other one runs
|
||||
PASS_REGULAR_EXPRESSION "All tests passed \\(1 assertion in 2 test cases\\)"
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME Warnings::InfiniteGenerators::SectionFilterWarns
|
||||
COMMAND $<TARGET_FILE:InfiniteGenerators>
|
||||
--warn InfiniteGenerators
|
||||
--section FooBarBaz
|
||||
)
|
||||
set_tests_properties(Warnings::InfiniteGenerators::SectionFilterWarns
|
||||
PROPERTIES
|
||||
# One test case fails with infinite generator, but the other one runs
|
||||
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
|
||||
set(EXTRA_TEST_BINARIES
|
||||
AllSkipped
|
||||
PrefixedMacros
|
||||
DisabledMacros
|
||||
DisabledExceptions-DefaultHandler
|
||||
DisabledExceptions-CustomHandler
|
||||
FallbackStringifier
|
||||
DisableStringification
|
||||
PartialTestCaseEvents
|
||||
DuplicatedTestCases-SameNameAndTags
|
||||
DuplicatedTestCases-SameNameDifferentTags
|
||||
DuplicatedTestCases-DuplicatedTestCaseMethods
|
||||
NoTests
|
||||
ListenersGetEventsBeforeReporters
|
||||
MixingClearedAndUnclearedMessages
|
||||
FastCompileMacros
|
||||
InfiniteGenerators
|
||||
ThreadSafetyTests
|
||||
# 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_TEST_TARGETS ${EXTRA_TEST_BINARIES})
|
||||
set(CATCH_TEST_TARGETS ${CATCH_TEST_TARGETS} PARENT_SCOPE)
|
||||
|
||||
@@ -3,7 +3,6 @@ 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
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
// 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 various basic macros work with CATCH_CONFIG_FAST_COMPILE.
|
||||
*
|
||||
* Note that the current checking is rather loose. We check that the
|
||||
* macros compile, and that the test cases (don't) fail as they are
|
||||
* supposed to.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace {
|
||||
|
||||
[[noreturn]]
|
||||
static void throws() {
|
||||
throw std::runtime_error{ "sup" };
|
||||
}
|
||||
static void doesnt_throw() {}
|
||||
[[noreturn]]
|
||||
static int throws_i() {
|
||||
throw std::runtime_error{ "sup" };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "Passing macros work" ) {
|
||||
REQUIRE( 1 != 2 );
|
||||
CHECK( 2 == 2 );
|
||||
REQUIRE_THROWS( throws() );
|
||||
REQUIRE_NOTHROW( doesnt_throw() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Failing macros work", "[!shouldfail]" ) {
|
||||
CHECK( 1 != 2 );
|
||||
CHECK( 2 == 2 );
|
||||
CHECK( 3 == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Failing NOTHROW works", "[!shouldfail]" ) {
|
||||
REQUIRE_NOTHROW( throws() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Failing THROW works", "[!shouldfail]" ) {
|
||||
REQUIRE_THROWS( doesnt_throw() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Unexpected exception in REQUIRE gets inverted properly",
|
||||
"[!shouldfail]" ) {
|
||||
REQUIRE( throws_i() == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Unexpected exception in REQUIRE fails properly" ) {
|
||||
REQUIRE( throws_i() == 2 );
|
||||
}
|
||||
@@ -33,6 +33,7 @@ namespace {
|
||||
|
||||
TEST_CASE() {
|
||||
auto _ = GENERATE( make_infinite_generator() );
|
||||
(void)_;
|
||||
}
|
||||
|
||||
TEST_CASE() {
|
||||
|
||||
@@ -437,6 +437,25 @@ TEST_CASE( "TextFlow::AnsiSkippingString iterates UTF-8 codepoints",
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::AnsiSkippingString handles invalid UTF-8",
|
||||
"[TextFlow][ansiskippingstring][approvals]" ) {
|
||||
SECTION( "Continuation byte at the start" ) {
|
||||
// 0x80 is a continuation byte
|
||||
AnsiSkippingString str( "\x80" );
|
||||
auto it = str.end();
|
||||
--it;
|
||||
CHECK( it == str.begin() );
|
||||
CHECK( *it == static_cast<char>( 0x80 ) );
|
||||
}
|
||||
SECTION( "Multiple continuation bytes at the start" ) {
|
||||
AnsiSkippingString str( "\x80\x80\x80" );
|
||||
auto it = str.end();
|
||||
--it;
|
||||
CHECK( it == str.begin() );
|
||||
CHECK( *it == static_cast<char>( 0x80 ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "TextFlow::Column wraps UTF-8 text correctly",
|
||||
"[TextFlow][column][approvals]" ) {
|
||||
// "äöü äöü äöü" = 11 codepoints, 17 bytes
|
||||
|
||||
@@ -12,6 +12,7 @@ import subprocess
|
||||
import sys
|
||||
import re
|
||||
import json
|
||||
import tempfile
|
||||
from collections import namedtuple
|
||||
from typing import List
|
||||
|
||||
@@ -72,14 +73,19 @@ def get_test_names(build_path: str) -> List[TestInfo]:
|
||||
config_path = "Debug" if os.name == 'nt' else ""
|
||||
full_path = os.path.join(build_path, config_path, 'tests')
|
||||
|
||||
|
||||
cmd = [full_path, '--reporter', 'json', '--list-tests']
|
||||
result = subprocess.run(cmd,
|
||||
capture_output = True,
|
||||
check = True,
|
||||
text = True)
|
||||
|
||||
test_listing = json.loads(result.stdout)
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
fname = f'{tmpdir}/listing-output.json'
|
||||
cmd = [full_path,
|
||||
'--list-tests',
|
||||
'--reporter', 'json',
|
||||
'--out', fname
|
||||
]
|
||||
result = subprocess.run(cmd,
|
||||
capture_output = False,
|
||||
check = True,
|
||||
text = True)
|
||||
with open(fname, mode='r', encoding='utf-8') as file:
|
||||
test_listing = json.load(file)
|
||||
|
||||
assert test_listing['version'] == 1
|
||||
|
||||
@@ -96,10 +102,18 @@ def get_ctest_listing(build_path):
|
||||
os.chdir(build_path)
|
||||
|
||||
cmd = ['ctest', '-C', 'debug', '--show-only=json-v1']
|
||||
result = subprocess.run(cmd,
|
||||
capture_output = True,
|
||||
check = True,
|
||||
text = True)
|
||||
try:
|
||||
result = subprocess.run(cmd,
|
||||
capture_output = True,
|
||||
check = True,
|
||||
text = True)
|
||||
except subprocess.CalledProcessError as err:
|
||||
print('Error when getting output from CTest')
|
||||
print(f'cmd: {err.cmd}')
|
||||
print(f'stderr: {err.stderr}')
|
||||
print(f'stdout: {err.stdout}')
|
||||
exit(4)
|
||||
|
||||
os.chdir(old_path)
|
||||
return result.stdout
|
||||
|
||||
|
||||
@@ -8,6 +8,24 @@
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
|
||||
struct PrintsWhenConstructed {
|
||||
PrintsWhenConstructed() {
|
||||
std::cout << "Hello\n";
|
||||
std::cerr << "Holla\n";
|
||||
std::fprintf(stdout, "Hullo\n");
|
||||
std::fprintf(stderr, "Hillo\n");
|
||||
}
|
||||
};
|
||||
|
||||
static PrintsWhenConstructed instance;
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("@Script[C:\\EPM1A]=x;\"SCALA_ZERO:\"", "[script regressions]"){}
|
||||
TEST_CASE("Some test") {}
|
||||
TEST_CASE( "Let's have a test case with a long name. Longer. No, even longer. "
|
||||
|
||||
Reference in New Issue
Block a user