Add AllTrue, AnyTrue, NoneTrue matchers

This commit is contained in:
Raphael Schaller
2021-11-14 17:05:31 +01:00
committed by Martin Hořeňovský
parent f993b702c6
commit 1bd233866c
22 changed files with 3104 additions and 27 deletions

View File

@@ -547,31 +547,288 @@ TEST_CASE("Usage of NoneMatch range matcher", "[matchers][templated][quantifiers
}
}
namespace {
struct ConvertibleToBool
{
bool v;
// This is a C++17 extension, and GCC refuses to compile such code
// unless it is set to C++17 or later
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 evalutes 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 evalutes 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 evalutes 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 evalutes 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 evalutes 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 evalutes 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;
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;
} ) ) );
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, AnyMatch( Predicate<int>( []( int elem ) {
return elem < 2;
} ) ) );
REQUIRE_THAT( diff_types, !NoneMatch( Predicate<int>( []( int elem ) {
return elem < 3;
} ) ) );
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() );
}
}
#endif