From 4ecb2e112e0565451c14fc42d63f438cb9ecb7dd Mon Sep 17 00:00:00 2001 From: Martin Moene Date: Fri, 13 Oct 2017 09:43:50 +0200 Subject: [PATCH] Add examples folder with initial examples --- examples/000-CatchMain.cpp | 15 + examples/010-TestCase.cpp | 36 ++ examples/020-TestCase-1.cpp | 35 ++ examples/020-TestCase-2.cpp | 33 ++ examples/030-Asn-Require-Check.cpp | 74 ++++ examples/100-Fix-Section.cpp | 69 ++++ examples/110-Fix-ClassFixture.cpp | 63 ++++ examples/120-Bdd-ScenarioGivenWhenThen.cpp | 73 ++++ examples/210-Evt-EventListeners.cpp | 416 +++++++++++++++++++++ 9 files changed, 814 insertions(+) create mode 100644 examples/000-CatchMain.cpp create mode 100644 examples/010-TestCase.cpp create mode 100644 examples/020-TestCase-1.cpp create mode 100644 examples/020-TestCase-2.cpp create mode 100644 examples/030-Asn-Require-Check.cpp create mode 100644 examples/100-Fix-Section.cpp create mode 100644 examples/110-Fix-ClassFixture.cpp create mode 100644 examples/120-Bdd-ScenarioGivenWhenThen.cpp create mode 100644 examples/210-Evt-EventListeners.cpp diff --git a/examples/000-CatchMain.cpp b/examples/000-CatchMain.cpp new file mode 100644 index 00000000..c8bf91e4 --- /dev/null +++ b/examples/000-CatchMain.cpp @@ -0,0 +1,15 @@ +// 000-CatchMain.cpp + +// In a Catch project with multiple files, dedicate one file to compile the +// source code of Catch itself and reuse the resulting object file for linking. + +// Let Catch provide main(): +#define CATCH_CONFIG_MAIN + +#include "catch.hpp" + +// That's it + +// Compile implementation of Catch for use with files that do contain tests: +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -c 000-CatchMain.cpp +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% -c 000-CatchMain.cpp diff --git a/examples/010-TestCase.cpp b/examples/010-TestCase.cpp new file mode 100644 index 00000000..16a212a3 --- /dev/null +++ b/examples/010-TestCase.cpp @@ -0,0 +1,36 @@ +// 010-TestCase.cpp + +// Let Catch provide main(): +#define CATCH_CONFIG_MAIN + +#include "catch.hpp" + +int Factorial( int number ) { + return number <= 1 ? number : Factorial( number - 1 ) * number; // fail +// return number <= 1 ? 1 : Factorial( number - 1 ) * number; // pass +} + +TEST_CASE( "Factorial of 0 is 1 (fail)", "[single-file]" ) { + REQUIRE( Factorial(0) == 1 ); +} + +TEST_CASE( "Factorials of 1 and higher are computed (pass)", "[single-file]" ) { + REQUIRE( Factorial(1) == 1 ); + REQUIRE( Factorial(2) == 2 ); + REQUIRE( Factorial(3) == 6 ); + REQUIRE( Factorial(10) == 3628800 ); +} + +// Compile & run: +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 010-TestCase 010-TestCase.cpp && 010-TestCase --success +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 010-TestCase.cpp && 010-TestCase --success + +// Expected compact output (all assertions): +// +// prompt> 010-TestCase --reporter compact --success +// 010-TestCase.cpp:14: failed: Factorial(0) == 1 for: 0 == 1 +// 010-TestCase.cpp:18: passed: Factorial(1) == 1 for: 1 == 1 +// 010-TestCase.cpp:19: passed: Factorial(2) == 2 for: 2 == 2 +// 010-TestCase.cpp:20: passed: Factorial(3) == 6 for: 6 == 6 +// 010-TestCase.cpp:21: passed: Factorial(10) == 3628800 for: 3628800 (0x375f00) == 3628800 (0x375f00) +// Failed 1 test case, failed 1 assertion. diff --git a/examples/020-TestCase-1.cpp b/examples/020-TestCase-1.cpp new file mode 100644 index 00000000..0d10276c --- /dev/null +++ b/examples/020-TestCase-1.cpp @@ -0,0 +1,35 @@ +// 020-TestCase-1.cpp + +// In a Catch project with multiple files, dedicate one file to compile the +// source code of Catch itself and reuse the resulting object file for linking. + +// Let Catch provide main(): +#define CATCH_CONFIG_MAIN + +#include "catch.hpp" + +TEST_CASE( "1: All test cases reside in other .cpp files (empty)", "[multi-file:1]" ) { +} + +// ^^^ +// Normally no TEST_CASEs in this file. +// Here just to show there are two source files via option --list-tests. + +// Compile & run: +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -c 020-TestCase-1.cpp +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 020-TestCase TestCase-1.o 020-TestCase-2.cpp && 020-TestCase --success +// +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% -c 020-TestCase-1.cpp +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% -Fe020-TestCase.exe 020-TestCase-1.obj 020-TestCase-2.cpp && 020-TestCase --success + +// Expected test case listing: +// +// prompt> 020-TestCase --list-tests * +// Matching test cases: +// 1: All test cases reside in other .cpp files (empty) +// [multi-file:1] +// 2: Factorial of 0 is computed (fail) +// [multi-file:2] +// 2: Factorials of 1 and higher are computed (pass) +// [multi-file:2] +// 3 matching test cases diff --git a/examples/020-TestCase-2.cpp b/examples/020-TestCase-2.cpp new file mode 100644 index 00000000..2cca3621 --- /dev/null +++ b/examples/020-TestCase-2.cpp @@ -0,0 +1,33 @@ +// 020-TestCase-2.cpp + +// main() provided by Catch in file 020-TestCase-1.cpp. + +#include "catch.hpp" + +int Factorial( int number ) { + return number <= 1 ? number : Factorial( number - 1 ) * number; // fail +// return number <= 1 ? 1 : Factorial( number - 1 ) * number; // pass +} + +TEST_CASE( "2: Factorial of 0 is 1 (fail)", "[multi-file:2]" ) { + REQUIRE( Factorial(0) == 1 ); +} + +TEST_CASE( "2: Factorials of 1 and higher are computed (pass)", "[multi-file:2]" ) { + REQUIRE( Factorial(1) == 1 ); + REQUIRE( Factorial(2) == 2 ); + REQUIRE( Factorial(3) == 6 ); + REQUIRE( Factorial(10) == 3628800 ); +} + +// Compile: see 020-TestCase-1.cpp + +// Expected compact output (all assertions): +// +// prompt> 020-TestCase --reporter compact --success +// 020-TestCase-2.cpp:13: failed: Factorial(0) == 1 for: 0 == 1 +// 020-TestCase-2.cpp:17: passed: Factorial(1) == 1 for: 1 == 1 +// 020-TestCase-2.cpp:18: passed: Factorial(2) == 2 for: 2 == 2 +// 020-TestCase-2.cpp:19: passed: Factorial(3) == 6 for: 6 == 6 +// 020-TestCase-2.cpp:20: passed: Factorial(10) == 3628800 for: 3628800 (0x375f00) == 3628800 (0x375f00) +// Failed 1 test case, failed 1 assertion. diff --git a/examples/030-Asn-Require-Check.cpp b/examples/030-Asn-Require-Check.cpp new file mode 100644 index 00000000..35f2ff79 --- /dev/null +++ b/examples/030-Asn-Require-Check.cpp @@ -0,0 +1,74 @@ +// 030-Asn-Require-Check.cpp + +// Catch has two natural expression assertion macro's: +// - REQUIRE() stops at first failure. +// - CHECK() continues after failure. + +// There are two variants to support decomposing negated expressions: +// - REQUIRE_FALSE() stops at first failure. +// - CHECK_FALSE() continues after failure. + +// main() provided in 000-CatchMain.cpp + +#include "catch.hpp" + +std::string one() { + return "1"; +} + +TEST_CASE( "Assert that something is true (pass)", "[require]" ) { + REQUIRE( one() == "1" ); +} + +TEST_CASE( "Assert that something is true (fail)", "[require]" ) { + REQUIRE( one() == "x" ); +} + +TEST_CASE( "Assert that something is true (stop at first failure)", "[require]" ) { + WARN( "REQUIRE stops at first failure:" ); + + REQUIRE( one() == "x" ); + REQUIRE( one() == "1" ); +} + +TEST_CASE( "Assert that something is true (continue after failure)", "[check]" ) { + WARN( "CHECK continues after failure:" ); + + CHECK( one() == "x" ); + REQUIRE( one() == "1" ); +} + +TEST_CASE( "Assert that something is false (stops at first failure)", "[require-false]" ) { + WARN( "REQUIRE_FALSE stops at first failure:" ); + + REQUIRE_FALSE( one() == "1" ); + REQUIRE_FALSE( one() != "1" ); +} + +TEST_CASE( "Assert that something is false (continue after failure)", "[check-false]" ) { + WARN( "CHECK_FALSE continues after failure:" ); + + CHECK_FALSE( one() == "1" ); + REQUIRE_FALSE( one() != "1" ); +} + +// Compile & run: +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 030-Asn-Require-Check 030-Asn-Require-Check.cpp 000-CatchMain.o && 030-Asn-Require-Check --success +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 030-Asn-Require-Check.cpp 000-CatchMain.obj && 030-Asn-Require-Check --success + +// Expected compact output (all assertions): +// +// prompt> 030-Asn-Require-Check.exe --reporter compact --success +// 030-Asn-Require-Check.cpp:20: passed: one() == "1" for: "1" == "1" +// 030-Asn-Require-Check.cpp:24: failed: one() == "x" for: "1" == "x" +// 030-Asn-Require-Check.cpp:28: warning: 'REQUIRE stops at first failure:' +// 030-Asn-Require-Check.cpp:30: failed: one() == "x" for: "1" == "x" +// 030-Asn-Require-Check.cpp:35: warning: 'CHECK continues after failure:' +// 030-Asn-Require-Check.cpp:37: failed: one() == "x" for: "1" == "x" +// 030-Asn-Require-Check.cpp:38: passed: one() == "1" for: "1" == "1" +// 030-Asn-Require-Check.cpp:42: warning: 'REQUIRE_FALSE stops at first failure:' +// 030-Asn-Require-Check.cpp:44: failed: !(one() == "1") for: !("1" == "1") +// 030-Asn-Require-Check.cpp:49: warning: 'CHECK_FALSE continues after failure:' +// 030-Asn-Require-Check.cpp:51: failed: !(one() == "1") for: !("1" == "1") +// 030-Asn-Require-Check.cpp:52: passed: !(one() != "1") for: !("1" != "1") +// Failed 5 test cases, failed 5 assertions. diff --git a/examples/100-Fix-Section.cpp b/examples/100-Fix-Section.cpp new file mode 100644 index 00000000..8cb94bff --- /dev/null +++ b/examples/100-Fix-Section.cpp @@ -0,0 +1,69 @@ +// 100-Fix-Section.cpp + +// Catch has two ways to express fixtures: +// - Sections (this file) +// - Traditional class-based fixtures + +// main() provided in 000-CatchMain.cpp + +#include "catch.hpp" + +TEST_CASE( "vectors can be sized and resized", "[vector]" ) { + + // For each section, vector v is anew: + + std::vector 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( "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 ); + } +} + +// Compile & run: +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 100-Fix-Section 100-Fix-Section.cpp 000-CatchMain.o && 100-Fix-Section --success +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 100-Fix-Section.cpp 000-CatchMain.obj && 100-Fix-Section --success + +// Expected compact output (all assertions): +// +// prompt> 100-Fix-Section.exe --reporter compact --success +// 100-Fix-Section.cpp:17: passed: v.size() == 5 for: 5 == 5 +// 100-Fix-Section.cpp:18: passed: v.capacity() >= 5 for: 5 >= 5 +// 100-Fix-Section.cpp:23: passed: v.size() == 10 for: 10 == 10 +// 100-Fix-Section.cpp:24: passed: v.capacity() >= 10 for: 10 >= 10 +// 100-Fix-Section.cpp:17: passed: v.size() == 5 for: 5 == 5 +// 100-Fix-Section.cpp:18: passed: v.capacity() >= 5 for: 5 >= 5 +// 100-Fix-Section.cpp:29: passed: v.size() == 0 for: 0 == 0 +// 100-Fix-Section.cpp:30: passed: v.capacity() >= 5 for: 5 >= 5 +// 100-Fix-Section.cpp:17: passed: v.size() == 5 for: 5 == 5 +// 100-Fix-Section.cpp:18: passed: v.capacity() >= 5 for: 5 >= 5 +// 100-Fix-Section.cpp:35: passed: v.size() == 5 for: 5 == 5 +// 100-Fix-Section.cpp:36: passed: v.capacity() >= 10 for: 10 >= 10 +// 100-Fix-Section.cpp:17: passed: v.size() == 5 for: 5 == 5 +// 100-Fix-Section.cpp:18: passed: v.capacity() >= 5 for: 5 >= 5 +// 100-Fix-Section.cpp:41: passed: v.size() == 5 for: 5 == 5 +// 100-Fix-Section.cpp:42: passed: v.capacity() >= 5 for: 5 >= 5 +// Passed 1 test case with 16 assertions. diff --git a/examples/110-Fix-ClassFixture.cpp b/examples/110-Fix-ClassFixture.cpp new file mode 100644 index 00000000..06c2cf32 --- /dev/null +++ b/examples/110-Fix-ClassFixture.cpp @@ -0,0 +1,63 @@ +// 110-Fix-ClassFixture.cpp + +// Catch has two ways to express fixtures: +// - Sections +// - Traditional class-based fixtures (this file) + +// main() provided in 000-CatchMain.cpp + +#include "catch.hpp" + +class DBConnection +{ +public: + static DBConnection createConnection( std::string const & /*dbName*/ ) { + return DBConnection(); + } + + bool executeSQL( std::string const & /*query*/, int const /*id*/, std::string const & arg ) { + if ( arg.length() == 0 ) { + throw std::logic_error("empty SQL query argument"); + } + return true; // ok + } +}; + +class UniqueTestsFixture +{ +protected: + UniqueTestsFixture() + : conn( DBConnection::createConnection( "myDB" ) ) + {} + + int getID() { + return ++uniqueID; + } + +protected: + DBConnection conn; + +private: + static int uniqueID; +}; + +int UniqueTestsFixture::uniqueID = 0; + +TEST_CASE_METHOD( UniqueTestsFixture, "Create Employee/No Name", "[create]" ) { + REQUIRE_THROWS( conn.executeSQL( "INSERT INTO employee (id, name) VALUES (?, ?)", getID(), "") ); +} + +TEST_CASE_METHOD( UniqueTestsFixture, "Create Employee/Normal", "[create]" ) { + REQUIRE( conn.executeSQL( "INSERT INTO employee (id, name) VALUES (?, ?)", getID(), "Joe Bloggs" ) ); +} + +// Compile & run: +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 110-Fix-ClassFixture 110-Fix-ClassFixture.cpp 000-CatchMain.o && 110-Fix-ClassFixture --success +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 110-Fix-ClassFixture.cpp 000-CatchMain.obj && 110-Fix-ClassFixture --success + +// Expected compact output (all assertions): +// +// prompt> 110-Fix-ClassFixture.exe --reporter compact --success +// 110-Fix-ClassFixture.cpp:47: passed: conn.executeSQL( "INSERT INTO employee (id, name) VALUES (?, ?)", getID(), "") +// 110-Fix-ClassFixture.cpp:51: passed: conn.executeSQL( "INSERT INTO employee (id, name) VALUES (?, ?)", getID(), "Joe Bloggs" ) for: true +// Passed both 2 test cases with 2 assertions. diff --git a/examples/120-Bdd-ScenarioGivenWhenThen.cpp b/examples/120-Bdd-ScenarioGivenWhenThen.cpp new file mode 100644 index 00000000..c45f1f26 --- /dev/null +++ b/examples/120-Bdd-ScenarioGivenWhenThen.cpp @@ -0,0 +1,73 @@ +// 120-Bdd-ScenarioGivenWhenThen.cpp + +// main() provided in 000-CatchMain.cpp + +#include "catch.hpp" + +SCENARIO( "vectors can be sized and resized", "[vector]" ) { + + GIVEN( "A vector with some items" ) { + std::vector v( 5 ); + + REQUIRE( v.size() == 5 ); + REQUIRE( v.capacity() >= 5 ); + + WHEN( "the size is increased" ) { + v.resize( 10 ); + + THEN( "the size and capacity change" ) { + REQUIRE( v.size() == 10 ); + REQUIRE( v.capacity() >= 10 ); + } + } + WHEN( "the size is reduced" ) { + v.resize( 0 ); + + THEN( "the size changes but not capacity" ) { + REQUIRE( v.size() == 0 ); + REQUIRE( v.capacity() >= 5 ); + } + } + WHEN( "more capacity is reserved" ) { + v.reserve( 10 ); + + THEN( "the capacity changes but not the size" ) { + REQUIRE( v.size() == 5 ); + REQUIRE( v.capacity() >= 10 ); + } + } + WHEN( "less capacity is reserved" ) { + v.reserve( 0 ); + + THEN( "neither size nor capacity are changed" ) { + REQUIRE( v.size() == 5 ); + REQUIRE( v.capacity() >= 5 ); + } + } + } +} + +// Compile & run: +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 120-Bdd-ScenarioGivenWhenThen 120-Bdd-ScenarioGivenWhenThen.cpp 000-CatchMain.o && 120-Bdd-ScenarioGivenWhenThen --success +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 120-Bdd-ScenarioGivenWhenThen.cpp 000-CatchMain.obj && 120-Bdd-ScenarioGivenWhenThen --success + +// Expected compact output (all assertions): +// +// prompt> 120-Bdd-ScenarioGivenWhenThen.exe --reporter compact --success +// 120-Bdd-ScenarioGivenWhenThen.cpp:12: passed: v.size() == 5 for: 5 == 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:13: passed: v.capacity() >= 5 for: 5 >= 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:19: passed: v.size() == 10 for: 10 == 10 +// 120-Bdd-ScenarioGivenWhenThen.cpp:20: passed: v.capacity() >= 10 for: 10 >= 10 +// 120-Bdd-ScenarioGivenWhenThen.cpp:12: passed: v.size() == 5 for: 5 == 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:13: passed: v.capacity() >= 5 for: 5 >= 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:27: passed: v.size() == 0 for: 0 == 0 +// 120-Bdd-ScenarioGivenWhenThen.cpp:28: passed: v.capacity() >= 5 for: 5 >= 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:12: passed: v.size() == 5 for: 5 == 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:13: passed: v.capacity() >= 5 for: 5 >= 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:35: passed: v.size() == 5 for: 5 == 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:36: passed: v.capacity() >= 10 for: 10 >= 10 +// 120-Bdd-ScenarioGivenWhenThen.cpp:12: passed: v.size() == 5 for: 5 == 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:13: passed: v.capacity() >= 5 for: 5 >= 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:43: passed: v.size() == 5 for: 5 == 5 +// 120-Bdd-ScenarioGivenWhenThen.cpp:44: passed: v.capacity() >= 5 for: 5 >= 5 +// Passed 1 test case with 16 assertions. diff --git a/examples/210-Evt-EventListeners.cpp b/examples/210-Evt-EventListeners.cpp new file mode 100644 index 00000000..a2103a0b --- /dev/null +++ b/examples/210-Evt-EventListeners.cpp @@ -0,0 +1,416 @@ +// 210-Evt-EventListeners.cpp + +// Contents: +// 1. Printing of listener data +// 2. My listener and registration +// 3. Test cases + +// main() provided in 000-CatchMain.cpp + +// Let Catch provide the required interfaces: +#define CATCH_CONFIG_EXTERNAL_INTERFACES + +#include "catch.hpp" +#include + +// ----------------------------------------------------------------------- +// 1. Printing of listener data: +// + +std::string ws(int const level) { + return std::string( 2 * level, ' ' ); +} + +template< typename T > +std::ostream& operator<<( std::ostream& os, std::vector const& v ) { + os << "{ "; + for ( auto x : v ) + os << x << ", "; + return os << "}"; +} + +// struct SourceLineInfo { +// char const* file; +// std::size_t line; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::SourceLineInfo const& info ) { + os << ws(level ) << title << ":\n" + << ws(level+1) << "- file: " << info.file << "\n" + << ws(level+1) << "- line: " << info.line << "\n"; +} + +//struct MessageInfo { +// std::string macroName; +// std::string message; +// SourceLineInfo lineInfo; +// ResultWas::OfType type; +// unsigned int sequence; +//}; + +void print( std::ostream& os, int const level, Catch::MessageInfo const& info ) { + os << ws(level+1) << "- macroName: '" << info.macroName << "'\n" + << ws(level+1) << "- message '" << info.message << "'\n"; + print( os,level+1 , "- lineInfo", info.lineInfo ); + os << ws(level+1) << "- sequence " << info.sequence << "\n"; +} + +void print( std::ostream& os, int const level, std::string const& title, std::vector const& v ) { + os << ws(level ) << title << ":\n"; + for ( auto x : v ) + { + os << ws(level+1) << "{\n"; + print( os, level+2, x ); + os << ws(level+1) << "}\n"; + } +// os << ws(level+1) << "\n"; +} + +// struct TestRunInfo { +// std::string name; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::TestRunInfo const& info ) { + os << ws(level ) << title << ":\n" + << ws(level+1) << "- name: " << info.name << "\n"; +} + +// struct Counts { +// std::size_t total() const; +// bool allPassed() const; +// bool allOk() const; +// +// std::size_t passed = 0; +// std::size_t failed = 0; +// std::size_t failedButOk = 0; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::Counts const& info ) { + os << ws(level ) << title << ":\n" + << ws(level+1) << "- total(): " << info.total() << "\n" + << ws(level+1) << "- allPassed(): " << info.allPassed() << "\n" + << ws(level+1) << "- allOk(): " << info.allOk() << "\n" + << ws(level+1) << "- passed: " << info.passed << "\n" + << ws(level+1) << "- failed: " << info.failed << "\n" + << ws(level+1) << "- failedButOk: " << info.failedButOk << "\n"; +} + +// struct Totals { +// Counts assertions; +// Counts testCases; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::Totals const& info ) { + os << ws(level) << title << ":\n"; + print( os, level+1, "- assertions", info.assertions ); + print( os, level+1, "- testCases" , info.testCases ); +} + +// struct TestRunStats { +// TestRunInfo runInfo; +// Totals totals; +// bool aborting; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::TestRunStats const& info ) { + os << ws(level) << title << ":\n"; + print( os, level+1 , "- runInfo", info.runInfo ); + print( os, level+1 , "- totals" , info.totals ); + os << ws(level+1) << "- aborting: " << info.aborting << "\n"; +} + +// struct TestCaseInfo { +// enum SpecialProperties{ +// None = 0, +// IsHidden = 1 << 1, +// ShouldFail = 1 << 2, +// MayFail = 1 << 3, +// Throws = 1 << 4, +// NonPortable = 1 << 5, +// Benchmark = 1 << 6 +// }; +// +// bool isHidden() const; +// bool throws() const; +// bool okToFail() const; +// bool expectedToFail() const; +// +// std::string tagsAsString() const; +// +// std::string name; +// std::string className; +// std::string description; +// std::vector tags; +// std::vector lcaseTags; +// SourceLineInfo lineInfo; +// SpecialProperties properties; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::TestCaseInfo const& info ) { + os << ws(level ) << title << ":\n" + << ws(level+1) << "- isHidden(): " << info.isHidden() << "\n" + << ws(level+1) << "- throws(): " << info.throws() << "\n" + << ws(level+1) << "- okToFail(): " << info.okToFail() << "\n" + << ws(level+1) << "- expectedToFail(): " << info.expectedToFail() << "\n" + << ws(level+1) << "- tagsAsString(): '" << info.tagsAsString() << "'\n" + << ws(level+1) << "- name: '" << info.name << "'\n" + << ws(level+1) << "- className: '" << info.className << "'\n" + << ws(level+1) << "- description: '" << info.description << "'\n" + << ws(level+1) << "- tags: " << info.tags << "\n" + << ws(level+1) << "- lcaseTags: " << info.lcaseTags << "\n"; + print( os, level+1 , "- lineInfo", info.lineInfo ); + os << ws(level+1) << "- properties (flags): 0x" << std::hex << info.properties << std::dec << "\n"; +} + +// struct TestCaseStats { +// TestCaseInfo testInfo; +// Totals totals; +// std::string stdOut; +// std::string stdErr; +// bool aborting; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::TestCaseStats const& info ) { + os << ws(level ) << title << ":\n"; + print( os, level+1 , "- testInfo", info.testInfo ); + print( os, level+1 , "- totals" , info.totals ); + os << ws(level+1) << "- stdOut: " << info.stdOut << "\n" + << ws(level+1) << "- stdErr: " << info.stdErr << "\n" + << ws(level+1) << "- aborting: " << info.aborting << "\n"; +} + +// struct SectionInfo { +// std::string name; +// std::string description; +// SourceLineInfo lineInfo; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::SectionInfo const& info ) { + os << ws(level ) << title << ":\n" + << ws(level+1) << "- name: " << info.name << "\n" + << ws(level+1) << "- description: '" << info.description << "'\n"; + print( os, level+1 , "- lineInfo", info.lineInfo ); +} + +// struct SectionStats { +// SectionInfo sectionInfo; +// Counts assertions; +// double durationInSeconds; +// bool missingAssertions; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::SectionStats const& info ) { + os << ws(level ) << title << ":\n"; + print( os, level+1 , "- sectionInfo", info.sectionInfo ); + print( os, level+1 , "- assertions" , info.assertions ); + os << ws(level+1) << "- durationInSeconds: " << info.durationInSeconds << "\n" + << ws(level+1) << "- missingAssertions: " << info.missingAssertions << "\n"; +} + +// struct AssertionInfo +// { +// StringRef macroName; +// SourceLineInfo lineInfo; +// StringRef capturedExpression; +// ResultDisposition::Flags resultDisposition; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionInfo const& info ) { + os << ws(level ) << title << ":\n" + << ws(level+1) << "- macroName: '" << info.macroName << "'\n"; + print( os, level+1 , "- lineInfo" , info.lineInfo ); + os << ws(level+1) << "- capturedExpression: '" << info.capturedExpression << "'\n" + << ws(level+1) << "- resultDisposition (flags): 0x" << std::hex << info.resultDisposition << std::dec << "\n"; +} + +//struct AssertionResultData +//{ +// std::string reconstructExpression() const; +// +// std::string message; +// mutable std::string reconstructedExpression; +// LazyExpression lazyExpression; +// ResultWas::OfType resultType; +//}; + +void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionResultData const& info ) { + os << ws(level ) << title << ":\n" + << ws(level+1) << "- reconstructExpression(): '" << info.reconstructExpression() << "'\n" + << ws(level+1) << "- message: '" << info.message << "'\n" + << ws(level+1) << "- lazyExpression: '" << "(info.lazyExpression)" << "'\n" + << ws(level+1) << "- resultType: '" << info.resultType << "'\n"; +} + +//class AssertionResult { +// bool isOk() const; +// bool succeeded() const; +// ResultWas::OfType getResultType() const; +// bool hasExpression() const; +// bool hasMessage() const; +// std::string getExpression() const; +// std::string getExpressionInMacro() const; +// bool hasExpandedExpression() const; +// std::string getExpandedExpression() const; +// std::string getMessage() const; +// SourceLineInfo getSourceInfo() const; +// std::string getTestMacroName() const; +// +// AssertionInfo m_info; +// AssertionResultData m_resultData; +//}; + +void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionResult const& info ) { + os << ws(level ) << title << ":\n" + << ws(level+1) << "- isOk(): " << info.isOk() << "\n" + << ws(level+1) << "- succeeded(): " << info.succeeded() << "\n" + << ws(level+1) << "- getResultType(): " << info.getResultType() << "\n" + << ws(level+1) << "- hasExpression(): " << info.hasExpression() << "\n" + << ws(level+1) << "- hasMessage(): " << info.hasMessage() << "\n" + << ws(level+1) << "- getExpression(): '" << info.getExpression() << "'\n" + << ws(level+1) << "- getExpressionInMacro(): '" << info.getExpressionInMacro() << "'\n" + << ws(level+1) << "- hasExpandedExpression(): " << info.hasExpandedExpression() << "\n" + << ws(level+1) << "- getExpandedExpression(): " << info.getExpandedExpression() << "'\n" + << ws(level+1) << "- getMessage(): '" << info.getMessage() << "'\n"; + print( os, level+1 , "- getSourceInfo(): ", info.getSourceInfo() ); + os << ws(level+1) << "- getTestMacroName(): '" << info.getTestMacroName() << "'\n"; + +// print( os, level+1 , "- *** m_info (AssertionInfo)", info.m_info ); +// print( os, level+1 , "- *** m_resultData (AssertionResultData)", info.m_resultData ); +} + +// struct AssertionStats { +// AssertionResult assertionResult; +// std::vector infoMessages; +// Totals totals; +// }; + +void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionStats const& info ) { + os << ws(level ) << title << ":\n"; + print( os, level+1 , "- assertionResult", info.assertionResult ); + print( os, level+1 , "- infoMessages", info.infoMessages ); + print( os, level+1 , "- totals", info.totals ); +} + +// ----------------------------------------------------------------------- +// 2. My listener and registration: +// + +const std::string dashed_line = + "--------------------------------------------------------------------------"; + +struct MyListener : Catch::TestEventListenerBase { + + using TestEventListenerBase::TestEventListenerBase; // inherit constructor + + // The whole test run starting + virtual void testRunStarting( Catch::TestRunInfo const& testRunInfo ) override { + std::cout + << std::boolalpha + << "\nEvent: testRunStarting:\n"; + print( std::cout, 1, "- testRunInfo", testRunInfo ); + } + + // The whole test run ending + virtual void testRunEnded( Catch::TestRunStats const& testRunStats ) override { + std::cout + << dashed_line + << "\nEvent: testRunEnded:\n"; + print( std::cout, 1, "- testRunStats", testRunStats ); + } + + // A test is being skipped (because it is "hidden") + virtual void skipTest( Catch::TestCaseInfo const& testInfo ) override { + std::cout + << dashed_line + << "\nEvent: skipTest:\n"; + print( std::cout, 1, "- testInfo", testInfo ); + } + + // Test cases starting + virtual void testCaseStarting( Catch::TestCaseInfo const& testInfo ) override { + std::cout + << dashed_line + << "\nEvent: testCaseStarting:\n"; + print( std::cout, 1, "- testInfo", testInfo ); + } + + // Test cases ending + virtual void testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override { + std::cout << "\nEvent: testCaseEnded:\n"; + print( std::cout, 1, "testCaseStats", testCaseStats ); + } + + // Sections starting + virtual void sectionStarting( Catch::SectionInfo const& sectionInfo ) override { + std::cout << "\nEvent: sectionStarting:\n"; + print( std::cout, 1, "- sectionInfo", sectionInfo ); + } + + // Sections ending + virtual void sectionEnded( Catch::SectionStats const& sectionStats ) override { + std::cout << "\nEvent: sectionEnded:\n"; + print( std::cout, 1, "- sectionStats", sectionStats ); + } + + // Assertions before/ after + virtual void assertionStarting( Catch::AssertionInfo const& assertionInfo ) override { + std::cout << "\nEvent: assertionStarting:\n"; + print( std::cout, 1, "- assertionInfo", assertionInfo ); + } + + virtual bool assertionEnded( Catch::AssertionStats const& assertionStats ) override { + std::cout << "\nEvent: assertionEnded:\n"; + print( std::cout, 1, "- assertionStats", assertionStats ); + return true; + } +}; + +CATCH_REGISTER_LISTENER( MyListener ) + +// ----------------------------------------------------------------------- +// 3. Test cases: +// + +TEST_CASE( "1: Hidden testcase", "[.hidden]" ) { +} + +TEST_CASE( "2: Testcase with sections", "[tag-A][tag-B]" ) { + + int i = 42; + + REQUIRE( i == 42 ); + + SECTION("Section 1") { + INFO("Section 1") + i = 7; + SECTION("Section 1.1") { + INFO("Section 1.1") + REQUIRE( i == 42 ); + } + } + + SECTION("Section 2") { + INFO("Section 2") + REQUIRE( i == 42 ); + } + WARN("At end of test case"); +} + +struct Fixture { + int fortytwo() const { + return 42; + } +}; + +TEST_CASE_METHOD( Fixture, "3: Testcase with class-based fixture", "[tag-C][tag-D]" ) { + REQUIRE( fortytwo() == 42 ); +} + +// Compile & run: +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 210-Evt-EventListeners 210-Evt-EventListeners.cpp 000-CatchMain.o && 210-Evt-EventListeners --success +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 210-Evt-EventListeners.cpp 000-CatchMain.obj && 210-Evt-EventListeners --success + +// Expected compact output (all assertions): +// +// prompt> 210-Evt-EventListeners --reporter compact --success +// result omitted for brevity.