catch2/tests/SelfTest/UsageTests/Tricky.tests.cpp

386 lines
8.6 KiB
C++
Raw Normal View History

// 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
2010-11-10 00:24:00 +01:00
2012-08-16 19:47:41 +02:00
#ifdef __clang__
#pragma clang diagnostic ignored "-Wpadded"
2012-08-16 19:47:41 +02:00
#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>
2010-11-10 00:24:00 +01:00
2020-02-04 18:41:11 +01:00
#include <cstdio>
#include <sstream>
#include <iostream>
struct Opaque
{
int val;
2011-03-10 15:09:32 +01:00
bool operator ==( const Opaque& o ) const
{
2010-11-16 20:48:05 +01:00
return val == o.val;
}
};
2011-03-10 15:09:32 +01:00
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"A failing expression with a non streamable type is still captured",
"[Tricky][failing][.]"
2011-03-10 15:09:32 +01:00
)
{
Opaque o1, o2;
o1.val = 7;
o2.val = 8;
CHECK( &o1 == &o2 );
CHECK( o1 == o2 );
2010-11-29 20:48:37 +01:00
}
2011-03-10 15:09:32 +01:00
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"An expression with side-effects should only be evaluated once",
"[Tricky]"
2011-03-10 15:09:32 +01:00
)
{
int i = 7;
2011-03-10 15:09:32 +01:00
REQUIRE( i++ == 7 );
REQUIRE( i++ == 8 );
2011-03-10 15:09:32 +01:00
}
2011-04-06 23:26:16 +02:00
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)
2011-04-06 23:26:16 +02:00
{
return (lhs.a == rhs.a);
}
inline bool operator==(const B::Y& lhs, const A::X& rhs)
2011-04-06 23:26:16 +02:00
{
return (lhs.a == rhs.a);
}
2011-04-06 23:26:16 +02:00
///////////////////////////////////////////////////////////////////////////////
/* This, currently, does not compile with LLVM
2011-04-06 23:26:16 +02:00
TEST_CASE
(
"Operators at different namespace levels not hijacked by Koenig lookup"
"[Tricky]"
2011-04-06 23:26:16 +02:00
)
{
A::X x;
B::Y y;
REQUIRE( x == y );
}
*/
2011-04-06 23:26:16 +02:00
namespace ObjectWithConversions
{
struct Object
2011-04-06 23:26:16 +02:00
{
operator unsigned int() const {return 0xc0000000;}
2011-04-06 23:26:16 +02:00
};
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"Implicit conversions are supported inside assertion macros",
2017-09-01 20:28:49 +02:00
"[Tricky][approvals]"
2011-04-06 23:26:16 +02:00
)
{
Object o;
REQUIRE(0xc0000000 == o );
2011-04-06 23:26:16 +02:00
}
}
namespace EnumBitFieldTests
{
2017-09-01 20:28:49 +02:00
enum Bits : uint32_t {
bit0 = 0x0001,
bit1 = 0x0002,
bit2 = 0x0004,
bit3 = 0x0008,
bit1and2 = bit1 | bit2,
bit30 = 0x40000000,
bit31 = 0x80000000,
bit30and31 = bit30 | bit31
};
2011-04-06 23:26:16 +02:00
TEST_CASE( "Test enum bit values", "[Tricky]" )
2011-04-06 23:26:16 +02:00
{
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 );
}
}
2012-10-28 21:57:21 +01:00
struct Boolable
{
explicit Boolable( bool value ) : m_value( value ) {}
2017-04-25 16:46:48 +02:00
explicit operator bool() const {
return m_value;
2012-10-28 21:57:21 +01:00
}
bool m_value;
};
TEST_CASE( "Objects that evaluated in boolean contexts can be checked", "[Tricky][SafeBool]" )
2012-10-28 21:57:21 +01:00
{
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 );
}
}
}
2013-04-12 11:43:06 +02:00
struct Awkward
2013-04-12 11:43:06 +02:00
{
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" );
}
2013-07-01 19:45:19 +02:00
inline void foo() {}
using fooptr_t = void (*)();
2013-07-01 19:45:19 +02:00
TEST_CASE( "Comparing function pointers", "[Tricky][function pointer]" )
2013-07-01 19:45:19 +02:00
{
// This was giving a warning in VS2010
// #179
fooptr_t a = foo;
REQUIRE( a );
REQUIRE( a == &foo );
}
struct S
{
void f() {}
};
2017-09-01 20:28:49 +02:00
TEST_CASE( "Comparing member function pointers", "[Tricky][member function pointer][approvals]" )
{
using MF = void (S::*)();
MF m = &S::f;
CHECK( m == &S::f );
}
2013-07-01 19:45:19 +02:00
class ClassName {};
TEST_CASE( "pointer to class", "[Tricky]" )
2013-07-01 19:45:19 +02:00
{
ClassName *p = 0;
2013-07-01 20:00:55 +02:00
REQUIRE( p == 0 );
2013-07-01 19:45:19 +02:00
}
#include <memory>
2017-07-13 09:52:51 +02:00
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(""); }
2024-09-15 20:46:24 +02:00
#include <chrono>
#include <thread>
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" );
2024-09-15 20:46:24 +02:00
fflush( stdout );
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
}
2017-04-26 17:12:48 +02:00
namespace {
struct constructor_throws {
[[noreturn]] constructor_throws() {
throw 1;
}
};
}
2017-04-26 17:12:48 +02:00
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);
}
2017-04-26 17:12:48 +02:00
}
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);
}
}