vendor Catch2 and ETL

This commit is contained in:
2024-10-29 10:49:46 +01:00
parent 3915e0d641
commit 5173292491
1763 changed files with 959387 additions and 71 deletions

View File

@ -0,0 +1,218 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_approx.hpp>
#include <cmath>
using Catch::Approx;
namespace {
static double divide(double a, double b) {
return a / b;
}
class StrongDoubleTypedef {
double d_ = 0.0;
public:
explicit StrongDoubleTypedef(double d) : d_(d) {}
explicit operator double() const { return d_; }
};
static std::ostream& operator<<(std::ostream& os, StrongDoubleTypedef td) {
return os << "StrongDoubleTypedef(" << static_cast<double>(td) << ")";
}
} // end unnamed namespace
using namespace Catch::literals;
///////////////////////////////////////////////////////////////////////////////
TEST_CASE( "A comparison that uses literals instead of the normal constructor", "[Approx]" ) {
double d = 1.23;
REQUIRE( d == 1.23_a );
REQUIRE( d != 1.22_a );
REQUIRE( -d == -1.23_a );
REQUIRE( d == 1.2_a .epsilon(.1) );
REQUIRE( d != 1.2_a .epsilon(.001) );
REQUIRE( d == 1_a .epsilon(.3) );
}
TEST_CASE( "Some simple comparisons between doubles", "[Approx]" ) {
double d = 1.23;
REQUIRE( d == Approx( 1.23 ) );
REQUIRE( d != Approx( 1.22 ) );
REQUIRE( d != Approx( 1.24 ) );
REQUIRE( d == 1.23_a );
REQUIRE( d != 1.22_a );
REQUIRE( Approx( d ) == 1.23 );
REQUIRE( Approx( d ) != 1.22 );
REQUIRE( Approx( d ) != 1.24 );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE( "Approximate comparisons with different epsilons", "[Approx]" ) {
double d = 1.23;
REQUIRE( d != Approx( 1.231 ) );
REQUIRE( d == Approx( 1.231 ).epsilon( 0.1 ) );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE( "Less-than inequalities with different epsilons", "[Approx]" ) {
double d = 1.23;
REQUIRE( d <= Approx( 1.24 ) );
REQUIRE( d <= Approx( 1.23 ) );
REQUIRE_FALSE( d <= Approx( 1.22 ) );
REQUIRE( d <= Approx( 1.22 ).epsilon(0.1) );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE( "Greater-than inequalities with different epsilons", "[Approx]" ) {
double d = 1.23;
REQUIRE( d >= Approx( 1.22 ) );
REQUIRE( d >= Approx( 1.23 ) );
REQUIRE_FALSE( d >= Approx( 1.24 ) );
REQUIRE( d >= Approx( 1.24 ).epsilon(0.1) );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE( "Approximate comparisons with floats", "[Approx]" ) {
REQUIRE( 1.23f == Approx( 1.23f ) );
REQUIRE( 0.0f == Approx( 0.0f ) );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE( "Approximate comparisons with ints", "[Approx]" ) {
REQUIRE( 1 == Approx( 1 ) );
REQUIRE( 0 == Approx( 0 ) );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE( "Approximate comparisons with mixed numeric types", "[Approx]" ) {
const double dZero = 0;
const double dSmall = 0.00001;
const double dMedium = 1.234;
REQUIRE( 1.0f == Approx( 1 ) );
REQUIRE( 0 == Approx( dZero) );
REQUIRE( 0 == Approx( dSmall ).margin( 0.001 ) );
REQUIRE( 1.234f == Approx( dMedium ) );
REQUIRE( dMedium == Approx( 1.234f ) );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE( "Use a custom approx", "[Approx][custom]" ) {
double d = 1.23;
Approx approx = Approx::custom().epsilon( 0.01 );
REQUIRE( d == approx( 1.23 ) );
REQUIRE( d == approx( 1.22 ) );
REQUIRE( d == approx( 1.24 ) );
REQUIRE( d != approx( 1.25 ) );
REQUIRE( approx( d ) == 1.23 );
REQUIRE( approx( d ) == 1.22 );
REQUIRE( approx( d ) == 1.24 );
REQUIRE( approx( d ) != 1.25 );
}
TEST_CASE( "Approximate PI", "[Approx][PI]" ) {
REQUIRE( divide( 22, 7 ) == Approx( 3.141 ).epsilon( 0.001 ) );
REQUIRE( divide( 22, 7 ) != Approx( 3.141 ).epsilon( 0.0001 ) );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE( "Absolute margin", "[Approx]" ) {
REQUIRE( 104.0 != Approx(100.0) );
REQUIRE( 104.0 == Approx(100.0).margin(5) );
REQUIRE( 104.0 == Approx(100.0).margin(4) );
REQUIRE( 104.0 != Approx(100.0).margin(3) );
REQUIRE( 100.3 != Approx(100.0) );
REQUIRE( 100.3 == Approx(100.0).margin(0.5) );
}
TEST_CASE("Approx with exactly-representable margin", "[Approx]") {
CHECK( 0.25f == Approx(0.0f).margin(0.25f) );
CHECK( 0.0f == Approx(0.25f).margin(0.25f) );
CHECK( 0.5f == Approx(0.25f).margin(0.25f) );
CHECK( 245.0f == Approx(245.25f).margin(0.25f) );
CHECK( 245.5f == Approx(245.25f).margin(0.25f) );
}
TEST_CASE("Approx setters validate their arguments", "[Approx]") {
REQUIRE_NOTHROW(Approx(0).margin(0));
REQUIRE_NOTHROW(Approx(0).margin(1234656));
REQUIRE_THROWS_AS(Approx(0).margin(-2), std::domain_error);
REQUIRE_NOTHROW(Approx(0).epsilon(0));
REQUIRE_NOTHROW(Approx(0).epsilon(1));
REQUIRE_THROWS_AS(Approx(0).epsilon(-0.001), std::domain_error);
REQUIRE_THROWS_AS(Approx(0).epsilon(1.0001), std::domain_error);
}
TEST_CASE("Default scale is invisible to comparison", "[Approx]") {
REQUIRE(101.000001 != Approx(100).epsilon(0.01));
REQUIRE(std::pow(10, -5) != Approx(std::pow(10, -7)));
}
TEST_CASE("Epsilon only applies to Approx's value", "[Approx]") {
REQUIRE(101.01 != Approx(100).epsilon(0.01));
}
TEST_CASE("Assorted miscellaneous tests", "[Approx][approvals]") {
REQUIRE(INFINITY == Approx(INFINITY));
REQUIRE(-INFINITY != Approx(INFINITY));
REQUIRE(1 != Approx(INFINITY));
REQUIRE(INFINITY != Approx(1));
REQUIRE(NAN != Approx(NAN));
REQUIRE_FALSE(NAN == Approx(NAN));
}
TEST_CASE( "Comparison with explicitly convertible types", "[Approx]" )
{
StrongDoubleTypedef td(10.0);
REQUIRE(td == Approx(10.0));
REQUIRE(Approx(10.0) == td);
REQUIRE(td != Approx(11.0));
REQUIRE(Approx(11.0) != td);
REQUIRE(td <= Approx(10.0));
REQUIRE(td <= Approx(11.0));
REQUIRE(Approx(10.0) <= td);
REQUIRE(Approx(9.0) <= td);
REQUIRE(td >= Approx(9.0));
REQUIRE(td >= Approx(td));
REQUIRE(Approx(td) >= td);
REQUIRE(Approx(11.0) >= td);
}
TEST_CASE("Approx::operator() is const correct", "[Approx][.approvals]") {
const Approx ap = Approx(0.0).margin(0.01);
// As long as this compiles, the test should be considered passing
REQUIRE(1.0 == ap(1.0));
}

View File

@ -0,0 +1,106 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
namespace {
static bool itDoesThis() { return true; }
static bool itDoesThat() { return true; }
// a trivial fixture example to support SCENARIO_METHOD tests
struct Fixture {
Fixture(): d_counter( 0 ) {}
int counter() { return d_counter++; }
int d_counter;
};
}
SCENARIO("Do that thing with the thing", "[Tags]") {
GIVEN("This stuff exists") {
// make stuff exist
AND_GIVEN("And some assumption") {
// Validate assumption
WHEN("I do this") {
// do this
THEN("it should do this") {
REQUIRE(itDoesThis());
AND_THEN("do that") {
REQUIRE(itDoesThat());
}
}
}
}
}
}
SCENARIO( "Vector resizing affects size and capacity",
"[vector][bdd][size][capacity]" ) {
GIVEN( "an empty vector" ) {
std::vector<int> v;
REQUIRE( v.size() == 0 );
WHEN( "it is made larger" ) {
v.resize( 10 );
THEN( "the size and capacity go up" ) {
REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 );
AND_WHEN( "it is made smaller again" ) {
v.resize( 5 );
THEN(
"the size goes down but the capacity stays the same" ) {
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 );
}
}
}
}
WHEN( "we reserve more space" ) {
v.reserve( 10 );
THEN( "The capacity is increased but the size remains the same" ) {
REQUIRE( v.capacity() >= 10 );
REQUIRE( v.size() == 0 );
}
}
}
}
SCENARIO("This is a really long scenario name to see how the list command deals with wrapping",
"[very long tags][lots][long][tags][verbose]"
"[one very long tag name that should cause line wrapping writing out using the list command]"
"[anotherReallyLongTagNameButThisOneHasNoObviousWrapPointsSoShouldSplitWithinAWordUsingADashCharacter]") {
GIVEN("A section name that is so long that it cannot fit in a single console width") {
WHEN("The test headers are printed as part of the normal running of the scenario") {
THEN("The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent") {
SUCCEED("boo!");
}
}
}
}
SCENARIO_METHOD(Fixture,
"BDD tests requiring Fixtures to provide commonly-accessed data or methods",
"[bdd][fixtures]") {
const int before(counter());
GIVEN("No operations precede me") {
REQUIRE(before == 0);
WHEN("We get the count") {
const int after(counter());
THEN("Subsequently values are higher") {
REQUIRE(after > before);
}
}
}
}

View File

@ -0,0 +1,173 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
// Adapted from donated nonius code.
#include <catch2/catch_test_macros.hpp>
#include <catch2/benchmark/catch_benchmark.hpp>
#include <catch2/benchmark/catch_constructor.hpp>
#include <catch2/generators/catch_generators_range.hpp>
#include <map>
namespace {
std::uint64_t Fibonacci(std::uint64_t number) {
return number < 2 ? number : Fibonacci(number - 1) + Fibonacci(number - 2);
}
}
TEST_CASE("Benchmark Fibonacci", "[!benchmark]") {
CHECK(Fibonacci(0) == 0);
// some more asserts..
CHECK(Fibonacci(5) == 5);
// some more asserts..
REQUIRE( Fibonacci( 20 ) == 6'765 );
BENCHMARK( "Fibonacci 20" ) {
return Fibonacci(20);
};
REQUIRE( Fibonacci( 25 ) == 75'025 );
BENCHMARK( "Fibonacci 25" ) {
return Fibonacci(25);
};
BENCHMARK("Fibonacci 30") {
return Fibonacci(30);
};
BENCHMARK("Fibonacci 35") {
return Fibonacci(35);
};
}
TEST_CASE("Benchmark containers", "[!benchmark]") {
static const int size = 100;
std::vector<int> v;
std::map<int, int> m;
SECTION("without generator") {
BENCHMARK("Load up a vector") {
v = std::vector<int>();
for (int i = 0; i < size; ++i)
v.push_back(i);
};
REQUIRE(v.size() == size);
// test optimizer control
BENCHMARK("Add up a vector's content") {
uint64_t add = 0;
for (int i = 0; i < size; ++i)
add += v[i];
return add;
};
BENCHMARK("Load up a map") {
m = std::map<int, int>();
for (int i = 0; i < size; ++i)
m.insert({ i, i + 1 });
};
REQUIRE(m.size() == size);
BENCHMARK("Reserved vector") {
v = std::vector<int>();
v.reserve(size);
for (int i = 0; i < size; ++i)
v.push_back(i);
};
REQUIRE(v.size() == size);
BENCHMARK("Resized vector") {
v = std::vector<int>();
v.resize(size);
for (int i = 0; i < size; ++i)
v[i] = i;
};
REQUIRE(v.size() == size);
int array[size] {};
BENCHMARK("A fixed size array that should require no allocations") {
for (int i = 0; i < size; ++i)
array[i] = i;
};
int sum = 0;
for (int val : array)
sum += val;
REQUIRE(sum > size);
SECTION("XYZ") {
BENCHMARK_ADVANCED("Load up vector with chronometer")(Catch::Benchmark::Chronometer meter) {
std::vector<int> k;
meter.measure([&](int idx) {
k = std::vector<int>();
for (int i = 0; i < size; ++i)
k.push_back(idx);
});
REQUIRE(k.size() == size);
};
int runs = 0;
BENCHMARK("Fill vector indexed", benchmarkIndex) {
v = std::vector<int>();
v.resize(size);
for (int i = 0; i < size; ++i)
v[i] = benchmarkIndex;
runs = benchmarkIndex;
};
for (int val : v) {
REQUIRE(val == runs);
}
}
}
SECTION("with generator") {
auto generated = GENERATE(range(0, 10));
BENCHMARK("Fill vector generated") {
v = std::vector<int>();
v.resize(size);
for (int i = 0; i < size; ++i)
v[i] = generated;
};
for (int val : v) {
REQUIRE(val == generated);
}
}
SECTION("construct and destroy example") {
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
meter.measure([&](int i) { storage[i].construct("thing"); });
};
BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
for(auto&& o : storage)
o.construct("thing");
meter.measure([&](int i) { storage[i].destruct(); });
};
}
}
TEST_CASE("Skip benchmark macros", "[!benchmark]") {
std::vector<int> v;
BENCHMARK("fill vector") {
v.emplace_back(1);
v.emplace_back(2);
v.emplace_back(3);
};
REQUIRE(v.size() == 0);
std::size_t counter{0};
BENCHMARK_ADVANCED("construct vector")(Catch::Benchmark::Chronometer meter) {
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
meter.measure([&](int i) { storage[i].construct("thing"); counter++; });
};
REQUIRE(counter == 0);
}

View File

@ -0,0 +1,159 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#if defined( __GNUC__ ) || defined( __clang__ )
# pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_template_test_macros.hpp>
#include <array>
namespace {
class TestClass {
std::string s;
public:
TestClass(): s( "hello" ) {}
void succeedingCase() { REQUIRE( s == "hello" ); }
void failingCase() { REQUIRE( s == "world" ); }
};
struct Fixture {
Fixture(): m_a( 1 ) {}
int m_a;
};
struct Persistent_Fixture {
mutable int m_a = 0;
};
template <typename T> struct Template_Fixture {
Template_Fixture(): m_a( 1 ) {}
T m_a;
};
template <typename T> struct Template_Fixture_2 {
Template_Fixture_2() = default;
T m_a;
};
template <typename T> struct Template_Foo {
size_t size() { return 0; }
};
template <typename T, size_t V> struct Template_Foo_2 {
size_t size() { return V; }
};
template <int V> struct Nttp_Fixture { int value = V; };
} // end unnamed namespace
METHOD_AS_TEST_CASE( TestClass::succeedingCase, "A METHOD_AS_TEST_CASE based test run that succeeds", "[class]" )
METHOD_AS_TEST_CASE( TestClass::failingCase, "A METHOD_AS_TEST_CASE based test run that fails", "[.][class][failing]" )
TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that succeeds", "[class]" )
{
REQUIRE( m_a == 1 );
}
TEST_CASE_PERSISTENT_FIXTURE( Persistent_Fixture, "A TEST_CASE_PERSISTENT_FIXTURE based test run that succeeds", "[class]" )
{
SECTION( "First partial run" ) {
REQUIRE( m_a++ == 0 );
}
SECTION( "Second partial run" ) {
REQUIRE( m_a == 1 );
}
}
TEMPLATE_TEST_CASE_METHOD(Template_Fixture, "A TEMPLATE_TEST_CASE_METHOD based test run that succeeds", "[class][template]", int, float, double) {
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
}
TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][nttp]",((int V), V), 1, 3, 6) {
REQUIRE(Nttp_Fixture<V>::value > 0);
}
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds","[class][template][product]",(std::vector,Template_Foo),(int,float))
{
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 0 );
}
TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][product][nttp]", ((typename T, size_t S), T, S),(std::array, Template_Foo_2), ((int,2), (float,6)))
{
REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() >= 2);
}
using MyTypes = std::tuple<int, char, double>;
TEMPLATE_LIST_TEST_CASE_METHOD(Template_Fixture, "Template test case method with test types specified inside std::tuple", "[class][template][list]", MyTypes)
{
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
}
// We should be able to write our tests within a different namespace
namespace Inner
{
TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that fails", "[.][class][failing]" )
{
REQUIRE( m_a == 2 );
}
TEST_CASE_PERSISTENT_FIXTURE( Persistent_Fixture, "A TEST_CASE_PERSISTENT_FIXTURE based test run that fails", "[.][class][failing]" )
{
SECTION( "First partial run" ) {
REQUIRE( m_a++ == 0 );
}
SECTION( "Second partial run" ) {
REQUIRE( m_a == 0 );
}
}
TEMPLATE_TEST_CASE_METHOD(Template_Fixture,"A TEMPLATE_TEST_CASE_METHOD based test run that fails", "[.][class][template][failing]", int, float, double)
{
REQUIRE( Template_Fixture<TestType>::m_a == 2 );
}
TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails", "[.][class][template][nttp][failing]", ((int V), V), 1, 3, 6) {
REQUIRE(Nttp_Fixture<V>::value == 0);
}
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails","[.][class][template][product][failing]",(std::vector,Template_Foo),(int,float))
{
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 );
}
TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails", "[.][class][template][product][nttp][failing]", ((typename T, size_t S), T, S), (std::array, Template_Foo_2), ((int, 2), (float, 6)))
{
REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() < 2);
}
} // namespace
// We want a class in nested namespace so we can test JUnit's classname normalization.
namespace {
namespace A {
namespace B {
class TestClass {};
}
}
} // namespace
TEST_CASE_METHOD( A::B::TestClass,
"A TEST_CASE_METHOD testing junit classname normalization",
"[class][approvals]" ) {
SUCCEED();
}

View File

