Improve String matcher handling of case sensitivity

The old implementation of String matchers worked by making a, potentially
lower-cased, copy of both the constructor arg, and the arg to `match` calls.

The new implementation does not make copies, and instead does per-character
lowering if needed. This is a win in **most** cases, with two exceptions:

1) Case-insensitive `Equals` between long strings. The old implementation
   is easy to autovectorize by the compiler, which wins over the extra copy
   with sufficiently long inputs.
2) Case-insensitive `ContainsSubstring` with inputs that trigger the worst
   case complexity of O(m*n) of the naive implementation.

The latter is fixable with some elbow grease by implementing a proper
string search algorithm, but the former is a cost we have to live with.
This commit is contained in:
Martin Hořeňovský
2026-08-24 15:11:48 +02:00
parent 499442d7ef
commit fc5bc1fa8b
10 changed files with 142 additions and 110 deletions
+77 -41
View File
@@ -9,70 +9,106 @@
#include <catch2/internal/catch_string_manip.hpp>
#include <catch2/catch_tostring.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
#include <regex>
namespace Catch {
namespace {
constexpr StringRef caseSensitivitySuffix( CaseSensitive caseSensitivity ) {
return caseSensitivity == CaseSensitive::Yes
? StringRef{}
: " (case insensitive)"_sr;
}
} // namespace
namespace Matchers {
CasedString::CasedString( std::string const& str, CaseSensitive caseSensitivity )
: m_caseSensitivity( caseSensitivity ),
m_str( adjustString( str ) )
{}
std::string CasedString::adjustString( std::string const& str ) const {
return m_caseSensitivity == CaseSensitive::No
? toLower( str )
: str;
}
StringRef CasedString::caseSensitivitySuffix() const {
return m_caseSensitivity == CaseSensitive::Yes
? StringRef()
: " (case insensitive)"_sr;
}
StringMatcherBase::StringMatcherBase( std::string target,
StringRef operation,
CaseSensitive caseSensitivity ):
m_target( CATCH_MOVE( target ) ),
m_operation( operation ),
m_caseSensitivity( caseSensitivity ) {}
StringMatcherBase::StringMatcherBase( StringRef operation, CasedString const& comparator )
: m_comparator( comparator ),
m_operation( operation ) {
}
std::string StringMatcherBase::describe() const {
std::string description;
description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
m_comparator.caseSensitivitySuffix().size());
description.reserve(5 + m_operation.size() + m_target.size() +
caseSensitivitySuffix(m_caseSensitivity).size());
description += m_operation;
description += ": \"";
description += m_comparator.m_str;
description += m_target;
description += '"';
description += m_comparator.caseSensitivitySuffix();
description += caseSensitivitySuffix(m_caseSensitivity);
return description;
}
StringEqualsMatcher::StringEqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals"_sr, comparator ) {}
StringEqualsMatcher::StringEqualsMatcher( std::string comparator, CaseSensitive caseSensitivity ):
StringMatcherBase( CATCH_MOVE( comparator ), "equals"_sr, caseSensitivity ) {}
bool StringEqualsMatcher::match( std::string const& source ) const {
return m_comparator.adjustString( source ) == m_comparator.m_str;
if (m_caseSensitivity == CaseSensitive::Yes) {
return m_target == source;
}
if (m_target.size() != source.size()) { return false; }
Catch::Detail::CaseInsensitiveEqualTo eq;
return eq( m_target, source );
}
StringContainsMatcher::StringContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains"_sr, comparator ) {}
StringContainsMatcher::StringContainsMatcher(
std::string comparator, CaseSensitive caseSensitivity ):
StringMatcherBase( CATCH_MOVE( comparator ), "contains"_sr, caseSensitivity ) {}
bool StringContainsMatcher::match( std::string const& source ) const {
return contains( m_comparator.adjustString( source ), m_comparator.m_str );
if ( m_caseSensitivity == CaseSensitive::Yes ) {
return contains( source, m_target );
}
if ( source.size() < m_target.size() ) { return false; }
StringRef as_ref( source );
// The worst case of this is O(m*n), which is terrible, BUT:
// * The average case is much better, the worst case only happens rarely
// * We can implement BMH/other better searchers later if it matters
Catch::Detail::CaseInsensitiveEqualTo eq;
for (size_t i = 0; i < source.size(); ++i) {
const auto substr = as_ref.substr( i, m_target.size() );
bool found = eq( substr, m_target );
if ( found ) { return true; }
}
return false;
}
StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with"_sr, comparator ) {}
StartsWithMatcher::StartsWithMatcher( std::string comparator,
CaseSensitive caseSensitivity ):
StringMatcherBase( CATCH_MOVE( comparator ), "starts with"_sr, caseSensitivity ) {}
bool StartsWithMatcher::match( std::string const& source ) const {
return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
if ( m_caseSensitivity == CaseSensitive::Yes ) {
return startsWith( source, m_target );
}
if (source.size() < m_target.size()) { return false; }
Catch::Detail::CaseInsensitiveEqualTo eq;
return eq(
StringRef( source ).substr( 0, m_target.size() ), m_target );
}
EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with"_sr, comparator ) {}
EndsWithMatcher::EndsWithMatcher( std::string comparator,
CaseSensitive caseSensitivity ):
StringMatcherBase( CATCH_MOVE( comparator ), "ends with"_sr, caseSensitivity ) {}
bool EndsWithMatcher::match( std::string const& source ) const {
return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
if ( m_caseSensitivity == CaseSensitive::Yes ) {
return endsWith( source, m_target );
}
if ( source.size() < m_target.size() ) { return false; }
Catch::Detail::CaseInsensitiveEqualTo eq;
const size_t start_point = source.size() - m_target.size();
return eq( StringRef( source ).substr( start_point, m_target.size() ), m_target );
}
@@ -93,21 +129,21 @@ namespace Matchers {
}
StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity ) {
return StringEqualsMatcher( CasedString( str, caseSensitivity) );
StringEqualsMatcher Equals( std::string str, CaseSensitive caseSensitivity ) {
return StringEqualsMatcher( CATCH_MOVE( str ), caseSensitivity );
}
StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity ) {
return StringContainsMatcher( CasedString( str, caseSensitivity) );
StringContainsMatcher ContainsSubstring( std::string str, CaseSensitive caseSensitivity ) {
return StringContainsMatcher( CATCH_MOVE( str ), caseSensitivity );
}
EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity ) {
return EndsWithMatcher( CasedString( str, caseSensitivity) );
EndsWithMatcher EndsWith( std::string str, CaseSensitive caseSensitivity ) {
return EndsWithMatcher( CATCH_MOVE( str ), caseSensitivity );
}
StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity ) {
return StartsWithMatcher( CasedString( str, caseSensitivity) );
StartsWithMatcher StartsWith( std::string str, CaseSensitive caseSensitivity ) {
return StartsWithMatcher( CATCH_MOVE( str ), caseSensitivity );
}
RegexMatcher Matches(std::string const& regex, CaseSensitive caseSensitivity) {
return RegexMatcher(regex, caseSensitivity);
RegexMatcher Matches(std::string regex, CaseSensitive caseSensitivity) {
return RegexMatcher( CATCH_MOVE( regex ), caseSensitivity );
}
} // namespace Matchers
+17 -21
View File
@@ -17,44 +17,40 @@
namespace Catch {
namespace Matchers {
struct CasedString {
CasedString( std::string const& str, CaseSensitive caseSensitivity );
std::string adjustString( std::string const& str ) const;
StringRef caseSensitivitySuffix() const;
CaseSensitive m_caseSensitivity;
std::string m_str;
};
class StringMatcherBase : public MatcherBase<std::string> {
protected:
CasedString m_comparator;
std::string m_target;
StringRef m_operation;
CaseSensitive m_caseSensitivity;
StringMatcherBase( std::string target,
StringRef operation,
CaseSensitive caseSensitivity );
public:
StringMatcherBase( StringRef operation,
CasedString const& comparator );
std::string describe() const override;
};
class StringEqualsMatcher final : public StringMatcherBase {
public:
StringEqualsMatcher( CasedString const& comparator );
StringEqualsMatcher( std::string comparator, CaseSensitive caseSensitivity );
bool match( std::string const& source ) const override;
};
class StringContainsMatcher final : public StringMatcherBase {
public:
StringContainsMatcher( CasedString const& comparator );
StringContainsMatcher( std::string comparator,
CaseSensitive caseSensitivity );
bool match( std::string const& source ) const override;
};
class StartsWithMatcher final : public StringMatcherBase {
public:
StartsWithMatcher( CasedString const& comparator );
StartsWithMatcher( std::string comparator,
CaseSensitive caseSensitivity );
bool match( std::string const& source ) const override;
};
class EndsWithMatcher final : public StringMatcherBase {
public:
EndsWithMatcher( CasedString const& comparator );
EndsWithMatcher( std::string comparator,
CaseSensitive caseSensitivity );
bool match( std::string const& source ) const override;
};
@@ -69,15 +65,15 @@ namespace Matchers {
};
//! Creates matcher that accepts strings that are exactly equal to `str`
StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
StringEqualsMatcher Equals( std::string str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
//! Creates matcher that accepts strings that contain `str`
StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
StringContainsMatcher ContainsSubstring( std::string str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
//! Creates matcher that accepts strings that _end_ with `str`
EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
EndsWithMatcher EndsWith( std::string str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
//! Creates matcher that accepts strings that _start_ with `str`
StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
StartsWithMatcher StartsWith( std::string str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
//! Creates matcher that accepts strings matching `regex`
RegexMatcher Matches( std::string const& regex, CaseSensitive caseSensitivity = CaseSensitive::Yes );
RegexMatcher Matches( std::string regex, CaseSensitive caseSensitivity = CaseSensitive::Yes );
} // namespace Matchers
} // namespace Catch
@@ -631,7 +631,7 @@ Condition.tests.cpp:<line number>: passed: x == Approx( 1.3 ) for: 1.30000000000
==
Approx( 1.30000000000000004 )
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Equals( "this string contains 'abc' as a substring" ) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" (case insensitive)
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Equals( "this string contains 'ABC' as a substring" ) for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring"
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Equals( "something else", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "something else" (case insensitive)
ToStringGeneral.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(WhatException{}) == "This exception has overridden what() method" for: "This exception has overridden what() method"
@@ -654,11 +654,11 @@ Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedExcep
Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) for: DerivedException::what matches "not starts with: "::what""
Matchers.tests.cpp:<line number>: passed: throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) for: SpecialException::what matches "starts with: "Special""
Exception.tests.cpp:<line number>: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception"
Exception.tests.cpp:<line number>: passed: thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expected exception" (case insensitive)
Exception.tests.cpp:<line number>: passed: thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expecteD Exception" (case insensitive)
Exception.tests.cpp:<line number>: passed: thisThrows(), StartsWith( "expected" ) for: "expected exception" starts with: "expected"
Exception.tests.cpp:<line number>: passed: thisThrows(), EndsWith( "exception" ) for: "expected exception" ends with: "exception"
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "except" ) for: "expected exception" contains: "except"
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive)
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "exCept" (case insensitive)
ToString.tests.cpp:<line number>: passed: tos == tos for: { stringification failed with an exception: "Invalid" }
==
{ stringification failed with an exception: "Invalid" }
@@ -1912,11 +1912,11 @@ ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify(arr) =
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "string" ) for: "this string contains 'abc' as a substring" contains: "string"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "string", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "string" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "abc" ) for: "this string contains 'abc' as a substring" contains: "abc"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "abc" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "aBC" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), StartsWith( "this" ) for: "this string contains 'abc' as a substring" starts with: "this"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" starts with: "this" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" starts with: "THIS" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith( "substring" ) for: "this string contains 'abc' as a substring" ends with: "substring"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: " substring" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: " SuBsTrInG" (case insensitive)
String.tests.cpp:<line number>: passed: empty.empty() for: true
String.tests.cpp:<line number>: passed: empty.size() == 0 for: 0 == 0
String.tests.cpp:<line number>: passed: std::strcmp( empty.data(), "" ) == 0 for: 0 == 0
@@ -629,7 +629,7 @@ Condition.tests.cpp:<line number>: passed: x == Approx( 1.3 ) for: 1.30000000000
==
Approx( 1.30000000000000004 )
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Equals( "this string contains 'abc' as a substring" ) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" (case insensitive)
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Equals( "this string contains 'ABC' as a substring" ) for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring"
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Equals( "something else", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "something else" (case insensitive)
ToStringGeneral.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(WhatException{}) == "This exception has overridden what() method" for: "This exception has overridden what() method"
@@ -652,11 +652,11 @@ Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedExcep
Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedException, MessageMatches( !StartsWith( "::what" ) ) for: DerivedException::what matches "not starts with: "::what""
Matchers.tests.cpp:<line number>: passed: throwsSpecialException( 2 ), SpecialException, MessageMatches( StartsWith( "Special" ) ) for: SpecialException::what matches "starts with: "Special""
Exception.tests.cpp:<line number>: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception"
Exception.tests.cpp:<line number>: passed: thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expected exception" (case insensitive)
Exception.tests.cpp:<line number>: passed: thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expecteD Exception" (case insensitive)
Exception.tests.cpp:<line number>: passed: thisThrows(), StartsWith( "expected" ) for: "expected exception" starts with: "expected"
Exception.tests.cpp:<line number>: passed: thisThrows(), EndsWith( "exception" ) for: "expected exception" ends with: "exception"
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "except" ) for: "expected exception" contains: "except"
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive)
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "exCept" (case insensitive)
ToString.tests.cpp:<line number>: passed: tos == tos for: { stringification failed with an exception: "Invalid" }
==
{ stringification failed with an exception: "Invalid" }
@@ -1905,11 +1905,11 @@ ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify(arr) =
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "string" ) for: "this string contains 'abc' as a substring" contains: "string"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "string", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "string" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "abc" ) for: "this string contains 'abc' as a substring" contains: "abc"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "abc" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "aBC" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), StartsWith( "this" ) for: "this string contains 'abc' as a substring" starts with: "this"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" starts with: "this" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" starts with: "THIS" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith( "substring" ) for: "this string contains 'abc' as a substring" ends with: "substring"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: " substring" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: " SuBsTrInG" (case insensitive)
String.tests.cpp:<line number>: passed: empty.empty() for: true
String.tests.cpp:<line number>: passed: empty.size() == 0 for: 0 == 0
String.tests.cpp:<line number>: passed: std::strcmp( empty.data(), "" ) == 0 for: 0 == 0
@@ -4521,7 +4521,7 @@ Matchers.tests.cpp:<line number>: PASSED:
CHECK_THAT( testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) )
with expansion:
"this string contains 'abc' as a substring" equals: "this string contains
'abc' as a substring" (case insensitive)
'ABC' as a substring" (case insensitive)
-------------------------------------------------------------------------------
Equals string matcher
@@ -4679,7 +4679,7 @@ Exception.tests.cpp:<line number>
Exception.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) )
with expansion:
"expected exception" equals: "expected exception" (case insensitive)
"expected exception" equals: "expecteD Exception" (case insensitive)
-------------------------------------------------------------------------------
Exception messages can be tested for
@@ -4706,7 +4706,7 @@ with expansion:
Exception.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_WITH( thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) )
with expansion:
"expected exception" contains: "except" (case insensitive)
"expected exception" contains: "exCept" (case insensitive)
-------------------------------------------------------------------------------
Exception thrown inside stringify does not fail the test
@@ -12195,7 +12195,7 @@ with expansion:
Matchers.tests.cpp:<line number>: PASSED:
CHECK_THAT( testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) )
with expansion:
"this string contains 'abc' as a substring" contains: "abc" (case
"this string contains 'abc' as a substring" contains: "aBC" (case
insensitive)
Matchers.tests.cpp:<line number>: PASSED:
@@ -12206,7 +12206,7 @@ with expansion:
Matchers.tests.cpp:<line number>: PASSED:
CHECK_THAT( testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) )
with expansion:
"this string contains 'abc' as a substring" starts with: "this" (case
"this string contains 'abc' as a substring" starts with: "THIS" (case
insensitive)
Matchers.tests.cpp:<line number>: PASSED:
@@ -12217,7 +12217,7 @@ with expansion:
Matchers.tests.cpp:<line number>: PASSED:
CHECK_THAT( testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) )
with expansion:
"this string contains 'abc' as a substring" ends with: " substring" (case
"this string contains 'abc' as a substring" ends with: " SuBsTrInG" (case
insensitive)
-------------------------------------------------------------------------------
@@ -4519,7 +4519,7 @@ Matchers.tests.cpp:<line number>: PASSED:
CHECK_THAT( testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) )
with expansion:
"this string contains 'abc' as a substring" equals: "this string contains
'abc' as a substring" (case insensitive)
'ABC' as a substring" (case insensitive)
-------------------------------------------------------------------------------
Equals string matcher
@@ -4677,7 +4677,7 @@ Exception.tests.cpp:<line number>
Exception.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) )
with expansion:
"expected exception" equals: "expected exception" (case insensitive)
"expected exception" equals: "expecteD Exception" (case insensitive)
-------------------------------------------------------------------------------
Exception messages can be tested for
@@ -4704,7 +4704,7 @@ with expansion:
Exception.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_WITH( thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) )
with expansion:
"expected exception" contains: "except" (case insensitive)
"expected exception" contains: "exCept" (case insensitive)
-------------------------------------------------------------------------------
Exception thrown inside stringify does not fail the test
@@ -12188,7 +12188,7 @@ with expansion:
Matchers.tests.cpp:<line number>: PASSED:
CHECK_THAT( testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) )
with expansion:
"this string contains 'abc' as a substring" contains: "abc" (case
"this string contains 'abc' as a substring" contains: "aBC" (case
insensitive)
Matchers.tests.cpp:<line number>: PASSED:
@@ -12199,7 +12199,7 @@ with expansion:
Matchers.tests.cpp:<line number>: PASSED:
CHECK_THAT( testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) )
with expansion:
"this string contains 'abc' as a substring" starts with: "this" (case
"this string contains 'abc' as a substring" starts with: "THIS" (case
insensitive)
Matchers.tests.cpp:<line number>: PASSED:
@@ -12210,7 +12210,7 @@ with expansion:
Matchers.tests.cpp:<line number>: PASSED:
CHECK_THAT( testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) )
with expansion:
"this string contains 'abc' as a substring" ends with: " substring" (case
"this string contains 'abc' as a substring" ends with: " SuBsTrInG" (case
insensitive)
-------------------------------------------------------------------------------
+6 -6
View File
@@ -1131,7 +1131,7 @@ ok {test-number} - x == Approx( 1.3 ) for: 1.30000000000000027 == Approx( 1.3000
# Equals
ok {test-number} - testStringForMatching(), Equals( "this string contains 'abc' as a substring" ) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring"
# Equals
ok {test-number} - testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive)
ok {test-number} - testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" (case insensitive)
# Equals string matcher
not ok {test-number} - testStringForMatching(), Equals( "this string contains 'ABC' as a substring" ) for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring"
# Equals string matcher
@@ -1169,7 +1169,7 @@ ok {test-number} - throwsSpecialException( 2 ), SpecialException, MessageMatches
# Exception messages can be tested for
ok {test-number} - thisThrows(), "expected exception" for: "expected exception" equals: "expected exception"
# Exception messages can be tested for
ok {test-number} - thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expected exception" (case insensitive)
ok {test-number} - thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expecteD Exception" (case insensitive)
# Exception messages can be tested for
ok {test-number} - thisThrows(), StartsWith( "expected" ) for: "expected exception" starts with: "expected"
# Exception messages can be tested for
@@ -1177,7 +1177,7 @@ ok {test-number} - thisThrows(), EndsWith( "exception" ) for: "expected exceptio
# Exception messages can be tested for
ok {test-number} - thisThrows(), ContainsSubstring( "except" ) for: "expected exception" contains: "except"
# Exception messages can be tested for
ok {test-number} - thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive)
ok {test-number} - thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "exCept" (case insensitive)
# Exception thrown inside stringify does not fail the test
ok {test-number} - tos == tos for: { stringification failed with an exception: "Invalid" } == { stringification failed with an exception: "Invalid" }
# Exceptions matchers
@@ -2916,15 +2916,15 @@ ok {test-number} - testStringForMatching(), ContainsSubstring( "string", Catch::
# String matchers
ok {test-number} - testStringForMatching(), ContainsSubstring( "abc" ) for: "this string contains 'abc' as a substring" contains: "abc"
# String matchers
ok {test-number} - testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "abc" (case insensitive)
ok {test-number} - testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "aBC" (case insensitive)
# String matchers
ok {test-number} - testStringForMatching(), StartsWith( "this" ) for: "this string contains 'abc' as a substring" starts with: "this"
# String matchers
ok {test-number} - testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" starts with: "this" (case insensitive)
ok {test-number} - testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" starts with: "THIS" (case insensitive)
# String matchers
ok {test-number} - testStringForMatching(), EndsWith( "substring" ) for: "this string contains 'abc' as a substring" ends with: "substring"
# String matchers
ok {test-number} - testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: " substring" (case insensitive)
ok {test-number} - testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: " SuBsTrInG" (case insensitive)
# StringRef
ok {test-number} - empty.empty() for: true
# StringRef
@@ -1129,7 +1129,7 @@ ok {test-number} - x == Approx( 1.3 ) for: 1.30000000000000027 == Approx( 1.3000
# Equals
ok {test-number} - testStringForMatching(), Equals( "this string contains 'abc' as a substring" ) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring"
# Equals
ok {test-number} - testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive)
ok {test-number} - testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" (case insensitive)
# Equals string matcher
not ok {test-number} - testStringForMatching(), Equals( "this string contains 'ABC' as a substring" ) for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring"
# Equals string matcher
@@ -1167,7 +1167,7 @@ ok {test-number} - throwsSpecialException( 2 ), SpecialException, MessageMatches
# Exception messages can be tested for
ok {test-number} - thisThrows(), "expected exception" for: "expected exception" equals: "expected exception"
# Exception messages can be tested for
ok {test-number} - thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expected exception" (case insensitive)
ok {test-number} - thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expecteD Exception" (case insensitive)
# Exception messages can be tested for
ok {test-number} - thisThrows(), StartsWith( "expected" ) for: "expected exception" starts with: "expected"
# Exception messages can be tested for
@@ -1175,7 +1175,7 @@ ok {test-number} - thisThrows(), EndsWith( "exception" ) for: "expected exceptio
# Exception messages can be tested for
ok {test-number} - thisThrows(), ContainsSubstring( "except" ) for: "expected exception" contains: "except"
# Exception messages can be tested for
ok {test-number} - thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive)
ok {test-number} - thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "exCept" (case insensitive)
# Exception thrown inside stringify does not fail the test
ok {test-number} - tos == tos for: { stringification failed with an exception: "Invalid" } == { stringification failed with an exception: "Invalid" }
# Exceptions matchers
@@ -2909,15 +2909,15 @@ ok {test-number} - testStringForMatching(), ContainsSubstring( "string", Catch::
# String matchers
ok {test-number} - testStringForMatching(), ContainsSubstring( "abc" ) for: "this string contains 'abc' as a substring" contains: "abc"
# String matchers
ok {test-number} - testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "abc" (case insensitive)
ok {test-number} - testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" contains: "aBC" (case insensitive)
# String matchers
ok {test-number} - testStringForMatching(), StartsWith( "this" ) for: "this string contains 'abc' as a substring" starts with: "this"
# String matchers
ok {test-number} - testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" starts with: "this" (case insensitive)
ok {test-number} - testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" starts with: "THIS" (case insensitive)
# String matchers
ok {test-number} - testStringForMatching(), EndsWith( "substring" ) for: "this string contains 'abc' as a substring" ends with: "substring"
# String matchers
ok {test-number} - testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: " substring" (case insensitive)
ok {test-number} - testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: " SuBsTrInG" (case insensitive)
# StringRef
ok {test-number} - empty.empty() for: true
# StringRef
+6 -6
View File
@@ -5102,7 +5102,7 @@ Approx( 1.30000000000000004 )
testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No )
</Original>
<Expanded>
"this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive)
"this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" (case insensitive)
</Expanded>
</Expression>
<OverallResult success="true" skips="0"/>
@@ -5295,7 +5295,7 @@ Approx( 1.30000000000000004 )
thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No )
</Original>
<Expanded>
"expected exception" equals: "expected exception" (case insensitive)
"expected exception" equals: "expecteD Exception" (case insensitive)
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
@@ -5330,7 +5330,7 @@ Approx( 1.30000000000000004 )
thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No )
</Original>
<Expanded>
"expected exception" contains: "except" (case insensitive)
"expected exception" contains: "exCept" (case insensitive)
</Expanded>
</Expression>
<OverallResults successes="4" failures="0" expectedFailures="0" skipped="false"/>
@@ -14357,7 +14357,7 @@ Message from section two
testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No )
</Original>
<Expanded>
"this string contains 'abc' as a substring" contains: "abc" (case insensitive)
"this string contains 'abc' as a substring" contains: "aBC" (case insensitive)
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -14373,7 +14373,7 @@ Message from section two
testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No )
</Original>
<Expanded>
"this string contains 'abc' as a substring" starts with: "this" (case insensitive)
"this string contains 'abc' as a substring" starts with: "THIS" (case insensitive)
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -14389,7 +14389,7 @@ Message from section two
testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No )
</Original>
<Expanded>
"this string contains 'abc' as a substring" ends with: " substring" (case insensitive)
"this string contains 'abc' as a substring" ends with: " SuBsTrInG" (case insensitive)
</Expanded>
</Expression>
<OverallResult success="true" skips="0"/>
@@ -5102,7 +5102,7 @@ Approx( 1.30000000000000004 )
testStringForMatching(), Equals( "this string contains 'ABC' as a substring", Catch::CaseSensitive::No )
</Original>
<Expanded>
"this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive)
"this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" (case insensitive)
</Expanded>
</Expression>
<OverallResult success="true" skips="0"/>
@@ -5295,7 +5295,7 @@ Approx( 1.30000000000000004 )
thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No )
</Original>
<Expanded>
"expected exception" equals: "expected exception" (case insensitive)
"expected exception" equals: "expecteD Exception" (case insensitive)
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
@@ -5330,7 +5330,7 @@ Approx( 1.30000000000000004 )
thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No )
</Original>
<Expanded>
"expected exception" contains: "except" (case insensitive)
"expected exception" contains: "exCept" (case insensitive)
</Expanded>
</Expression>
<OverallResults successes="4" failures="0" expectedFailures="0" skipped="false"/>
@@ -14357,7 +14357,7 @@ Message from section two
testStringForMatching(), ContainsSubstring( "aBC", Catch::CaseSensitive::No )
</Original>
<Expanded>
"this string contains 'abc' as a substring" contains: "abc" (case insensitive)
"this string contains 'abc' as a substring" contains: "aBC" (case insensitive)
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -14373,7 +14373,7 @@ Message from section two
testStringForMatching(), StartsWith( "THIS", Catch::CaseSensitive::No )
</Original>
<Expanded>
"this string contains 'abc' as a substring" starts with: "this" (case insensitive)
"this string contains 'abc' as a substring" starts with: "THIS" (case insensitive)
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -14389,7 +14389,7 @@ Message from section two
testStringForMatching(), EndsWith( " SuBsTrInG", Catch::CaseSensitive::No )
</Original>
<Expanded>
"this string contains 'abc' as a substring" ends with: " substring" (case insensitive)
"this string contains 'abc' as a substring" ends with: " SuBsTrInG" (case insensitive)
</Expanded>
</Expression>
<OverallResult success="true" skips="0"/>