mirror of
https://github.com/catchorg/Catch2.git
synced 2024-12-25 20:43:28 +01:00
Feature: generic matchers (#1843)
This commit extends the Matchers feature with the ability to have type-independent (e.g. templated) matchers. This is done by adding a new base type that Matchers can extend, `MatcherGenericBase`, and overloads of operators `!`, `&&` and `||` that handle matchers extending `MatcherGenericBase` in a special manner. These new matchers can also take their arguments as values and non-const references. Closes #1307 Closes #1553 Closes #1554 Co-authored-by: Martin Hořeňovský <martin.horenovsky@gmail.com>
This commit is contained in:
parent
db1a0465dc
commit
17c4b2d093
@ -77,6 +77,7 @@ set(INTERNAL_HEADERS
|
||||
${SOURCES_DIR}/catch_matchers_floating.h
|
||||
${SOURCES_DIR}/catch_matchers_generic.hpp
|
||||
${SOURCES_DIR}/catch_matchers_string.h
|
||||
${SOURCES_DIR}/catch_matchers_templates.hpp
|
||||
${SOURCES_DIR}/catch_matchers_vector.h
|
||||
${SOURCES_DIR}/catch_message.h
|
||||
${SOURCES_DIR}/catch_meta.hpp
|
||||
@ -159,6 +160,7 @@ set(IMPL_SOURCES
|
||||
${SOURCES_DIR}/catch_matchers_floating.cpp
|
||||
${SOURCES_DIR}/catch_matchers_generic.cpp
|
||||
${SOURCES_DIR}/catch_matchers_string.cpp
|
||||
${SOURCES_DIR}/catch_matchers_templates.cpp
|
||||
${SOURCES_DIR}/catch_message.cpp
|
||||
${SOURCES_DIR}/catch_output_redirect.cpp
|
||||
${SOURCES_DIR}/catch_registry_hub.cpp
|
||||
|
@ -17,7 +17,7 @@ namespace Catch {
|
||||
// the Equals matcher (so the header does not mention matchers)
|
||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) {
|
||||
std::string exceptionMessage = Catch::translateActiveException();
|
||||
MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
|
||||
MatchExpr<std::string, StringMatcher const&> expr( std::move(exceptionMessage), matcher, matcherString );
|
||||
handler.handleExpr( expr );
|
||||
}
|
||||
|
||||
|
@ -16,13 +16,13 @@ namespace Catch {
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
class MatchExpr : public ITransientExpression {
|
||||
ArgT const& m_arg;
|
||||
ArgT && m_arg;
|
||||
MatcherT m_matcher;
|
||||
StringRef m_matcherString;
|
||||
public:
|
||||
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
|
||||
: ITransientExpression{ true, matcher.match( arg ) },
|
||||
m_arg( arg ),
|
||||
MatchExpr( ArgT && arg, MatcherT const& matcher, StringRef const& matcherString )
|
||||
: ITransientExpression{ true, matcher.match( arg ) }, // not forwarding arg here on purpose
|
||||
m_arg( std::forward<ArgT>(arg) ),
|
||||
m_matcher( matcher ),
|
||||
m_matcherString( matcherString )
|
||||
{}
|
||||
@ -42,8 +42,8 @@ namespace Catch {
|
||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString );
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {
|
||||
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
|
||||
auto makeMatchExpr( ArgT && arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {
|
||||
return MatchExpr<ArgT, MatcherT>( std::forward<ArgT>(arg), matcher, matcherString );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
32
src/catch2/catch_matchers_templates.cpp
Normal file
32
src/catch2/catch_matchers_templates.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include <catch2/catch_matchers_templates.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
namespace Impl {
|
||||
MatcherGenericBase::~MatcherGenericBase() {}
|
||||
|
||||
std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end) {
|
||||
std::string description;
|
||||
std::size_t combined_size = 4;
|
||||
for ( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
|
||||
combined_size += desc->size();
|
||||
}
|
||||
combined_size += (descriptions_end - descriptions_begin - 1) * combine.size();
|
||||
|
||||
description.reserve(combined_size);
|
||||
|
||||
description += "( ";
|
||||
bool first = true;
|
||||
for( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
|
||||
if( first )
|
||||
first = false;
|
||||
else
|
||||
description += combine;
|
||||
description += *desc;
|
||||
}
|
||||
description += " )";
|
||||
return description;
|
||||
}
|
||||
}
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
262
src/catch2/catch_matchers_templates.hpp
Normal file
262
src/catch2/catch_matchers_templates.hpp
Normal file
@ -0,0 +1,262 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_TEMPLATES_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_TEMPLATES_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_common.h>
|
||||
#include <catch2/catch_matchers.h>
|
||||
#include <catch2/catch_stringref.h>
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
namespace Impl {
|
||||
|
||||
template<typename... MatcherTs> struct MatchAllOfGeneric;
|
||||
template<typename... MatcherTs> struct MatchAnyOfGeneric;
|
||||
template<typename MatcherT> struct MatchNotOfGeneric;
|
||||
|
||||
struct MatcherGenericBase : MatcherUntypedBase {
|
||||
virtual ~MatcherGenericBase();
|
||||
};
|
||||
|
||||
template<std::size_t N, std::size_t M>
|
||||
std::array<void const*, N + M> array_cat(std::array<void const*, N> && lhs, std::array<void const*, M> && rhs) {
|
||||
std::array<void const*, N + M> arr{};
|
||||
std::copy_n(lhs.begin(), N, arr.begin());
|
||||
std::copy_n(rhs.begin(), M, arr.begin() + N);
|
||||
return arr;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
std::array<void const*, N+1> array_cat(std::array<void const*, N> && lhs, void const* rhs) {
|
||||
std::array<void const*, N+1> arr{};
|
||||
std::copy_n(lhs.begin(), N, arr.begin());
|
||||
arr[N] = rhs;
|
||||
return arr;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
std::array<void const*, N+1> array_cat(void const* lhs, std::array<void const*, N> && rhs) {
|
||||
std::array<void const*, N+1> arr{lhs};
|
||||
std::copy_n(rhs.begin(), N, arr.begin() + 1);
|
||||
return arr;
|
||||
}
|
||||
|
||||
#ifdef CATCH_CPP17_OR_GREATER
|
||||
|
||||
using std::conjunction;
|
||||
|
||||
#else // CATCH_CPP17_OR_GREATER
|
||||
|
||||
template<typename... Cond>
|
||||
struct conjunction : std::true_type {};
|
||||
|
||||
template<typename Cond, typename... Rest>
|
||||
struct conjunction<Cond, Rest...> : std::integral_constant<bool, Cond::value && conjunction<Rest...>::value> {};
|
||||
|
||||
#endif // CATCH_CPP17_OR_GREATER
|
||||
|
||||
template<typename T>
|
||||
using is_generic_matcher = std::is_base_of<
|
||||
Catch::Matchers::Impl::MatcherGenericBase,
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type
|
||||
>;
|
||||
|
||||
template<typename... Ts>
|
||||
using are_generic_matchers = conjunction<is_generic_matcher<Ts>...>;
|
||||
|
||||
template<typename T>
|
||||
using is_matcher = std::is_base_of<
|
||||
Catch::Matchers::Impl::MatcherUntypedBase,
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type
|
||||
>;
|
||||
|
||||
|
||||
template<std::size_t N, typename Arg>
|
||||
bool match_all_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
|
||||
bool match_all_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
|
||||
return static_cast<T const*>(matchers[Idx])->match(arg) && match_all_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
|
||||
}
|
||||
|
||||
|
||||
template<std::size_t N, typename Arg>
|
||||
bool match_any_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
|
||||
bool match_any_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
|
||||
return static_cast<T const*>(matchers[Idx])->match(arg) || match_any_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
|
||||
}
|
||||
|
||||
std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end);
|
||||
|
||||
template<typename... MatcherTs, std::size_t... Idx>
|
||||
std::string describe_multi_matcher(StringRef combine, std::array<void const*, sizeof...(MatcherTs)> const& matchers, std::index_sequence<Idx...>) {
|
||||
std::array<std::string, sizeof...(MatcherTs)> descriptions {{
|
||||
static_cast<MatcherTs const*>(matchers[Idx])->toString()...
|
||||
}};
|
||||
|
||||
return describe_multi_matcher(combine, descriptions.data(), descriptions.data() + descriptions.size());
|
||||
}
|
||||
|
||||
|
||||
template<typename... MatcherTs>
|
||||
struct MatchAllOfGeneric : MatcherGenericBase {
|
||||
MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{std::addressof(matchers)...} {}
|
||||
explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
|
||||
|
||||
template<typename Arg>
|
||||
bool match(Arg&& arg) const {
|
||||
return match_all_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return describe_multi_matcher<MatcherTs...>(" and "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
|
||||
}
|
||||
|
||||
std::array<void const*, sizeof...(MatcherTs)> m_matchers;
|
||||
};
|
||||
|
||||
|
||||
template<typename... MatcherTs>
|
||||
struct MatchAnyOfGeneric : MatcherGenericBase {
|
||||
MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{std::addressof(matchers)...} {}
|
||||
explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
|
||||
|
||||
template<typename Arg>
|
||||
bool match(Arg&& arg) const {
|
||||
return match_any_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return describe_multi_matcher<MatcherTs...>(" or "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
|
||||
}
|
||||
|
||||
std::array<void const*, sizeof...(MatcherTs)> m_matchers;
|
||||
};
|
||||
|
||||
|
||||
template<typename MatcherT>
|
||||
struct MatchNotOfGeneric : MatcherGenericBase {
|
||||
explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{matcher} {}
|
||||
|
||||
template<typename Arg>
|
||||
bool match(Arg&& arg) const {
|
||||
return !m_matcher.match(arg);
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "not " + m_matcher.toString();
|
||||
}
|
||||
|
||||
MatcherT const& m_matcher;
|
||||
};
|
||||
|
||||
// compose only generic matchers
|
||||
template<typename MatcherLHS, typename MatcherRHS>
|
||||
typename std::enable_if<are_generic_matchers<MatcherLHS, MatcherRHS>::value, MatchAllOfGeneric<MatcherLHS, MatcherRHS>>::type
|
||||
operator && (MatcherLHS const& lhs, MatcherRHS const& rhs) {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
template<typename MatcherLHS, typename MatcherRHS>
|
||||
typename std::enable_if<are_generic_matchers<MatcherLHS, MatcherRHS>::value, MatchAnyOfGeneric<MatcherLHS, MatcherRHS>>::type
|
||||
operator || (MatcherLHS const& lhs, MatcherRHS const& rhs) {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
template<typename MatcherT>
|
||||
typename std::enable_if<is_generic_matcher<MatcherT>::value, MatchNotOfGeneric<MatcherT>>::type
|
||||
operator ! (MatcherT const& matcher) {
|
||||
return MatchNotOfGeneric<MatcherT>{matcher};
|
||||
}
|
||||
|
||||
|
||||
// compose mixed generic and non-generic matchers
|
||||
template<typename MatcherLHS, typename ArgRHS>
|
||||
typename std::enable_if<is_generic_matcher<MatcherLHS>::value, MatchAllOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>::type
|
||||
operator && (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
template<typename ArgLHS, typename MatcherRHS>
|
||||
typename std::enable_if<is_generic_matcher<MatcherRHS>::value, MatchAllOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>::type
|
||||
operator && (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
template<typename MatcherLHS, typename ArgRHS>
|
||||
typename std::enable_if<is_generic_matcher<MatcherLHS>::value, MatchAnyOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>::type
|
||||
operator || (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
template<typename ArgLHS, typename MatcherRHS>
|
||||
typename std::enable_if<is_generic_matcher<MatcherRHS>::value, MatchAnyOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>::type
|
||||
operator || (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
|
||||
// avoid deep nesting of matcher templates
|
||||
template<typename... MatchersLHS, typename... MatchersRHS>
|
||||
MatchAllOfGeneric<MatchersLHS..., MatchersRHS...>
|
||||
operator && (MatchAllOfGeneric<MatchersLHS...> && lhs, MatchAllOfGeneric<MatchersRHS...> && rhs) {
|
||||
return MatchAllOfGeneric<MatchersLHS..., MatchersRHS...>{array_cat(std::move(lhs.m_matchers), std::move(rhs.m_matchers))};
|
||||
}
|
||||
|
||||
template<typename... MatchersLHS, typename MatcherRHS>
|
||||
typename std::enable_if<is_matcher<MatcherRHS>::value, MatchAllOfGeneric<MatchersLHS..., MatcherRHS>>::type
|
||||
operator && (MatchAllOfGeneric<MatchersLHS...> && lhs, MatcherRHS const& rhs) {
|
||||
return MatchAllOfGeneric<MatchersLHS..., MatcherRHS>{array_cat(std::move(lhs.m_matchers), static_cast<void const*>(&rhs))};
|
||||
}
|
||||
|
||||
template<typename MatcherLHS, typename... MatchersRHS>
|
||||
typename std::enable_if<is_matcher<MatcherLHS>::value, MatchAllOfGeneric<MatcherLHS, MatchersRHS...>>::type
|
||||
operator && (MatcherLHS const& lhs, MatchAllOfGeneric<MatchersRHS...> && rhs) {
|
||||
return MatchAllOfGeneric<MatcherLHS, MatchersRHS...>{array_cat(static_cast<void const*>(std::addressof(lhs)), std::move(rhs.m_matchers))};
|
||||
}
|
||||
|
||||
template<typename... MatchersLHS, typename... MatchersRHS>
|
||||
MatchAnyOfGeneric<MatchersLHS..., MatchersRHS...>
|
||||
operator || (MatchAnyOfGeneric<MatchersLHS...> && lhs, MatchAnyOfGeneric<MatchersRHS...> && rhs) {
|
||||
return MatchAnyOfGeneric<MatchersLHS..., MatchersRHS...>{array_cat(std::move(lhs.m_matchers), std::move(rhs.m_matchers))};
|
||||
}
|
||||
|
||||
template<typename... MatchersLHS, typename MatcherRHS>
|
||||
typename std::enable_if<is_matcher<MatcherRHS>::value, MatchAnyOfGeneric<MatchersLHS..., MatcherRHS>>::type
|
||||
operator || (MatchAnyOfGeneric<MatchersLHS...> && lhs, MatcherRHS const& rhs) {
|
||||
return MatchAnyOfGeneric<MatchersLHS..., MatcherRHS>{array_cat(std::move(lhs.m_matchers), static_cast<void const*>(std::addressof(rhs)))};
|
||||
}
|
||||
|
||||
template<typename MatcherLHS, typename... MatchersRHS>
|
||||
typename std::enable_if<is_matcher<MatcherLHS>::value, MatchAnyOfGeneric<MatcherLHS, MatchersRHS...>>::type
|
||||
operator || (MatcherLHS const& lhs, MatchAnyOfGeneric<MatchersRHS...> && rhs) {
|
||||
return MatchAnyOfGeneric<MatcherLHS, MatchersRHS...>{array_cat(static_cast<void const*>(std::addressof(lhs)), std::move(rhs.m_matchers))};
|
||||
}
|
||||
|
||||
template<typename MatcherT>
|
||||
MatcherT const& operator ! (MatchNotOfGeneric<MatcherT> const& matcher) {
|
||||
return matcher.m_matcher;
|
||||
}
|
||||
|
||||
} // namespace Impl
|
||||
|
||||
} // namespace Matchers
|
||||
|
||||
using namespace Matchers;
|
||||
using Matchers::Impl::MatcherGenericBase;
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif //TWOBLUECUBES_CATCH_MATCHERS_TEMPLATES_HPP_INCLUDED
|
@ -85,6 +85,13 @@ Nor would this
|
||||
:test-result: PASS CAPTURE parses string and character constants
|
||||
:test-result: PASS Capture and info messages
|
||||
:test-result: PASS Character pretty printing
|
||||
:test-result: PASS Combining MatchAllOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchAnyOfGeneric does not nest
|
||||
:test-result: PASS Combining MatchNotOfGeneric does not nest
|
||||
:test-result: PASS Combining concrete matchers does not use templated matchers
|
||||
:test-result: PASS Combining only templated matchers
|
||||
:test-result: PASS Combining templated and concrete matchers
|
||||
:test-result: PASS Combining templated matchers
|
||||
:test-result: PASS Commas in various macros are allowed
|
||||
:test-result: PASS Comparing function pointers
|
||||
:test-result: PASS Comparison ops
|
||||
@ -147,6 +154,7 @@ Nor would this
|
||||
:test-result: PASS Ordering comparison checks that should succeed
|
||||
:test-result: PASS Our PCG implementation provides expected results for known seeds
|
||||
:test-result: FAIL Output from all sections is reported
|
||||
:test-result: PASS Overloaded comma or address-of operators are not used
|
||||
:test-result: PASS Parse test names and tags
|
||||
:test-result: PASS Pointers can be compared to null
|
||||
:test-result: PASS Precision of floating point stringification can be set
|
||||
|
@ -263,6 +263,37 @@ ToStringGeneral.tests.cpp:<line number>: passed: c == i for: 2 == 2
|
||||
ToStringGeneral.tests.cpp:<line number>: passed: c == i for: 3 == 3
|
||||
ToStringGeneral.tests.cpp:<line number>: passed: c == i for: 4 == 4
|
||||
ToStringGeneral.tests.cpp:<line number>: passed: c == i for: 5 == 5
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(MatcherA() && MatcherB() && MatcherC()), Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 1, MatcherA() && MatcherB() && MatcherC() for: 1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T) 1 )
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(MatcherA() && MatcherB() && MatcherC() && MatcherD()), Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC, MatcherD> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 1, MatcherA() && MatcherB() && MatcherC() && MatcherD() for: 1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T) 1 and equals: true )
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(MatcherA() || MatcherB() || MatcherC()), Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 1, MatcherA() || MatcherB() || MatcherC() for: 1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1 )
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(MatcherA() || MatcherB() || MatcherC() || MatcherD()), Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC, MatcherD> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 1, MatcherA() || MatcherB() || MatcherC() || MatcherD() for: 1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1 or equals: true )
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(!MatcherA()), Catch::Matchers::Impl::MatchNotOfGeneric<MatcherA> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 0, !MatcherA() for: 0 not equals: (int) 1 or (float) 1.0f
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(!!MatcherA()), MatcherA const& >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 1, !!MatcherA() for: 1 equals: (int) 1 or (float) 1.0f
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(!!!MatcherA()), Catch::Matchers::Impl::MatchNotOfGeneric<MatcherA> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 0, !!!MatcherA() for: 0 not equals: (int) 1 or (float) 1.0f
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(!!!!MatcherA()), MatcherA const & >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 1, !!!!MatcherA() for: 1 equals: (int) 1 or (float) 1.0f
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(StartsWith("foo") || (StartsWith("bar") && EndsWith("bar") && !EndsWith("foo"))), Catch::Matchers::Impl::MatchAnyOf<std::string> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(MatcherA() || MatcherB()), Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 1, MatcherA() || MatcherB() for: 1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 )
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(MatcherA() && MatcherB()), Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 1, MatcherA() && MatcherB() for: 1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 )
|
||||
Matchers.tests.cpp:<line number>: passed: with 1 message: 'std::is_same< decltype(MatcherA() || !MatcherB()), Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, Catch::Matchers::Impl::MatchNotOfGeneric<MatcherB>> >::value'
|
||||
Matchers.tests.cpp:<line number>: passed: 1, MatcherA() || !MatcherB() for: 1 ( equals: (int) 1 or (float) 1.0f or not equals: (long long) 1 )
|
||||
Matchers.tests.cpp:<line number>: passed: vec, Predicate<std::vector<int>>([](auto const& vec) { return std::all_of(vec.begin(), vec.end(), [](int elem) { return elem % 2 == 1; }); }, "All elements are odd") && !EqualsRange(a) for: { 1, 3, 5 } ( matches predicate: "All elements are odd" and not Equals: { 5, 3, 1 } )
|
||||
Matchers.tests.cpp:<line number>: passed: str, StartsWith("foo") && EqualsRange(arr) && EndsWith("bar") for: "foobar" ( starts with: "foo" and Equals: { 'f', 'o', 'o', 'b', 'a', 'r' } and ends with: "bar" )
|
||||
Matchers.tests.cpp:<line number>: passed: str, StartsWith("foo") && !EqualsRange(bad_arr) && EndsWith("bar") for: "foobar" ( starts with: "foo" and not Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } and ends with: "bar" )
|
||||
Matchers.tests.cpp:<line number>: passed: str, EqualsRange(arr) && StartsWith("foo") && EndsWith("bar") for: "foobar" ( Equals: { 'f', 'o', 'o', 'b', 'a', 'r' } and starts with: "foo" and ends with: "bar" )
|
||||
Matchers.tests.cpp:<line number>: passed: str, !EqualsRange(bad_arr) && StartsWith("foo") && EndsWith("bar") for: "foobar" ( not Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } and starts with: "foo" and ends with: "bar" )
|
||||
Matchers.tests.cpp:<line number>: passed: str, EqualsRange(bad_arr) || (StartsWith("foo") && EndsWith("bar")) for: "foobar" ( Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } or ( starts with: "foo" and ends with: "bar" ) )
|
||||
Matchers.tests.cpp:<line number>: passed: str, (StartsWith("foo") && EndsWith("bar")) || EqualsRange(bad_arr) for: "foobar" ( ( starts with: "foo" and ends with: "bar" ) or Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } )
|
||||
Matchers.tests.cpp:<line number>: passed: container, EqualsRange(a) || EqualsRange(b) || EqualsRange(c) for: { 1, 2, 3 } ( Equals: { 1, 2, 3 } or Equals: { 0, 1, 2 } or Equals: { 4, 5, 6 } )
|
||||
Tricky.tests.cpp:<line number>: passed: std::vector<constructor_throws>{constructor_throws{}, constructor_throws{}}
|
||||
Tricky.tests.cpp:<line number>: passed: std::vector<constructor_throws>{constructor_throws{}, constructor_throws{}}
|
||||
Tricky.tests.cpp:<line number>: passed: std::vector<int>{1, 2, 3} == std::vector<int>{1, 2, 3}
|
||||
@ -883,6 +914,10 @@ RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits>
|
||||
4261393167 (0x<hex digits>)
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'Message from section one'
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'Message from section two'
|
||||
Matchers.tests.cpp:<line number>: passed: (EvilMatcher(), EvilMatcher()), EvilCommaOperatorUsed
|
||||
Matchers.tests.cpp:<line number>: passed: &EvilMatcher(), EvilAddressOfOperatorUsed
|
||||
Matchers.tests.cpp:<line number>: passed: EvilMatcher() || EvilMatcher() && !EvilMatcher()
|
||||
Matchers.tests.cpp:<line number>: passed: (EvilMatcher() && EvilMatcher()) || !EvilMatcher()
|
||||
CmdLine.tests.cpp:<line number>: passed: spec.hasFilters() == false for: false == false
|
||||
CmdLine.tests.cpp:<line number>: passed: spec.matches( *tcA ) == false for: false == false
|
||||
CmdLine.tests.cpp:<line number>: passed: spec.matches( *tcB ) == false for: false == false
|
||||
|
@ -1380,6 +1380,6 @@ due to unexpected exception with message:
|
||||
Why would you throw a std::string?
|
||||
|
||||
===============================================================================
|
||||
test cases: 320 | 246 passed | 70 failed | 4 failed as expected
|
||||
assertions: 1792 | 1640 passed | 131 failed | 21 failed as expected
|
||||
test cases: 328 | 254 passed | 70 failed | 4 failed as expected
|
||||
assertions: 1827 | 1675 passed | 131 failed | 21 failed as expected
|
||||
|
||||
|
@ -2116,6 +2116,217 @@ ToStringGeneral.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
5 == 5
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining MatchAllOfGeneric does not nest
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() && MatcherB() && MatcherC()), Catch::
|
||||
Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() && MatcherB() && MatcherC() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T)
|
||||
1 )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() && MatcherB() && MatcherC() && MatcherD()),
|
||||
Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC,
|
||||
MatcherD> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() && MatcherB() && MatcherC() && MatcherD() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T)
|
||||
1 and equals: true )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining MatchAnyOfGeneric does not nest
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() || MatcherB() || MatcherC()), Catch::
|
||||
Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() || MatcherB() || MatcherC() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1
|
||||
)
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() || MatcherB() || MatcherC() || MatcherD()),
|
||||
Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC,
|
||||
MatcherD> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() || MatcherB() || MatcherC() || MatcherD() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1
|
||||
or equals: true )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining MatchNotOfGeneric does not nest
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(!MatcherA()), Catch::Matchers::Impl::MatchNotOfGeneric
|
||||
<MatcherA> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 0, !MatcherA() )
|
||||
with expansion:
|
||||
0 not equals: (int) 1 or (float) 1.0f
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(!!MatcherA()), MatcherA const& >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, !!MatcherA() )
|
||||
with expansion:
|
||||
1 equals: (int) 1 or (float) 1.0f
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(!!!MatcherA()), Catch::Matchers::Impl::
|
||||
MatchNotOfGeneric<MatcherA> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 0, !!!MatcherA() )
|
||||
with expansion:
|
||||
0 not equals: (int) 1 or (float) 1.0f
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(!!!!MatcherA()), MatcherA const & >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, !!!!MatcherA() )
|
||||
with expansion:
|
||||
1 equals: (int) 1 or (float) 1.0f
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining concrete matchers does not use templated matchers
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(StartsWith("foo") || (StartsWith("bar") && EndsWith
|
||||
("bar") && !EndsWith("foo"))), Catch::Matchers::Impl::MatchAnyOf<std::string>
|
||||
>::value
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining only templated matchers
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() || MatcherB()), Catch::Matchers::Impl::
|
||||
MatchAnyOfGeneric<MatcherA, MatcherB> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() || MatcherB() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() && MatcherB()), Catch::Matchers::Impl::
|
||||
MatchAllOfGeneric<MatcherA, MatcherB> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() && MatcherB() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
with message:
|
||||
std::is_same< decltype(MatcherA() || !MatcherB()), Catch::Matchers::Impl::
|
||||
MatchAnyOfGeneric<MatcherA, Catch::Matchers::Impl::MatchNotOfGeneric
|
||||
<MatcherB>> >::value
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( 1, MatcherA() || !MatcherB() )
|
||||
with expansion:
|
||||
1 ( equals: (int) 1 or (float) 1.0f or not equals: (long long) 1 )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining templated and concrete matchers
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( vec, Predicate<std::vector<int>>([](auto const& vec) { return std::all_of(vec.begin(), vec.end(), [](int elem) { return elem % 2 == 1; }); }, "All elements are odd") && !EqualsRange(a) )
|
||||
with expansion:
|
||||
{ 1, 3, 5 } ( matches predicate: "All elements are odd" and not Equals: { 5,
|
||||
3, 1 } )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, StartsWith("foo") && EqualsRange(arr) && EndsWith("bar") )
|
||||
with expansion:
|
||||
"foobar" ( starts with: "foo" and Equals: { 'f', 'o', 'o', 'b', 'a', 'r' }
|
||||
and ends with: "bar" )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, StartsWith("foo") && !EqualsRange(bad_arr) && EndsWith("bar") )
|
||||
with expansion:
|
||||
"foobar" ( starts with: "foo" and not Equals: { 'o', 'o', 'f', 'b', 'a', 'r'
|
||||
} and ends with: "bar" )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, EqualsRange(arr) && StartsWith("foo") && EndsWith("bar") )
|
||||
with expansion:
|
||||
"foobar" ( Equals: { 'f', 'o', 'o', 'b', 'a', 'r' } and starts with: "foo"
|
||||
and ends with: "bar" )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, !EqualsRange(bad_arr) && StartsWith("foo") && EndsWith("bar") )
|
||||
with expansion:
|
||||
"foobar" ( not Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } and starts with:
|
||||
"foo" and ends with: "bar" )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, EqualsRange(bad_arr) || (StartsWith("foo") && EndsWith("bar")) )
|
||||
with expansion:
|
||||
"foobar" ( Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } or ( starts with: "foo"
|
||||
and ends with: "bar" ) )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( str, (StartsWith("foo") && EndsWith("bar")) || EqualsRange(bad_arr) )
|
||||
with expansion:
|
||||
"foobar" ( ( starts with: "foo" and ends with: "bar" ) or Equals: { 'o', 'o',
|
||||
'f', 'b', 'a', 'r' } )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Combining templated matchers
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THAT( container, EqualsRange(a) || EqualsRange(b) || EqualsRange(c) )
|
||||
with expansion:
|
||||
{ 1, 2, 3 } ( Equals: { 1, 2, 3 } or Equals: { 0, 1, 2 } or Equals: { 4, 5, 6
|
||||
} )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Commas in various macros are allowed
|
||||
-------------------------------------------------------------------------------
|
||||
@ -6414,6 +6625,24 @@ Message.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
Message from section two
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Overloaded comma or address-of operators are not used
|
||||
-------------------------------------------------------------------------------
|
||||
Matchers.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS_AS( (EvilMatcher(), EvilMatcher()), EvilCommaOperatorUsed )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS_AS( &EvilMatcher(), EvilAddressOfOperatorUsed )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_NOTHROW( EvilMatcher() || EvilMatcher() && !EvilMatcher() )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_NOTHROW( (EvilMatcher() && EvilMatcher()) || !EvilMatcher() )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Parse test names and tags
|
||||
Empty test spec should have no filters
|
||||
@ -14053,6 +14282,6 @@ Misc.tests.cpp:<line number>
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
===============================================================================
|
||||
test cases: 320 | 230 passed | 86 failed | 4 failed as expected
|
||||
assertions: 1809 | 1640 passed | 148 failed | 21 failed as expected
|
||||
test cases: 328 | 238 passed | 86 failed | 4 failed as expected
|
||||
assertions: 1844 | 1675 passed | 148 failed | 21 failed as expected
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuitesloose text artifact
|
||||
>
|
||||
<testsuite name="<exe-name>" errors="17" failures="132" tests="1810" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testsuite name="<exe-name>" errors="17" failures="132" tests="1845" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<properties>
|
||||
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals] *"/>
|
||||
<property name="random-seed" value="1"/>
|
||||
@ -350,6 +350,13 @@ Exception.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Character pretty printing/Specifically escaped" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Character pretty printing/General chars" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Character pretty printing/Low ASCII" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Combining MatchAllOfGeneric does not nest" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Combining MatchAnyOfGeneric does not nest" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Combining MatchNotOfGeneric does not nest" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Combining concrete matchers does not use templated matchers" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Combining only templated matchers" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Combining templated and concrete matchers" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Combining templated matchers" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Commas in various macros are allowed" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparing function pointers" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparison ops" time="{duration}"/>
|
||||
@ -950,6 +957,7 @@ Message from section two
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="Overloaded comma or address-of operators are not used" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Parse test names and tags/Empty test spec should have no filters" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from empty string should have no filters" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Parse test names and tags/Test spec from just a comma should have no filters" time="{duration}"/>
|
||||
|
@ -915,6 +915,13 @@ Exception.tests.cpp:<line number>
|
||||
<file path="tests/<exe-name>/UsageTests/Matchers.tests.cpp">
|
||||
<testCase name="Arbitrary predicate matcher/Function pointer" duration="{duration}"/>
|
||||
<testCase name="Arbitrary predicate matcher/Lambdas + different type" duration="{duration}"/>
|
||||
<testCase name="Combining MatchAllOfGeneric does not nest" duration="{duration}"/>
|
||||
<testCase name="Combining MatchAnyOfGeneric does not nest" duration="{duration}"/>
|
||||
<testCase name="Combining MatchNotOfGeneric does not nest" duration="{duration}"/>
|
||||
<testCase name="Combining concrete matchers does not use templated matchers" duration="{duration}"/>
|
||||
<testCase name="Combining only templated matchers" duration="{duration}"/>
|
||||
<testCase name="Combining templated and concrete matchers" duration="{duration}"/>
|
||||
<testCase name="Combining templated matchers" duration="{duration}"/>
|
||||
<testCase name="Contains string matcher" duration="{duration}">
|
||||
<failure message="CHECK_THAT(testStringForMatching(), Contains("not there", Catch::CaseSensitive::No))">
|
||||
FAILED:
|
||||
@ -1042,6 +1049,7 @@ with expansion:
|
||||
Matchers.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testCase>
|
||||
<testCase name="Overloaded comma or address-of operators are not used" duration="{duration}"/>
|
||||
<testCase name="Predicate matcher can accept const char*" duration="{duration}"/>
|
||||
<testCase name="Regex string matcher" duration="{duration}">
|
||||
<failure message="CHECK_THAT(testStringForMatching(), Matches("this STRING contains 'abc' as a substring"))">
|
||||
|
@ -524,6 +524,68 @@ ok {test-number} - c == i for: 3 == 3
|
||||
ok {test-number} - c == i for: 4 == 4
|
||||
# Character pretty printing
|
||||
ok {test-number} - c == i for: 5 == 5
|
||||
# Combining MatchAllOfGeneric does not nest
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(MatcherA() && MatcherB() && MatcherC()), Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC> >::value'
|
||||
# Combining MatchAllOfGeneric does not nest
|
||||
ok {test-number} - 1, MatcherA() && MatcherB() && MatcherC() for: 1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T) 1 )
|
||||
# Combining MatchAllOfGeneric does not nest
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(MatcherA() && MatcherB() && MatcherC() && MatcherD()), Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC, MatcherD> >::value'
|
||||
# Combining MatchAllOfGeneric does not nest
|
||||
ok {test-number} - 1, MatcherA() && MatcherB() && MatcherC() && MatcherD() for: 1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T) 1 and equals: true )
|
||||
# Combining MatchAnyOfGeneric does not nest
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(MatcherA() || MatcherB() || MatcherC()), Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC> >::value'
|
||||
# Combining MatchAnyOfGeneric does not nest
|
||||
ok {test-number} - 1, MatcherA() || MatcherB() || MatcherC() for: 1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1 )
|
||||
# Combining MatchAnyOfGeneric does not nest
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(MatcherA() || MatcherB() || MatcherC() || MatcherD()), Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC, MatcherD> >::value'
|
||||
# Combining MatchAnyOfGeneric does not nest
|
||||
ok {test-number} - 1, MatcherA() || MatcherB() || MatcherC() || MatcherD() for: 1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1 or equals: true )
|
||||
# Combining MatchNotOfGeneric does not nest
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(!MatcherA()), Catch::Matchers::Impl::MatchNotOfGeneric<MatcherA> >::value'
|
||||
# Combining MatchNotOfGeneric does not nest
|
||||
ok {test-number} - 0, !MatcherA() for: 0 not equals: (int) 1 or (float) 1.0f
|
||||
# Combining MatchNotOfGeneric does not nest
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(!!MatcherA()), MatcherA const& >::value'
|
||||
# Combining MatchNotOfGeneric does not nest
|
||||
ok {test-number} - 1, !!MatcherA() for: 1 equals: (int) 1 or (float) 1.0f
|
||||
# Combining MatchNotOfGeneric does not nest
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(!!!MatcherA()), Catch::Matchers::Impl::MatchNotOfGeneric<MatcherA> >::value'
|
||||
# Combining MatchNotOfGeneric does not nest
|
||||
ok {test-number} - 0, !!!MatcherA() for: 0 not equals: (int) 1 or (float) 1.0f
|
||||
# Combining MatchNotOfGeneric does not nest
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(!!!!MatcherA()), MatcherA const & >::value'
|
||||
# Combining MatchNotOfGeneric does not nest
|
||||
ok {test-number} - 1, !!!!MatcherA() for: 1 equals: (int) 1 or (float) 1.0f
|
||||
# Combining concrete matchers does not use templated matchers
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(StartsWith("foo") || (StartsWith("bar") && EndsWith("bar") && !EndsWith("foo"))), Catch::Matchers::Impl::MatchAnyOf<std::string> >::value'
|
||||
# Combining only templated matchers
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(MatcherA() || MatcherB()), Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB> >::value'
|
||||
# Combining only templated matchers
|
||||
ok {test-number} - 1, MatcherA() || MatcherB() for: 1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 )
|
||||
# Combining only templated matchers
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(MatcherA() && MatcherB()), Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB> >::value'
|
||||
# Combining only templated matchers
|
||||
ok {test-number} - 1, MatcherA() && MatcherB() for: 1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 )
|
||||
# Combining only templated matchers
|
||||
ok {test-number} - with 1 message: 'std::is_same< decltype(MatcherA() || !MatcherB()), Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, Catch::Matchers::Impl::MatchNotOfGeneric<MatcherB>> >::value'
|
||||
# Combining only templated matchers
|
||||
ok {test-number} - 1, MatcherA() || !MatcherB() for: 1 ( equals: (int) 1 or (float) 1.0f or not equals: (long long) 1 )
|
||||
# Combining templated and concrete matchers
|
||||
ok {test-number} - vec, Predicate<std::vector<int>>([](auto const& vec) { return std::all_of(vec.begin(), vec.end(), [](int elem) { return elem % 2 == 1; }); }, "All elements are odd") && !EqualsRange(a) for: { 1, 3, 5 } ( matches predicate: "All elements are odd" and not Equals: { 5, 3, 1 } )
|
||||
# Combining templated and concrete matchers
|
||||
ok {test-number} - str, StartsWith("foo") && EqualsRange(arr) && EndsWith("bar") for: "foobar" ( starts with: "foo" and Equals: { 'f', 'o', 'o', 'b', 'a', 'r' } and ends with: "bar" )
|
||||
# Combining templated and concrete matchers
|
||||
ok {test-number} - str, StartsWith("foo") && !EqualsRange(bad_arr) && EndsWith("bar") for: "foobar" ( starts with: "foo" and not Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } and ends with: "bar" )
|
||||
# Combining templated and concrete matchers
|
||||
ok {test-number} - str, EqualsRange(arr) && StartsWith("foo") && EndsWith("bar") for: "foobar" ( Equals: { 'f', 'o', 'o', 'b', 'a', 'r' } and starts with: "foo" and ends with: "bar" )
|
||||
# Combining templated and concrete matchers
|
||||
ok {test-number} - str, !EqualsRange(bad_arr) && StartsWith("foo") && EndsWith("bar") for: "foobar" ( not Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } and starts with: "foo" and ends with: "bar" )
|
||||
# Combining templated and concrete matchers
|
||||
ok {test-number} - str, EqualsRange(bad_arr) || (StartsWith("foo") && EndsWith("bar")) for: "foobar" ( Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } or ( starts with: "foo" and ends with: "bar" ) )
|
||||
# Combining templated and concrete matchers
|
||||
ok {test-number} - str, (StartsWith("foo") && EndsWith("bar")) || EqualsRange(bad_arr) for: "foobar" ( ( starts with: "foo" and ends with: "bar" ) or Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } )
|
||||
# Combining templated matchers
|
||||
ok {test-number} - container, EqualsRange(a) || EqualsRange(b) || EqualsRange(c) for: { 1, 2, 3 } ( Equals: { 1, 2, 3 } or Equals: { 0, 1, 2 } or Equals: { 4, 5, 6 } )
|
||||
# Commas in various macros are allowed
|
||||
ok {test-number} - std::vector<constructor_throws>{constructor_throws{}, constructor_throws{}}
|
||||
# Commas in various macros are allowed
|
||||
@ -1688,6 +1750,14 @@ ok {test-number} - rng() == 0x<hex digits> for: 4261393167 (0x<hex digits>) == 4
|
||||
not ok {test-number} - explicitly with 1 message: 'Message from section one'
|
||||
# Output from all sections is reported
|
||||
not ok {test-number} - explicitly with 1 message: 'Message from section two'
|
||||
# Overloaded comma or address-of operators are not used
|
||||
ok {test-number} - (EvilMatcher(), EvilMatcher()), EvilCommaOperatorUsed
|
||||
# Overloaded comma or address-of operators are not used
|
||||
ok {test-number} - &EvilMatcher(), EvilAddressOfOperatorUsed
|
||||
# Overloaded comma or address-of operators are not used
|
||||
ok {test-number} - EvilMatcher() || EvilMatcher() && !EvilMatcher()
|
||||
# Overloaded comma or address-of operators are not used
|
||||
ok {test-number} - (EvilMatcher() && EvilMatcher()) || !EvilMatcher()
|
||||
# Parse test names and tags
|
||||
ok {test-number} - spec.hasFilters() == false for: false == false
|
||||
# Parse test names and tags
|
||||
@ -3610,5 +3680,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
|
||||
ok {test-number} -
|
||||
# xmlentitycheck
|
||||
ok {test-number} -
|
||||
1..1801
|
||||
1..1836
|
||||
|
||||
|
@ -203,6 +203,20 @@ Exception.tests.cpp:<line number>|nunexpected exception with message:|n "unexpe
|
||||
##teamcity[testFinished name='Capture and info messages' duration="{duration}"]
|
||||
##teamcity[testStarted name='Character pretty printing']
|
||||
##teamcity[testFinished name='Character pretty printing' duration="{duration}"]
|
||||
##teamcity[testStarted name='Combining MatchAllOfGeneric does not nest']
|
||||
##teamcity[testFinished name='Combining MatchAllOfGeneric does not nest' duration="{duration}"]
|
||||
##teamcity[testStarted name='Combining MatchAnyOfGeneric does not nest']
|
||||
##teamcity[testFinished name='Combining MatchAnyOfGeneric does not nest' duration="{duration}"]
|
||||
##teamcity[testStarted name='Combining MatchNotOfGeneric does not nest']
|
||||
##teamcity[testFinished name='Combining MatchNotOfGeneric does not nest' duration="{duration}"]
|
||||
##teamcity[testStarted name='Combining concrete matchers does not use templated matchers']
|
||||
##teamcity[testFinished name='Combining concrete matchers does not use templated matchers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Combining only templated matchers']
|
||||
##teamcity[testFinished name='Combining only templated matchers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Combining templated and concrete matchers']
|
||||
##teamcity[testFinished name='Combining templated and concrete matchers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Combining templated matchers']
|
||||
##teamcity[testFinished name='Combining templated matchers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Commas in various macros are allowed']
|
||||
##teamcity[testFinished name='Commas in various macros are allowed' duration="{duration}"]
|
||||
##teamcity[testStarted name='Comparing function pointers']
|
||||
@ -395,6 +409,8 @@ Condition.tests.cpp:<line number>|nexpression failed|n CHECK( data.str_hello <=
|
||||
Message.tests.cpp:<line number>|nexplicit failure with message:|n "Message from section one"']
|
||||
Message.tests.cpp:<line number>|nexplicit failure with message:|n "Message from section two"']
|
||||
##teamcity[testFinished name='Output from all sections is reported' duration="{duration}"]
|
||||
##teamcity[testStarted name='Overloaded comma or address-of operators are not used']
|
||||
##teamcity[testFinished name='Overloaded comma or address-of operators are not used' duration="{duration}"]
|
||||
##teamcity[testStarted name='Parse test names and tags']
|
||||
##teamcity[testFinished name='Parse test names and tags' duration="{duration}"]
|
||||
##teamcity[testStarted name='Pointers can be compared to null']
|
||||
|
@ -2417,6 +2417,179 @@ Nor would this
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Combining MatchAllOfGeneric does not nest" tags="[matchers][templated]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
1, MatcherA() && MatcherB() && MatcherC()
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T) 1 )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
1, MatcherA() && MatcherB() && MatcherC() && MatcherD()
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 and equals: (T) 1 and equals: true )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Combining MatchAnyOfGeneric does not nest" tags="[matchers][templated]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
1, MatcherA() || MatcherB() || MatcherC()
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1 )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
1, MatcherA() || MatcherB() || MatcherC() || MatcherD()
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 or equals: (T) 1 or equals: true )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Combining MatchNotOfGeneric does not nest" tags="[matchers][templated]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
0, !MatcherA()
|
||||
</Original>
|
||||
<Expanded>
|
||||
0 not equals: (int) 1 or (float) 1.0f
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
1, !!MatcherA()
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 equals: (int) 1 or (float) 1.0f
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
0, !!!MatcherA()
|
||||
</Original>
|
||||
<Expanded>
|
||||
0 not equals: (int) 1 or (float) 1.0f
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
1, !!!!MatcherA()
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 equals: (int) 1 or (float) 1.0f
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Combining concrete matchers does not use templated matchers" tags="[matchers][templated]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Combining only templated matchers" tags="[matchers][templated]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
1, MatcherA() || MatcherB()
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 ( equals: (int) 1 or (float) 1.0f or equals: (long long) 1 )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
1, MatcherA() && MatcherB()
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 ( equals: (int) 1 or (float) 1.0f and equals: (long long) 1 )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
1, MatcherA() || !MatcherB()
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 ( equals: (int) 1 or (float) 1.0f or not equals: (long long) 1 )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Combining templated and concrete matchers" tags="[matchers][templated]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
vec, Predicate<std::vector<int>>([](auto const& vec) { return std::all_of(vec.begin(), vec.end(), [](int elem) { return elem % 2 == 1; }); }, "All elements are odd") && !EqualsRange(a)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 1, 3, 5 } ( matches predicate: "All elements are odd" and not Equals: { 5, 3, 1 } )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
str, StartsWith("foo") && EqualsRange(arr) && EndsWith("bar")
|
||||
</Original>
|
||||
<Expanded>
|
||||
"foobar" ( starts with: "foo" and Equals: { 'f', 'o', 'o', 'b', 'a', 'r' } and ends with: "bar" )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
str, StartsWith("foo") && !EqualsRange(bad_arr) && EndsWith("bar")
|
||||
</Original>
|
||||
<Expanded>
|
||||
"foobar" ( starts with: "foo" and not Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } and ends with: "bar" )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
str, EqualsRange(arr) && StartsWith("foo") && EndsWith("bar")
|
||||
</Original>
|
||||
<Expanded>
|
||||
"foobar" ( Equals: { 'f', 'o', 'o', 'b', 'a', 'r' } and starts with: "foo" and ends with: "bar" )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
str, !EqualsRange(bad_arr) && StartsWith("foo") && EndsWith("bar")
|
||||
</Original>
|
||||
<Expanded>
|
||||
"foobar" ( not Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } and starts with: "foo" and ends with: "bar" )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
str, EqualsRange(bad_arr) || (StartsWith("foo") && EndsWith("bar"))
|
||||
</Original>
|
||||
<Expanded>
|
||||
"foobar" ( Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } or ( starts with: "foo" and ends with: "bar" ) )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
str, (StartsWith("foo") && EndsWith("bar")) || EqualsRange(bad_arr)
|
||||
</Original>
|
||||
<Expanded>
|
||||
"foobar" ( ( starts with: "foo" and ends with: "bar" ) or Equals: { 'o', 'o', 'f', 'b', 'a', 'r' } )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Combining templated matchers" tags="[matchers][templated]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
container, EqualsRange(a) || EqualsRange(b) || EqualsRange(c)
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ 1, 2, 3 } ( Equals: { 1, 2, 3 } or Equals: { 0, 1, 2 } or Equals: { 4, 5, 6 } )
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Commas in various macros are allowed" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THROWS" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Original>
|
||||
@ -8025,6 +8198,41 @@ Nor would this
|
||||
</Section>
|
||||
<OverallResult success="false"/>
|
||||
</TestCase>
|
||||
<TestCase name="Overloaded comma or address-of operators are not used" tags="[matchers][templated]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THROWS_AS" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
(EvilMatcher(), EvilMatcher()), EvilCommaOperatorUsed
|
||||
</Original>
|
||||
<Expanded>
|
||||
(EvilMatcher(), EvilMatcher()), EvilCommaOperatorUsed
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THROWS_AS" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
&EvilMatcher(), EvilAddressOfOperatorUsed
|
||||
</Original>
|
||||
<Expanded>
|
||||
&EvilMatcher(), EvilAddressOfOperatorUsed
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_NOTHROW" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
EvilMatcher() || EvilMatcher() && !EvilMatcher()
|
||||
</Original>
|
||||
<Expanded>
|
||||
EvilMatcher() || EvilMatcher() && !EvilMatcher()
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_NOTHROW" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
(EvilMatcher() && EvilMatcher()) || !EvilMatcher()
|
||||
</Original>
|
||||
<Expanded>
|
||||
(EvilMatcher() && EvilMatcher()) || !EvilMatcher()
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Parse test names and tags" tags="[command-line][test-spec]" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
|
||||
<Section name="Empty test spec should have no filters" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
|
||||
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
|
||||
@ -16909,7 +17117,7 @@ loose text artifact
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<OverallResults successes="1640" failures="149" expectedFailures="21"/>
|
||||
<OverallResults successes="1675" failures="149" expectedFailures="21"/>
|
||||
</Group>
|
||||
<OverallResults successes="1640" failures="148" expectedFailures="21"/>
|
||||
<OverallResults successes="1675" failures="148" expectedFailures="21"/>
|
||||
</Catch>
|
||||
|
@ -9,10 +9,12 @@
|
||||
#include <catch2/catch_matchers_generic.hpp>
|
||||
#include <catch2/catch_matchers_string.h>
|
||||
#include <catch2/catch_matchers_vector.h>
|
||||
#include <catch2/catch_matchers_templates.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
@ -554,6 +556,302 @@ namespace { namespace MatchersTests {
|
||||
REQUIRE_THROWS_MATCHES(throwsSpecialException(2), SpecialException, Message("SpecialException::what"));
|
||||
}
|
||||
|
||||
|
||||
template<typename Range>
|
||||
struct EqualsRangeMatcher : Catch::MatcherGenericBase {
|
||||
|
||||
EqualsRangeMatcher(Range const& range) : range{ range } {}
|
||||
|
||||
template<typename OtherRange>
|
||||
bool match(OtherRange const& other) const {
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
return std::equal(begin(range), end(range), begin(other), end(other));
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "Equals: " + Catch::rangeToString(range);
|
||||
}
|
||||
|
||||
private:
|
||||
Range const& range;
|
||||
};
|
||||
|
||||
template<typename Range>
|
||||
auto EqualsRange(const Range& range) -> EqualsRangeMatcher<Range> {
|
||||
return EqualsRangeMatcher<Range>{range};
|
||||
}
|
||||
|
||||
TEST_CASE("Combining templated matchers", "[matchers][templated]") {
|
||||
std::array<int, 3> container{{ 1,2,3 }};
|
||||
|
||||
std::array<int, 3> a{{ 1,2,3 }};
|
||||
std::vector<int> b{ 0,1,2 };
|
||||
std::list<int> c{ 4,5,6 };
|
||||
|
||||
REQUIRE_THAT(container, EqualsRange(a) || EqualsRange(b) || EqualsRange(c));
|
||||
}
|
||||
|
||||
TEST_CASE("Combining templated and concrete matchers", "[matchers][templated]") {
|
||||
using namespace Catch::Matchers;
|
||||
std::vector<int> vec{ 1, 3, 5 };
|
||||
|
||||
std::array<int, 3> a{{ 5, 3, 1 }};
|
||||
|
||||
REQUIRE_THAT(vec,
|
||||
Predicate<std::vector<int>>([](auto const& vec) {
|
||||
return std::all_of(vec.begin(), vec.end(), [](int elem) {
|
||||
return elem % 2 == 1;
|
||||
});
|
||||
}, "All elements are odd") &&
|
||||
!EqualsRange(a));
|
||||
|
||||
const std::string str = "foobar";
|
||||
const std::array<char, 6> arr{{ 'f', 'o', 'o', 'b', 'a', 'r' }};
|
||||
const std::array<char, 6> bad_arr{{ 'o', 'o', 'f', 'b', 'a', 'r' }};
|
||||
|
||||
using Catch::Matchers::StartsWith;
|
||||
using Catch::Matchers::EndsWith;
|
||||
|
||||
REQUIRE_THAT(str, StartsWith("foo") && EqualsRange(arr) && EndsWith("bar"));
|
||||
REQUIRE_THAT(str, StartsWith("foo") && !EqualsRange(bad_arr) && EndsWith("bar"));
|
||||
|
||||
REQUIRE_THAT(str, EqualsRange(arr) && StartsWith("foo") && EndsWith("bar"));
|
||||
REQUIRE_THAT(str, !EqualsRange(bad_arr) && StartsWith("foo") && EndsWith("bar"));
|
||||
|
||||
REQUIRE_THAT(str, EqualsRange(bad_arr) || (StartsWith("foo") && EndsWith("bar")));
|
||||
REQUIRE_THAT(str, (StartsWith("foo") && EndsWith("bar")) || EqualsRange(bad_arr));
|
||||
}
|
||||
|
||||
TEST_CASE("Combining concrete matchers does not use templated matchers", "[matchers][templated]") {
|
||||
using Catch::Matchers::StartsWith;
|
||||
using Catch::Matchers::EndsWith;
|
||||
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(StartsWith("foo") || (StartsWith("bar") && EndsWith("bar") && !EndsWith("foo"))),
|
||||
Catch::Matchers::Impl::MatchAnyOf<std::string>
|
||||
>::value);
|
||||
}
|
||||
|
||||
struct MatcherA : Catch::MatcherGenericBase {
|
||||
std::string describe() const override { return "equals: (int) 1 or (float) 1.0f"; }
|
||||
bool match(int i) const { return i == 1; }
|
||||
bool match(float f) const { return f == 1.0f; }
|
||||
};
|
||||
|
||||
struct MatcherB : Catch::MatcherGenericBase {
|
||||
std::string describe() const override { return "equals: (long long) 1"; }
|
||||
bool match(long long l) const { return l == 1ll; }
|
||||
};
|
||||
|
||||
struct MatcherC : Catch::MatcherGenericBase {
|
||||
std::string describe() const override { return "equals: (T) 1"; }
|
||||
template<typename T>
|
||||
bool match(T t) const { return t == T{1}; }
|
||||
};
|
||||
|
||||
struct MatcherD : Catch::MatcherGenericBase {
|
||||
std::string describe() const override { return "equals: true"; }
|
||||
bool match(bool b) const { return b == true; }
|
||||
};
|
||||
|
||||
TEST_CASE("Combining only templated matchers", "[matchers][templated]") {
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(MatcherA() || MatcherB()),
|
||||
Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB>
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(1, MatcherA() || MatcherB());
|
||||
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(MatcherA() && MatcherB()),
|
||||
Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB>
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(1, MatcherA() && MatcherB());
|
||||
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(MatcherA() || !MatcherB()),
|
||||
Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, Catch::Matchers::Impl::MatchNotOfGeneric<MatcherB>>
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(1, MatcherA() || !MatcherB());
|
||||
}
|
||||
|
||||
TEST_CASE("Combining MatchAnyOfGeneric does not nest", "[matchers][templated]") {
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(MatcherA() || MatcherB() || MatcherC()),
|
||||
Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC>
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(1, MatcherA() || MatcherB() || MatcherC());
|
||||
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(MatcherA() || MatcherB() || MatcherC() || MatcherD()),
|
||||
Catch::Matchers::Impl::MatchAnyOfGeneric<MatcherA, MatcherB, MatcherC, MatcherD>
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(1, MatcherA() || MatcherB() || MatcherC() || MatcherD());
|
||||
}
|
||||
|
||||
TEST_CASE("Combining MatchAllOfGeneric does not nest", "[matchers][templated]") {
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(MatcherA() && MatcherB() && MatcherC()),
|
||||
Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC>
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(1, MatcherA() && MatcherB() && MatcherC());
|
||||
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(MatcherA() && MatcherB() && MatcherC() && MatcherD()),
|
||||
Catch::Matchers::Impl::MatchAllOfGeneric<MatcherA, MatcherB, MatcherC, MatcherD>
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(1, MatcherA() && MatcherB() && MatcherC() && MatcherD());
|
||||
}
|
||||
|
||||
TEST_CASE("Combining MatchNotOfGeneric does not nest", "[matchers][templated]") {
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(!MatcherA()),
|
||||
Catch::Matchers::Impl::MatchNotOfGeneric<MatcherA>
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(0, !MatcherA());
|
||||
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(!!MatcherA()),
|
||||
MatcherA const&
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(1, !!MatcherA());
|
||||
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(!!!MatcherA()),
|
||||
Catch::Matchers::Impl::MatchNotOfGeneric<MatcherA>
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(0, !!!MatcherA());
|
||||
|
||||
STATIC_REQUIRE(std::is_same<
|
||||
decltype(!!!!MatcherA()),
|
||||
MatcherA const &
|
||||
>::value);
|
||||
|
||||
REQUIRE_THAT(1, !!!!MatcherA());
|
||||
}
|
||||
|
||||
struct EvilAddressOfOperatorUsed : std::exception {
|
||||
EvilAddressOfOperatorUsed() {}
|
||||
const char* what() const noexcept override {
|
||||
return "overloaded address-of operator of matcher was used instead of std::addressof";
|
||||
}
|
||||
};
|
||||
|
||||
struct EvilCommaOperatorUsed : std::exception {
|
||||
EvilCommaOperatorUsed() {}
|
||||
const char* what() const noexcept override {
|
||||
return "overloaded comma operator of matcher was used";
|
||||
}
|
||||
};
|
||||
|
||||
struct EvilMatcher : Catch::MatcherGenericBase {
|
||||
std::string describe() const override {
|
||||
return "equals: 45";
|
||||
}
|
||||
|
||||
bool match(int i) const {
|
||||
return i == 45;
|
||||
}
|
||||
|
||||
EvilMatcher const* operator& () const {
|
||||
throw EvilAddressOfOperatorUsed();
|
||||
}
|
||||
|
||||
int operator,(EvilMatcher const&) const {
|
||||
throw EvilCommaOperatorUsed();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Overloaded comma or address-of operators are not used", "[matchers][templated]") {
|
||||
REQUIRE_THROWS_AS((EvilMatcher(), EvilMatcher()), EvilCommaOperatorUsed);
|
||||
REQUIRE_THROWS_AS(&EvilMatcher(), EvilAddressOfOperatorUsed);
|
||||
REQUIRE_NOTHROW(EvilMatcher() || EvilMatcher() && !EvilMatcher());
|
||||
REQUIRE_NOTHROW((EvilMatcher() && EvilMatcher()) || !EvilMatcher());
|
||||
}
|
||||
|
||||
struct ImmovableMatcher : Catch::MatcherGenericBase {
|
||||
ImmovableMatcher() = default;
|
||||
ImmovableMatcher(ImmovableMatcher const&) = delete;
|
||||
ImmovableMatcher(ImmovableMatcher &&) = delete;
|
||||
ImmovableMatcher& operator=(ImmovableMatcher const&) = delete;
|
||||
ImmovableMatcher& operator=(ImmovableMatcher &&) = delete;
|
||||
|
||||
std::string describe() const override {
|
||||
return "always false";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool match(T&&) const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct MatcherWasMovedOrCopied : std::exception {
|
||||
MatcherWasMovedOrCopied() {}
|
||||
const char* what() const noexcept override {
|
||||
return "attempted to copy or move a matcher";
|
||||
}
|
||||
};
|
||||
|
||||
struct ThrowOnCopyOrMoveMatcher : Catch::MatcherGenericBase {
|
||||
ThrowOnCopyOrMoveMatcher() = default;
|
||||
[[noreturn]]
|
||||
ThrowOnCopyOrMoveMatcher(ThrowOnCopyOrMoveMatcher const&) {
|
||||
throw MatcherWasMovedOrCopied();
|
||||
}
|
||||
[[noreturn]]
|
||||
ThrowOnCopyOrMoveMatcher(ThrowOnCopyOrMoveMatcher &&) {
|
||||
throw MatcherWasMovedOrCopied();
|
||||
}
|
||||
ThrowOnCopyOrMoveMatcher& operator=(ThrowOnCopyOrMoveMatcher const&) {
|
||||
throw MatcherWasMovedOrCopied();
|
||||
}
|
||||
ThrowOnCopyOrMoveMatcher& operator=(ThrowOnCopyOrMoveMatcher &&) {
|
||||
throw MatcherWasMovedOrCopied();
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "always false";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool match(T&&) const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Matchers are not moved or copied", "[matchers][templated][approvals]") {
|
||||
REQUIRE_NOTHROW((ThrowOnCopyOrMoveMatcher() && ThrowOnCopyOrMoveMatcher()) || !ThrowOnCopyOrMoveMatcher());
|
||||
}
|
||||
|
||||
TEST_CASE("Immovable matchers can be used", "[matchers][templated][approvals]") {
|
||||
REQUIRE_THAT(123, (ImmovableMatcher() && ImmovableMatcher()) || !ImmovableMatcher());
|
||||
}
|
||||
|
||||
struct ReferencingMatcher : Catch::MatcherGenericBase {
|
||||
std::string describe() const override {
|
||||
return "takes reference";
|
||||
}
|
||||
bool match(int& i) const {
|
||||
return i == 22;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Matchers can take references", "[matchers][templated][approvals]") {
|
||||
REQUIRE_THAT(22, ReferencingMatcher{});
|
||||
}
|
||||
|
||||
} } // namespace MatchersTests
|
||||
|
||||
#ifdef __clang__
|
||||
|
Loading…
Reference in New Issue
Block a user