@ -0,0 +1,469 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <helpers/type_with_lit_0_comparisons.hpp>
#include <type_traits>
// Setup for #1403 -- look for global overloads of operator << for classes
// in a different namespace.
#include <ostream>
namespace foo {
struct helper_1403 {
bool operator==(helper_1403) const { return true; }
};
}
namespace bar {
template <typename... Ts>
struct TypeList {};
}
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wmissing-declarations"
#endif
static std::ostream& operator<<(std::ostream& out, foo::helper_1403 const&) {
return out << "[1403 helper]";
}
///////////////////////////////
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <cstring>
// Comparison operators can return non-booleans.
// This is unusual, but should be supported.
struct logic_t {
logic_t operator< (logic_t) const { return {}; }
logic_t operator<=(logic_t) const { return {}; }
logic_t operator> (logic_t) const { return {}; }
logic_t operator>=(logic_t) const { return {}; }
logic_t operator==(logic_t) const { return {}; }
logic_t operator!=(logic_t) const { return {}; }
explicit operator bool() const { return true; }
};
static void throws_int(bool b) {
if (b) {
throw 1;
}
}
template<typename T>
bool templated_tests(T t) {
int a = 3;
REQUIRE(a == t);
CHECK(a == t);
REQUIRE_THROWS(throws_int(true));
CHECK_THROWS_AS(throws_int(true), int);
REQUIRE_NOTHROW(throws_int(false));
REQUIRE_THAT("aaa", Catch::Matchers::EndsWith("aaa"));
return true;
}
struct A {};
static std::ostream &operator<<(std::ostream &o, const A &) { return o << 0; }
struct B : private A {
bool operator==(int) const { return true; }
};
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#ifdef __GNUC__
// Note that because -~GCC~-, this warning cannot be silenced temporarily, by pushing diagnostic stack...
// Luckily it is firing in test files and thus can be silenced for the whole file, without losing much.
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
B f();
std::ostream g();
#ifdef __clang__
#pragma clang diagnostic pop
#endif
template <typename, typename>
struct Fixture_1245 {};
// This is a minimal example for an issue we have found in 1.7.0
struct dummy_809 {
int i;
};
template<typename T>
bool operator==(const T& val, dummy_809 f) {
return val == f.i;
}
TEST_CASE("#809") {
dummy_809 f;
f.i = 42;
REQUIRE(42 == f);
}
// ------------------------------------------------------------------
// Changes to REQUIRE_THROWS_AS made it stop working in a template in
// an unfixable way (as long as C++03 compatibility is being kept).
// To prevent these from happening in the future, this needs to compile
TEST_CASE("#833") {
REQUIRE(templated_tests<int>(3));
}
// Test containing example where original stream insertable check breaks compilation
TEST_CASE("#872") {
A dummy;
CAPTURE(dummy);
B x;
REQUIRE (x == 4);
}
TEST_CASE("#1027: Bitfields can be captured") {
struct Y {
uint32_t v : 1;
};
Y y{ 0 };
REQUIRE(y.v == 0);
REQUIRE(0 == y.v);
}
// Comparison operators can return non-booleans.
// This is unusual, but should be supported.
TEST_CASE("#1147") {
logic_t t1, t2;
REQUIRE(t1 == t2);
REQUIRE(t1 != t2);
REQUIRE(t1 < t2);
REQUIRE(t1 > t2);
REQUIRE(t1 <= t2);
REQUIRE(t1 >= t2);
}
// unsigned array
TEST_CASE("#1238") {
unsigned char uarr[] = "123";
CAPTURE(uarr);
signed char sarr[] = "456";
CAPTURE(sarr);
REQUIRE(std::memcmp(uarr, "123", sizeof(uarr)) == 0);
REQUIRE(std::memcmp(sarr, "456", sizeof(sarr)) == 0);
}
TEST_CASE_METHOD((Fixture_1245<int, int>), "#1245", "[compilation]") {
SUCCEED();
}
TEST_CASE("#1403", "[compilation]") {
::foo::helper_1403 h1, h2;
REQUIRE(h1 == h2);
}
TEST_CASE("Optionally static assertions", "[compilation]") {
STATIC_REQUIRE( std::is_void<void>::value );
STATIC_REQUIRE_FALSE( std::is_void<int>::value );
STATIC_CHECK( std::is_void<void>::value );
STATIC_CHECK_FALSE( std::is_void<int>::value );
}
TEST_CASE("#1548", "[compilation]") {
using namespace bar;
REQUIRE(std::is_same<TypeList<int>, TypeList<int>>::value);
}
// #925
using signal_t = void (*) (void*);
struct TestClass {
signal_t testMethod_uponComplete_arg = nullptr;
};
namespace utility {
inline static void synchronizing_callback( void * ) { }
}
#if defined (_MSC_VER)
#pragma warning(push)
// The function pointer comparison below triggers warning because of
// calling conventions
#pragma warning(disable:4244)
#endif
TEST_CASE("#925: comparing function pointer to function address failed to compile", "[!nonportable]" ) {
TestClass test;
REQUIRE(utility::synchronizing_callback != test.testMethod_uponComplete_arg);
}
#if defined (_MSC_VER)
#pragma warning(pop)
#endif
TEST_CASE( "#1319: Sections can have description (even if it is not saved",
"[compilation]" ) {
SECTION( "SectionName", "This is a long form section description" ) {
SUCCEED();
}
}
TEST_CASE("Lambdas in assertions") {
REQUIRE([]() { return true; }());
}
namespace {
struct HasBitOperators {
int value;
friend HasBitOperators operator| (HasBitOperators lhs, HasBitOperators rhs) {
return { lhs.value | rhs.value };
}
friend HasBitOperators operator& (HasBitOperators lhs, HasBitOperators rhs) {
return { lhs.value & rhs.value };
}
friend HasBitOperators operator^ (HasBitOperators lhs, HasBitOperators rhs) {
return { lhs.value ^ rhs.value };
}
explicit operator bool() const {
return !!value;
}
friend std::ostream& operator<<(std::ostream& out, HasBitOperators val) {
out << "Val: " << val.value;
return out;
}
};
}
TEST_CASE("Assertion macros support bit operators and bool conversions", "[compilation][bitops]") {
HasBitOperators lhs{ 1 }, rhs{ 2 };
REQUIRE(lhs | rhs);
REQUIRE_FALSE(lhs & rhs);
REQUIRE(HasBitOperators{ 1 } & HasBitOperators{ 1 });
REQUIRE(lhs ^ rhs);
REQUIRE_FALSE(lhs ^ lhs);
}
namespace {
struct ImmovableType {
ImmovableType() = default;
ImmovableType(ImmovableType const&) = delete;
ImmovableType& operator=(ImmovableType const&) = delete;
ImmovableType(ImmovableType&&) = delete;
ImmovableType& operator=(ImmovableType&&) = delete;
friend bool operator==(ImmovableType const&, ImmovableType const&) {
return true;
}
};
}
TEST_CASE("Immovable types are supported in basic assertions", "[compilation][.approvals]") {
REQUIRE(ImmovableType{} == ImmovableType{});
}
namespace adl {
struct always_true {
explicit operator bool() const { return true; }
};
#define COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(op) \
template <class T, class U> \
auto operator op (T&&, U&&) { \
return always_true{}; \
}
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(==)
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(!=)
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(<)
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(>)
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(<=)
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(>=)
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(|)
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(&)
COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(^)
#undef COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR
}
TEST_CASE("ADL universal operators don't hijack expression deconstruction", "[compilation][.approvals]") {
REQUIRE(adl::always_true{});
REQUIRE(0 == adl::always_true{});
REQUIRE(0 != adl::always_true{});
REQUIRE(0 < adl::always_true{});
REQUIRE(0 > adl::always_true{});
REQUIRE(0 <= adl::always_true{});
REQUIRE(0 >= adl::always_true{});
REQUIRE(0 | adl::always_true{});
REQUIRE(0 & adl::always_true{});
REQUIRE(0 ^ adl::always_true{});
}
TEST_CASE( "#2555 - types that can only be compared with 0 literal implemented as pointer conversion are supported",
"[compilation][approvals]" ) {
REQUIRE( TypeWithLit0Comparisons{} < 0 );
REQUIRE_FALSE( 0 < TypeWithLit0Comparisons{} );
REQUIRE( TypeWithLit0Comparisons{} <= 0 );
REQUIRE_FALSE( 0 <= TypeWithLit0Comparisons{} );
REQUIRE( TypeWithLit0Comparisons{} > 0 );
REQUIRE_FALSE( 0 > TypeWithLit0Comparisons{} );
REQUIRE( TypeWithLit0Comparisons{} >= 0 );
REQUIRE_FALSE( 0 >= TypeWithLit0Comparisons{} );
REQUIRE( TypeWithLit0Comparisons{} == 0 );
REQUIRE_FALSE( 0 == TypeWithLit0Comparisons{} );
REQUIRE( TypeWithLit0Comparisons{} != 0 );
REQUIRE_FALSE( 0 != TypeWithLit0Comparisons{} );
}
// These tests require `consteval` to propagate through `constexpr` calls
// which is a late DR against C++20.
#if defined( CATCH_CPP20_OR_GREATER ) && defined( __cpp_consteval ) && \
__cpp_consteval >= 202211L
// Can't have internal linkage to avoid warnings
void ZeroLiteralErrorFunc();
namespace {
struct ZeroLiteralConsteval {
template <class T, std::enable_if_t<std::is_same_v<T, int>, int> = 0>
consteval ZeroLiteralConsteval( T zero ) noexcept {
if ( zero != 0 ) { ZeroLiteralErrorFunc(); }
}
};
// Should only be constructible from literal 0. Uses the propagating
// consteval constructor trick (currently used by MSVC, might be used
// by libc++ in the future as well).
struct TypeWithConstevalLit0Comparison {
# define DEFINE_COMP_OP( op ) \
constexpr friend bool operator op( TypeWithConstevalLit0Comparison, \
ZeroLiteralConsteval ) { \
return true; \
} \
constexpr friend bool operator op( ZeroLiteralConsteval, \
TypeWithConstevalLit0Comparison ) { \
return false; \
} \
/* std::orderings only have these for ==, but we add them for all \
operators so we can test all overloads for decomposer */ \
constexpr friend bool operator op( TypeWithConstevalLit0Comparison, \
TypeWithConstevalLit0Comparison ) { \
return true; \
}
DEFINE_COMP_OP( < )
DEFINE_COMP_OP( <= )
DEFINE_COMP_OP( > )
DEFINE_COMP_OP( >= )
DEFINE_COMP_OP( == )
DEFINE_COMP_OP( != )
#undef DEFINE_COMP_OP
};
} // namespace
namespace Catch {
template <>
struct capture_by_value<TypeWithConstevalLit0Comparison> : std::true_type {};
}
TEST_CASE( "#2555 - types that can only be compared with 0 literal implemented as consteval check are supported",
"[compilation][approvals]" ) {
REQUIRE( TypeWithConstevalLit0Comparison{} < 0 );
REQUIRE_FALSE( 0 < TypeWithConstevalLit0Comparison{} );
REQUIRE( TypeWithConstevalLit0Comparison{} <= 0 );
REQUIRE_FALSE( 0 <= TypeWithConstevalLit0Comparison{} );
REQUIRE( TypeWithConstevalLit0Comparison{} > 0 );
REQUIRE_FALSE( 0 > TypeWithConstevalLit0Comparison{} );
REQUIRE( TypeWithConstevalLit0Comparison{} >= 0 );
REQUIRE_FALSE( 0 >= TypeWithConstevalLit0Comparison{} );
REQUIRE( TypeWithConstevalLit0Comparison{} == 0 );
REQUIRE_FALSE( 0 == TypeWithConstevalLit0Comparison{} );
REQUIRE( TypeWithConstevalLit0Comparison{} != 0 );
REQUIRE_FALSE( 0 != TypeWithConstevalLit0Comparison{} );
}
// We check all comparison ops to test, even though orderings, the primary
// motivation for this functionality, only have self-comparison (and thus
// have the ambiguity issue) for `==` and `!=`.
TEST_CASE( "Comparing const instances of type registered with capture_by_value",
"[regression][approvals][compilation]" ) {
SECTION("Type with consteval-int constructor") {
auto const const_Lit0Type_1 = TypeWithConstevalLit0Comparison{};
auto const const_Lit0Type_2 = TypeWithConstevalLit0Comparison{};
REQUIRE( const_Lit0Type_1 == const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 <= const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 < const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 >= const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 > const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 != const_Lit0Type_2 );
}
SECTION("Type with constexpr-int constructor") {
auto const const_Lit0Type_1 = TypeWithLit0Comparisons{};
auto const const_Lit0Type_2 = TypeWithLit0Comparisons{};
REQUIRE( const_Lit0Type_1 == const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 <= const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 < const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 >= const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 > const_Lit0Type_2 );
REQUIRE( const_Lit0Type_1 != const_Lit0Type_2 );
}
}
#endif // C++20 consteval
namespace {
struct MultipleImplicitConstructors {
MultipleImplicitConstructors( double ) {}
MultipleImplicitConstructors( int64_t ) {}
bool operator==( MultipleImplicitConstructors ) const { return true; }
bool operator!=( MultipleImplicitConstructors ) const { return true; }
bool operator<( MultipleImplicitConstructors ) const { return true; }
bool operator<=( MultipleImplicitConstructors ) const { return true; }
bool operator>( MultipleImplicitConstructors ) const { return true; }
bool operator>=( MultipleImplicitConstructors ) const { return true; }
};
}
TEST_CASE("#2571 - tests compile types that have multiple implicit constructors from lit 0",
"[compilation][approvals]") {
MultipleImplicitConstructors mic1( 0.0 );
MultipleImplicitConstructors mic2( 0.0 );
REQUIRE( mic1 == mic2 );
REQUIRE( mic1 != mic2 );
REQUIRE( mic1 < mic2 );
REQUIRE( mic1 <= mic2 );
REQUIRE( mic1 > mic2 );
REQUIRE( mic1 >= mic2 );
}
#if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
// This test does not test all the related codepaths, but it is the original
// reproducer
TEST_CASE( "Comparing const std::weak_ordering instances must compile",
"[compilation][approvals][regression]" ) {
auto const const_ordering_1 = std::weak_ordering::less;
auto const const_ordering_2 = std::weak_ordering::less;
auto plain_ordering_1 = std::weak_ordering::less;
REQUIRE( const_ordering_1 == plain_ordering_1 );
REQUIRE( const_ordering_1 == const_ordering_2 );
REQUIRE( plain_ordering_1 == const_ordering_1 );
}
#endif

View File

