Add IsEmpty and SizeIs matchers for ranges/containers

`SizeIs` can accept both `size_t` and a matcher. In the first case,
it checks whether the size of the range is equal to specified size.
In the second case, it checks whether the provided matcher accepts
the size of the range.
This commit is contained in:
Martin Hořeňovský 2020-03-09 11:13:07 +01:00
parent f52a58e857
commit 3a3efebd16
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
15 changed files with 666 additions and 10 deletions

View File

@ -58,10 +58,12 @@
* This does not change `TEST_CASE` and friends in any way
* `IStreamingReporter::IsMulti` member function was removed
* This is _very_ unlikely to actually affect anyone, as it was default-implemented in the interface, and only used internally
* Various classes not designed for user-extension have been made final
* `ListeningReporter` is now `final`
* Concrete Matchers (e.g. `UnorderedEquals` vector matcher) are now `final`
* `ListeningReporter` is now final
### Improvements
* Matchers have been extended with the ability to use different signatures of `match` (#1307, #1553, #1554, #1843)
* This includes having templated `match` member function

View File

@ -33,13 +33,14 @@ set(BENCHMARK_SOURCES
SOURCE_GROUP("benchmark" FILES ${BENCHMARK_HEADERS} ${BENCHMARK_SOURCES})
set(INTERNAL_HEADERS
${SOURCES_DIR}/internal/catch_capture_matchers.h
${SOURCES_DIR}/internal/catch_container_nonmembers.hpp
${SOURCES_DIR}/catch.hpp
${SOURCES_DIR}/catch_approx.h
${SOURCES_DIR}/catch_assertionhandler.h
${SOURCES_DIR}/catch_assertioninfo.h
${SOURCES_DIR}/catch_assertionresult.h
${SOURCES_DIR}/catch_capture.hpp
${SOURCES_DIR}/internal/catch_capture_matchers.h
${SOURCES_DIR}/catch_clara.h
${SOURCES_DIR}/catch_commandline.h
${SOURCES_DIR}/catch_common.h
@ -73,6 +74,7 @@ set(INTERNAL_HEADERS
${SOURCES_DIR}/catch_leak_detector.h
${SOURCES_DIR}/catch_list.h
${SOURCES_DIR}/matchers/catch_matchers.hpp
${SOURCES_DIR}/matchers/catch_matchers_container_properties.hpp
${SOURCES_DIR}/matchers/catch_matchers_contains.hpp
${SOURCES_DIR}/matchers/catch_matchers_exception.hpp
${SOURCES_DIR}/matchers/catch_matchers_floating.hpp
@ -157,6 +159,7 @@ set(IMPL_SOURCES
${SOURCES_DIR}/catch_list.cpp
${SOURCES_DIR}/catch_leak_detector.cpp
${SOURCES_DIR}/matchers/catch_matchers.cpp
${SOURCES_DIR}/matchers/catch_matchers_container_properties.cpp
${SOURCES_DIR}/matchers/catch_matchers_exception.cpp
${SOURCES_DIR}/matchers/catch_matchers_floating.cpp
${SOURCES_DIR}/matchers/catch_matchers_generic.cpp

View File

@ -0,0 +1,67 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef TWOBLUECUBES_CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
#include <catch2/catch_compiler_capabilities.h>
// We want a simple polyfill over `std::empty`, `std::size` and so on
// for C++14 or C++ libraries with incomplete support.
// We also have to handle that MSVC std lib will happily provide these
// under older standards.
#if defined(CATCH_CPP17_OR_GREATER) || defined(_MSC_VER)
// We are already using this header either way, so there shouldn't
// be much additional overhead in including it to get the feature
// test macros
#include <string>
# if !defined(__cpp_lib_nonmember_container_access)
# define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
# endif
#else
#define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
#endif
namespace Catch {
namespace Detail {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
template <typename Container>
constexpr auto empty(Container const& cont) -> decltype(cont.empty()) {
return cont.empty();
}
template <typename T, std::size_t N>
constexpr bool empty(const T (&)[N]) noexcept {
// GCC < 7 does not support the const T(&)[] parameter syntax
// so we have to ignore the length explicitly
(void)N;
return false;
}
template <typename T>
constexpr bool empty(std::initializer_list<T> list) noexcept {
return list.size() > 0;
}
template <typename Container>
constexpr auto size(Container const& cont) -> decltype(cont.size()) {
return cont.size();
}
template <typename T, std::size_t N>
constexpr std::size_t size(const T(&)[N]) noexcept {
return N;
}
#endif // CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
} // end namespace Detail
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED

View File

@ -0,0 +1,30 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <catch2/matchers/catch_matchers_container_properties.hpp>
#include <catch2/catch_stream.h>
namespace Catch {
namespace Matchers {
std::string IsEmptyMatcher::describe() const {
return "is empty";
}
std::string HasSizeMatcher::describe() const {
ReusableStringStream sstr;
sstr << "has size == " << m_target_size;
return sstr.str();
}
IsEmptyMatcher IsEmpty() {
return {};
}
HasSizeMatcher SizeIs(std::size_t sz) {
return HasSizeMatcher{ sz };
}
} // end namespace Matchers
} // end namespace Catch

View File

@ -0,0 +1,86 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef TWOBLUECUBES_CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
#include <catch2/matchers/catch_matchers_templates.hpp>
#include <catch2/internal/catch_container_nonmembers.hpp>
namespace Catch {
namespace Matchers {
class IsEmptyMatcher final : public MatcherGenericBase {
public:
// todo: Use polyfills
template <typename RangeLike>
bool match(RangeLike&& rng) const {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
using Catch::Detail::empty;
#else
using std::empty;
#endif
return empty(rng);
}
std::string describe() const override;
};
class HasSizeMatcher final : public MatcherGenericBase {
std::size_t m_target_size;
public:
explicit HasSizeMatcher(std::size_t target_size):
m_target_size(target_size)
{}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
using Catch::Detail::size;
#else
using std::size;
#endif
return size(rng) == m_target_size;
}
std::string describe() const override;
};
template <typename Matcher>
class SizeMatchesMatcher final : public MatcherGenericBase {
Matcher m_matcher;
public:
explicit SizeMatchesMatcher(Matcher m):
m_matcher(std::move(m))
{}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
using Catch::Detail::size;
#else
using std::size;
#endif
return m_matcher.match(size(rng));
}
std::string describe() const override {
return "size matches " + m_matcher.describe();
}
};
//! Creates a matcher that accepts empty ranges/containers
IsEmptyMatcher IsEmpty();
//! Creates a matcher that accepts ranges/containers with specific size
HasSizeMatcher SizeIs(std::size_t sz);
template <typename Matcher>
std::enable_if_t<Detail::is_matcher<Matcher>::value,
SizeMatchesMatcher<Matcher>> SizeIs(Matcher&& m) {
return SizeMatchesMatcher<Matcher>{std::forward<Matcher>(m)};
}
} // end namespace Matchers
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED

View File

@ -81,6 +81,7 @@ Nor would this
:test-result: PASS Arbitrary predicate matcher
:test-result: PASS Assertions then sections
:test-result: PASS Basic use of the Contains range matcher
:test-result: PASS Basic use of the Empty range matcher
:test-result: PASS CAPTURE can deal with complex expressions
:test-result: PASS CAPTURE can deal with complex expressions involving commas
:test-result: PASS CAPTURE parses string and character constants
@ -218,6 +219,7 @@ Message from section two
:test-result: PASS Tracker
:test-result: PASS Trim strings
:test-result: FAIL Unexpected exceptions can be translated
:test-result: PASS Usage of the SizeIs range matcher
:test-result: PASS Use a custom approx
:test-result: PASS Variadic macros
:test-result: PASS Vector Approx matcher

View File

@ -256,6 +256,14 @@ MatchersRanges.tests.cpp:<line number>: passed: in, !Contains(8) for: { 1, 2, 3,
MatchersRanges.tests.cpp:<line number>: passed: in, Contains(MoveOnlyTestElement{ 2 }) for: { 1, 2, 3 } contains element 2
MatchersRanges.tests.cpp:<line number>: passed: in, !Contains(MoveOnlyTestElement{ 9 }) for: { 1, 2, 3 } not contains element 9
MatchersRanges.tests.cpp:<line number>: passed: in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)) for: { 1.0, 2.0, 3.0, 0.0 } contains element matching is within 0.5 of 0.5
MatchersRanges.tests.cpp:<line number>: passed: empty_array, IsEmpty() for: { } is empty
MatchersRanges.tests.cpp:<line number>: passed: non_empty_array, !IsEmpty() for: { 0.0 } not is empty
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, IsEmpty() for: { } is empty
MatchersRanges.tests.cpp:<line number>: passed: non_empty_vec, !IsEmpty() for: { 'a', 'b', 'c' } not is empty
MatchersRanges.tests.cpp:<line number>: passed: inner_lists_are_empty, !IsEmpty() for: { { } } not is empty
MatchersRanges.tests.cpp:<line number>: passed: inner_lists_are_empty.front(), IsEmpty() for: { } is empty
MatchersRanges.tests.cpp:<line number>: passed: has_empty{}, !IsEmpty() for: {?} not is empty
MatchersRanges.tests.cpp:<line number>: passed: unrelated::ADL_empty{}, IsEmpty() for: {?} is empty
Message.tests.cpp:<line number>: passed: with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true'
Message.tests.cpp:<line number>: passed: with 7 messages: 'std::vector<int>{1, 2, 3}[0, 1, 2] := 3' and 'std::vector<int>{1, 2, 3}[(0, 1)] := 2' and 'std::vector<int>{1, 2, 3}[0] := 1' and '(helper_1436<int, int>{12, -12}) := { 12, -12 }' and '(helper_1436<int, int>(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3'
Message.tests.cpp:<line number>: passed: with 11 messages: '("comma, in string", "escaped, \", ") := "escaped, ", "' and '"single quote in string,'," := "single quote in string,',"' and '"some escapes, \\,\\\\" := "some escapes, \,\\"' and '"some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<"' and ''"' := '"'' and ''\'' := '''' and '',' := ','' and ''}' := '}'' and '')' := ')'' and ''(' := '('' and ''{' := '{''
@ -1563,6 +1571,15 @@ StringManip.tests.cpp:<line number>: passed: trim(StringRef(whitespace_at_both_e
==
There is no extra whitespace here
Exception.tests.cpp:<line number>: failed: unexpected exception with message: '3.14'
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, SizeIs(0) for: { } has size == 0
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, !SizeIs(2) for: { } not has size == 2
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2
MatchersRanges.tests.cpp:<line number>: passed: arr, SizeIs(2) for: { 0, 0 } has size == 2
MatchersRanges.tests.cpp:<line number>: passed: arr, SizeIs( Lt(3)) for: { 0, 0 } size matches is less than 3
MatchersRanges.tests.cpp:<line number>: passed: arr, !SizeIs(!Lt(3)) for: { 0, 0 } not size matches not is less than 3
MatchersRanges.tests.cpp:<line number>: passed: map, SizeIs(3) for: { {?}, {?}, {?} } has size == 3
MatchersRanges.tests.cpp:<line number>: passed: unrelated::ADL_size{}, SizeIs(12) for: {?} has size == 12
MatchersRanges.tests.cpp:<line number>: passed: has_size{}, SizeIs(13) for: {?} has size == 13
Approx.tests.cpp:<line number>: passed: d == approx( 1.23 ) for: 1.23 == Approx( 1.23 )
Approx.tests.cpp:<line number>: passed: d == approx( 1.22 ) for: 1.23 == Approx( 1.22 )
Approx.tests.cpp:<line number>: passed: d == approx( 1.24 ) for: 1.23 == Approx( 1.24 )

View File

@ -1380,6 +1380,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
test cases: 329 | 255 passed | 70 failed | 4 failed as expected
assertions: 1851 | 1699 passed | 131 failed | 21 failed as expected
test cases: 331 | 257 passed | 70 failed | 4 failed as expected
assertions: 1868 | 1716 passed | 131 failed | 21 failed as expected

View File

@ -2050,6 +2050,67 @@ MatchersRanges.tests.cpp:<line number>: PASSED:
with expansion:
{ 1.0, 2.0, 3.0, 0.0 } contains element matching is within 0.5 of 0.5
-------------------------------------------------------------------------------
Basic use of the Empty range matcher
Simple, std-provided containers
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( empty_array, IsEmpty() )
with expansion:
{ } is empty
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( non_empty_array, !IsEmpty() )
with expansion:
{ 0.0 } not is empty
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( empty_vec, IsEmpty() )
with expansion:
{ } is empty
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( non_empty_vec, !IsEmpty() )
with expansion:
{ 'a', 'b', 'c' } not is empty
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( inner_lists_are_empty, !IsEmpty() )
with expansion:
{ { } } not is empty
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( inner_lists_are_empty.front(), IsEmpty() )
with expansion:
{ } is empty
-------------------------------------------------------------------------------
Basic use of the Empty range matcher
Type with empty
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( has_empty{}, !IsEmpty() )
with expansion:
{?} not is empty
-------------------------------------------------------------------------------
Basic use of the Empty range matcher
Type requires ADL found empty free function
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( unrelated::ADL_empty{}, IsEmpty() )
with expansion:
{?} is empty
-------------------------------------------------------------------------------
CAPTURE can deal with complex expressions
-------------------------------------------------------------------------------
@ -11379,6 +11440,72 @@ Exception.tests.cpp:<line number>: FAILED:
due to unexpected exception with message:
3.14
-------------------------------------------------------------------------------
Usage of the SizeIs range matcher
Some with stdlib containers
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( empty_vec, SizeIs(0) )
with expansion:
{ } has size == 0
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( empty_vec, !SizeIs(2) )
with expansion:
{ } not has size == 2
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( empty_vec, SizeIs(Lt(2)) )
with expansion:
{ } size matches is less than 2
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( arr, SizeIs(2) )
with expansion:
{ 0, 0 } has size == 2
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( arr, SizeIs( Lt(3)) )
with expansion:
{ 0, 0 } size matches is less than 3
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( arr, !SizeIs(!Lt(3)) )
with expansion:
{ 0, 0 } not size matches not is less than 3
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( map, SizeIs(3) )
with expansion:
{ {?}, {?}, {?} } has size == 3
-------------------------------------------------------------------------------
Usage of the SizeIs range matcher
Type requires ADL found size free function
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( unrelated::ADL_size{}, SizeIs(12) )
with expansion:
{?} has size == 12
-------------------------------------------------------------------------------
Usage of the SizeIs range matcher
Type has size member
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( has_size{}, SizeIs(13) )
with expansion:
{?} has size == 13
-------------------------------------------------------------------------------
Use a custom approx
-------------------------------------------------------------------------------
@ -14498,6 +14625,6 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>: PASSED:
===============================================================================
test cases: 329 | 239 passed | 86 failed | 4 failed as expected
assertions: 1868 | 1699 passed | 148 failed | 21 failed as expected
test cases: 331 | 241 passed | 86 failed | 4 failed as expected
assertions: 1885 | 1716 passed | 148 failed | 21 failed as expected

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="17" failures="132" tests="1869" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="132" tests="1886" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals] *"/>
<property name="random-seed" value="1"/>
@ -348,6 +348,9 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Basic use of the Contains range matcher/Can handle type that requires ADL-found free function begin and end" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Basic use of the Contains range matcher/Initialization with move only types" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Basic use of the Contains range matcher/Matching using matcher" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Basic use of the Empty range matcher/Simple, std-provided containers" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Basic use of the Empty range matcher/Type with empty" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Basic use of the Empty range matcher/Type requires ADL found empty free function" time="{duration}"/>
<testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions" time="{duration}"/>
<testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions involving commas" time="{duration}"/>
<testcase classname="<exe-name>.global" name="CAPTURE parses string and character constants" time="{duration}"/>
@ -1249,6 +1252,9 @@ FAILED:
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Some with stdlib containers" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Type requires ADL found size free function" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Type has size member" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Use a custom approx" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Variadic macros/Section with one argument" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Vector Approx matcher/Empty vector is roughly equal to an empty vector" time="{duration}"/>

View File

@ -1222,6 +1222,12 @@ Matchers.tests.cpp:<line number>
<testCase name="Basic use of the Contains range matcher/Can handle type that requires ADL-found free function begin and end" duration="{duration}"/>
<testCase name="Basic use of the Contains range matcher/Initialization with move only types" duration="{duration}"/>
<testCase name="Basic use of the Contains range matcher/Matching using matcher" duration="{duration}"/>
<testCase name="Basic use of the Empty range matcher/Simple, std-provided containers" duration="{duration}"/>
<testCase name="Basic use of the Empty range matcher/Type with empty" duration="{duration}"/>
<testCase name="Basic use of the Empty range matcher/Type requires ADL found empty free function" duration="{duration}"/>
<testCase name="Usage of the SizeIs range matcher/Some with stdlib containers" duration="{duration}"/>
<testCase name="Usage of the SizeIs range matcher/Type requires ADL found size free function" duration="{duration}"/>
<testCase name="Usage of the SizeIs range matcher/Type has size member" duration="{duration}"/>
</file>
<file path="tests/<exe-name>/UsageTests/Message.tests.cpp">
<testCase name="#1455 - INFO and WARN can start with a linebreak" duration="{duration}"/>

View File

@ -510,6 +510,22 @@ ok {test-number} - in, Contains(MoveOnlyTestElement{ 2 }) for: { 1, 2, 3 } conta
ok {test-number} - in, !Contains(MoveOnlyTestElement{ 9 }) for: { 1, 2, 3 } not contains element 9
# Basic use of the Contains range matcher
ok {test-number} - in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)) for: { 1.0, 2.0, 3.0, 0.0 } contains element matching is within 0.5 of 0.5
# Basic use of the Empty range matcher
ok {test-number} - empty_array, IsEmpty() for: { } is empty
# Basic use of the Empty range matcher
ok {test-number} - non_empty_array, !IsEmpty() for: { 0.0 } not is empty
# Basic use of the Empty range matcher
ok {test-number} - empty_vec, IsEmpty() for: { } is empty
# Basic use of the Empty range matcher
ok {test-number} - non_empty_vec, !IsEmpty() for: { 'a', 'b', 'c' } not is empty
# Basic use of the Empty range matcher
ok {test-number} - inner_lists_are_empty, !IsEmpty() for: { { } } not is empty
# Basic use of the Empty range matcher
ok {test-number} - inner_lists_are_empty.front(), IsEmpty() for: { } is empty
# Basic use of the Empty range matcher
ok {test-number} - has_empty{}, !IsEmpty() for: {?} not is empty
# Basic use of the Empty range matcher
ok {test-number} - unrelated::ADL_empty{}, IsEmpty() for: {?} is empty
# CAPTURE can deal with complex expressions
ok {test-number} - with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true'
# CAPTURE can deal with complex expressions involving commas
@ -2973,6 +2989,24 @@ ok {test-number} - trim(StringRef(trailing_whitespace)) == StringRef(no_whitespa
ok {test-number} - trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) for: There is no extra whitespace here == There is no extra whitespace here
# Unexpected exceptions can be translated
not ok {test-number} - unexpected exception with message: '3.14'
# Usage of the SizeIs range matcher
ok {test-number} - empty_vec, SizeIs(0) for: { } has size == 0
# Usage of the SizeIs range matcher
ok {test-number} - empty_vec, !SizeIs(2) for: { } not has size == 2
# Usage of the SizeIs range matcher
ok {test-number} - empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2
# Usage of the SizeIs range matcher
ok {test-number} - arr, SizeIs(2) for: { 0, 0 } has size == 2
# Usage of the SizeIs range matcher
ok {test-number} - arr, SizeIs( Lt(3)) for: { 0, 0 } size matches is less than 3
# Usage of the SizeIs range matcher
ok {test-number} - arr, !SizeIs(!Lt(3)) for: { 0, 0 } not size matches not is less than 3
# Usage of the SizeIs range matcher
ok {test-number} - map, SizeIs(3) for: { {?}, {?}, {?} } has size == 3
# Usage of the SizeIs range matcher
ok {test-number} - unrelated::ADL_size{}, SizeIs(12) for: {?} has size == 12
# Usage of the SizeIs range matcher
ok {test-number} - has_size{}, SizeIs(13) for: {?} has size == 13
# Use a custom approx
ok {test-number} - d == approx( 1.23 ) for: 1.23 == Approx( 1.23 )
# Use a custom approx
@ -3728,5 +3762,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
ok {test-number} -
# xmlentitycheck
ok {test-number} -
1..1860
1..1877

View File

@ -195,6 +195,8 @@ Exception.tests.cpp:<line number>|nunexpected exception with message:|n "unexpe
##teamcity[testFinished name='Assertions then sections' duration="{duration}"]
##teamcity[testStarted name='Basic use of the Contains range matcher']
##teamcity[testFinished name='Basic use of the Contains range matcher' duration="{duration}"]
##teamcity[testStarted name='Basic use of the Empty range matcher']
##teamcity[testFinished name='Basic use of the Empty range matcher' duration="{duration}"]
##teamcity[testStarted name='CAPTURE can deal with complex expressions']
##teamcity[testFinished name='CAPTURE can deal with complex expressions' duration="{duration}"]
##teamcity[testStarted name='CAPTURE can deal with complex expressions involving commas']
@ -539,6 +541,8 @@ Exception.tests.cpp:<line number>|nunexpected exception with message:|n "For so
##teamcity[testStarted name='Unexpected exceptions can be translated']
Exception.tests.cpp:<line number>|nunexpected exception with message:|n "3.14"']
##teamcity[testFinished name='Unexpected exceptions can be translated' duration="{duration}"]
##teamcity[testStarted name='Usage of the SizeIs range matcher']
##teamcity[testFinished name='Usage of the SizeIs range matcher' duration="{duration}"]
##teamcity[testStarted name='Use a custom approx']
##teamcity[testFinished name='Use a custom approx' duration="{duration}"]
##teamcity[testStarted name='Variadic macros']

View File

@ -2295,6 +2295,82 @@ Nor would this
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Basic use of the Empty range matcher" tags="[empty][matchers][templated]" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Section name="Simple, std-provided containers" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
empty_array, IsEmpty()
</Original>
<Expanded>
{ } is empty
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
non_empty_array, !IsEmpty()
</Original>
<Expanded>
{ 0.0 } not is empty
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
empty_vec, IsEmpty()
</Original>
<Expanded>
{ } is empty
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
non_empty_vec, !IsEmpty()
</Original>
<Expanded>
{ 'a', 'b', 'c' } not is empty
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
inner_lists_are_empty, !IsEmpty()
</Original>
<Expanded>
{ { } } not is empty
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
inner_lists_are_empty.front(), IsEmpty()
</Original>
<Expanded>
{ } is empty
</Expanded>
</Expression>
<OverallResults successes="6" failures="0" expectedFailures="0"/>
</Section>
<Section name="Type with empty" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
has_empty{}, !IsEmpty()
</Original>
<Expanded>
{?} not is empty
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Type requires ADL found empty free function" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
unrelated::ADL_empty{}, IsEmpty()
</Original>
<Expanded>
{?} is empty
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="CAPTURE can deal with complex expressions" tags="[capture][messages]" filename="tests/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
a := 1
@ -13749,6 +13825,90 @@ There is no extra whitespace here
</Exception>
<OverallResult success="false"/>
</TestCase>
<TestCase name="Usage of the SizeIs range matcher" tags="[matchers][size][templated]" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Section name="Some with stdlib containers" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
empty_vec, SizeIs(0)
</Original>
<Expanded>
{ } has size == 0
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
empty_vec, !SizeIs(2)
</Original>
<Expanded>
{ } not has size == 2
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
empty_vec, SizeIs(Lt(2))
</Original>
<Expanded>
{ } size matches is less than 2
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
arr, SizeIs(2)
</Original>
<Expanded>
{ 0, 0 } has size == 2
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
arr, SizeIs( Lt(3))
</Original>
<Expanded>
{ 0, 0 } size matches is less than 3
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
arr, !SizeIs(!Lt(3))
</Original>
<Expanded>
{ 0, 0 } not size matches not is less than 3
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
map, SizeIs(3)
</Original>
<Expanded>
{ {?}, {?}, {?} } has size == 3
</Expanded>
</Expression>
<OverallResults successes="7" failures="0" expectedFailures="0"/>
</Section>
<Section name="Type requires ADL found size free function" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
unrelated::ADL_size{}, SizeIs(12)
</Original>
<Expanded>
{?} has size == 12
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Type has size member" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
has_size{}, SizeIs(13)
</Original>
<Expanded>
{?} has size == 13
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Use a custom approx" tags="[Approx][custom]" filename="tests/<exe-name>/UsageTests/Approx.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Approx.tests.cpp" >
<Original>
@ -17381,7 +17541,7 @@ loose text artifact
</Section>
<OverallResult success="true"/>
</TestCase>
<OverallResults successes="1699" failures="149" expectedFailures="21"/>
<OverallResults successes="1716" failures="149" expectedFailures="21"/>
</Group>
<OverallResults successes="1699" failures="148" expectedFailures="21"/>
<OverallResults successes="1716" failures="148" expectedFailures="21"/>
</Catch>

View File

@ -2,14 +2,17 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_container_properties.hpp>
#include <catch2/matchers/catch_matchers_contains.hpp>
#include <catch2/matchers/catch_matchers_floating.hpp>
#include <array>
#include <cmath>
#include <list>
#include <map>
#include <vector>
namespace {
namespace unrelated {
class needs_ADL_begin {
std::array<int, 5> elements{ {1, 2, 3, 4, 5} };
@ -27,6 +30,7 @@ namespace unrelated {
return rhs.End();
}
};
} // end unrelated namespace
} // end anon namespace
struct MoveOnlyTestElement {
@ -105,3 +109,111 @@ TEST_CASE("Basic use of the Contains range matcher", "[matchers][templated][cont
REQUIRE_THAT(in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)));
}
}
namespace {
struct has_empty {
bool empty() const { return false; }
};
namespace unrelated {
struct ADL_empty {
bool Empty() const { return true; }
friend bool empty(ADL_empty e) {
return e.Empty();
}
};
} // end namespace unrelated
} // end unnamed namespace
TEST_CASE("Basic use of the Empty range matcher", "[matchers][templated][empty]") {
using Catch::Matchers::IsEmpty;
SECTION("Simple, std-provided containers") {
std::array<int, 0> empty_array{};
std::array<double, 1> non_empty_array{};
REQUIRE_THAT(empty_array, IsEmpty());
REQUIRE_THAT(non_empty_array, !IsEmpty());
std::vector<std::string> empty_vec;
std::vector<char> non_empty_vec{ 'a', 'b', 'c' };
REQUIRE_THAT(empty_vec, IsEmpty());
REQUIRE_THAT(non_empty_vec, !IsEmpty());
std::list<std::list<std::list<int>>> inner_lists_are_empty;
inner_lists_are_empty.push_back({});
REQUIRE_THAT(inner_lists_are_empty, !IsEmpty());
REQUIRE_THAT(inner_lists_are_empty.front(), IsEmpty());
}
SECTION("Type with empty") {
REQUIRE_THAT(has_empty{}, !IsEmpty());
}
SECTION("Type requires ADL found empty free function") {
REQUIRE_THAT(unrelated::ADL_empty{}, IsEmpty());
}
}
namespace {
class LessThanMatcher final : public Catch::Matchers::MatcherBase<size_t> {
size_t m_target;
public:
explicit LessThanMatcher(size_t target):
m_target(target)
{}
bool match(size_t const& size) const override {
return size < m_target;
}
std::string describe() const override {
return "is less than " + std::to_string(m_target);
}
};
LessThanMatcher Lt(size_t sz) {
return LessThanMatcher{ sz };
}
namespace unrelated {
struct ADL_size {
size_t sz() const {
return 12;
}
friend size_t size(ADL_size s) {
return s.sz();
}
};
} // end namespace unrelated
struct has_size {
size_t size() const {
return 13;
}
};
} // end unnamed namespace
TEST_CASE("Usage of the SizeIs range matcher", "[matchers][templated][size]") {
using Catch::Matchers::SizeIs;
SECTION("Some with stdlib containers") {
std::vector<int> empty_vec;
REQUIRE_THAT(empty_vec, SizeIs(0));
REQUIRE_THAT(empty_vec, !SizeIs(2));
REQUIRE_THAT(empty_vec, SizeIs(Lt(2)));
std::array<int, 2> arr{};
REQUIRE_THAT(arr, SizeIs(2));
REQUIRE_THAT(arr, SizeIs( Lt(3)));
REQUIRE_THAT(arr, !SizeIs(!Lt(3)));
std::map<int, int> map{ {1, 1}, {2, 2}, {3, 3} };
REQUIRE_THAT(map, SizeIs(3));
}
SECTION("Type requires ADL found size free function") {
REQUIRE_THAT(unrelated::ADL_size{}, SizeIs(12));
}
SECTION("Type has size member") {
REQUIRE_THAT(has_size{}, SizeIs(13));
}
}