@ -0,0 +1,334 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wpadded"
// Wdouble-promotion is not supported until 3.8
# if (__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ > 7)
# pragma clang diagnostic ignored "-Wdouble-promotion"
# endif
#endif
#include <catch2/catch_approx.hpp>
#include <catch2/catch_test_macros.hpp>
using Catch::Approx;
#include <string>
#include <limits>
#include <cstdint>
namespace {
struct TestData {
int int_seven = 7;
std::string str_hello = "hello";
float float_nine_point_one = 9.1f;
double double_pi = 3.1415926535;
};
static const char* returnsConstNull() { return nullptr; }
static char* returnsNull() { return nullptr; }
} // end unnamed namespace
// The "failing" tests all use the CHECK macro, which continues if the specific test fails.
// This allows us to see all results, even if an earlier check fails
// Equality tests
TEST_CASE( "Equality checks that should succeed" )
{
TestData data;
REQUIRE( data.int_seven == 7 );
REQUIRE( data.float_nine_point_one == Approx( 9.1f ) );
REQUIRE( data.double_pi == Approx( 3.1415926535 ) );
REQUIRE( data.str_hello == "hello" );
REQUIRE( "hello" == data.str_hello );
REQUIRE( data.str_hello.size() == 5 );
double x = 1.1 + 0.1 + 0.1;
REQUIRE( x == Approx( 1.3 ) );
}
TEST_CASE( "Equality checks that should fail", "[.][failing][!mayfail]" )
{
TestData data;
CHECK( data.int_seven == 6 );
CHECK( data.int_seven == 8 );
CHECK( data.int_seven == 0 );
CHECK( data.float_nine_point_one == Approx( 9.11f ) );
CHECK( data.float_nine_point_one == Approx( 9.0f ) );
CHECK( data.float_nine_point_one == Approx( 1 ) );
CHECK( data.float_nine_point_one == Approx( 0 ) );
CHECK( data.double_pi == Approx( 3.1415 ) );
CHECK( data.str_hello == "goodbye" );
CHECK( data.str_hello == "hell" );
CHECK( data.str_hello == "hello1" );
CHECK( data.str_hello.size() == 6 );
double x = 1.1 + 0.1 + 0.1;
CHECK( x == Approx( 1.301 ) );
}
// Needed to test junit reporter's handling of mayfail test cases and sections
TEST_CASE("Mayfail test case with nested sections", "[!mayfail]") {
SECTION("A") {
SECTION("1") { FAIL(); }
SECTION("2") { FAIL(); }
}
SECTION("B") {
SECTION("1") { FAIL(); }
SECTION("2") { FAIL(); }
}
}
TEST_CASE( "Inequality checks that should succeed" )
{
TestData data;
REQUIRE( data.int_seven != 6 );
REQUIRE( data.int_seven != 8 );
REQUIRE( data.float_nine_point_one != Approx( 9.11f ) );
REQUIRE( data.float_nine_point_one != Approx( 9.0f ) );
REQUIRE( data.float_nine_point_one != Approx( 1 ) );
REQUIRE( data.float_nine_point_one != Approx( 0 ) );
REQUIRE( data.double_pi != Approx( 3.1415 ) );
REQUIRE( data.str_hello != "goodbye" );
REQUIRE( data.str_hello != "hell" );
REQUIRE( data.str_hello != "hello1" );
REQUIRE( data.str_hello.size() != 6 );
}
TEST_CASE( "Inequality checks that should fail", "[.][failing][!shouldfail]" )
{
TestData data;
CHECK( data.int_seven != 7 );
CHECK( data.float_nine_point_one != Approx( 9.1f ) );
CHECK( data.double_pi != Approx( 3.1415926535 ) );
CHECK( data.str_hello != "hello" );
CHECK( data.str_hello.size() != 5 );
}
// Ordering comparison tests
TEST_CASE( "Ordering comparison checks that should succeed" )
{
TestData data;
REQUIRE( data.int_seven < 8 );
REQUIRE( data.int_seven > 6 );
REQUIRE( data.int_seven > 0 );
REQUIRE( data.int_seven > -1 );
REQUIRE( data.int_seven >= 7 );
REQUIRE( data.int_seven >= 6 );
REQUIRE( data.int_seven <= 7 );
REQUIRE( data.int_seven <= 8 );
REQUIRE( data.float_nine_point_one > 9 );
REQUIRE( data.float_nine_point_one < 10 );
REQUIRE( data.float_nine_point_one < 9.2 );
REQUIRE( data.str_hello <= "hello" );
REQUIRE( data.str_hello >= "hello" );
REQUIRE( data.str_hello < "hellp" );
REQUIRE( data.str_hello < "zebra" );
REQUIRE( data.str_hello > "hellm" );
REQUIRE( data.str_hello > "a" );
}
TEST_CASE( "Ordering comparison checks that should fail", "[.][failing]" )
{
TestData data;
CHECK( data.int_seven > 7 );
CHECK( data.int_seven < 7 );
CHECK( data.int_seven > 8 );
CHECK( data.int_seven < 6 );
CHECK( data.int_seven < 0 );
CHECK( data.int_seven < -1 );
CHECK( data.int_seven >= 8 );
CHECK( data.int_seven <= 6 );
CHECK( data.float_nine_point_one < 9 );
CHECK( data.float_nine_point_one > 10 );
CHECK( data.float_nine_point_one > 9.2 );
CHECK( data.str_hello > "hello" );
CHECK( data.str_hello < "hello" );
CHECK( data.str_hello > "hellp" );
CHECK( data.str_hello > "z" );
CHECK( data.str_hello < "hellm" );
CHECK( data.str_hello < "a" );
CHECK( data.str_hello >= "z" );
CHECK( data.str_hello <= "a" );
}
#ifdef __clang__
# pragma clang diagnostic pop
#endif
// Comparisons with int literals
TEST_CASE( "Comparisons with int literals don't warn when mixing signed/ unsigned" )
{
int i = 1;
unsigned int ui = 2;
long l = 3;
unsigned long ul = 4;
char c = 5;
unsigned char uc = 6;
REQUIRE( i == 1 );
REQUIRE( ui == 2 );
REQUIRE( l == 3 );
REQUIRE( ul == 4 );
REQUIRE( c == 5 );
REQUIRE( uc == 6 );
REQUIRE( 1 == i );
REQUIRE( 2 == ui );
REQUIRE( 3 == l );
REQUIRE( 4 == ul );
REQUIRE( 5 == c );
REQUIRE( 6 == uc );
REQUIRE( (std::numeric_limits<uint32_t>::max)() > ul );
}
// Disable warnings about sign conversions for the next two tests
// (as we are deliberately invoking them)
// - Currently only disabled for GCC/ LLVM. Should add VC++ too
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#ifdef _MSC_VER
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
#endif
TEST_CASE( "comparisons between int variables" )
{
long long_var = 1L;
unsigned char unsigned_char_var = 1;
unsigned short unsigned_short_var = 1;
unsigned int unsigned_int_var = 1;
unsigned long unsigned_long_var = 1L;
REQUIRE( long_var == unsigned_char_var );
REQUIRE( long_var == unsigned_short_var );
REQUIRE( long_var == unsigned_int_var );
REQUIRE( long_var == unsigned_long_var );
}
TEST_CASE( "comparisons between const int variables" )
{
const unsigned char unsigned_char_var = 1;
const unsigned short unsigned_short_var = 1;
const unsigned int unsigned_int_var = 1;
const unsigned long unsigned_long_var = 1L;
REQUIRE( unsigned_char_var == 1 );
REQUIRE( unsigned_short_var == 1 );
REQUIRE( unsigned_int_var == 1 );
REQUIRE( unsigned_long_var == 1 );
}
TEST_CASE( "Comparisons between unsigned ints and negative signed ints match c++ standard behaviour" )
{
CHECK( ( -1 > 2u ) );
CHECK( -1 > 2u );
CHECK( ( 2u < -1 ) );
CHECK( 2u < -1 );
const int minInt = (std::numeric_limits<int>::min)();
CHECK( ( minInt > 2u ) );
CHECK( minInt > 2u );
}
TEST_CASE( "Comparisons between ints where one side is computed" )
{
CHECK( 54 == 6*9 );
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
TEST_CASE( "Pointers can be compared to null" )
{
TestData* p = nullptr;
TestData* pNULL = nullptr;
REQUIRE( p == nullptr );
REQUIRE( p == pNULL );
TestData data;
p = &data;
REQUIRE( p != nullptr );
const TestData* cp = p;
REQUIRE( cp != nullptr );
const TestData* const cpc = p;
REQUIRE( cpc != nullptr );
REQUIRE( returnsNull() == nullptr );
REQUIRE( returnsConstNull() == nullptr );
REQUIRE( nullptr != p );
}
// Not (!) tests
// The problem with the ! operator is that it has right-to-left associativity.
// This means we can't isolate it when we decompose. The simple REQUIRE( !false ) form, therefore,
// cannot have the operand value extracted. The test will work correctly, and the situation
// is detected and a warning issued.
// An alternative form of the macros (CHECK_FALSE and REQUIRE_FALSE) can be used instead to capture
// the operand value.
TEST_CASE( "'Not' checks that should succeed" )
{
bool falseValue = false;
REQUIRE( false == false );
REQUIRE( true == true );
REQUIRE( !false );
REQUIRE_FALSE( false );
REQUIRE( !falseValue );
REQUIRE_FALSE( falseValue );
REQUIRE( !(1 == 2) );
REQUIRE_FALSE( 1 == 2 );
}
TEST_CASE( "'Not' checks that should fail", "[.][failing]" )
{
bool trueValue = true;
CHECK( false != false );
CHECK( true != true );
CHECK( !true );
CHECK_FALSE( true );
CHECK( !trueValue );
CHECK_FALSE( trueValue );
CHECK( !(1 == 1) );
CHECK_FALSE( 1 == 1 );
}

View File

@ -0,0 +1,41 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <iostream>
#include <cstdio>
namespace {
struct truthy {
truthy(bool b):m_value(b){}
operator bool() const {
return false;
}
bool m_value;
};
std::ostream& operator<<(std::ostream& o, truthy) {
o << "Hey, its truthy!";
return o;
}
} // end anonymous namespace
#include <catch2/catch_test_macros.hpp>
TEST_CASE( "Reconstruction should be based on stringification: #914" , "[Decomposition][failing][.]") {
CHECK(truthy(false));
}
TEST_CASE("#1005: Comparing pointer to int and long (NULL can be either on various systems)", "[Decomposition][approvals]") {
FILE* fptr = nullptr;
REQUIRE( fptr == 0 );
REQUIRE_FALSE( fptr != 0 );
REQUIRE( fptr == 0l );
REQUIRE_FALSE( fptr != 0l );
}

View File

@ -0,0 +1,108 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <catch2/internal/catch_enum_values_registry.hpp>
namespace {
// Enum without user-provided stream operator
enum Enum1 { Enum1Value0, Enum1Value1 };
// Enum with user-provided stream operator
enum Enum2 { Enum2Value0, Enum2Value1 };
std::ostream& operator<<( std::ostream& os, Enum2 v ) {
return os << "E2{" << static_cast<int>(v) << "}";
}
} // end anonymous namespace
TEST_CASE( "toString(enum)", "[toString][enum]" ) {
Enum1 e0 = Enum1Value0;
CHECK( ::Catch::Detail::stringify(e0) == "0" );
Enum1 e1 = Enum1Value1;
CHECK( ::Catch::Detail::stringify(e1) == "1" );
}
TEST_CASE( "toString(enum w/operator<<)", "[toString][enum]" ) {
Enum2 e0 = Enum2Value0;
CHECK( ::Catch::Detail::stringify(e0) == "E2{0}" );
Enum2 e1 = Enum2Value1;
CHECK( ::Catch::Detail::stringify(e1) == "E2{1}" );
}
// Enum class without user-provided stream operator
namespace {
enum class EnumClass1 { EnumClass1Value0, EnumClass1Value1 };
// Enum class with user-provided stream operator
enum class EnumClass2 { EnumClass2Value0, EnumClass2Value1 };
std::ostream& operator<<( std::ostream& os, EnumClass2 e2 ) {
switch( static_cast<int>( e2 ) ) {
case static_cast<int>( EnumClass2::EnumClass2Value0 ):
return os << "E2/V0";
case static_cast<int>( EnumClass2::EnumClass2Value1 ):
return os << "E2/V1";
default:
return os << "Unknown enum value " << static_cast<int>( e2 );
}
}
} // end anonymous namespace
TEST_CASE( "toString(enum class)", "[toString][enum][enumClass]" ) {
EnumClass1 e0 = EnumClass1::EnumClass1Value0;
CHECK( ::Catch::Detail::stringify(e0) == "0" );
EnumClass1 e1 = EnumClass1::EnumClass1Value1;
CHECK( ::Catch::Detail::stringify(e1) == "1" );
}
TEST_CASE( "toString(enum class w/operator<<)", "[toString][enum][enumClass]" ) {
EnumClass2 e0 = EnumClass2::EnumClass2Value0;
CHECK( ::Catch::Detail::stringify(e0) == "E2/V0" );
EnumClass2 e1 = EnumClass2::EnumClass2Value1;
CHECK( ::Catch::Detail::stringify(e1) == "E2/V1" );
auto e3 = static_cast<EnumClass2>(10);
CHECK( ::Catch::Detail::stringify(e3) == "Unknown enum value 10" );
}
enum class EnumClass3 { Value1, Value2, Value3, Value4 };
CATCH_REGISTER_ENUM( EnumClass3, EnumClass3::Value1, EnumClass3::Value2, EnumClass3::Value3 )
TEST_CASE( "Enums can quickly have stringification enabled using REGISTER_ENUM" ) {
using Catch::Detail::stringify;
REQUIRE( stringify( EnumClass3::Value1 ) == "Value1" );
REQUIRE( stringify( EnumClass3::Value2 ) == "Value2" );
REQUIRE( stringify( EnumClass3::Value3 ) == "Value3" );
REQUIRE( stringify( EnumClass3::Value4 ) == "{** unexpected enum value **}" );
EnumClass3 ec3 = EnumClass3::Value2;
REQUIRE( stringify( ec3 ) == "Value2" );
}
namespace Bikeshed {
enum class Colours { Red, Green, Blue };
}
// Important!: This macro must appear at top level scope - not inside a namespace
// You can fully qualify the names, or use a using if you prefer
CATCH_REGISTER_ENUM( Bikeshed::Colours,
Bikeshed::Colours::Red,
Bikeshed::Colours::Green,
Bikeshed::Colours::Blue )
TEST_CASE( "Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM" ) {
using Catch::Detail::stringify;
REQUIRE( stringify( Bikeshed::Colours::Red ) == "Red" );
REQUIRE( stringify( Bikeshed::Colours::Blue ) == "Blue" );
}

View File

@ -0,0 +1,204 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_translate_exception.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <string>
#include <stdexcept>
#ifdef _MSC_VER
#pragma warning(disable:4702) // Unreachable code -- unconditional throws and so on
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wweak-vtables"
#pragma clang diagnostic ignored "-Wmissing-noreturn"
#pragma clang diagnostic ignored "-Wunreachable-code-return"
#endif
namespace {
int thisThrows() {
throw std::domain_error("expected exception");
return 1;
}
int thisDoesntThrow() {
return 0;
}
class CustomException {
public:
explicit CustomException(const std::string& msg)
: m_msg(msg) {}
std::string const& getMessage() const {
return m_msg;
}
private:
std::string m_msg;
};
class CustomStdException : public std::exception {
public:
explicit CustomStdException(const std::string& msg)
: m_msg(msg) {}
~CustomStdException() noexcept override = default;
CustomStdException( CustomStdException const& ) = default;
CustomStdException& operator=( CustomStdException const& ) = default;
std::string const& getMessage() const {
return m_msg;
}
private:
std::string m_msg;
};
[[noreturn]] void throwCustom() {
throw CustomException("custom exception - not std");
}
}
TEST_CASE( "When checked exceptions are thrown they can be expected or unexpected", "[!throws]" ) {
REQUIRE_THROWS_AS( thisThrows(), std::domain_error );
REQUIRE_NOTHROW( thisDoesntThrow() );
REQUIRE_THROWS( thisThrows() );
}
TEST_CASE( "Expected exceptions that don't throw or unexpected exceptions fail the test", "[.][failing][!throws]" ) {
CHECK_THROWS_AS( thisThrows(), std::string );
CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error );
CHECK_NOTHROW( thisThrows() );
}
TEST_CASE( "When unchecked exceptions are thrown directly they are always failures", "[.][failing][!throws]" ) {
throw std::domain_error( "unexpected exception" );
}
TEST_CASE( "An unchecked exception reports the line of the last assertion", "[.][failing][!throws]" ) {
CHECK( 1 == 1 );
throw std::domain_error( "unexpected exception" );
}
TEST_CASE( "When unchecked exceptions are thrown from sections they are always failures", "[.][failing][!throws]" ) {
SECTION( "section name" ) {
throw std::domain_error("unexpected exception");
}
}
TEST_CASE( "When unchecked exceptions are thrown from functions they are always failures", "[.][failing][!throws]" ) {
CHECK( thisThrows() == 0 );
}
TEST_CASE( "When unchecked exceptions are thrown during a REQUIRE the test should abort fail", "[.][failing][!throws]" ) {
REQUIRE( thisThrows() == 0 );
FAIL( "This should never happen" );
}
TEST_CASE( "When unchecked exceptions are thrown during a CHECK the test should continue", "[.][failing][!throws]" ) {
try {
CHECK(thisThrows() == 0);
}
catch(...) {
FAIL( "This should never happen" );
}
}
TEST_CASE( "When unchecked exceptions are thrown, but caught, they do not affect the test", "[!throws]" ) {
try {
throw std::domain_error( "unexpected exception" );
}
catch(...) {} // NOLINT(bugprone-empty-catch)
}
CATCH_TRANSLATE_EXCEPTION( CustomException const& ex ) {
return ex.getMessage();
}
CATCH_TRANSLATE_EXCEPTION( CustomStdException const& ex ) {
return ex.getMessage();
}
CATCH_TRANSLATE_EXCEPTION( double const& ex ) {
return Catch::Detail::stringify( ex );
}
TEST_CASE("Non-std exceptions can be translated", "[.][failing][!throws]" ) {
throw CustomException( "custom exception" );
}
TEST_CASE("Custom std-exceptions can be custom translated", "[.][failing][!throws]" ) {
throw CustomStdException( "custom std exception" );
}
TEST_CASE( "Custom exceptions can be translated when testing for nothrow", "[.][failing][!throws]" ) {
REQUIRE_NOTHROW( throwCustom() );
}
TEST_CASE( "Custom exceptions can be translated when testing for throwing as something else", "[.][failing][!throws]" ) {
REQUIRE_THROWS_AS( throwCustom(), std::exception );
}
TEST_CASE( "Unexpected exceptions can be translated", "[.][failing][!throws]" ) {
throw double( 3.14 ); // NOLINT(readability-redundant-casting): the type is important here, so we want to be explicit
}
TEST_CASE("Thrown string literals are translated", "[.][failing][!throws]") {
throw "For some reason someone is throwing a string literal!";
}
TEST_CASE("thrown std::strings are translated", "[.][failing][!throws]") {
throw std::string{ "Why would you throw a std::string?" };
}
TEST_CASE( "Exception messages can be tested for", "[!throws]" ) {
using namespace Catch::Matchers;
SECTION( "exact match" )
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
SECTION( "different case" )
REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) );
SECTION( "wildcarded" ) {
REQUIRE_THROWS_WITH( thisThrows(), StartsWith( "expected" ) );
REQUIRE_THROWS_WITH( thisThrows(), EndsWith( "exception" ) );
REQUIRE_THROWS_WITH( thisThrows(), ContainsSubstring( "except" ) );
REQUIRE_THROWS_WITH( thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) );
}
}
TEST_CASE( "Mismatching exception messages failing the test", "[.][failing][!throws]" ) {
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
REQUIRE_THROWS_WITH( thisThrows(), "should fail" );
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
}
TEST_CASE( "#748 - captures with unexpected exceptions", "[.][failing][!throws][!shouldfail]" ) {
int answer = 42;
CAPTURE( answer );
// the message should be printed on the first two sections but not on the third
SECTION( "outside assertions" ) {
thisThrows();
}
SECTION( "inside REQUIRE_NOTHROW" ) {
REQUIRE_NOTHROW( thisThrows() );
}
SECTION( "inside REQUIRE_THROWS" ) {
REQUIRE_THROWS( thisThrows() );
}
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif

View File

@ -0,0 +1,323 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generator_exception.hpp>
#include <catch2/generators/catch_generators_adapters.hpp>
#include <catch2/generators/catch_generators_random.hpp>
#include <catch2/generators/catch_generators_range.hpp>
#include <cstring>
// Generators and sections can be nested freely
TEST_CASE("Generators -- simple", "[generators]") {
auto i = GENERATE(1, 2, 3);
SECTION("one") {
auto j = GENERATE(values({ -3, -2, -1 }));
REQUIRE(j < i);
}
SECTION("two") {
// You can also explicitly set type for generators via Catch::Generators::as
auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");
REQUIRE(4u * i > str.size());
}
}
// You can create a cartesian-product of generators by creating multiple ones
TEST_CASE("3x3x3 ints", "[generators]") {
auto x = GENERATE(1, 2, 3);
auto y = GENERATE(4, 5, 6);
auto z = GENERATE(7, 8, 9);
// These assertions will be run 27 times (3x3x3)
CHECK(x < y);
CHECK(y < z);
REQUIRE(x < z);
}
// You can also create data tuples
TEST_CASE("tables", "[generators]") {
// Note that this will not compile with libstdc++ older than libstdc++6
// See https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list
// for possible workarounds
// auto data = GENERATE(table<char const*, int>({
// {"first", 5},
// {"second", 6},
// {"third", 5},
// {"etc...", 6}
// }));
// Workaround for the libstdc++ bug mentioned above
using tuple_type = std::tuple<char const*, int>;
auto data = GENERATE(table<char const*, int>({
tuple_type{"first", 5},
tuple_type{"second", 6},
tuple_type{"third", 5},
tuple_type{"etc...", 6}
}));
REQUIRE(strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)));
}
#ifdef __cpp_structured_bindings
// Structured bindings make the table utility much nicer to use
TEST_CASE( "strlen2", "[approvals][generators]" ) {
using tuple_type = std::tuple<std::string, int>; // see above workaround
auto [test_input, expected] =
GENERATE( table<std::string, size_t>( { tuple_type{ "one", 3 },
tuple_type{ "two", 3 },
tuple_type{ "three", 5 },
tuple_type{ "four", 4 } } ) );
REQUIRE( test_input.size() == expected );
}
#endif
// An alternate way of doing data tables without structured bindings
struct Data { std::string str; size_t len; };
TEST_CASE( "strlen3", "[generators]" ) {
auto data = GENERATE( values<Data>({
{"one", 3},
{"two", 3},
{"three", 5},
{"four", 4}
}));
REQUIRE( data.str.size() == data.len );
}
#ifdef __cpp_structured_bindings
// Based on example from https://docs.cucumber.io/gherkin/reference/#scenario-outline
// (thanks to https://github.com/catchorg/Catch2/issues/850#issuecomment-399504851)
// Note that GIVEN, WHEN, and THEN now forward onto DYNAMIC_SECTION instead of SECTION.
// DYNAMIC_SECTION takes its name as a stringstream-style expression, so can be formatted using
// variables in scope - such as the generated variables here. This reads quite nicely in the
// test name output (the full scenario description).
static auto eatCucumbers( int start, int eat ) -> int { return start-eat; }
SCENARIO("Eating cucumbers", "[generators][approvals]") {
using tuple_type = std::tuple<int, int, int>;
auto [start, eat, left] = GENERATE( table<int, int, int>(
{ tuple_type{ 12, 5, 7 }, tuple_type{ 20, 5, 15 } } ) );
GIVEN( "there are " << start << " cucumbers" )
WHEN( "I eat " << eat << " cucumbers" )
THEN( "I should have " << left << " cucumbers" ) {
REQUIRE( eatCucumbers( start, eat ) == left );
}
}
#endif
// There are also some generic generator manipulators
TEST_CASE("Generators -- adapters", "[generators][generic]") {
// TODO: This won't work yet, introduce GENERATE_VAR?
//auto numbers = Catch::Generators::values({ 1, 2, 3, 4, 5, 6 });
SECTION("Filtering by predicate") {
SECTION("Basic usage") {
// This filters out all odd (false) numbers, giving [2, 4, 6]
auto i = GENERATE(filter([] (int val) { return val % 2 == 0; }, values({ 1, 2, 3, 4, 5, 6 })));
REQUIRE(i % 2 == 0);
}
SECTION("Throws if there are no matching values") {
using namespace Catch::Generators;
REQUIRE_THROWS_AS(filter([] (int) {return false; }, value(1)), Catch::GeneratorException);
}
}
SECTION("Shortening a range") {
// This takes the first 3 elements from the values, giving back [1, 2, 3]
auto i = GENERATE(take(3, values({ 1, 2, 3, 4, 5, 6 })));
REQUIRE(i < 4);
}
SECTION("Transforming elements") {
SECTION("Same type") {
// This doubles values [1, 2, 3] into [2, 4, 6]
auto i = GENERATE(map([] (int val) { return val * 2; }, values({ 1, 2, 3 })));
REQUIRE(i % 2 == 0);
}
SECTION("Different type") {
// This takes a generator that returns ints and maps them into strings
auto i = GENERATE(map<std::string>([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
REQUIRE(i.size() == 1);
}
SECTION("Different deduced type") {
// This takes a generator that returns ints and maps them into strings
auto i = GENERATE(map([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
REQUIRE(i.size() == 1);
}
}
SECTION("Repeating a generator") {
// This will return values [1, 2, 3, 1, 2, 3]
auto j = GENERATE(repeat(2, values({ 1, 2, 3 })));
REQUIRE(j > 0);
}
SECTION("Chunking a generator into sized pieces") {
SECTION("Number of elements in source is divisible by chunk size") {
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3, 3 })));
REQUIRE(chunk2.size() == 2);
REQUIRE(chunk2.front() == chunk2.back());
}
SECTION("Number of elements in source is not divisible by chunk size") {
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3 })));
REQUIRE(chunk2.size() == 2);
REQUIRE(chunk2.front() == chunk2.back());
REQUIRE(chunk2.front() < 3);
}
SECTION("Chunk size of zero") {
auto chunk2 = GENERATE(take(3, chunk(0, value(1))));
REQUIRE(chunk2.size() == 0);
}
SECTION("Throws on too small generators") {
using namespace Catch::Generators;
REQUIRE_THROWS_AS(chunk(2, value(1)), Catch::GeneratorException);
}
}
}
// Note that because of the non-reproducibility of distributions,
// anything involving the random generators cannot be part of approvals
TEST_CASE("Random generator", "[generators][approvals]") {
SECTION("Infer int from integral arguments") {
auto val = GENERATE(take(4, random(0, 1)));
STATIC_REQUIRE(std::is_same<decltype(val), int>::value);
REQUIRE(0 <= val);
REQUIRE(val <= 1);
}
SECTION("Infer double from double arguments") {
auto val = GENERATE(take(4, random(0., 1.)));
STATIC_REQUIRE(std::is_same<decltype(val), double>::value);
REQUIRE(0. <= val);
REQUIRE(val < 1);
}
}
TEST_CASE("Nested generators and captured variables", "[generators]") {
// Workaround for old libstdc++
using record = std::tuple<int, int>;
// Set up 3 ranges to generate numbers from
auto extent = GENERATE(table<int, int>({
record{3, 7},
record{-5, -3},
record{90, 100}
}));
auto from = std::get<0>(extent);
auto to = std::get<1>(extent);
auto values = GENERATE_COPY(range(from, to));
REQUIRE(values > -6);
}
namespace {
size_t call_count = 0;
size_t test_count = 0;
std::vector<int> make_data() {
return { 1, 3, 5, 7, 9, 11 };
}
std::vector<int> make_data_counted() {
++call_count;
return make_data();
}
}
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wexit-time-destructors"
#endif
TEST_CASE("Copy and then generate a range", "[generators]") {
SECTION("from var and iterators") {
static auto data = make_data();
// It is important to notice that a generator is only initialized
// **once** per run. What this means is that modifying data will not
// modify the underlying generator.
auto elem = GENERATE_REF(from_range(data.begin(), data.end()));
REQUIRE(elem % 2 == 1);
}
SECTION("From a temporary container") {
auto elem = GENERATE(from_range(make_data_counted()));
++test_count;
REQUIRE(elem % 2 == 1);
}
SECTION("Final validation") {
REQUIRE(call_count == 1);
REQUIRE(make_data().size() == test_count);
}
}
#if defined( __clang__ )
# pragma clang diagnostic pop
#endif
TEST_CASE("#1913 - GENERATE inside a for loop should not keep recreating the generator", "[regression][generators]") {
static int counter = 0;
for (int i = 0; i < 3; ++i) {
int _ = GENERATE(1, 2);
(void)_;
++counter;
}
// There should be at most 6 (3 * 2) counter increments
REQUIRE(counter < 7);
}
TEST_CASE("#1913 - GENERATEs can share a line", "[regression][generators]") {
int i = GENERATE(1, 2); int j = GENERATE(3, 4);
REQUIRE(i != j);
}
namespace {
class test_generator : public Catch::Generators::IGenerator<int> {
public:
[[noreturn]] explicit test_generator() {
// removing the following line will cause the program to terminate
// gracefully.
throw Catch::GeneratorException( "failure to init" );
}
auto get() const -> int const& override {
static constexpr int value = 1;
return value;
}
auto next() -> bool override { return false; }
};
static auto make_test_generator()
-> Catch::Generators::GeneratorWrapper<int> {
return { new test_generator() };
}
} // namespace
TEST_CASE( "#2615 - Throwing in constructor generator fails test case but does not abort",
"[!shouldfail][regression][generators]" ) {
// this should fail the test case, but not abort the application
auto sample = GENERATE( make_test_generator() );
// this assertion shouldn't trigger
REQUIRE( sample == 0 );
}
TEST_CASE( "GENERATE can combine literals and generators", "[generators]" ) {
auto i = GENERATE( 2,
4,
take( 2,
filter( []( int val ) { return val % 2 == 0; },
random( -100, 100 ) ) ) );
REQUIRE( i % 2 == 0 );
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,917 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#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_range_equals.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <catch2/matchers/catch_matchers_quantifiers.hpp>
#include <catch2/matchers/catch_matchers_predicate.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <helpers/range_test_helpers.hpp>
#include <cmath>
#include <list>
#include <map>
#include <type_traits>
#include <vector>
#include <memory>
struct MoveOnlyTestElement {
int num = 0;
MoveOnlyTestElement(int n) :num(n) {}
MoveOnlyTestElement(MoveOnlyTestElement&& rhs) = default;
MoveOnlyTestElement& operator=(MoveOnlyTestElement&& rhs) = default;
friend bool operator==(MoveOnlyTestElement const& lhs, MoveOnlyTestElement const& rhs) {
return lhs.num == rhs.num;
}
friend std::ostream& operator<<(std::ostream& out, MoveOnlyTestElement const& elem) {
out << elem.num;
return out;
}
};
TEST_CASE("Basic use of the Contains range matcher", "[matchers][templated][contains]") {
using Catch::Matchers::Contains;
SECTION("Different argument ranges, same element type, default comparison") {
std::array<int, 3> a{ { 1,2,3 } };
std::vector<int> b{ 0,1,2 };
std::list<int> c{ 4,5,6 };
// A contains 1
REQUIRE_THAT(a, Contains(1));
// B contains 1
REQUIRE_THAT(b, Contains(1));
// C does not contain 1
REQUIRE_THAT(c, !Contains(1));
}
SECTION("Different argument ranges, same element type, custom comparison") {
std::array<int, 3> a{ { 1,2,3 } };
std::vector<int> b{ 0,1,2 };
std::list<int> c{ 4,5,6 };
auto close_enough = [](int lhs, int rhs) { return std::abs(lhs - rhs) <= 1; };
// A contains 1, which is "close enough" to 0
REQUIRE_THAT(a, Contains(0, close_enough));
// B contains 0 directly
REQUIRE_THAT(b, Contains(0, close_enough));
// C does not contain anything "close enough" to 0
REQUIRE_THAT(c, !Contains(0, close_enough));
}
SECTION("Different element type, custom comparisons") {
std::array<std::string, 3> a{ { "abc", "abcd" , "abcde" } };
REQUIRE_THAT(a, Contains(4, [](auto&& lhs, size_t sz) {
return lhs.size() == sz;
}));
}
SECTION("Can handle type that requires ADL-found free function begin and end") {
unrelated::needs_ADL_begin<int> in{1, 2, 3, 4, 5};
REQUIRE_THAT(in, Contains(1));
REQUIRE_THAT(in, !Contains(8));
}
SECTION("Initialization with move only types") {
std::array<MoveOnlyTestElement, 3> in{ { MoveOnlyTestElement{ 1 }, MoveOnlyTestElement{ 2 }, MoveOnlyTestElement{ 3 } } };
REQUIRE_THAT(in, Contains(MoveOnlyTestElement{ 2 }));
REQUIRE_THAT(in, !Contains(MoveOnlyTestElement{ 9 }));
}
SECTION("Matching using matcher") {
std::array<double, 4> in{ {1, 2, 3} };
REQUIRE_THAT(in, Contains(Catch::Matchers::WithinAbs(0.5, 0.5)));
}
}
namespace {
struct has_empty {
bool empty() const { return false; }
};
} // 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 };
}
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));
}
}
TEST_CASE("Usage of AllMatch range matcher", "[matchers][templated][quantifiers]") {
using Catch::Matchers::AllMatch;
using Catch::Matchers::Predicate;
SECTION("Basic usage") {
using Catch::Matchers::Contains;
using Catch::Matchers::SizeIs;
std::array<std::array<int, 5>, 5> data{{
{{ 0, 1, 2, 3, 5 }},
{{ 4,-3,-2, 5, 0 }},
{{ 0, 0, 0, 5, 0 }},
{{ 0,-5, 0, 5, 0 }},
{{ 1, 0, 0,-1, 5 }}
}};
REQUIRE_THAT(data, AllMatch(SizeIs(5)));
REQUIRE_THAT(data, !AllMatch(Contains(0) && Contains(1)));
}
SECTION("Type requires ADL found begin and end") {
unrelated::needs_ADL_begin<int> needs_adl{ 1, 2, 3, 4, 5 };
REQUIRE_THAT( needs_adl, AllMatch( Predicate<int>( []( int elem ) {
return elem < 6;
} ) ) );
}
SECTION("Shortcircuiting") {
with_mocked_iterator_access<int> mocked{ 1, 2, 3, 4, 5 };
SECTION("All are read") {
auto allMatch = AllMatch(Predicate<int>([](int elem) {
return elem < 10;
}));
REQUIRE_THAT(mocked, allMatch);
REQUIRE(mocked.m_derefed[0]);
REQUIRE(mocked.m_derefed[1]);
REQUIRE(mocked.m_derefed[2]);
REQUIRE(mocked.m_derefed[3]);
REQUIRE(mocked.m_derefed[4]);
}
SECTION("Short-circuited") {
auto allMatch = AllMatch(Predicate<int>([](int elem) {
return elem < 3;
}));
REQUIRE_THAT(mocked, !allMatch);
REQUIRE(mocked.m_derefed[0]);
REQUIRE(mocked.m_derefed[1]);
REQUIRE(mocked.m_derefed[2]);
REQUIRE_FALSE(mocked.m_derefed[3]);
REQUIRE_FALSE(mocked.m_derefed[4]);
}
}
}
TEST_CASE("Usage of AnyMatch range matcher", "[matchers][templated][quantifiers]") {
using Catch::Matchers::AnyMatch;
using Catch::Matchers::Predicate;
SECTION("Basic usage") {
using Catch::Matchers::Contains;
using Catch::Matchers::SizeIs;
std::array<std::array<int, 5>, 5> data{ {
{{ 0, 1, 2, 3, 5 }},
{{ 4,-3,-2, 5, 0 }},
{{ 0, 0, 0, 5, 0 }},
{{ 0,-5, 0, 5, 0 }},
{{ 1, 0, 0,-1, 5 }}
} };
REQUIRE_THAT(data, AnyMatch(SizeIs(5)));
REQUIRE_THAT(data, !AnyMatch(Contains(0) && Contains(10)));
}
SECTION( "Type requires ADL found begin and end" ) {
unrelated::needs_ADL_begin<int> needs_adl{ 1, 2, 3, 4, 5 };
REQUIRE_THAT( needs_adl, AnyMatch( Predicate<int>( []( int elem ) {
return elem < 3;
} ) ) );
}
SECTION("Shortcircuiting") {
with_mocked_iterator_access<int> mocked{ 1, 2, 3, 4, 5 };
SECTION("All are read") {
auto anyMatch = AnyMatch(
Predicate<int>( []( int elem ) { return elem > 10; } ) );
REQUIRE_THAT( mocked, !anyMatch );
REQUIRE( mocked.m_derefed[0] );
REQUIRE( mocked.m_derefed[1] );
REQUIRE( mocked.m_derefed[2] );
REQUIRE( mocked.m_derefed[3] );
REQUIRE( mocked.m_derefed[4] );
}
SECTION("Short-circuited") {
auto anyMatch = AnyMatch(
Predicate<int>( []( int elem ) { return elem < 3; } ) );
REQUIRE_THAT( mocked, anyMatch );
REQUIRE( mocked.m_derefed[0] );
REQUIRE_FALSE( mocked.m_derefed[1] );
REQUIRE_FALSE( mocked.m_derefed[2] );
REQUIRE_FALSE( mocked.m_derefed[3] );
REQUIRE_FALSE( mocked.m_derefed[4] );
}
}
}
TEST_CASE("Usage of NoneMatch range matcher", "[matchers][templated][quantifiers]") {
using Catch::Matchers::NoneMatch;
using Catch::Matchers::Predicate;
SECTION("Basic usage") {
using Catch::Matchers::Contains;
using Catch::Matchers::SizeIs;
std::array<std::array<int, 5>, 5> data{ {
{{ 0, 1, 2, 3, 5 }},
{{ 4,-3,-2, 5, 0 }},
{{ 0, 0, 0, 5, 0 }},
{{ 0,-5, 0, 5, 0 }},
{{ 1, 0, 0,-1, 5 }}
} };
REQUIRE_THAT(data, NoneMatch(SizeIs(6)));
REQUIRE_THAT(data, !NoneMatch(Contains(0) && Contains(1)));
}
SECTION( "Type requires ADL found begin and end" ) {
unrelated::needs_ADL_begin<int> needs_adl{ 1, 2, 3, 4, 5 };
REQUIRE_THAT( needs_adl, NoneMatch( Predicate<int>( []( int elem ) {
return elem > 6;
} ) ) );
}
SECTION("Shortcircuiting") {
with_mocked_iterator_access<int> mocked{ 1, 2, 3, 4, 5 };
SECTION("All are read") {
auto noneMatch = NoneMatch(
Predicate<int>([](int elem) { return elem > 10; }));
REQUIRE_THAT(mocked, noneMatch);
REQUIRE(mocked.m_derefed[0]);
REQUIRE(mocked.m_derefed[1]);
REQUIRE(mocked.m_derefed[2]);
REQUIRE(mocked.m_derefed[3]);
REQUIRE(mocked.m_derefed[4]);
}
SECTION("Short-circuited") {
auto noneMatch = NoneMatch(
Predicate<int>([](int elem) { return elem < 3; }));
REQUIRE_THAT(mocked, !noneMatch);
REQUIRE(mocked.m_derefed[0]);
REQUIRE_FALSE(mocked.m_derefed[1]);
REQUIRE_FALSE(mocked.m_derefed[2]);
REQUIRE_FALSE(mocked.m_derefed[3]);
REQUIRE_FALSE(mocked.m_derefed[4]);
}
}
}
namespace {
struct ConvertibleToBool
{
bool v;
explicit operator bool() const
{
return v;
}
};
}
namespace Catch {
template <>
struct StringMaker<ConvertibleToBool> {
static std::string
convert( ConvertibleToBool const& convertible_to_bool ) {
return ::Catch::Detail::stringify( convertible_to_bool.v );
}
};
} // namespace Catch
TEST_CASE("Usage of AllTrue range matcher", "[matchers][templated][quantifiers]") {
using Catch::Matchers::AllTrue;
SECTION( "Basic usage" ) {
SECTION( "All true evaluates to true" ) {
std::array<bool, 5> const data{ { true, true, true, true, true } };
REQUIRE_THAT( data, AllTrue() );
}
SECTION( "Empty evaluates to true" ) {
std::array<bool, 0> const data{};
REQUIRE_THAT( data, AllTrue() );
}
SECTION( "One false evaluates to false" ) {
std::array<bool, 5> const data{ { true, true, false, true, true } };
REQUIRE_THAT( data, !AllTrue() );
}
SECTION( "All false evaluates to false" ) {
std::array<bool, 5> const data{
{ false, false, false, false, false } };
REQUIRE_THAT( data, !AllTrue() );
}
}
SECTION( "Contained type is convertible to bool" ) {
SECTION( "All true evaluates to true" ) {
std::array<ConvertibleToBool, 5> const data{
{ { true }, { true }, { true }, { true }, { true } } };
REQUIRE_THAT( data, AllTrue() );
}
SECTION( "One false evaluates to false" ) {
std::array<ConvertibleToBool, 5> const data{
{ { true }, { true }, { false }, { true }, { true } } };
REQUIRE_THAT( data, !AllTrue() );
}
SECTION( "All false evaluates to false" ) {
std::array<ConvertibleToBool, 5> const data{
{ { false }, { false }, { false }, { false }, { false } } };
REQUIRE_THAT( data, !AllTrue() );
}
}
SECTION( "Shortcircuiting" ) {
SECTION( "All are read" ) {
with_mocked_iterator_access<bool> const mocked{
true, true, true, true, true };
REQUIRE_THAT( mocked, AllTrue() );
REQUIRE( mocked.m_derefed[0] );
REQUIRE( mocked.m_derefed[1] );
REQUIRE( mocked.m_derefed[2] );
REQUIRE( mocked.m_derefed[3] );
REQUIRE( mocked.m_derefed[4] );
}
SECTION( "Short-circuited" ) {
with_mocked_iterator_access<bool> const mocked{
true, true, false, true, true };
REQUIRE_THAT( mocked, !AllTrue() );
REQUIRE( mocked.m_derefed[0] );
REQUIRE( mocked.m_derefed[1] );
REQUIRE( mocked.m_derefed[2] );
REQUIRE_FALSE( mocked.m_derefed[3] );
REQUIRE_FALSE( mocked.m_derefed[4] );
}
}
}
TEST_CASE( "Usage of NoneTrue range matcher", "[matchers][templated][quantifiers]" ) {
using Catch::Matchers::NoneTrue;
SECTION( "Basic usage" ) {
SECTION( "All true evaluates to false" ) {
std::array<bool, 5> const data{ { true, true, true, true, true } };
REQUIRE_THAT( data, !NoneTrue() );
}
SECTION( "Empty evaluates to true" ) {
std::array<bool, 0> const data{};
REQUIRE_THAT( data, NoneTrue() );
}
SECTION( "One true evaluates to false" ) {
std::array<bool, 5> const data{
{ false, false, true, false, false } };
REQUIRE_THAT( data, !NoneTrue() );
}
SECTION( "All false evaluates to true" ) {
std::array<bool, 5> const data{
{ false, false, false, false, false } };
REQUIRE_THAT( data, NoneTrue() );
}
}
SECTION( "Contained type is convertible to bool" ) {
SECTION( "All true evaluates to false" ) {
std::array<ConvertibleToBool, 5> const data{
{ { true }, { true }, { true }, { true }, { true } } };
REQUIRE_THAT( data, !NoneTrue() );
}
SECTION( "One true evaluates to false" ) {
std::array<ConvertibleToBool, 5> const data{
{ { false }, { false }, { true }, { false }, { false } } };
REQUIRE_THAT( data, !NoneTrue() );
}
SECTION( "All false evaluates to true" ) {
std::array<ConvertibleToBool, 5> const data{
{ { false }, { false }, { false }, { false }, { false } } };
REQUIRE_THAT( data, NoneTrue() );
}
}
SECTION( "Shortcircuiting" ) {
SECTION( "All are read" ) {
with_mocked_iterator_access<bool> const mocked{
false, false, false, false, false };
REQUIRE_THAT( mocked, NoneTrue() );
REQUIRE( mocked.m_derefed[0] );
REQUIRE( mocked.m_derefed[1] );
REQUIRE( mocked.m_derefed[2] );
REQUIRE( mocked.m_derefed[3] );
REQUIRE( mocked.m_derefed[4] );
}
SECTION( "Short-circuited" ) {
with_mocked_iterator_access<bool> const mocked{
false, false, true, true, true };
REQUIRE_THAT( mocked, !NoneTrue() );
REQUIRE( mocked.m_derefed[0] );
REQUIRE( mocked.m_derefed[1] );
REQUIRE( mocked.m_derefed[2] );
REQUIRE_FALSE( mocked.m_derefed[3] );
REQUIRE_FALSE( mocked.m_derefed[4] );
}
}
}
TEST_CASE( "Usage of AnyTrue range matcher", "[matchers][templated][quantifiers]" ) {
using Catch::Matchers::AnyTrue;
SECTION( "Basic usage" ) {
SECTION( "All true evaluates to true" ) {
std::array<bool, 5> const data{ { true, true, true, true, true } };
REQUIRE_THAT( data, AnyTrue() );
}
SECTION( "Empty evaluates to false" ) {
std::array<bool, 0> const data{};
REQUIRE_THAT( data, !AnyTrue() );
}
SECTION( "One true evaluates to true" ) {
std::array<bool, 5> const data{
{ false, false, true, false, false } };
REQUIRE_THAT( data, AnyTrue() );
}
SECTION( "All false evaluates to false" ) {
std::array<bool, 5> const data{
{ false, false, false, false, false } };
REQUIRE_THAT( data, !AnyTrue() );
}
}
SECTION( "Contained type is convertible to bool" ) {
SECTION( "All true evaluates to true" ) {
std::array<ConvertibleToBool, 5> const data{
{ { true }, { true }, { true }, { true }, { true } } };
REQUIRE_THAT( data, AnyTrue() );
}
SECTION( "One true evaluates to true" ) {
std::array<ConvertibleToBool, 5> const data{
{ { false }, { false }, { true }, { false }, { false } } };
REQUIRE_THAT( data, AnyTrue() );
}
SECTION( "All false evaluates to false" ) {
std::array<ConvertibleToBool, 5> const data{
{ { false }, { false }, { false }, { false }, { false } } };
REQUIRE_THAT( data, !AnyTrue() );
}
}
SECTION( "Shortcircuiting" ) {
SECTION( "All are read" ) {
with_mocked_iterator_access<bool> const mocked{
false, false, false, false, true };
REQUIRE_THAT( mocked, AnyTrue() );
REQUIRE( mocked.m_derefed[0] );
REQUIRE( mocked.m_derefed[1] );
REQUIRE( mocked.m_derefed[2] );
REQUIRE( mocked.m_derefed[3] );
REQUIRE( mocked.m_derefed[4] );
}
SECTION( "Short-circuited" ) {
with_mocked_iterator_access<bool> const mocked{
false, false, true, true, true };
REQUIRE_THAT( mocked, AnyTrue() );
REQUIRE( mocked.m_derefed[0] );
REQUIRE( mocked.m_derefed[1] );
REQUIRE( mocked.m_derefed[2] );
REQUIRE_FALSE( mocked.m_derefed[3] );
REQUIRE_FALSE( mocked.m_derefed[4] );
}
}
}
TEST_CASE("All/Any/None True matchers support types with ADL begin",
"[approvals][matchers][quantifiers][templated]") {
using Catch::Matchers::AllTrue;
using Catch::Matchers::NoneTrue;
using Catch::Matchers::AnyTrue;
SECTION( "Type requires ADL found begin and end" ) {
unrelated::needs_ADL_begin<bool> const needs_adl{
true, true, true, true, true };
REQUIRE_THAT( needs_adl, AllTrue() );
}
SECTION( "Type requires ADL found begin and end" ) {
unrelated::needs_ADL_begin<bool> const needs_adl{
false, false, false, false, false };
REQUIRE_THAT( needs_adl, NoneTrue() );
}
SECTION( "Type requires ADL found begin and end" ) {
unrelated::needs_ADL_begin<bool> const needs_adl{
false, false, true, false, false };
REQUIRE_THAT( needs_adl, AnyTrue() );
}
}
// Range loop iterating over range with different types for begin and end is a
// C++17 feature, and GCC refuses to compile such code unless the lang mode is
// set to C++17 or later.
#if defined(CATCH_CPP17_OR_GREATER)
TEST_CASE( "The quantifier range matchers support types with different types returned from begin and end",
"[matchers][templated][quantifiers][approvals]" ) {
using Catch::Matchers::AllMatch;
using Catch::Matchers::AllTrue;
using Catch::Matchers::AnyMatch;
using Catch::Matchers::AnyTrue;
using Catch::Matchers::NoneMatch;
using Catch::Matchers::NoneTrue;
using Catch::Matchers::Predicate;
SECTION( "AllAnyNoneMatch" ) {
has_different_begin_end_types<int> diff_types{ 1, 2, 3, 4, 5 };
REQUIRE_THAT( diff_types, !AllMatch( Predicate<int>( []( int elem ) {
return elem < 3;
} ) ) );
REQUIRE_THAT( diff_types, AnyMatch( Predicate<int>( []( int elem ) {
return elem < 2;
} ) ) );
REQUIRE_THAT( diff_types, !NoneMatch( Predicate<int>( []( int elem ) {
return elem < 3;
} ) ) );
}
SECTION( "AllAnyNoneTrue" ) {
has_different_begin_end_types<bool> diff_types{ false, false, true, false, false };
REQUIRE_THAT( diff_types, !AllTrue() );
REQUIRE_THAT( diff_types, AnyTrue() );
REQUIRE_THAT( diff_types, !NoneTrue() );
}
}
TEST_CASE( "RangeEquals supports ranges with different types returned from begin and end",
"[matchers][templated][range][approvals] ") {
using Catch::Matchers::RangeEquals;
using Catch::Matchers::UnorderedRangeEquals;
has_different_begin_end_types<int> diff_types{ 1, 2, 3, 4, 5 };
std::array<int, 5> arr1{ { 1, 2, 3, 4, 5 } }, arr2{ { 2, 3, 4, 5, 6 } };
REQUIRE_THAT( diff_types, RangeEquals( arr1 ) );
REQUIRE_THAT( diff_types, RangeEquals( arr2, []( int l, int r ) {
return l + 1 == r;
} ) );
REQUIRE_THAT( diff_types, UnorderedRangeEquals( diff_types ) );
}
TEST_CASE( "RangeContains supports ranges with different types returned from "
"begin and end",
"[matchers][templated][range][approvals]" ) {
using Catch::Matchers::Contains;
has_different_begin_end_types<size_t> diff_types{ 1, 2, 3, 4, 5 };
REQUIRE_THAT( diff_types, Contains( size_t( 3 ) ) );
REQUIRE_THAT( diff_types, Contains( LessThanMatcher( size_t( 4 ) ) ) );
}
#endif
TEST_CASE( "Usage of RangeEquals range matcher", "[matchers][templated][quantifiers]" ) {
using Catch::Matchers::RangeEquals;
// In these tests, the types are always the same - type conversion is in the next section
SECTION( "Basic usage" ) {
SECTION( "Empty container matches empty container" ) {
const std::vector<int> empty_vector;
CHECK_THAT( empty_vector, RangeEquals( empty_vector ) );
}
SECTION( "Empty container does not match non-empty container" ) {
const std::vector<int> empty_vector;
const std::vector<int> non_empty_vector{ 1 };
CHECK_THAT( empty_vector, !RangeEquals( non_empty_vector ) );
// ...and in reverse
CHECK_THAT( non_empty_vector, !RangeEquals( empty_vector ) );
}
SECTION( "Two equal 1-length non-empty containers" ) {
const std::array<int, 1> non_empty_array{ { 1 } };
CHECK_THAT( non_empty_array, RangeEquals( non_empty_array ) );
}
SECTION( "Two equal-sized, equal, non-empty containers" ) {
const std::array<int, 3> array_a{ { 1, 2, 3 } };
CHECK_THAT( array_a, RangeEquals( array_a ) );
}
SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
const std::array<int, 3> array_a{ { 1, 2, 3 } };
const std::array<int, 3> array_b{ { 2, 2, 3 } };
const std::array<int, 3> array_c{ { 1, 2, 2 } };
CHECK_THAT( array_a, !RangeEquals( array_b ) );
CHECK_THAT( array_a, !RangeEquals( array_c ) );
}
SECTION( "Two non-equal-sized, non-empty containers (with same first "
"elements)" ) {
const std::vector<int> vector_a{ 1, 2, 3 };
const std::vector<int> vector_b{ 1, 2, 3, 4 };
CHECK_THAT( vector_a, !RangeEquals( vector_b ) );
}
}
SECTION( "Custom predicate" ) {
auto close_enough = []( int lhs, int rhs ) {
return std::abs( lhs - rhs ) <= 1;
};
SECTION( "Two equal non-empty containers (close enough)" ) {
const std::vector<int> vector_a{ { 1, 2, 3 } };
const std::vector<int> vector_a_plus_1{ { 2, 3, 4 } };
CHECK_THAT( vector_a, RangeEquals( vector_a_plus_1, close_enough ) );
}
SECTION( "Two non-equal non-empty containers (close enough)" ) {
const std::vector<int> vector_a{ { 1, 2, 3 } };
const std::vector<int> vector_b{ { 3, 3, 4 } };
CHECK_THAT( vector_a, !RangeEquals( vector_b, close_enough ) );
}
}
SECTION( "Ranges that need ADL begin/end" ) {
unrelated::needs_ADL_begin<int> const
needs_adl1{ 1, 2, 3, 4, 5 },
needs_adl2{ 1, 2, 3, 4, 5 },
needs_adl3{ 2, 3, 4, 5, 6 };
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl2 ) );
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) {
return l + 1 == r;
} ) );
}
SECTION("Check short-circuiting behaviour") {
with_mocked_iterator_access<int> const mocked1{ 1, 2, 3, 4 };
SECTION( "Check short-circuits on failure" ) {
std::array<int, 4> arr{ { 1, 2, 4, 4 } };
REQUIRE_THAT( mocked1, !RangeEquals( arr ) );
REQUIRE( mocked1.m_derefed[0] );
REQUIRE( mocked1.m_derefed[1] );
REQUIRE( mocked1.m_derefed[2] );
REQUIRE_FALSE( mocked1.m_derefed[3] );
}
SECTION("All elements are checked on success") {
std::array<int, 4> arr{ { 1, 2, 3, 4 } };
REQUIRE_THAT( mocked1, RangeEquals( arr ) );
REQUIRE( mocked1.m_derefed[0] );
REQUIRE( mocked1.m_derefed[1] );
REQUIRE( mocked1.m_derefed[2] );
REQUIRE( mocked1.m_derefed[3] );
}
}
}
TEST_CASE( "Usage of UnorderedRangeEquals range matcher",
"[matchers][templated][quantifiers]" ) {
using Catch::Matchers::UnorderedRangeEquals;
// In these tests, the types are always the same - type conversion is in the
// next section
SECTION( "Basic usage" ) {
SECTION( "Empty container matches empty container" ) {
const std::vector<int> empty_vector;
CHECK_THAT( empty_vector, UnorderedRangeEquals( empty_vector ) );
}
SECTION( "Empty container does not match non-empty container" ) {
const std::vector<int> empty_vector;
const std::vector<int> non_empty_vector{ 1 };
CHECK_THAT( empty_vector,
!UnorderedRangeEquals( non_empty_vector ) );
// ...and in reverse
CHECK_THAT( non_empty_vector,
!UnorderedRangeEquals( empty_vector ) );
}
SECTION( "Two equal 1-length non-empty containers" ) {
const std::array<int, 1> non_empty_array{ { 1 } };
CHECK_THAT( non_empty_array,
UnorderedRangeEquals( non_empty_array ) );
}
SECTION( "Two equal-sized, equal, non-empty containers" ) {
const std::array<int, 3> array_a{ { 1, 2, 3 } };
CHECK_THAT( array_a, UnorderedRangeEquals( array_a ) );
}
SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
const std::array<int, 3> array_a{ { 1, 2, 3 } };
const std::array<int, 3> array_b{ { 2, 2, 3 } };
CHECK_THAT( array_a, !UnorderedRangeEquals( array_b ) );
}
SECTION( "Two non-equal-sized, non-empty containers" ) {
const std::vector<int> vector_a{ 1, 2, 3 };
const std::vector<int> vector_b{ 1, 2, 3, 4 };
CHECK_THAT( vector_a, !UnorderedRangeEquals( vector_b ) );
}
}
SECTION( "Custom predicate" ) {
auto close_enough = []( int lhs, int rhs ) {
return std::abs( lhs - rhs ) <= 1;
};
SECTION( "Two equal non-empty containers (close enough)" ) {
const std::vector<int> vector_a{ { 1, 10, 20 } };
const std::vector<int> vector_a_plus_1{ { 11, 21, 2 } };
CHECK_THAT( vector_a,
UnorderedRangeEquals( vector_a_plus_1, close_enough ) );
}
SECTION( "Two non-equal non-empty containers (close enough)" ) {
const std::vector<int> vector_a{ { 1, 10, 21 } };
const std::vector<int> vector_b{ { 11, 21, 3 } };
CHECK_THAT( vector_a,
!UnorderedRangeEquals( vector_b, close_enough ) );
}
}
SECTION( "Ranges that need ADL begin/end" ) {
unrelated::needs_ADL_begin<int> const
needs_adl1{ 1, 2, 3, 4, 5 },
needs_adl2{ 1, 2, 3, 4, 5 };
REQUIRE_THAT( needs_adl1, UnorderedRangeEquals( needs_adl2 ) );
}
}
/**
* Return true if the type given has a random access iterator type.
*/
template <typename Container>
static constexpr bool ContainerIsRandomAccess( const Container& ) {
using array_iter_category = typename std::iterator_traits<
typename Container::iterator>::iterator_category;
return std::is_base_of<std::random_access_iterator_tag,
array_iter_category>::value;
}
TEST_CASE( "Type conversions of RangeEquals and similar",
"[matchers][templated][quantifiers]" ) {
using Catch::Matchers::RangeEquals;
using Catch::Matchers::UnorderedRangeEquals;
// In these test, we can always test RangeEquals and
// UnorderedRangeEquals in the same way, since we're mostly
// testing the template type deductions (and RangeEquals
// implies UnorderedRangeEquals)
SECTION( "Container conversions" ) {
SECTION( "Two equal containers of different container types" ) {
const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
const int c_array[3] = { 1, 2, 3 };
CHECK_THAT( array_int_a, RangeEquals( c_array ) );
CHECK_THAT( array_int_a, UnorderedRangeEquals( c_array ) );
}
SECTION( "Two equal containers of different container types "
"(differ in array N)" ) {
const std::array<int, 3> array_int_3{ { 1, 2, 3 } };
const std::array<int, 4> array_int_4{ { 1, 2, 3, 4 } };
CHECK_THAT( array_int_3, !RangeEquals( array_int_4 ) );
CHECK_THAT( array_int_3, !UnorderedRangeEquals( array_int_4 ) );
}
SECTION( "Two equal containers of different container types and value "
"types" ) {
const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
const std::vector<int> vector_char_a{ 1, 2, 3 };
CHECK_THAT( array_int_a, RangeEquals( vector_char_a ) );
CHECK_THAT( array_int_a, UnorderedRangeEquals( vector_char_a ) );
}
SECTION( "Two equal containers, one random access, one not" ) {
const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
const std::list<int> list_char_a{ 1, 2, 3 };
// Verify these types really are different in random access nature
STATIC_REQUIRE( ContainerIsRandomAccess( array_int_a ) !=
ContainerIsRandomAccess( list_char_a ) );
CHECK_THAT( array_int_a, RangeEquals( list_char_a ) );
CHECK_THAT( array_int_a, UnorderedRangeEquals( list_char_a ) );
}
}
SECTION( "Value type" ) {
SECTION( "Two equal containers of different value types" ) {
const std::vector<int> vector_int_a{ 1, 2, 3 };
const std::vector<char> vector_char_a{ 1, 2, 3 };
CHECK_THAT( vector_int_a, RangeEquals( vector_char_a ) );
CHECK_THAT( vector_int_a, UnorderedRangeEquals( vector_char_a ) );
}
SECTION( "Two non-equal containers of different value types" ) {
const std::vector<int> vector_int_a{ 1, 2, 3 };
const std::vector<char> vector_char_b{ 1, 2, 2 };
CHECK_THAT( vector_int_a, !RangeEquals( vector_char_b ) );
CHECK_THAT( vector_int_a, !UnorderedRangeEquals( vector_char_b ) );
}
}
SECTION( "Ranges with begin that needs ADL" ) {
unrelated::needs_ADL_begin<int> a{ 1, 2, 3 }, b{ 3, 2, 1 };
REQUIRE_THAT( a, !RangeEquals( b ) );
REQUIRE_THAT( a, UnorderedRangeEquals( b ) );
}
SECTION( "Custom predicate" ) {
auto close_enough = []( int lhs, int rhs ) {
return std::abs( lhs - rhs ) <= 1;
};
SECTION( "Two equal non-empty containers (close enough)" ) {
const std::vector<int> vector_a{ { 1, 2, 3 } };
const std::array<char, 3> array_a_plus_1{ { 2, 3, 4 } };
CHECK_THAT( vector_a,
RangeEquals( array_a_plus_1, close_enough ) );
CHECK_THAT( vector_a,
UnorderedRangeEquals( array_a_plus_1, close_enough ) );
}
}
}

View File

@ -0,0 +1,312 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <iostream>
TEST_CASE( "INFO and WARN do not abort tests", "[messages][.]" ) {
INFO( "this is a " << "message" ); // This should output the message if a failure occurs
WARN( "this is a " << "warning" ); // This should always output the message but then continue
}
TEST_CASE( "#1455 - INFO and WARN can start with a linebreak", "[messages][.]" ) {
// Previously these would be hidden from the console reporter output,
// because it would fail at properly reflowing the text
INFO( "\nThis info message starts with a linebreak" );
WARN( "\nThis warning message starts with a linebreak" );
}
TEST_CASE( "SUCCEED counts as a test pass", "[messages]" ) {
SUCCEED( "this is a " << "success" );
}
TEST_CASE( "INFO gets logged on failure", "[failing][messages][.]" ) {
INFO( "this message should be logged" );
INFO( "so should this" );
int a = 2;
REQUIRE( a == 1 );
}
TEST_CASE( "INFO gets logged on failure, even if captured before successful assertions", "[failing][messages][.]" ) {
INFO( "this message may be logged later" );
int a = 2;
CHECK( a == 2 );
INFO( "this message should be logged" );
CHECK( a == 1 );
INFO( "and this, but later" );
CHECK( a == 0 );
INFO( "but not this" );
CHECK( a == 2 );
}
TEST_CASE( "FAIL aborts the test", "[failing][messages][.]" ) {
FAIL( "This is a " << "failure" ); // This should output the message and abort
WARN( "We should never see this");
}
TEST_CASE( "FAIL_CHECK does not abort the test", "[failing][messages][.]" ) {
FAIL_CHECK( "This is a " << "failure" ); // This should output the message then continue
WARN( "This message appears in the output");
}
TEST_CASE( "FAIL does not require an argument", "[failing][messages][.]" ) {
FAIL();
}
TEST_CASE( "SUCCEED does not require an argument", "[messages][.]" ) {
SUCCEED();
}
TEST_CASE( "Output from all sections is reported", "[failing][messages][.]" ) {
SECTION( "one" ) {
FAIL( "Message from section one" );
}
SECTION( "two" ) {
FAIL( "Message from section two" );
}
}
TEST_CASE( "Standard output from all sections is reported", "[messages][.]" ) {
SECTION( "one" ) {
std::cout << "Message from section one\n";
}
SECTION( "two" ) {
std::cout << "Message from section two\n";
}
}
TEST_CASE( "Standard error is reported and redirected", "[messages][.][approvals]" ) {
SECTION( "std::cerr" ) {
std::cerr << "Write to std::cerr\n";
}
SECTION( "std::clog" ) {
std::clog << "Write to std::clog\n";
}
SECTION( "Interleaved writes to cerr and clog" ) {
std::cerr << "Inter";
std::clog << "leaved";
std::cerr << ' ';
std::clog << "writes";
std::cerr << " to error";
std::clog << " streams\n" << std::flush;
}
}
TEST_CASE( "INFO is reset for each loop", "[messages][failing][.]" ) {
for( int i=0; i<100; i++ )
{
INFO( "current counter " << i );
CAPTURE( i );
REQUIRE( i < 10 );
}
}
TEST_CASE( "The NO_FAIL macro reports a failure but does not fail the test", "[messages]" ) {
CHECK_NOFAIL( 1 == 2 );
}
TEST_CASE( "just info", "[info][isolated info][messages]" ) {
INFO( "this should never be seen" );
}
TEST_CASE( "just failure", "[fail][isolated info][.][messages]" ) {
FAIL( "Previous info should not be seen" );
}
TEST_CASE( "sends information to INFO", "[.][failing]" ) {
INFO( "hi" );
int i = 7;
CAPTURE( i );
REQUIRE( false );
}
TEST_CASE( "Pointers can be converted to strings", "[messages][.][approvals]" ) {
int p;
WARN( "actual address of p: " << &p );
WARN( "toString(p): " << ::Catch::Detail::stringify( &p ) );
}
template <typename T>
static void unscoped_info( T msg ) {
UNSCOPED_INFO( msg );
}
TEST_CASE( "just unscoped info", "[unscoped][info]" ) {
unscoped_info( "this should NOT be seen" );
unscoped_info( "this also should NOT be seen" );
}
TEST_CASE( "just failure after unscoped info", "[failing][.][unscoped][info]" ) {
FAIL( "previous unscoped info SHOULD not be seen" );
}
TEST_CASE( "print unscoped info if passing unscoped info is printed", "[unscoped][info]" ) {
unscoped_info( "this MAY be seen IF info is printed for passing assertions" );
REQUIRE( true );
}
TEST_CASE( "prints unscoped info on failure", "[failing][.][unscoped][info]" ) {
unscoped_info( "this SHOULD be seen" );
unscoped_info( "this SHOULD also be seen" );
REQUIRE( false );
unscoped_info( "but this should NOT be seen" );
}
TEST_CASE( "not prints unscoped info from previous failures", "[failing][.][unscoped][info]" ) {
unscoped_info( "this MAY be seen only for the FIRST assertion IF info is printed for passing assertions" );
REQUIRE( true );
unscoped_info( "this MAY be seen only for the SECOND assertion IF info is printed for passing assertions" );
REQUIRE( true );
unscoped_info( "this SHOULD be seen" );
REQUIRE( false );
}
TEST_CASE( "prints unscoped info only for the first assertion", "[failing][.][unscoped][info]" ) {
unscoped_info( "this SHOULD be seen only ONCE" );
CHECK( false );
CHECK( true );
unscoped_info( "this MAY also be seen only ONCE IF info is printed for passing assertions" );
CHECK( true );
CHECK( true );
}
TEST_CASE( "stacks unscoped info in loops", "[failing][.][unscoped][info]" ) {
UNSCOPED_INFO("Count 1 to 3...");
for (int i = 1; i <= 3; i++) {
unscoped_info(i);
}
CHECK( false );
UNSCOPED_INFO("Count 4 to 6...");
for (int i = 4; i <= 6; i++) {
unscoped_info(i);
}
CHECK( false );
}
TEST_CASE( "mix info, unscoped info and warning", "[unscoped][info]" ) {
INFO("info");
unscoped_info("unscoped info");
WARN("and warn may mix");
WARN("they are not cleared after warnings");
}
TEST_CASE( "CAPTURE can deal with complex expressions", "[messages][capture]" ) {
int a = 1;
int b = 2;
int c = 3;
CAPTURE( a, b, c, a + b, a+b, c > b, a == 1 );
SUCCEED();
}
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value" // In (1, 2), the "1" is unused ...
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-value" // All the comma operators are side-effect free
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4709) // comma in indexing operator
#endif
template <typename T1, typename T2>
struct helper_1436 {
helper_1436(T1 t1_, T2 t2_):
t1{ t1_ },
t2{ t2_ }
{}
T1 t1;
T2 t2;
};
template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& out, helper_1436<T1, T2> const& helper) {
out << "{ " << helper.t1 << ", " << helper.t2 << " }";
return out;
}
// Clang and gcc have different names for this warning, and clang also
// warns about an unused value. This warning must be disabled for C++20.
#if defined(__GNUG__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wcomma-subscript"
#elif defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunknown-warning-option"
#pragma clang diagnostic ignored "-Wdeprecated-comma-subscript"
#pragma clang diagnostic ignored "-Wunused-value"
#endif
namespace {
template <typename T>
struct custom_index_op {
constexpr custom_index_op( std::initializer_list<T> ) {}
constexpr T operator[]( size_t ) { return T{}; }
#if defined( __cpp_multidimensional_subscript ) && \
__cpp_multidimensional_subscript >= 202110L
constexpr T operator[]( size_t, size_t, size_t ) const noexcept {
return T{};
}
#endif
};
}
TEST_CASE("CAPTURE can deal with complex expressions involving commas", "[messages][capture]") {
CAPTURE(custom_index_op<int>{1, 2, 3}[0, 1, 2],
custom_index_op<int>{1, 2, 3}[(0, 1)],
custom_index_op<int>{1, 2, 3}[0]);
CAPTURE((helper_1436<int, int>{12, -12}),
(helper_1436<int, int>(-12, 12)));
CAPTURE( (1, 2), (2, 3) );
SUCCEED();
}
#ifdef __GNUG__
#pragma GCC diagnostic pop
#endif
TEST_CASE("CAPTURE parses string and character constants", "[messages][capture]") {
CAPTURE(("comma, in string", "escaped, \", "), "single quote in string,',", "some escapes, \\,\\\\");
CAPTURE("some, ), unmatched, } prenheses {[<");
CAPTURE('"', '\'', ',', '}', ')', '(', '{');
SUCCEED();
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
TEST_CASE( "INFO and UNSCOPED_INFO can stream multiple arguments",
"[messages][info][.failing]" ) {
INFO( "This info"
<< " has multiple"
<< " parts." );
UNSCOPED_INFO( "This unscoped info"
<< " has multiple"
<< " parts." );
FAIL( "Show infos!" );
}

View File

@ -0,0 +1,560 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_template_test_macros.hpp>
#include <catch2/internal/catch_config_wchar.hpp>
#include <catch2/internal/catch_windows_h_proxy.hpp>
#include <iostream>
#include <cerrno>
#include <limits>
#include <array>
#include <tuple>
namespace {
static const char* makeString(bool makeNull) {
return makeNull ? nullptr : "valid string";
}
static bool testCheckedIf(bool flag) {
CHECKED_IF(flag)
return true;
else
return false;
}
static bool testCheckedElse(bool flag) {
CHECKED_ELSE(flag)
return false;
return true;
}
static unsigned int Factorial(unsigned int number) {
return number > 1 ? Factorial(number - 1) * number : 1;
}
static int f() {
return 1;
}
static void manuallyRegisteredTestFunction() {
SUCCEED("was called");
}
struct AutoTestReg {
AutoTestReg() {
REGISTER_TEST_CASE(manuallyRegisteredTestFunction, "ManuallyRegistered");
}
};
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
static AutoTestReg autoTestReg;
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
template<typename T>
struct Foo {
size_t size() { return 0; }
};
template<typename T, size_t S>
struct Bar {
size_t size() { return S; }
};
}
TEST_CASE( "random SECTION tests", "[.][sections][failing]" ) {
int a = 1;
int b = 2;
SECTION( "doesn't equal" ) {
REQUIRE( a != b );
REQUIRE( b != a );
}
SECTION( "not equal" ) {
REQUIRE( a != b);
}
}
TEST_CASE( "nested SECTION tests", "[.][sections][failing]" ) {
int a = 1;
int b = 2;
SECTION( "doesn't equal" ) {
REQUIRE( a != b );
REQUIRE( b != a );
SECTION( "not equal" ) {
REQUIRE( a != b);
}
}
}
TEST_CASE( "more nested SECTION tests", "[sections][failing][.]" ) {
int a = 1;
int b = 2;
SECTION( "doesn't equal" ) {
SECTION( "equal" ) {
REQUIRE( a == b );
}
SECTION( "not equal" ) {
REQUIRE( a != b );
}
SECTION( "less than" ) {
REQUIRE( a < b );
}
}
}
TEST_CASE( "even more nested SECTION tests", "[sections]" ) {
SECTION( "c" ) {
SECTION( "d (leaf)" ) {
SUCCEED(); // avoid failing due to no tests
}
SECTION( "e (leaf)" ) {
SUCCEED(); // avoid failing due to no tests
}
}
SECTION( "f (leaf)" ) {
SUCCEED(); // avoid failing due to no tests
}
}
TEST_CASE( "looped SECTION tests", "[.][failing][sections]" ) {
int a = 1;
for( int b = 0; b < 10; ++b ) {
DYNAMIC_SECTION( "b is currently: " << b ) {
CHECK( b > a );
}
}
}
TEST_CASE( "looped tests", "[.][failing]" ) {
static const int fib[] = { 1, 1, 2, 3, 5, 8, 13, 21 };
for( std::size_t i=0; i < sizeof(fib)/sizeof(int); ++i ) {
INFO( "Testing if fib[" << i << "] (" << fib[i] << ") is even" );
CHECK( ( fib[i] % 2 ) == 0 );
}
}
TEST_CASE( "Sends stuff to stdout and stderr", "[.]" ) {
std::cout << "A string sent directly to stdout\n" << std::flush;
std::cerr << "A string sent directly to stderr\n" << std::flush;
std::clog << "A string sent to stderr via clog\n" << std::flush;
}
TEST_CASE( "null strings" ) {
REQUIRE( makeString( false ) != static_cast<char*>(nullptr));
REQUIRE( makeString( true ) == static_cast<char*>(nullptr));
}
TEST_CASE( "checkedIf" ) {
REQUIRE( testCheckedIf( true ) );
}
TEST_CASE( "checkedIf, failing", "[failing][.]" ) {
REQUIRE( testCheckedIf( false ) );
}
TEST_CASE( "checkedElse" ) {
REQUIRE( testCheckedElse( true ) );
}
TEST_CASE( "checkedElse, failing", "[failing][.]" ) {
REQUIRE( testCheckedElse( false ) );
}
TEST_CASE("Testing checked-if", "[checked-if]") {
CHECKED_IF(true) {
SUCCEED();
}
CHECKED_IF(false) {
FAIL();
}
CHECKED_ELSE(true) {
FAIL();
}
CHECKED_ELSE(false) {
SUCCEED();
}
}
TEST_CASE("Testing checked-if 2", "[checked-if][!shouldfail]") {
CHECKED_IF(true) {
FAIL();
}
// If the checked if is not entered, this passes and the test
// fails, because of the [!shouldfail] tag.
SUCCEED();
}
TEST_CASE("Testing checked-if 3", "[checked-if][!shouldfail]") {
CHECKED_ELSE(false) {
FAIL();
}
// If the checked false is not entered, this passes and the test
// fails, because of the [!shouldfail] tag.
SUCCEED();
}
[[noreturn]]
TEST_CASE("Testing checked-if 4", "[checked-if][!shouldfail]") {
CHECKED_ELSE(true) {}
throw std::runtime_error("Uncaught exception should fail!");
}
[[noreturn]]
TEST_CASE("Testing checked-if 5", "[checked-if][!shouldfail]") {
CHECKED_ELSE(false) {}
throw std::runtime_error("Uncaught exception should fail!");
}
TEST_CASE( "xmlentitycheck" ) {
SECTION( "embedded xml: <test>it should be possible to embed xml characters, such as <, \" or &, or even whole <xml>documents</xml> within an attribute</test>" ) {
SUCCEED(); // We need this here to stop it failing due to no tests
}
SECTION( "encoded chars: these should all be encoded: &&&\"\"\"<<<&\"<<&\"" ) {
SUCCEED(); // We need this here to stop it failing due to no tests
}
}
TEST_CASE( "send a single char to INFO", "[failing][.]" ) {
INFO(3);
REQUIRE(false);
}
TEST_CASE( "Factorials are computed", "[factorial]" ) {
REQUIRE( Factorial(0) == 1 );
REQUIRE( Factorial(1) == 1 );
REQUIRE( Factorial(2) == 2 );
REQUIRE( Factorial(3) == 6 );
REQUIRE( Factorial(10) == 3628800 );
}
TEST_CASE( "An empty test with no assertions", "[empty]" ) {}
TEST_CASE( "Nice descriptive name", "[tag1][tag2][tag3][.]" ) {
WARN( "This one ran" );
}
TEST_CASE( "first tag", "[tag1]" ) {}
TEST_CASE( "second tag", "[tag2]" ) {}
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
std::vector<int> v( 5 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
SECTION( "resizing bigger changes size and capacity" ) {
v.resize( 10 );
REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 );
}
SECTION( "resizing smaller changes size but not capacity" ) {
v.resize( 0 );
REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 );
SECTION( "We can use the 'swap trick' to reset the capacity" ) {
std::vector<int> empty;
empty.swap( v );
REQUIRE( v.capacity() == 0 );
}
}
SECTION( "reserving bigger changes capacity but not size" ) {
v.reserve( 10 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 );
}
SECTION( "reserving smaller does not change size or capacity" ) {
v.reserve( 0 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
}
}
TEMPLATE_TEST_CASE( "TemplateTest: vectors can be sized and resized", "[vector][template]", int, float, std::string, (std::tuple<int,float>) ) {
std::vector<TestType> v( 5 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
SECTION( "resizing bigger changes size and capacity" ) {
v.resize( 10 );
REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 );
}
SECTION( "resizing smaller changes size but not capacity" ) {
v.resize( 0 );
REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 );
SECTION( "We can use the 'swap trick' to reset the capacity" ) {
std::vector<TestType> empty;
empty.swap( v );
REQUIRE( v.capacity() == 0 );
}
}
SECTION( "reserving bigger changes capacity but not size" ) {
v.reserve( 10 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 );
}
SECTION( "reserving smaller does not change size or capacity" ) {
v.reserve( 0 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
}
}
TEMPLATE_TEST_CASE_SIG("TemplateTestSig: vectors can be sized and resized", "[vector][template][nttp]", ((typename TestType, int V), TestType, V), (int,5), (float,4), (std::string,15), ((std::tuple<int, float>), 6)) {
std::vector<TestType> v(V);
REQUIRE(v.size() == V);
REQUIRE(v.capacity() >= V);
SECTION("resizing bigger changes size and capacity") {
v.resize(2 * V);
REQUIRE(v.size() == 2 * V);
REQUIRE(v.capacity() >= 2 * V);
}
SECTION("resizing smaller changes size but not capacity") {
v.resize(0);
REQUIRE(v.size() == 0);
REQUIRE(v.capacity() >= V);
SECTION("We can use the 'swap trick' to reset the capacity") {
std::vector<TestType> empty;
empty.swap(v);
REQUIRE(v.capacity() == 0);
}
}
SECTION("reserving bigger changes capacity but not size") {
v.reserve(2 * V);
REQUIRE(v.size() == V);
REQUIRE(v.capacity() >= 2 * V);
}
SECTION("reserving smaller does not change size or capacity") {
v.reserve(0);
REQUIRE(v.size() == V);
REQUIRE(v.capacity() >= V);
}
}
TEMPLATE_PRODUCT_TEST_CASE("A Template product test case", "[template][product]", (std::vector, Foo), (int, float)) {
TestType x;
REQUIRE(x.size() == 0);
}
TEMPLATE_PRODUCT_TEST_CASE_SIG("A Template product test case with array signature", "[template][product][nttp]", ((typename T, size_t S), T, S), (std::array, Bar), ((int, 9), (float, 42))) {
TestType x;
REQUIRE(x.size() > 0);
}
TEMPLATE_PRODUCT_TEST_CASE("Product with differing arities", "[template][product]", std::tuple, (int, (int, double), (int, double, float))) {
REQUIRE(std::tuple_size<TestType>::value >= 1);
}
using MyTypes = std::tuple<int, char, float>;
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std::tuple", "[template][list]", MyTypes)
{
REQUIRE(std::is_arithmetic<TestType>::value);
}
struct NonDefaultConstructibleType {
NonDefaultConstructibleType() = delete;
};
using MyNonDefaultConstructibleTypes = std::tuple<NonDefaultConstructibleType, float>;
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside non-default-constructible std::tuple", "[template][list]", MyNonDefaultConstructibleTypes)
{
REQUIRE(std::is_trivially_copyable<TestType>::value);
}
struct NonCopyableAndNonMovableType {
NonCopyableAndNonMovableType() = default;
NonCopyableAndNonMovableType(NonCopyableAndNonMovableType const &) = delete;
NonCopyableAndNonMovableType(NonCopyableAndNonMovableType &&) = delete;
auto operator=(NonCopyableAndNonMovableType const &) -> NonCopyableAndNonMovableType & = delete;
auto operator=(NonCopyableAndNonMovableType &&) -> NonCopyableAndNonMovableType & = delete;
};
using NonCopyableAndNonMovableTypes = std::tuple<NonCopyableAndNonMovableType, float>;
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside non-copyable and non-movable std::tuple", "[template][list]", NonCopyableAndNonMovableTypes)
{
REQUIRE(std::is_default_constructible<TestType>::value);
}
// https://github.com/philsquared/Catch/issues/166
TEST_CASE("A couple of nested sections followed by a failure", "[failing][.]") {
SECTION("Outer")
SECTION("Inner")
SUCCEED("that's not flying - that's failing in style");
FAIL("to infinity and beyond");
}
TEST_CASE("not allowed", "[!throws]") {
// This test case should not be included if you run with -e on the command line
SUCCEED();
}
TEST_CASE( "Tabs and newlines show in output", "[.][whitespace][failing]" ) {
// Based on issue #242
std::string s1 = "if ($b == 10) {\n\t\t$a\t= 20;\n}";
std::string s2 = "if ($b == 10) {\n\t$a = 20;\n}\n";
CHECK( s1 == s2 );
}
#if defined(CATCH_CONFIG_WCHAR)
TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) {
const wchar_t * const s = L"wide load";
std::string result = ::Catch::Detail::stringify( s );
CHECK( result == "\"wide load\"" );
}
TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[toString]" ) {
const wchar_t * s = L"wide load";
std::string result = ::Catch::Detail::stringify( s );
CHECK( result == "\"wide load\"" );
}
TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) {
auto const s = const_cast<wchar_t*>( L"wide load" );
std::string result = ::Catch::Detail::stringify( s );
CHECK( result == "\"wide load\"" );
}
TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
auto s = const_cast<wchar_t*>( L"wide load" );
std::string result = ::Catch::Detail::stringify( s );
CHECK( result == "\"wide load\"" );
}
#endif // CATCH_CONFIG_WCHAR
TEST_CASE( "long long" ) {
constexpr long long l = std::numeric_limits<long long>::max();
REQUIRE( l == std::numeric_limits<long long>::max() );
}
TEST_CASE( "This test 'should' fail but doesn't", "[.][failing][!shouldfail]" ) {
SUCCEED( "oops!" );
}
TEST_CASE( "# A test name that starts with a #" ) {
SUCCEED( "yay" );
}
TEST_CASE( "#835 -- errno should not be touched by Catch2", "[.][failing][!shouldfail]" ) {
errno = 1;
// Check that reporting failed test doesn't change errno.
CHECK(f() == 0);
// We want to avoid expanding `errno` macro in assertion, because
// we capture the expression after macro expansion, and would have
// to normalize the ways different platforms spell `errno`.
const auto errno_after = errno;
REQUIRE(errno_after == 1);
}
TEST_CASE( "#961 -- Dynamically created sections should all be reported", "[.]" ) {
for (char i = '0'; i < '5'; ++i) {
SECTION(std::string("Looped section ") + i) {
SUCCEED( "Everything is OK" );
}
}
}
TEST_CASE( "#1175 - Hidden Test", "[.]" ) {
// Just for checking that hidden test is not listed by default
SUCCEED();
}
TEMPLATE_TEST_CASE_SIG("#1954 - 7 arg template test case sig compiles", "[regression][.compilation]",
((int Tnx, int Tnu, int Tny, int Tph, int Tch, int Tineq, int Teq), Tnx, Tnu, Tny, Tph, Tch, Tineq, Teq),
(1, 1, 1, 1, 1, 0, 0), (5, 1, 1, 1, 1, 0, 0), (5, 3, 1, 1, 1, 0, 0)) {
SUCCEED();
}
TEST_CASE("Same test name but with different tags is fine", "[.approvals][some-tag]") {}
TEST_CASE("Same test name but with different tags is fine", "[.approvals][other-tag]") {}
// MinGW doesn't support __try, and Clang has only very partial support
#if defined(_MSC_VER)
void throw_and_catch()
{
__try {
RaiseException(0xC0000005, 0, 0, NULL);
}
__except (1)
{
}
}
TEST_CASE("Validate SEH behavior - handled", "[approvals][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]")
{
// Validate that Catch2 framework correctly handles tests raising and handling SEH exceptions.
throw_and_catch();
}
void throw_no_catch()
{
RaiseException(0xC0000005, 0, 0, NULL);
}
TEST_CASE("Validate SEH behavior - unhandled", "[.approvals][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]")
{
// Validate that Catch2 framework correctly handles tests raising and not handling SEH exceptions.
throw_no_catch();
}
static LONG CALLBACK dummyExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
return EXCEPTION_CONTINUE_SEARCH;
}
TEST_CASE("Validate SEH behavior - no crash for stack unwinding", "[approvals][!throws][!shouldfail][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]")
{
// Trigger stack unwinding with SEH top-level filter changed and validate the test fails expectedly with no application crash
SetUnhandledExceptionFilter(dummyExceptionFilter);
throw 1;
}
#endif // _MSC_VER

View File

@ -0,0 +1,100 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators_range.hpp>
#include <iostream>
TEST_CASE( "tests can be skipped dynamically at runtime", "[skipping]" ) {
SKIP();
FAIL( "this is not reached" );
}
TEST_CASE( "skipped tests can optionally provide a reason", "[skipping]" ) {
const int answer = 43;
SKIP( "skipping because answer = " << answer );
FAIL( "this is not reached" );
}
TEST_CASE( "sections can be skipped dynamically at runtime", "[skipping]" ) {
SECTION( "not skipped" ) { SUCCEED(); }
SECTION( "skipped" ) { SKIP(); }
SECTION( "also not skipped" ) { SUCCEED(); }
}
TEST_CASE( "nested sections can be skipped dynamically at runtime",
"[skipping]" ) {
SECTION( "A" ) { std::cout << "a"; }
SECTION( "B" ) {
SECTION( "B1" ) { std::cout << "b1"; }
SECTION( "B2" ) { SKIP(); }
}
std::cout << "!\n";
}
TEST_CASE( "dynamic skipping works with generators", "[skipping]" ) {
const int answer = GENERATE( 41, 42, 43 );
if ( answer != 42 ) { SKIP( "skipping because answer = " << answer ); }
SUCCEED();
}
TEST_CASE( "failed assertions before SKIP cause test case to fail",
"[skipping][!shouldfail]" ) {
CHECK( 3 == 4 );
SKIP();
}
TEST_CASE( "a succeeding test can still be skipped",
"[skipping][!shouldfail]" ) {
SUCCEED();
SKIP();
}
TEST_CASE( "failing in some unskipped sections causes entire test case to fail",
"[skipping][!shouldfail]" ) {
SECTION( "skipped" ) { SKIP(); }
SECTION( "not skipped" ) { FAIL(); }
}
TEST_CASE( "failing for some generator values causes entire test case to fail",
"[skipping][!shouldfail]" ) {
int i = GENERATE( 1, 2, 3, 4 );
if ( i % 2 == 0 ) {
SKIP();
} else {
FAIL();
}
}
namespace {
class test_skip_generator : public Catch::Generators::IGenerator<int> {
public:
explicit test_skip_generator() { SKIP( "This generator is empty" ); }
auto get() const -> int const& override {
static constexpr int value = 1;
return value;
}
auto next() -> bool override { return false; }
};
static auto make_test_skip_generator()
-> Catch::Generators::GeneratorWrapper<int> {
return { new test_skip_generator() };
}
} // namespace
TEST_CASE( "Empty generators can SKIP in constructor", "[skipping]" ) {
// The generator signals emptiness with `SKIP`
auto sample = GENERATE( make_test_skip_generator() );
// This assertion would fail, but shouldn't trigger
REQUIRE( sample == 0 );
}

View File

@ -0,0 +1,23 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#if defined(CATCH_CONFIG_CPP17_BYTE)
TEST_CASE( "std::byte -> toString", "[toString][byte][approvals]" ) {
using type = std::byte;
REQUIRE( "0" == ::Catch::Detail::stringify( type{ 0 } ) );
}
TEST_CASE( "std::vector<std::byte> -> toString", "[toString][byte][approvals]" ) {
using type = std::vector<std::byte>;
REQUIRE( "{ 0, 1, 2 }" == ::Catch::Detail::stringify( type{ std::byte{0}, std::byte{1}, std::byte{2} } ) );
}
#endif // CATCH_INTERNAL_CONFIG_CPP17_BYTE

View File

@ -0,0 +1,51 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <chrono>
#include <cstdint>
TEST_CASE("Stringifying std::chrono::duration helpers", "[toString][chrono]") {
// No literals because we still support c++11
auto hour = std::chrono::hours(1);
auto minute = std::chrono::minutes(1);
auto seconds = std::chrono::seconds(60);
auto micro = std::chrono::microseconds(1);
auto milli = std::chrono::milliseconds(1);
auto nano = std::chrono::nanoseconds(1);
REQUIRE(minute == seconds);
REQUIRE(hour != seconds);
REQUIRE(micro != milli);
REQUIRE(nano != micro);
}
TEST_CASE("Stringifying std::chrono::duration with weird ratios", "[toString][chrono]") {
std::chrono::duration<int64_t, std::ratio<30>> half_minute(1);
std::chrono::duration<int64_t, std::ratio<1, 1000000000000>> pico_second(1);
std::chrono::duration<int64_t, std::ratio<1, 1000000000000000>> femto_second(1);
std::chrono::duration<int64_t, std::ratio<1, 1000000000000000000>> atto_second(1);
REQUIRE(half_minute != femto_second);
REQUIRE(pico_second != atto_second);
}
TEST_CASE("Stringifying std::chrono::time_point<system_clock>", "[toString][chrono]") {
auto now = std::chrono::system_clock::now();
auto later = now + std::chrono::minutes(2);
REQUIRE(now != later);
}
TEST_CASE("Stringifying std::chrono::time_point<Clock>", "[toString][chrono][!nonportable]") {
auto now = std::chrono::high_resolution_clock::now();
auto later = now + std::chrono::minutes(2);
REQUIRE(now != later);
auto now2 = std::chrono::steady_clock::now();
auto later2 = now2 + std::chrono::minutes(2);
REQUIRE(now2 != later2);
}

View File

@ -0,0 +1,200 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
#include <catch2/catch_test_macros.hpp>
#include <map>
#include <set>
TEST_CASE( "Character pretty printing" ){
SECTION("Specifically escaped"){
CHECK(::Catch::Detail::stringify('\t') == "'\\t'");
CHECK(::Catch::Detail::stringify('\n') == "'\\n'");
CHECK(::Catch::Detail::stringify('\r') == "'\\r'");
CHECK(::Catch::Detail::stringify('\f') == "'\\f'");
}
SECTION("General chars"){
CHECK(::Catch::Detail::stringify( ' ' ) == "' '" );
CHECK(::Catch::Detail::stringify( 'A' ) == "'A'" );
CHECK(::Catch::Detail::stringify( 'z' ) == "'z'" );
}
SECTION("Low ASCII"){
CHECK(::Catch::Detail::stringify( '\0' ) == "0" );
CHECK(::Catch::Detail::stringify( static_cast<char>(2) ) == "2" );
CHECK(::Catch::Detail::stringify( static_cast<char>(5) ) == "5" );
}
}
TEST_CASE( "Capture and info messages" ) {
SECTION("Capture should stringify like assertions") {
int i = 2;
CAPTURE(i);
REQUIRE(true);
}
SECTION("Info should NOT stringify the way assertions do") {
int i = 3;
INFO(i);
REQUIRE(true);
}
}
TEST_CASE( "std::map is convertible string", "[toString]" ) {
SECTION( "empty" ) {
std::map<std::string, int> emptyMap;
REQUIRE( Catch::Detail::stringify( emptyMap ) == "{ }" );
}
SECTION( "single item" ) {
std::map<std::string, int> map = { { "one", 1 } };
REQUIRE( Catch::Detail::stringify( map ) == "{ { \"one\", 1 } }" );
}
SECTION( "several items" ) {
std::map<std::string, int> map = {
{ "abc", 1 },
{ "def", 2 },
{ "ghi", 3 }
};
REQUIRE( Catch::Detail::stringify( map ) == "{ { \"abc\", 1 }, { \"def\", 2 }, { \"ghi\", 3 } }" );
}
}
TEST_CASE( "std::set is convertible string", "[toString]" ) {
SECTION( "empty" ) {
std::set<std::string> emptySet;
REQUIRE( Catch::Detail::stringify( emptySet ) == "{ }" );
}
SECTION( "single item" ) {
std::set<std::string> set = { "one" };
REQUIRE( Catch::Detail::stringify( set ) == "{ \"one\" }" );
}
SECTION( "several items" ) {
std::set<std::string> set = { "abc", "def", "ghi" };
REQUIRE( Catch::Detail::stringify( set ) == "{ \"abc\", \"def\", \"ghi\" }" );
}
}
TEST_CASE("Static arrays are convertible to string", "[toString]") {
SECTION("Single item") {
int singular[1] = { 1 };
REQUIRE(Catch::Detail::stringify(singular) == "{ 1 }");
}
SECTION("Multiple") {
int arr[3] = { 3, 2, 1 };
REQUIRE(Catch::Detail::stringify(arr) == "{ 3, 2, 1 }");
}
SECTION("Non-trivial inner items") {
std::vector<std::string> arr[2] = { {"1:1", "1:2", "1:3"}, {"2:1", "2:2"} };
REQUIRE(Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })");
}
}
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
TEST_CASE("String views are stringified like other strings", "[toString][approvals]") {
std::string_view view{"abc"};
CHECK(Catch::Detail::stringify(view) == R"("abc")");
std::string_view arr[] { view };
CHECK(Catch::Detail::stringify(arr) == R"({ "abc" })");
}
#endif
TEST_CASE("Precision of floating point stringification can be set", "[toString][floatingPoint]") {
SECTION("Floats") {
using sm = Catch::StringMaker<float>;
const auto oldPrecision = sm::precision;
const float testFloat = 1.12345678901234567899f;
sm::precision = 5;
auto str1 = sm::convert( testFloat );
// "1." prefix = 2 chars, f suffix is another char
CHECK(str1.size() == 3 + 5);
sm::precision = 10;
auto str2 = sm::convert(testFloat);
REQUIRE(str2.size() == 3 + 10);
sm::precision = oldPrecision;
}
SECTION("Double") {
using sm = Catch::StringMaker<double>;
const auto oldPrecision = sm::precision;
const double testDouble = 1.123456789012345678901234567899;
sm::precision = 5;
auto str1 = sm::convert(testDouble);
// "1." prefix = 2 chars
CHECK(str1.size() == 2 + 5);
sm::precision = 15;
auto str2 = sm::convert(testDouble);
REQUIRE(str2.size() == 2 + 15);
sm::precision = oldPrecision;
}
}
namespace {
struct WhatException : std::exception {
char const* what() const noexcept override {
return "This exception has overridden what() method";
}
~WhatException() override;
};
struct OperatorException : std::exception {
~OperatorException() override;
};
std::ostream& operator<<(std::ostream& out, OperatorException const&) {
out << "OperatorException";
return out;
}
struct StringMakerException : std::exception {
~StringMakerException() override;
};
} // end anonymous namespace
namespace Catch {
template <>
struct StringMaker<StringMakerException> {
static std::string convert(StringMakerException const&) {
return "StringMakerException";
}
};
}
// Avoid -Wweak-tables
WhatException::~WhatException() = default;
OperatorException::~OperatorException() = default;
StringMakerException::~StringMakerException() = default;
TEST_CASE("Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified", "[toString][exception]") {
REQUIRE(::Catch::Detail::stringify(WhatException{}) == "This exception has overridden what() method");
REQUIRE(::Catch::Detail::stringify(OperatorException{}) == "OperatorException");
REQUIRE(::Catch::Detail::stringify(StringMakerException{}) == "StringMakerException");
}

View File

@ -0,0 +1,35 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
#include <catch2/catch_test_macros.hpp>
#if defined(CATCH_CONFIG_CPP17_OPTIONAL)
TEST_CASE( "std::optional<int> -> toString", "[toString][optional][approvals]" ) {
using type = std::optional<int>;
REQUIRE( "{ }" == ::Catch::Detail::stringify( type{} ) );
REQUIRE( "0" == ::Catch::Detail::stringify( type{ 0 } ) );
}
TEST_CASE( "std::optional<std::string> -> toString", "[toString][optional][approvals]" ) {
using type = std::optional<std::string>;
REQUIRE( "{ }" == ::Catch::Detail::stringify( type{} ) );
REQUIRE( "\"abc\"" == ::Catch::Detail::stringify( type{ "abc" } ) );
}
TEST_CASE( "std::vector<std::optional<int> > -> toString", "[toString][optional][approvals]" ) {
using type = std::vector<std::optional<int> >;
REQUIRE( "{ 0, { }, 2 }" == ::Catch::Detail::stringify( type{ 0, {}, 2 } ) );
}
TEST_CASE( "std::nullopt -> toString", "[toString][optional][approvals]" ) {
REQUIRE( "{ }" == ::Catch::Detail::stringify( std::nullopt ) );
}
#endif // CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL

View File

@ -0,0 +1,38 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
#include <catch2/catch_test_macros.hpp>
TEST_CASE( "std::pair<int,std::string> -> toString", "[toString][pair]" ) {
std::pair<int,std::string> value( 34, "xyzzy" );
REQUIRE( ::Catch::Detail::stringify( value ) == "{ 34, \"xyzzy\" }" );
}
TEST_CASE( "std::pair<int,const std::string> -> toString", "[toString][pair]" ) {
std::pair<int,const std::string> value( 34, "xyzzy" );
REQUIRE( ::Catch::Detail::stringify(value) == "{ 34, \"xyzzy\" }" );
}
TEST_CASE( "std::vector<std::pair<std::string,int> > -> toString", "[toString][pair]" ) {
std::vector<std::pair<std::string,int> > pr;
pr.push_back( std::make_pair("green", 55 ) );
REQUIRE( ::Catch::Detail::stringify( pr ) == "{ { \"green\", 55 } }" );
}
// This is pretty contrived - I figure if this works, anything will...
TEST_CASE( "pair<pair<int,const char *,pair<std::string,int> > -> toString", "[toString][pair]" ) {
typedef std::pair<int,const char *> left_t;
typedef std::pair<std::string,int> right_t;
left_t left( 42, "Arthur" );
right_t right( "Ford", 24 );
std::pair<left_t,right_t> pair( left, right );
REQUIRE( ::Catch::Detail::stringify( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" );
}

View File

@ -0,0 +1,54 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
#include <catch2/catch_test_macros.hpp>
#include <tuple>
TEST_CASE( "tuple<>", "[toString][tuple]" )
{
typedef std::tuple<> type;
CHECK( "{ }" == ::Catch::Detail::stringify(type{}) );
type value {};
CHECK( "{ }" == ::Catch::Detail::stringify(value) );
}
TEST_CASE( "tuple<int>", "[toString][tuple]" )
{
typedef std::tuple<int> type;
CHECK( "{ 0 }" == ::Catch::Detail::stringify(type{0}) );
}
TEST_CASE( "tuple<float,int>", "[toString][tuple]" )
{
typedef std::tuple<float,int> type;
CHECK( "1.5f" == ::Catch::Detail::stringify(float(1.5)) );
CHECK( "{ 1.5f, 0 }" == ::Catch::Detail::stringify(type{1.5f,0}) );
}
TEST_CASE( "tuple<string,string>", "[toString][tuple]" )
{
typedef std::tuple<std::string,std::string> type;
CHECK( "{ \"hello\", \"world\" }" == ::Catch::Detail::stringify(type{"hello","world"}) );
}
TEST_CASE( "tuple<tuple<int>,tuple<>,float>", "[toString][tuple]" )
{
typedef std::tuple<std::tuple<int>,std::tuple<>,float> type;
type value { std::tuple<int>{42}, {}, 1.5f };
CHECK( "{ { 42 }, { }, 1.5f }" == ::Catch::Detail::stringify(value) );
}
TEST_CASE( "tuple<nullptr,int,const char *>", "[approvals][toString][tuple]" ) {
typedef std::tuple<std::nullptr_t,int,const char *> type;
type value { nullptr, 42, "Catch me" };
CHECK( "{ nullptr, 42, \"Catch me\" }" == ::Catch::Detail::stringify(value) );
}

View File

@ -0,0 +1,99 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
#include <catch2/catch_test_macros.hpp>
#if defined(CATCH_CONFIG_CPP17_VARIANT)
#include <string>
#include <variant>
// We need 2 types with non-trivial copies/moves
struct MyType1 {
MyType1() = default;
[[noreturn]] MyType1(MyType1 const&) { throw 1; }
MyType1& operator=(MyType1 const&) { throw 3; }
};
struct MyType2 {
MyType2() = default;
[[noreturn]] MyType2(MyType2 const&) { throw 2; }
MyType2& operator=(MyType2 const&) { throw 4; }
};
TEST_CASE( "variant<std::monostate>", "[toString][variant][approvals]")
{
using type = std::variant<std::monostate>;
CHECK( "{ }" == ::Catch::Detail::stringify(type{}) );
type value {};
CHECK( "{ }" == ::Catch::Detail::stringify(value) );
CHECK( "{ }" == ::Catch::Detail::stringify(std::get<0>(value)) );
}
TEST_CASE( "variant<int>", "[toString][variant][approvals]")
{
using type = std::variant<int>;
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
}
TEST_CASE( "variant<float, int>", "[toString][variant][approvals]")
{
using type = std::variant<float, int>;
CHECK( "0.5f" == ::Catch::Detail::stringify(type{0.5f}) );
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
}
TEST_CASE( "variant -- valueless-by-exception", "[toString][variant][approvals]" ) {
using type = std::variant<MyType1, MyType2>;
type value;
REQUIRE_THROWS_AS(value.emplace<MyType2>(MyType2{}), int);
REQUIRE(value.valueless_by_exception());
CHECK("{valueless variant}" == ::Catch::Detail::stringify(value));
}
TEST_CASE( "variant<string, int>", "[toString][variant][approvals]")
{
using type = std::variant<std::string, int>;
CHECK( "\"foo\"" == ::Catch::Detail::stringify(type{"foo"}) );
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
}
TEST_CASE( "variant<variant<float, int>, string>", "[toString][variant][approvals]")
{
using inner = std::variant<MyType1, float, int>;
using type = std::variant<inner, std::string>;
CHECK( "0.5f" == ::Catch::Detail::stringify(type{0.5f}) );
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
CHECK( "\"foo\"" == ::Catch::Detail::stringify(type{"foo"}) );
SECTION("valueless nested variant") {
type value = inner{0.5f};
REQUIRE( std::holds_alternative<inner>(value) );
REQUIRE( std::holds_alternative<float>(std::get<inner>(value)) );
REQUIRE_THROWS_AS( std::get<0>(value).emplace<MyType1>(MyType1{}), int );
// outer variant is still valid and contains inner
REQUIRE( std::holds_alternative<inner>(value) );
// inner variant is valueless
REQUIRE( std::get<inner>(value).valueless_by_exception() );
CHECK( "{valueless variant}" == ::Catch::Detail::stringify(value) );
}
}
TEST_CASE( "variant<nullptr,int,const char *>", "[toString][variant][approvals]" )
{
using type = std::variant<std::nullptr_t,int,const char *>;
CHECK( "nullptr" == ::Catch::Detail::stringify(type{nullptr}) );
CHECK( "42" == ::Catch::Detail::stringify(type{42}) );
CHECK( "\"Catch me\"" == ::Catch::Detail::stringify(type{"Catch me"}) );
}
#endif // CATCH_INTERNAL_CONFIG_CPP17_VARIANT

View File

@ -0,0 +1,94 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <vector>
#include <array>
// vector
TEST_CASE( "vector<int> -> toString", "[toString][vector]" )
{
std::vector<int> vv;
REQUIRE( ::Catch::Detail::stringify(vv) == "{ }" );
vv.push_back( 42 );
REQUIRE( ::Catch::Detail::stringify(vv) == "{ 42 }" );
vv.push_back( 250 );
REQUIRE( ::Catch::Detail::stringify(vv) == "{ 42, 250 }" );
}
TEST_CASE( "vector<string> -> toString", "[toString][vector]" )
{
std::vector<std::string> vv;
REQUIRE( ::Catch::Detail::stringify(vv) == "{ }" );
vv.emplace_back( "hello" );
REQUIRE( ::Catch::Detail::stringify(vv) == "{ \"hello\" }" );
vv.emplace_back( "world" );
REQUIRE( ::Catch::Detail::stringify(vv) == "{ \"hello\", \"world\" }" );
}
namespace {
/* Minimal Allocator */
template<typename T>
struct minimal_allocator {
using value_type = T;
using size_type = std::size_t;
minimal_allocator() = default;
template <typename U>
minimal_allocator(const minimal_allocator<U>&) {}
T *allocate( size_type n ) {
return static_cast<T *>( ::operator new( n * sizeof(T) ) );
}
void deallocate( T *p, size_type /*n*/ ) {
::operator delete( static_cast<void *>(p) );
}
template<typename U>
bool operator==( const minimal_allocator<U>& ) const { return true; }
template<typename U>
bool operator!=( const minimal_allocator<U>& ) const { return false; }
};
}
TEST_CASE( "vector<int,allocator> -> toString", "[toString][vector,allocator]" ) {
std::vector<int,minimal_allocator<int> > vv;
REQUIRE( ::Catch::Detail::stringify(vv) == "{ }" );
vv.push_back( 42 );
REQUIRE( ::Catch::Detail::stringify(vv) == "{ 42 }" );
vv.push_back( 250 );
REQUIRE( ::Catch::Detail::stringify(vv) == "{ 42, 250 }" );
}
TEST_CASE( "vec<vec<string,alloc>> -> toString", "[toString][vector,allocator]" ) {
using inner = std::vector<std::string, minimal_allocator<std::string>>;
using vector = std::vector<inner>;
vector v;
REQUIRE( ::Catch::Detail::stringify(v) == "{ }" );
v.push_back( inner { "hello" } );
v.push_back( inner { "world" } );
REQUIRE( ::Catch::Detail::stringify(v) == "{ { \"hello\" }, { \"world\" } }" );
}
// Based on PR by mat-so: https://github.com/catchorg/Catch2/pull/606/files#diff-43562f40f8c6dcfe2c54557316e0f852
TEST_CASE( "vector<bool> -> toString", "[toString][containers][vector]" ) {
std::vector<bool> bools;
REQUIRE( ::Catch::Detail::stringify(bools) == "{ }");
bools.push_back(true);
REQUIRE( ::Catch::Detail::stringify(bools) == "{ true }");
bools.push_back(false);
REQUIRE( ::Catch::Detail::stringify(bools) == "{ true, false }");
}
TEST_CASE( "array<int, N> -> toString", "[toString][containers][array]" ) {
std::array<int, 0> empty;
REQUIRE( Catch::Detail::stringify( empty ) == "{ }" );
std::array<int, 1> oneValue = {{ 42 }};
REQUIRE( Catch::Detail::stringify( oneValue ) == "{ 42 }" );
std::array<int, 2> twoValues = {{ 42, 250 }};
REQUIRE( Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" );
}

View File

@ -0,0 +1,186 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#if defined(__GNUC__)
// This has to be left enabled until end of the TU, because the GCC
// frontend reports operator<<(std::ostream& os, const has_maker_and_operator&)
// as unused anyway
# pragma GCC diagnostic ignored "-Wunused-function"
#endif
namespace {
struct has_operator { };
struct has_maker {};
struct has_maker_and_operator {};
struct has_neither {};
struct has_template_operator {};
std::ostream& operator<<(std::ostream& os, const has_operator&) {
os << "operator<<( has_operator )";
return os;
}
std::ostream& operator<<(std::ostream& os, const has_maker_and_operator&) {
os << "operator<<( has_maker_and_operator )";
return os;
}
template <typename StreamT>
StreamT& operator<<(StreamT& os, const has_template_operator&) {
os << "operator<<( has_template_operator )";
return os;
}
} // end anonymous namespace
namespace Catch {
template<>
struct StringMaker<has_maker> {
static std::string convert( const has_maker& ) {
return "StringMaker<has_maker>";
}
};
template<>
struct StringMaker<has_maker_and_operator> {
static std::string convert( const has_maker_and_operator& ) {
return "StringMaker<has_maker_and_operator>";
}
};
}
// Call the operator
TEST_CASE( "stringify( has_operator )", "[toString]" ) {
has_operator item;
REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" );
}
// Call the stringmaker
TEST_CASE( "stringify( has_maker )", "[toString]" ) {
has_maker item;
REQUIRE( ::Catch::Detail::stringify( item ) == "StringMaker<has_maker>" );
}
// Call the stringmaker
TEST_CASE( "stringify( has_maker_and_operator )", "[toString]" ) {
has_maker_and_operator item;
REQUIRE( ::Catch::Detail::stringify( item ) == "StringMaker<has_maker_and_operator>" );
}
TEST_CASE("stringify( has_neither )", "[toString]") {
has_neither item;
REQUIRE( ::Catch::Detail::stringify(item) == "{?}" );
}
// Call the templated operator
TEST_CASE( "stringify( has_template_operator )", "[toString]" ) {
has_template_operator item;
REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" );
}
// Vectors...
TEST_CASE( "stringify( vectors<has_operator> )", "[toString]" ) {
std::vector<has_operator> v(1);
REQUIRE( ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" );
}
TEST_CASE( "stringify( vectors<has_maker> )", "[toString]" ) {
std::vector<has_maker> v(1);
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" );
}
TEST_CASE( "stringify( vectors<has_maker_and_operator> )", "[toString]" ) {
std::vector<has_maker_and_operator> v(1);
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker_and_operator> }" );
}
namespace {
// Range-based conversion should only be used if other possibilities fail
struct int_iterator {
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = int;
using reference = int&;
using pointer = int*;
int_iterator() = default;
int_iterator(int i) :val(i) {}
value_type operator*() const { return val; }
bool operator==(int_iterator rhs) const { return val == rhs.val; }
bool operator!=(int_iterator rhs) const { return val != rhs.val; }
int_iterator operator++() { ++val; return *this; }
int_iterator operator++(int) {
auto temp(*this);
++val;
return temp;
}
private:
int val = 5;
};
struct streamable_range {
int_iterator begin() const { return int_iterator{ 1 }; }
int_iterator end() const { return {}; }
};
std::ostream& operator<<(std::ostream& os, const streamable_range&) {
os << "op<<(streamable_range)";
return os;
}
struct stringmaker_range {
int_iterator begin() const { return int_iterator{ 1 }; }
int_iterator end() const { return {}; }
};
} // end anonymous namespace
namespace Catch {
template <>
struct StringMaker<stringmaker_range> {
static std::string convert(stringmaker_range const&) {
return "stringmaker(streamable_range)";
}
};
}
namespace {
struct just_range {
int_iterator begin() const { return int_iterator{ 1 }; }
int_iterator end() const { return {}; }
};
struct disabled_range {
int_iterator begin() const { return int_iterator{ 1 }; }
int_iterator end() const { return {}; }
};
} // end anonymous namespace
namespace Catch {
template <>
struct is_range<disabled_range> {
static const bool value = false;
};
}
TEST_CASE("stringify ranges", "[toString]") {
REQUIRE(::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)");
REQUIRE(::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)");
REQUIRE(::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }");
REQUIRE(::Catch::Detail::stringify(disabled_range{}) == "{?}");
}

View File

@ -0,0 +1,380 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#ifdef __clang__
#pragma clang diagnostic ignored "-Wpadded"
#endif
#ifdef _MSC_VER
#pragma warning (disable : 4702) // Disable unreachable code warning for the last test
// that is triggered when compiling as Win32|Release
#endif
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include <catch2/generators/catch_generators_range.hpp>
#include <cstdio>
#include <sstream>
#include <iostream>
struct Opaque
{
int val;
bool operator ==( const Opaque& o ) const
{
return val == o.val;
}
};
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"A failing expression with a non streamable type is still captured",
"[Tricky][failing][.]"
)
{
Opaque o1, o2;
o1.val = 7;
o2.val = 8;
CHECK( &o1 == &o2 );
CHECK( o1 == o2 );
}
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"An expression with side-effects should only be evaluated once",
"[Tricky]"
)
{
int i = 7;
REQUIRE( i++ == 7 );
REQUIRE( i++ == 8 );
}
namespace A {
struct X
{
X() : a(4), b(2), c(7) {}
X(int v) : a(v), b(2), c(7) {}
int a;
int b;
int c;
};
}
namespace B {
struct Y
{
Y() : a(4), b(2), c(7) {}
Y(int v) : a(v), b(2), c(7) {}
int a;
int b;
int c;
};
}
inline bool operator==(const A::X& lhs, const B::Y& rhs)
{
return (lhs.a == rhs.a);
}
inline bool operator==(const B::Y& lhs, const A::X& rhs)
{
return (lhs.a == rhs.a);
}
///////////////////////////////////////////////////////////////////////////////
/* This, currently, does not compile with LLVM
TEST_CASE
(
"Operators at different namespace levels not hijacked by Koenig lookup"
"[Tricky]"
)
{
A::X x;
B::Y y;
REQUIRE( x == y );
}
*/
namespace ObjectWithConversions
{
struct Object
{
operator unsigned int() const {return 0xc0000000;}
};
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"Implicit conversions are supported inside assertion macros",
"[Tricky][approvals]"
)
{
Object o;
REQUIRE(0xc0000000 == o );
}
}
namespace EnumBitFieldTests
{
enum Bits : uint32_t {
bit0 = 0x0001,
bit1 = 0x0002,
bit2 = 0x0004,
bit3 = 0x0008,
bit1and2 = bit1 | bit2,
bit30 = 0x40000000,
bit31 = 0x80000000,
bit30and31 = bit30 | bit31
};
TEST_CASE( "Test enum bit values", "[Tricky]" )
{
REQUIRE( 0xc0000000 == bit30and31 );
}
}
struct Obj
{
Obj():prop(&p){}
int p = 0;
int* prop;
};
TEST_CASE("boolean member", "[Tricky]")
{
Obj obj;
REQUIRE( obj.prop != nullptr );
}
// Tests for a problem submitted by Ralph McArdell
//
// The static bool value should not need to be defined outside the
// struct it is declared in - but when evaluating it in a deduced
// context it appears to require the extra definition.
// The issue was fixed by adding bool overloads to bypass the
// templates that were there to deduce it.
template <bool B>
struct is_true
{
static const bool value = B;
};
TEST_CASE( "(unimplemented) static bools can be evaluated", "[Tricky]" )
{
SECTION("compare to true")
{
REQUIRE( is_true<true>::value == true );
REQUIRE( true == is_true<true>::value );
}
SECTION("compare to false")
{
REQUIRE( is_true<false>::value == false );
REQUIRE( false == is_true<false>::value );
}
SECTION("negation")
{
REQUIRE( !is_true<false>::value );
}
SECTION("double negation")
{
REQUIRE( !!is_true<true>::value );
}
SECTION("direct")
{
REQUIRE( is_true<true>::value );
REQUIRE_FALSE( is_true<false>::value );
}
}
struct Boolable
{
explicit Boolable( bool value ) : m_value( value ) {}
explicit operator bool() const {
return m_value;
}
bool m_value;
};
TEST_CASE( "Objects that evaluated in boolean contexts can be checked", "[Tricky][SafeBool]" )
{
Boolable True( true );
Boolable False( false );
CHECK( True );
CHECK( !False );
CHECK_FALSE( False );
}
TEST_CASE( "Assertions then sections", "[Tricky]" )
{
// This was causing a failure due to the way the console reporter was handling
// the current section
REQUIRE( true );
SECTION( "A section" )
{
REQUIRE( true );
SECTION( "Another section" )
{
REQUIRE( true );
}
SECTION( "Another other section" )
{
REQUIRE( true );
}
}
}
struct Awkward
{
operator int() const { return 7; }
};
TEST_CASE( "non streamable - with conv. op", "[Tricky]" )
{
Awkward awkward;
std::string s = ::Catch::Detail::stringify( awkward );
REQUIRE( s == "7" );
}
inline void foo() {}
using fooptr_t = void (*)();
TEST_CASE( "Comparing function pointers", "[Tricky][function pointer]" )
{
// This was giving a warning in VS2010
// #179
fooptr_t a = foo;
REQUIRE( a );
REQUIRE( a == &foo );
}
struct S
{
void f() {}
};
TEST_CASE( "Comparing member function pointers", "[Tricky][member function pointer][approvals]" )
{
using MF = void (S::*)();
MF m = &S::f;
CHECK( m == &S::f );
}
class ClassName {};
TEST_CASE( "pointer to class", "[Tricky]" )
{
ClassName *p = 0;
REQUIRE( p == 0 );
}
#include <memory>
TEST_CASE( "null_ptr", "[Tricky]" )
{
std::unique_ptr<int> ptr;
REQUIRE(ptr.get() == nullptr);
}
TEST_CASE( "X/level/0/a", "[Tricky]" ) { SUCCEED(""); }
TEST_CASE( "X/level/0/b", "[Tricky][fizz]" ){ SUCCEED(""); }
TEST_CASE( "X/level/1/a", "[Tricky]" ) { SUCCEED(""); }
TEST_CASE( "X/level/1/b", "[Tricky]" ) { SUCCEED(""); }
TEST_CASE( "has printf" ) {
// This can cause problems as, currently, stdout itself is not redirected - only the cout (and cerr) buffer
printf( "loose text artifact\n" );
}
namespace {
struct constructor_throws {
[[noreturn]] constructor_throws() {
throw 1;
}
};
}
TEST_CASE("Commas in various macros are allowed") {
REQUIRE_THROWS( std::vector<constructor_throws>{constructor_throws{}, constructor_throws{}} );
CHECK_THROWS( std::vector<constructor_throws>{constructor_throws{}, constructor_throws{}} );
REQUIRE_NOTHROW( std::vector<int>{1, 2, 3} == std::vector<int>{1, 2, 3} );
CHECK_NOTHROW( std::vector<int>{1, 2, 3} == std::vector<int>{1, 2, 3} );
REQUIRE(std::vector<int>{1, 2} == std::vector<int>{1, 2});
CHECK( std::vector<int>{1, 2} == std::vector<int>{1, 2} );
REQUIRE_FALSE(std::vector<int>{1, 2} == std::vector<int>{1, 2, 3});
CHECK_FALSE( std::vector<int>{1, 2} == std::vector<int>{1, 2, 3} );
CHECK_NOFAIL( std::vector<int>{1, 2} == std::vector<int>{1, 2} );
CHECKED_IF( std::vector<int>{1, 2} == std::vector<int>{1, 2} ) {
REQUIRE(true);
} CHECKED_ELSE( std::vector<int>{1, 2} == std::vector<int>{1, 2} ) {
CHECK(true);
}
}
TEST_CASE( "non-copyable objects", "[.][failing]" ) {
// Thanks to Agustin Bergé (@k-ballo on the cpplang Slack) for raising this
std::type_info const& ti = typeid(int);
CHECK( ti == typeid(int) );
}
TEST_CASE("#1514: stderr/stdout is not captured in tests aborted by an exception", "[output-capture][regression][.]") {
std::cout << "This would not be caught previously\n" << std::flush;
std::clog << "Nor would this\n" << std::flush;
// FAIL aborts the test by throwing a Catch exception
FAIL("1514");
}
TEST_CASE( "#2025: -c shouldn't cause infinite loop", "[sections][generators][regression][.approvals]" ) {
SECTION( "Check cursor from buffer offset" ) {
auto bufPos = GENERATE_REF( range( 0, 44 ) );
WHEN( "Buffer position is " << bufPos ) { REQUIRE( 1 == 1 ); }
}
}
TEST_CASE("#2025: original repro", "[sections][generators][regression][.approvals]") {
auto fov = GENERATE(true, false);
DYNAMIC_SECTION("fov_" << fov) {
std::cout << "inside with fov: " << fov << '\n';
}
}
TEST_CASE("#2025: same-level sections", "[sections][generators][regression][.approvals]") {
SECTION("A") {
SUCCEED();
}
auto i = GENERATE(1, 2, 3);
SECTION("B") {
REQUIRE(i < 4);
}
}

View File

@ -0,0 +1,29 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
TEST_CASE()
{
SUCCEED( "anonymous test case" );
}
TEST_CASE( "Test case with one argument" )
{
SUCCEED( "no assertions" );
}
TEST_CASE( "Variadic macros", "[variadic][sections]" )
{
SECTION( "Section with one argument" )
{
SUCCEED( "no assertions" );
}
}