diff --git a/.travis.yml b/.travis.yml index cda2ad27..e63a76a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,163 @@ language: cpp +sudo: false -compiler: - - clang - - gcc +cache: + ccache: true + directories: + - $HOME/.ccache env: - - BUILD_TYPE=Debug - - BUILD_TYPE=Release + global: + - USE_CCACHE=1 + - CCACHE_COMPRESS=1 + - CCACHE_MAXSIZE=200M + - CCACHE_CPP2=1 + + +matrix: + include: + + # 1/ Linux Clang Builds + - os: linux + compiler: clang + addons: &clang35 + apt: + sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test'] + packages: ['clang-3.5'] + env: COMPILER='ccache clang++-3.5' BUILD_TYPE='Release' + + - os: linux + compiler: clang + addons: *clang35 + env: COMPILER='ccache clang++-3.5' BUILD_TYPE='Debug' + + + - os: linux + compiler: clang + addons: &clang36 + apt: + sources: ['llvm-toolchain-precise-3.6', 'ubuntu-toolchain-r-test'] + packages: ['clang-3.6'] + env: COMPILER='ccache clang++-3.6' BUILD_TYPE='Release' + + - os: linux + compiler: clang + addons: *clang36 + env: COMPILER='ccache clang++-3.6' BUILD_TYPE='Debug' + + + - os: linux + compiler: clang + addons: &clang37 + apt: + sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test'] + packages: ['clang-3.7'] + env: COMPILER='ccache clang++-3.7' BUILD_TYPE='Release' + + - os: linux + compiler: clang + addons: *clang37 + env: COMPILER='ccache clang++-3.7' BUILD_TYPE='Debug' + + + - os: linux + compiler: clang + addons: &clang38 + apt: + sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test'] + packages: ['clang-3.8'] + env: COMPILER='ccache clang++-3.8' BUILD_TYPE='Release' + + - os: linux + compiler: clang + addons: *clang38 + env: COMPILER='ccache clang++-3.8' BUILD_TYPE='Debug' + + + # 2/ Linux GCC Builds + - os: linux + compiler: gcc + addons: &gcc48 + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-4.8'] + env: COMPILER='ccache g++-4.8' BUILD_TYPE='Release' + + - os: linux + compiler: gcc + addons: *gcc48 + env: COMPILER='ccache g++-4.8' BUILD_TYPE='Debug' + + + - os: linux + compiler: gcc + addons: &gcc49 + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-4.9'] + env: COMPILER='ccache g++-4.9' BUILD_TYPE='Release' + + - os: linux + compiler: gcc + addons: *gcc49 + env: COMPILER='ccache g++-4.9' BUILD_TYPE='Debug' + + + - os: linux + compiler: gcc + addons: &gcc5 + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-5'] + env: COMPILER='ccache g++-5' BUILD_TYPE='Release' + + - os: linux + compiler: gcc + addons: *gcc5 + env: COMPILER='ccache g++-5' BUILD_TYPE='Debug' + + + # 3/ OSX Clang Builds + - os: osx + osx_image: xcode6.4 + compiler: clang + env: COMPILER='ccache clang++' BUILD_TYPE='Debug' + + - os: osx + osx_image: xcode6.4 + compiler: clang + env: COMPILER='ccache clang++' BUILD_TYPE='Release' + + + - os: osx + osx_image: xcode7 + compiler: clang + env: COMPILER='ccache clang++' BUILD_TYPE='Debug' + + - os: osx + osx_image: xcode7 + compiler: clang + env: COMPILER='ccache clang++' BUILD_TYPE='Release' + install: - - cmake -Hprojects/CMake -BBuild -DCMAKE_BUILD_TYPE=$BUILD_TYPE + - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" + - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} + - | + if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then + CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz" + mkdir cmake && travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake + export PATH=${DEPS_DIR}/cmake/bin:${PATH} + elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + brew install cmake ccache + fi + +before_script: + - export CXX=${COMPILER} + - cd ${TRAVIS_BUILD_DIR} + - cmake -Hprojects/CMake -BBuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} - cd Build - - make - - cd .. script: - - cd Build - - ctest -V + - make -j 2 + - ctest -V -j 2 diff --git a/README.md b/README.md index fade0d0a..d7669177 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![catch logo](catch-logo-small.png) -*v1.2.1* +*v1.3.0* Build status (on Travis CI) [![Build Status](https://travis-ci.org/philsquared/Catch.png)](https://travis-ci.org/philsquared/Catch) diff --git a/docs/configuration.md b/docs/configuration.md index d1788c34..33052190 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -58,6 +58,9 @@ This can be useful on certain platforms that do not provide ```std::cout``` and CATCH_CONFIG_CPP11_IS_ENUM // std::is_enum is supported? CATCH_CONFIG_CPP11_TUPLE // std::tuple is supported CATCH_CONFIG_VARIADIC_MACROS // Usually pre-C++11 compiler extensions are sufficient + CATCH_CONFIG_CPP11_LONG_LONG // generates overloads for the long long type + CATCH_CONFIG_CPP11_OVERRIDE // CATCH_OVERRIDE expands to override (for virtual function implementations) + CATCH_CONFIG_CPP11_UNIQUE_PTR // Use std::unique_ptr instead of std::auto_ptr Catch has some basic compiler detection that will attempt to select the appropriate mix of these macros. However being incomplete - and often without access to the respective compilers - this detection tends to be conservative. So overriding control is given to the user. If a compiler supports a feature (and Catch does not already detect it) then one or more of these may be defined to enable it (or suppress it, in some cases). If you do do this please raise an issue, specifying your compiler version (ideally with an idea of how to detect it) and stating that it has such support. diff --git a/docs/test-cases-and-sections.md b/docs/test-cases-and-sections.md index 28426d78..86644f00 100644 --- a/docs/test-cases-and-sections.md +++ b/docs/test-cases-and-sections.md @@ -28,10 +28,36 @@ The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects For more detail on command line selection see [the command line docs](command-line.md#specifying-which-tests-to-run) -A special tag name, ```[hide]``` causes test cases to be skipped from the default list (ie when no test cases have been explicitly selected through tag expressions or name wildcards). ```[.]``` is an alias for ```[hide]```. - Tag names are not case sensitive. +### Special Tags + +All tag names beginning with non-alphanumeric characters are reserved by Catch. Catch defines a number of "special" tags, which have meaning to the test runner itself. These special tags all begin with a symbol character. Following is a list of currently defined special tags and their meanings. + +* `[!hide]` or `[.]` (or, for legacy reasons, `[hide]`) - causes test cases to be skipped from the default list (ie when no test cases have been explicitly selected through tag expressions or name wildcards). The hide tag is often combined with another, user, tag (for example `[.][integration]` - so all integration tests are excluded from the default run but can be run by passing `[integration]` on the command line). As a short-cut you can combine these by simply prefixing your user tag with a `.` - e.g. `[.integration]`. Because the hide tag has evolved to have several forms, all forms are added as tags if you use one of them. + +* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be exluded when running with `-e` or `--nothrow`. + +* `[!shouldfail]` - reverse the failing logic of the test: if the test is successful if it fails, and vice-versa. + +* `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in the your tests. + +* `[#]` - running with `-#` or `--filenames-as-tags` causes Catch to add the filename, prefixed with `#` (and with any extension stripped) as a tag. e.g. tests in testfile.cpp would all be tagged `[#testfile]`. + +* `[@]` - tag aliases all begin with `@` (see below). + +## Tag aliases + +Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. this can be done, in code, using the following form: + + CATCH_REGISTER_TAG_ALIAS( , ) + +Aliases must begining with the `@` character. An example of a tag alias is: + + CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" ) + +Now when `[@nhf]` is used on the command line this matches all tests that are tagged `[failing]`, but which are not also hidden. + ## BDD-style test cases In addition to Catch's take on the classic style of test cases, Catch supports an alternative syntax that allow tests to be written as "executable specifications" (one of the early goals of [Behaviour Driven Development](http://dannorth.net/introducing-bdd/)). This set of macros map on to ```TEST_CASE```s and ```SECTION```s, with a little internal support to make them smoother to work with. diff --git a/docs/tostring.md b/docs/tostring.md index 1f801b3a..dbb6cb8d 100644 --- a/docs/tostring.md +++ b/docs/tostring.md @@ -55,6 +55,16 @@ namespace Catch { } ``` +## Exceptions + +By default all exceptions deriving from `std::exception` will be translated to strings by calling the `what()` method. For exception types that do not derive from `std::exception` - or if `what()` does not return a suitable string - use `CATCH_TRANSLATE_EXCEPTION`. This defines a function that takes your exception type, by reference, and returns a string. It can appear anywhere in the code - it doesn't have to be in the same translation unit. For example: + +``` +CATCH_TRANSLATE_EXCEPTION( MyType& ex ) { + return ex.message(); +} +``` + --- [Home](Readme.md) diff --git a/docs/tutorial.md b/docs/tutorial.md index ce81fb81..0fdaff9b 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -96,7 +96,7 @@ Although this was a simple test it's been enough to demonstrate a few things abo Most test frameworks have a class-based fixture mechanism. That is, test cases map to methods on a class and common setup and teardown can be performed in ```setup()``` and ```teardown()``` methods (or constructor/ destructor in languages, like C++, that support deterministic destruction). -While Catch fully supports this way of working there are a few problems with the approach. In particular, the way your code must be split up and the blunt granularity of cause problems. You can only have one setup/ teardown pair across a set of methods, but sometimes you want slightly different setup in each method, or you may even want several levels of setup (a concept which we will clarify later on in this tutorial). It was problems like these that led James Newkirk, who led the team that built NUnit, to start again from scratch and build xUnit). +While Catch fully supports this way of working there are a few problems with the approach. In particular the way your code must be split up, and the blunt granularity of it, may cause problems. You can only have one setup/ teardown pair across a set of methods, but sometimes you want slightly different setup in each method, or you may even want several levels of setup (a concept which we will clarify later on in this tutorial). It was problems like these that led James Newkirk, who led the team that built NUnit, to start again from scratch and build xUnit). Catch takes a different approach (to both NUnit and xUnit) that is a more natural fit for C++ and the C family of languages. This is best explained through an example: diff --git a/include/catch.hpp b/include/catch.hpp index f6359c02..06ed7eee 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -70,8 +70,9 @@ #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) @@ -82,6 +83,7 @@ #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) @@ -97,6 +99,7 @@ #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) @@ -104,6 +107,7 @@ #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) @@ -123,11 +127,11 @@ #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) -#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) -#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -135,8 +139,9 @@ #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) @@ -145,8 +150,9 @@ #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) @@ -162,6 +168,7 @@ #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) @@ -169,6 +176,7 @@ #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) @@ -192,11 +200,11 @@ #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define GIVEN( desc ) SECTION( " Given: " desc, "" ) -#define WHEN( desc ) SECTION( " When: " desc, "" ) -#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) -#define THEN( desc ) SECTION( " Then: " desc, "" ) -#define AND_THEN( desc ) SECTION( " And: " desc, "" ) +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) using Catch::Detail::Approx; diff --git a/include/catch_runner.hpp b/include/catch_session.hpp similarity index 51% rename from include/catch_runner.hpp rename to include/catch_session.hpp index 8023d970..9cfc28fd 100644 --- a/include/catch_runner.hpp +++ b/include/catch_session.hpp @@ -10,7 +10,7 @@ #include "internal/catch_commandline.hpp" #include "internal/catch_list.hpp" -#include "internal/catch_runner_impl.hpp" +#include "internal/catch_run_context.hpp" #include "internal/catch_test_spec.hpp" #include "internal/catch_version.h" #include "internal/catch_text.h" @@ -21,89 +21,88 @@ namespace Catch { - class Runner { + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } - public: - Runner( Ptr const& config ) - : m_config( config ) - { - openStream(); - makeReporter(); + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); } - Totals runTests() { + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } - RunContext context( m_config.get(), m_reporter ); + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; - Totals totals; + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); - context.testGroupStarting( "all tests", 1, 1 ); // deprecated? + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); - TestSpec testSpec = m_config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests - - std::vector testCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); - - int testsRunForGroup = 0; - for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); - it != itEnd; - ++it ) { - testsRunForGroup++; - if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { - - if( context.aborting() ) - break; - - totals += context.runTest( *it ); - m_testsAlreadyRun.insert( *it ); - } - } - std::vector skippedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); - - for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); - it != itEnd; - ++it ) - m_reporter->skipTest( *it ); - - context.testGroupEnded( "all tests", totals, 1, 1 ); - return totals; + tags.insert( "#" + filename ); + setTags( test, tags ); } - - private: - void openStream() { - // Open output file, if specified - if( !m_config->getFilename().empty() ) { - m_ofs.open( m_config->getFilename().c_str() ); - if( m_ofs.fail() ) { - std::ostringstream oss; - oss << "Unable to open file: '" << m_config->getFilename() << "'"; - throw std::domain_error( oss.str() ); - } - m_config->setStreamBuf( m_ofs.rdbuf() ); - } - } - void makeReporter() { - std::string reporterName = m_config->getReporterName().empty() - ? "console" - : m_config->getReporterName(); - - m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); - if( !m_reporter ) { - std::ostringstream oss; - oss << "No reporter registered with name: '" << reporterName << "'"; - throw std::domain_error( oss.str() ); - } - } - - private: - Ptr m_config; - std::ofstream m_ofs; - Ptr m_reporter; - std::set m_testsAlreadyRun; - }; + } class Session : NonCopyable { static bool alreadyInstantiated; @@ -132,7 +131,7 @@ namespace Catch { Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } - int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + int applyCommandLine( int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); @@ -159,7 +158,7 @@ namespace Catch { m_config.reset(); } - int run( int argc, char* const argv[] ) { + int run( int argc, char const* const argv[] ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) @@ -175,15 +174,16 @@ namespace Catch { { config(); // Force config to be constructed - std::srand( m_configData.rngSeed ); + seedRng( *m_config ); - Runner runner( m_config ); + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); - return static_cast( runner.runTests().assertions.failed ); + return static_cast( runTests( m_config ).assertions.failed ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; @@ -205,7 +205,6 @@ namespace Catch { m_config = new Config( m_configData ); return *m_config; } - private: Clara::CommandLine m_cli; std::vector m_unusedTokens; diff --git a/include/external/clara.h b/include/external/clara.h index bc162806..2c03f985 100644 --- a/include/external/clara.h +++ b/include/external/clara.h @@ -264,11 +264,11 @@ namespace Clara { template class BoundArgFunction { public: - BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction() : functionObj( CATCH_NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CATCH_NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL; delete functionObj; functionObj = newFunctionObj; return *this; @@ -284,7 +284,7 @@ namespace Clara { bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { - return functionObj != NULL; + return functionObj != CATCH_NULL; } private: IArgFunction* functionObj; @@ -503,12 +503,7 @@ namespace Clara { } }; - // NOTE: std::auto_ptr is deprecated in c++11/c++0x -#if defined(__cplusplus) && __cplusplus > 199711L - typedef std::unique_ptr ArgAutoPtr; -#else - typedef std::auto_ptr ArgAutoPtr; -#endif + typedef CATCH_AUTO_PTR( Arg ) ArgAutoPtr; friend void addOptName( Arg& arg, std::string const& optName ) { @@ -585,8 +580,8 @@ namespace Clara { m_arg->description = description; return *this; } - ArgBuilder& detail( std::string const& detail ) { - m_arg->detail = detail; + ArgBuilder& detail( std::string const& _detail ) { + m_arg->detail = _detail; return *this; } @@ -670,14 +665,14 @@ namespace Clara { maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usage( it->commands(), Detail::TextAttributes() + Detail::Text usageText( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); - for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { - std::string usageCol = i < usage.size() ? usage[i] : ""; + for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) { + std::string usageCol = i < usageText.size() ? usageText[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 7bfef0e1..22cf6959 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -66,16 +66,16 @@ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + __catchResult.captureExpectedException( matcher ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ @@ -131,12 +131,12 @@ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ try { \ - std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + std::string matcherAsString = (matcher).toString(); \ __catchResult \ .setLhs( Catch::toString( arg ) ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setOp( "matches" ) \ - .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + .setResultType( (matcher).match( arg ) ); \ __catchResult.captureExpression(); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp index 8b085365..640b304d 100644 --- a/include/internal/catch_commandline.hpp +++ b/include/internal/catch_commandline.hpp @@ -23,6 +23,7 @@ namespace Catch { config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) @@ -116,7 +117,7 @@ namespace Catch { cli["-r"]["--reporter"] // .placeholder( "name[:filename]" ) .describe( "reporter to use (defaults to console)" ) - .bind( &ConfigData::reporterName, "name" ); + .bind( &addReporterName, "name" ); cli["-n"]["--name"] .describe( "suite name" ) @@ -153,12 +154,16 @@ namespace Catch { .describe( "load test names to run from a file" ) .bind( &loadTestNamesFromFile, "filename" ); + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) .bind( &ConfigData::listTestNamesOnly ); - cli["--list-reporters"] + cli["--list-reporters"] .describe( "list all reporters" ) .bind( &ConfigData::listReporters ); diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h index 9f07e47c..7f9cfc44 100644 --- a/include/internal/catch_common.h +++ b/include/internal/catch_common.h @@ -23,6 +23,13 @@ namespace Catch { + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + class NonCopyable { #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; @@ -109,6 +116,9 @@ namespace Catch { void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as diff --git a/include/internal/catch_common.hpp b/include/internal/catch_common.hpp index 8a42d0a0..2342ae61 100644 --- a/include/internal/catch_common.hpp +++ b/include/internal/catch_common.hpp @@ -36,7 +36,7 @@ namespace Catch { return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; } - + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { bool replaced = false; std::size_t i = str.find( replaceThis ); @@ -50,7 +50,7 @@ namespace Catch { } return replaced; } - + pluralise::pluralise( std::size_t count, std::string const& label ) : m_count( count ), m_label( label ) @@ -82,6 +82,14 @@ namespace Catch { return line < other.line || ( line == other.line && file < other.file ); } + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << "(" << info.line << ")"; diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h index 20528c29..7ac7b73f 100644 --- a/include/internal/catch_compiler_capabilities.h +++ b/include/internal/catch_compiler_capabilities.h @@ -16,11 +16,18 @@ // CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? // CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. @@ -66,10 +73,13 @@ // GCC #ifdef __GNUC__ -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR #endif +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + #endif // __GNUC__ @@ -79,6 +89,7 @@ #if (_MSC_VER >= 1600) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) @@ -88,6 +99,8 @@ #endif // _MSC_VER +//////////////////////////////////////////////////////////////////////////////// + // Use variadic macros if the compiler supports them #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ @@ -102,7 +115,7 @@ // C++ language feature support // catch all support for C++11 -#if (__cplusplus >= 201103L) +#if defined(__cplusplus) && __cplusplus >= 201103L # define CATCH_CPP11_OR_GREATER @@ -130,6 +143,18 @@ # define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + + #endif // __cplusplus >= 201103L // Now set the actual defines based on the above + anything the user has configured @@ -149,7 +174,16 @@ # define CATCH_CONFIG_CPP11_TUPLE #endif #if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) -#define CATCH_CONFIG_VARIADIC_MACROS +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif @@ -162,6 +196,26 @@ # define CATCH_NOEXCEPT_IS(x) #endif +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif #endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp index 1f3ca64a..a09210cb 100644 --- a/include/internal/catch_config.hpp +++ b/include/internal/catch_config.hpp @@ -38,6 +38,7 @@ namespace Catch { showHelp( false ), showInvisibles( false ), forceColour( false ), + filenamesAsTags( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), @@ -57,6 +58,7 @@ namespace Catch { bool showHelp; bool showInvisibles; bool forceColour; + bool filenamesAsTags; int abortAfter; unsigned int rngSeed; @@ -66,11 +68,11 @@ namespace Catch { ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; - std::string reporterName; std::string outputFilename; std::string name; std::string processName; + std::vector reporterNames; std::vector testsOrTags; }; @@ -83,12 +85,11 @@ namespace Catch { public: Config() - : m_os( Catch::cout().rdbuf() ) {} Config( ConfigData const& data ) : m_data( data ), - m_os( Catch::cout().rdbuf() ) + m_stream( openStream() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); @@ -99,12 +100,6 @@ namespace Catch { } virtual ~Config() { - m_os.rdbuf( Catch::cout().rdbuf() ); - m_stream.release(); - } - - void setFilename( std::string const& filename ) { - m_data.outputFilename = filename; } std::string const& getFilename() const { @@ -120,18 +115,7 @@ namespace Catch { bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } - void setStreamBuf( std::streambuf* buf ) { - m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); - } - - void useStream( std::string const& streamName ) { - Stream stream = createStream( streamName ); - setStreamBuf( stream.streamBuf ); - m_stream.release(); - m_stream = stream; - } - - std::string getReporterName() const { return m_data.reporterName; } + std::vector getReporterNames() const { return m_data.reporterNames; } int abortAfter() const { return m_data.abortAfter; } @@ -142,7 +126,7 @@ namespace Catch { // IConfig interface virtual bool allowThrows() const { return !m_data.noThrow; } - virtual std::ostream& stream() const { return m_os; } + virtual std::ostream& stream() const { return m_stream->stream(); } virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } @@ -152,14 +136,25 @@ namespace Catch { virtual bool forceColour() const { return m_data.forceColour; } private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } ConfigData m_data; - Stream m_stream; - mutable std::ostream m_os; + std::auto_ptr m_stream; TestSpec m_testSpec; }; - } // end namespace Catch #endif // TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED diff --git a/include/internal/catch_console_colour_impl.hpp b/include/internal/catch_console_colour_impl.hpp index 2c4b36c3..9ca915ff 100644 --- a/include/internal/catch_console_colour_impl.hpp +++ b/include/internal/catch_console_colour_impl.hpp @@ -60,12 +60,13 @@ namespace { { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalAttributes = csbiInfo.wAttributes; + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); @@ -85,10 +86,11 @@ namespace { private: void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); } HANDLE stdoutHandle; - WORD originalAttributes; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; }; IColourImpl* platformColourInstance() { diff --git a/include/internal/catch_context_impl.hpp b/include/internal/catch_context_impl.hpp index a495503c..030f29e2 100644 --- a/include/internal/catch_context_impl.hpp +++ b/include/internal/catch_context_impl.hpp @@ -8,7 +8,7 @@ #ifndef TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED #define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED -#include "catch_runner_impl.hpp" +#include "catch_run_context.hpp" #include "catch_context.h" #include "catch_stream.hpp" @@ -17,7 +17,7 @@ namespace Catch { class Context : public IMutableContext { - Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} Context( Context const& ); void operator=( Context const& ); @@ -63,7 +63,7 @@ namespace Catch { m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second - : NULL; + : CATCH_NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { @@ -84,7 +84,7 @@ namespace Catch { }; namespace { - Context* currentContext = NULL; + Context* currentContext = CATCH_NULL; } IMutableContext& getCurrentMutableContext() { if( !currentContext ) @@ -95,17 +95,9 @@ namespace Catch { return getCurrentMutableContext(); } - Stream createStream( std::string const& streamName ) { - if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); - if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); - if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); - - throw std::domain_error( "Unknown stream: " + streamName ); - } - void cleanUpContext() { delete currentContext; - currentContext = NULL; + currentContext = CATCH_NULL; } } diff --git a/include/internal/catch_debugger.hpp b/include/internal/catch_debugger.hpp index 4151aec7..8c552661 100644 --- a/include/internal/catch_debugger.hpp +++ b/include/internal/catch_debugger.hpp @@ -50,7 +50,7 @@ // Call sysctl. size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } diff --git a/include/internal/catch_evaluate.hpp b/include/internal/catch_evaluate.hpp index 2f85a2b9..1d8ca93e 100644 --- a/include/internal/catch_evaluate.hpp +++ b/include/internal/catch_evaluate.hpp @@ -160,13 +160,51 @@ namespace Internal { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + #ifdef CATCH_CONFIG_CPP11_NULLPTR // pointer to nullptr_t (when comparing against nullptr) template bool compare( std::nullptr_t, T* rhs ) { - return Evaluator::evaluate( NULL, rhs ); + return Evaluator::evaluate( nullptr, rhs ); } template bool compare( T* lhs, std::nullptr_t ) { - return Evaluator::evaluate( lhs, NULL ); + return Evaluator::evaluate( lhs, nullptr ); } #endif // CATCH_CONFIG_CPP11_NULLPTR diff --git a/include/internal/catch_exception_translator_registry.hpp b/include/internal/catch_exception_translator_registry.hpp index 29ddf8e7..c4bdb400 100644 --- a/include/internal/catch_exception_translator_registry.hpp +++ b/include/internal/catch_exception_translator_registry.hpp @@ -32,13 +32,13 @@ namespace Catch { #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { - throw; + return tryTranslators(); } @catch (NSException *exception) { return Catch::toString( [exception description] ); } #else - throw; + return tryTranslators(); #endif } catch( TestFailureException& ) { @@ -54,20 +54,15 @@ namespace Catch { return msg; } catch(...) { - return tryTranslators( m_translators.begin() ); + return "Unknown exception"; } } - std::string tryTranslators( std::vector::const_iterator it ) const { - if( it == m_translators.end() ) - return "Unknown exception"; - - try { - return (*it)->translate(); - } - catch(...) { - return tryTranslators( it+1 ); - } + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); } private: diff --git a/include/internal/catch_impl.hpp b/include/internal/catch_impl.hpp index 24a8c3f8..53c89574 100644 --- a/include/internal/catch_impl.hpp +++ b/include/internal/catch_impl.hpp @@ -16,7 +16,7 @@ #pragma clang diagnostic ignored "-Wweak-vtables" #endif -#include "../catch_runner.hpp" +#include "../catch_session.hpp" #include "catch_registry_hub.hpp" #include "catch_notimplemented_exception.hpp" #include "catch_context_impl.hpp" @@ -35,15 +35,23 @@ #include "catch_tostring.hpp" #include "catch_result_builder.hpp" #include "catch_tag_alias_registry.hpp" +#include "catch_test_case_tracker.hpp" +#include "../reporters/catch_reporter_multi.hpp" #include "../reporters/catch_reporter_xml.hpp" #include "../reporters/catch_reporter_junit.hpp" #include "../reporters/catch_reporter_console.hpp" #include "../reporters/catch_reporter_compact.hpp" namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods NonCopyable::~NonCopyable() {} IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} IContext::~IContext() {} IResultCapture::~IResultCapture() {} @@ -77,6 +85,7 @@ namespace Catch { FreeFunctionTestCase::~FreeFunctionTestCase() {} IGeneratorInfo::~IGeneratorInfo() {} IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} TestSpec::Pattern::~Pattern() {} TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} @@ -88,6 +97,13 @@ namespace Catch { Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } } #ifdef __clang__ diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h index bdbcfb2f..b7b6e32d 100644 --- a/include/internal/catch_interfaces_capture.h +++ b/include/internal/catch_interfaces_capture.h @@ -18,6 +18,7 @@ namespace Catch { class AssertionResult; struct AssertionInfo; struct SectionInfo; + struct SectionEndInfo; struct MessageInfo; class ScopedMessageBuilder; struct Counts; @@ -29,7 +30,8 @@ namespace Catch { virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; - virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; diff --git a/include/internal/catch_interfaces_exception.h b/include/internal/catch_interfaces_exception.h index c2fc5bf5..67247e1e 100644 --- a/include/internal/catch_interfaces_exception.h +++ b/include/internal/catch_interfaces_exception.h @@ -9,15 +9,20 @@ #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include +#include + #include "catch_interfaces_registry_hub.h" namespace Catch { typedef std::string(*exceptionTranslateFunction)(); + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + struct IExceptionTranslator { virtual ~IExceptionTranslator(); - virtual std::string translate() const = 0; + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; }; struct IExceptionTranslatorRegistry { @@ -35,9 +40,12 @@ namespace Catch { : m_translateFunction( translateFunction ) {} - virtual std::string translate() const { + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { try { - throw; + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); } catch( T& ex ) { return m_translateFunction( ex ); diff --git a/include/internal/catch_interfaces_registry_hub.h b/include/internal/catch_interfaces_registry_hub.h index b657183b..ec06ca29 100644 --- a/include/internal/catch_interfaces_registry_hub.h +++ b/include/internal/catch_interfaces_registry_hub.h @@ -8,6 +8,8 @@ #ifndef TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED +#include "catch_ptr.hpp" + #include namespace Catch { @@ -29,7 +31,8 @@ namespace Catch { struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; }; diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h index ff893038..d1c6e704 100644 --- a/include/internal/catch_interfaces_reporter.h +++ b/include/internal/catch_interfaces_reporter.h @@ -26,18 +26,18 @@ namespace Catch { struct ReporterConfig { - explicit ReporterConfig( Ptr const& _fullConfig ) + explicit ReporterConfig( Ptr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& stream() const { return *m_stream; } - Ptr fullConfig() const { return m_fullConfig; } + Ptr fullConfig() const { return m_fullConfig; } private: std::ostream* m_stream; - Ptr m_fullConfig; + Ptr m_fullConfig; }; struct ReporterPreferences { @@ -240,29 +240,34 @@ namespace Catch // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; }; - struct IReporterFactory { + struct IReporterFactory : IShared { virtual ~IReporterFactory(); virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { - typedef std::map FactoryMap; + typedef std::map > FactoryMap; + typedef std::vector > Listeners; virtual ~IReporterRegistry(); - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; }; + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + } #endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED diff --git a/include/internal/catch_interfaces_testcase.h b/include/internal/catch_interfaces_testcase.h index a23ff9f4..a1052b71 100644 --- a/include/internal/catch_interfaces_testcase.h +++ b/include/internal/catch_interfaces_testcase.h @@ -28,9 +28,13 @@ namespace Catch { struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; - + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + } #endif // TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED diff --git a/include/internal/catch_list.hpp b/include/internal/catch_list.hpp index 1c510ef8..4c87ccf4 100644 --- a/include/internal/catch_list.hpp +++ b/include/internal/catch_list.hpp @@ -34,8 +34,7 @@ namespace Catch { nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -63,8 +62,7 @@ namespace Catch { if( !config.testSpec().hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -104,8 +102,7 @@ namespace Catch { std::map tagCounts; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { diff --git a/include/internal/catch_matchers.hpp b/include/internal/catch_matchers.hpp index 028ff678..27878612 100644 --- a/include/internal/catch_matchers.hpp +++ b/include/internal/catch_matchers.hpp @@ -12,6 +12,12 @@ namespace Catch { namespace Matchers { namespace Impl { + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + template struct Matcher : SharedImpl { @@ -21,6 +27,10 @@ namespace Matchers { virtual Ptr clone() const = 0; virtual bool match( ExpressionT const& expr ) const = 0; virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; }; template @@ -32,6 +42,22 @@ namespace Matchers { }; namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; template class AllOf : public MatcherImpl, ExpressionT> { @@ -63,6 +89,12 @@ namespace Matchers { return oss.str(); } + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + private: std::vector > > m_matchers; }; @@ -97,85 +129,146 @@ namespace Matchers { return oss.str(); } + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + private: std::vector > > m_matchers; }; + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; } + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { inline std::string makeString( std::string const& str ) { return str; } inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + struct Equals : MatcherImpl { - Equals( std::string const& str ) : m_str( str ){} - Equals( Equals const& other ) : m_str( other.m_str ){} + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} virtual ~Equals(); virtual bool match( std::string const& expr ) const { - return m_str == expr; + return m_data.m_str == m_data.adjustString( expr );; } virtual std::string toString() const { - return "equals: \"" + m_str + "\""; + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } - std::string m_str; + CasedString m_data; }; struct Contains : MatcherImpl { - Contains( std::string const& substr ) : m_substr( substr ){} - Contains( Contains const& other ) : m_substr( other.m_substr ){} + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} virtual ~Contains(); virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) != std::string::npos; + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; } virtual std::string toString() const { - return "contains: \"" + m_substr + "\""; + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } - std::string m_substr; + CasedString m_data; }; struct StartsWith : MatcherImpl { - StartsWith( std::string const& substr ) : m_substr( substr ){} - StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} virtual ~StartsWith(); virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == 0; + return m_data.adjustString( expr ).find( m_data.m_str ) == 0; } virtual std::string toString() const { - return "starts with: \"" + m_substr + "\""; + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } - std::string m_substr; + CasedString m_data; }; struct EndsWith : MatcherImpl { - EndsWith( std::string const& substr ) : m_substr( substr ){} - EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} virtual ~EndsWith(); virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == expr.size() - m_substr.size(); + return m_data.adjustString( expr ).find( m_data.m_str ) == expr.size() - m_data.m_str.size(); } virtual std::string toString() const { - return "ends with: \"" + m_substr + "\""; + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } - std::string m_substr; + CasedString m_data; }; } // namespace StdString } // namespace Impl // The following functions create the actual matcher objects. // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + template inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, Impl::Matcher const& m2 ) { @@ -199,17 +292,17 @@ namespace Matchers { return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); } - inline Impl::StdString::Equals Equals( std::string const& str ) { - return Impl::StdString::Equals( str ); + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); } - inline Impl::StdString::Equals Equals( const char* str ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); } - inline Impl::StdString::Contains Contains( std::string const& substr ) { - return Impl::StdString::Contains( substr ); + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); } - inline Impl::StdString::Contains Contains( const char* substr ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); } inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { return Impl::StdString::StartsWith( substr ); diff --git a/include/internal/catch_objc.hpp b/include/internal/catch_objc.hpp index 7e315c22..489cf558 100644 --- a/include/internal/catch_objc.hpp +++ b/include/internal/catch_objc.hpp @@ -72,7 +72,7 @@ namespace Catch { inline size_t registerTestMethods() { size_t noTestMethods = 0; - int noClasses = objc_getClassList( NULL, 0 ); + int noClasses = objc_getClassList( CATCH_NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); diff --git a/include/internal/catch_option.hpp b/include/internal/catch_option.hpp index bf3bce3d..5413abf0 100644 --- a/include/internal/catch_option.hpp +++ b/include/internal/catch_option.hpp @@ -16,12 +16,12 @@ namespace Catch { template class Option { public: - Option() : nullableValue( NULL ) {} + Option() : nullableValue( CATCH_NULL ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) {} ~Option() { @@ -45,7 +45,7 @@ namespace Catch { void reset() { if( nullableValue ) nullableValue->~T(); - nullableValue = NULL; + nullableValue = CATCH_NULL; } T& operator*() { return *nullableValue; } @@ -57,10 +57,10 @@ namespace Catch { return nullableValue ? *nullableValue : defaultValue; } - bool some() const { return nullableValue != NULL; } - bool none() const { return nullableValue == NULL; } + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } - bool operator !() const { return nullableValue == NULL; } + bool operator !() const { return nullableValue == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( some() ); } diff --git a/include/internal/catch_ptr.hpp b/include/internal/catch_ptr.hpp index 3d76e328..940e5d19 100644 --- a/include/internal/catch_ptr.hpp +++ b/include/internal/catch_ptr.hpp @@ -23,7 +23,7 @@ namespace Catch { template class Ptr { public: - Ptr() : m_p( NULL ){} + Ptr() : m_p( CATCH_NULL ){} Ptr( T* p ) : m_p( p ){ if( m_p ) m_p->addRef(); @@ -39,7 +39,7 @@ namespace Catch { void reset() { if( m_p ) m_p->release(); - m_p = NULL; + m_p = CATCH_NULL; } Ptr& operator = ( T* p ){ Ptr temp( p ); @@ -52,12 +52,11 @@ namespace Catch { return *this; } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() { return m_p; } - const T* get() const{ return m_p; } + T* get() const{ return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } - bool operator !() const { return m_p == NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } private: T* m_p; diff --git a/include/internal/catch_registry_hub.hpp b/include/internal/catch_registry_hub.hpp index 303a843a..35293bf5 100644 --- a/include/internal/catch_registry_hub.hpp +++ b/include/internal/catch_registry_hub.hpp @@ -26,24 +26,27 @@ namespace Catch { public: // IRegistryHub RegistryHub() { } - virtual IReporterRegistry const& getReporterRegistry() const { + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { return m_reporterRegistry; } - virtual ITestCaseRegistry const& getTestCaseRegistry() const { + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { return m_testCaseRegistry; } - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { return m_exceptionTranslatorRegistry; } public: // IMutableRegistryHub - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerReporter( name, factory ); } - virtual void registerTest( TestCase const& testInfo ) { + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { m_testCaseRegistry.registerTest( testInfo ); } - virtual void registerTranslator( const IExceptionTranslator* translator ) { + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { m_exceptionTranslatorRegistry.registerTranslator( translator ); } @@ -55,7 +58,7 @@ namespace Catch { // Single, global, instance inline RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = NULL; + static RegistryHub* theRegistryHub = CATCH_NULL; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; @@ -70,7 +73,7 @@ namespace Catch { } void cleanUp() { delete getTheRegistryHub(); - getTheRegistryHub() = NULL; + getTheRegistryHub() = CATCH_NULL; cleanUpContext(); } std::string translateActiveException() { diff --git a/include/internal/catch_reporter_registrars.hpp b/include/internal/catch_reporter_registrars.hpp index 51465556..7bd7b610 100644 --- a/include/internal/catch_reporter_registrars.hpp +++ b/include/internal/catch_reporter_registrars.hpp @@ -36,7 +36,7 @@ namespace Catch { template class ReporterRegistrar { - class ReporterFactory : public IReporterFactory { + class ReporterFactory : public SharedImpl { // *** Please Note ***: // - If you end up here looking at a compiler error because it's trying to register @@ -64,11 +64,35 @@ namespace Catch { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; } #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + #endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED diff --git a/include/internal/catch_reporter_registry.hpp b/include/internal/catch_reporter_registry.hpp index 2ce24bef..71f23ff7 100644 --- a/include/internal/catch_reporter_registry.hpp +++ b/include/internal/catch_reporter_registry.hpp @@ -18,27 +18,32 @@ namespace Catch { public: - virtual ~ReporterRegistry() { - deleteAllValues( m_factories ); - } + virtual ~ReporterRegistry() CATCH_OVERRIDE {} - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { FactoryMap::const_iterator it = m_factories.find( name ); if( it == m_factories.end() ) - return NULL; + return CATCH_NULL; return it->second->create( ReporterConfig( config ) ); } - void registerReporter( std::string const& name, IReporterFactory* factory ) { + void registerReporter( std::string const& name, Ptr const& factory ) { m_factories.insert( std::make_pair( name, factory ) ); } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } - FactoryMap const& getFactories() const { + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { return m_factories; } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } private: FactoryMap m_factories; + Listeners m_listeners; }; } diff --git a/include/internal/catch_result_builder.h b/include/internal/catch_result_builder.h index b44882bb..89002660 100644 --- a/include/internal/catch_result_builder.h +++ b/include/internal/catch_result_builder.h @@ -11,6 +11,7 @@ #include "catch_result_type.h" #include "catch_assertionresult.h" #include "catch_common.h" +#include "catch_matchers.hpp" namespace Catch { @@ -38,7 +39,8 @@ namespace Catch { ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, - ResultDisposition::Flags resultDisposition ); + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); template ExpressionLhs operator <= ( T const& operand ); @@ -67,6 +69,9 @@ namespace Catch { void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void captureResult( ResultWas::OfType resultType ); void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; bool allowThrows() const; @@ -80,7 +85,7 @@ namespace Catch { std::string lhs, rhs, op; } m_exprComponents; CopyableStream m_stream; - + bool m_shouldDebugBreak; bool m_shouldThrow; }; diff --git a/include/internal/catch_result_builder.hpp b/include/internal/catch_result_builder.hpp index 8ce4a4fb..d453fecf 100644 --- a/include/internal/catch_result_builder.hpp +++ b/include/internal/catch_result_builder.hpp @@ -14,15 +14,21 @@ #include "catch_interfaces_runner.h" #include "catch_interfaces_capture.h" #include "catch_interfaces_registry_hub.h" - +#include "catch_wildcard_pattern.hpp" namespace Catch { + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), m_shouldDebugBreak( false ), m_shouldThrow( false ) {} @@ -63,9 +69,35 @@ namespace Catch { setResultType( resultType ); captureExpression(); } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } void ResultBuilder::captureExpression() { AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { getResultCapture().assertionEnded( result ); if( !result.isOk() ) { diff --git a/include/internal/catch_result_type.h b/include/internal/catch_result_type.h index beaff369..4c3d77dc 100644 --- a/include/internal/catch_result_type.h +++ b/include/internal/catch_result_type.h @@ -55,7 +55,7 @@ namespace Catch { inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - + } // end namespace Catch #endif // TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED diff --git a/include/internal/catch_runner_impl.hpp b/include/internal/catch_run_context.hpp similarity index 81% rename from include/internal/catch_runner_impl.hpp rename to include/internal/catch_run_context.hpp index e6893518..da5990ad 100644 --- a/include/internal/catch_runner_impl.hpp +++ b/include/internal/catch_run_context.hpp @@ -59,15 +59,12 @@ namespace Catch { public: - explicit RunContext( Ptr const& config, Ptr const& reporter ) - : m_runInfo( config->name() ), + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), m_context( getCurrentMutableContext() ), - m_activeTestCase( NULL ), - m_config( config ), - m_reporter( reporter ), - m_prevRunner( m_context.getRunner() ), - m_prevResultCapture( m_context.getResultCapture() ), - m_prevConfig( m_context.getConfig() ) + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) { m_context.setRunner( this ); m_context.setConfig( m_config ); @@ -77,10 +74,6 @@ namespace Catch { virtual ~RunContext() { m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); - m_context.setRunner( m_prevRunner ); - m_context.setConfig( NULL ); - m_context.setResultCapture( m_prevResultCapture ); - m_context.setConfig( m_prevConfig ); } void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { @@ -101,14 +94,18 @@ namespace Catch { m_reporter->testCaseStarting( testInfo ); m_activeTestCase = &testCase; - m_testCaseTracker = TestCaseTracker( testInfo.name ); + do { + m_trackerContext.startRun(); do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); runCurrentTest( redirectedCout, redirectedCerr ); } - while( !m_testCaseTracker->isCompleted() && !aborting() ); + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); } + // !TBD: deprecated - this will be replaced by indexed trackers while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); @@ -119,8 +116,8 @@ namespace Catch { redirectedCerr, aborting() ) ); - m_activeTestCase = NULL; - m_testCaseTracker.reset(); + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; return deltaTotals; } @@ -156,8 +153,10 @@ namespace Catch { std::ostringstream oss; oss << sectionInfo.name << "@" << sectionInfo.lineInfo; - if( !m_testCaseTracker->enterSection( oss.str() ) ) + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) return false; + m_activeSections.push_back( §ionTracker ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; @@ -168,30 +167,40 @@ namespace Catch { return true; } bool testForMissingAssertions( Counts& assertions ) { - if( assertions.total() != 0 || - !m_config->warnAboutMissingAssertions() || - m_testCaseTracker->currentSectionHasChildren() ) + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) return false; m_totals.assertions.failed++; assertions.failed++; return true; } - virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { - if( std::uncaught_exception() ) { - m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); - return; - } - - Counts assertions = m_totals.assertions - prevAssertions; + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); - m_testCaseTracker->leaveSection(); + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } - m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); m_messages.clear(); } + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + virtual void pushScopedMessage( MessageInfo const& message ) { m_messages.push_back( message ); } @@ -257,7 +266,8 @@ namespace Catch { double duration = 0; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); - TestCaseTracker::Guard guard( *m_testCaseTracker ); + + seedRng( *m_config ); Timer timer; timer.start(); @@ -277,6 +287,7 @@ namespace Catch { catch(...) { makeUnexpectedResultBuilder().useActiveException(); } + m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); @@ -311,39 +322,29 @@ namespace Catch { void handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. - for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it ) - sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + sectionEnded( *it ); m_unfinishedSections.clear(); } - struct UnfinishedSections { - UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) - : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - - SectionInfo info; - Counts prevAssertions; - double durationInSeconds; - }; - TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase; - Option m_testCaseTracker; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; AssertionResult m_lastResult; Ptr m_config; Totals m_totals; Ptr m_reporter; std::vector m_messages; - IRunner* m_prevRunner; - IResultCapture* m_prevResultCapture; - Ptr m_prevConfig; AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; }; IResultCapture& getResultCapture() { diff --git a/include/internal/catch_section.hpp b/include/internal/catch_section.hpp index ec4c1518..de65c4cd 100644 --- a/include/internal/catch_section.hpp +++ b/include/internal/catch_section.hpp @@ -32,8 +32,13 @@ namespace Catch { } Section::~Section() { - if( m_sectionIncluded ) - getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } } // This indicates whether the section should be executed or not diff --git a/include/internal/catch_section_info.h b/include/internal/catch_section_info.h index 93f3840e..00b65600 100644 --- a/include/internal/catch_section_info.h +++ b/include/internal/catch_section_info.h @@ -9,6 +9,7 @@ #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED #include "catch_common.h" +#include "catch_totals.hpp" namespace Catch { @@ -23,6 +24,16 @@ namespace Catch { SourceLineInfo lineInfo; }; + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + } // end namespace Catch #endif // TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED diff --git a/include/internal/catch_section_info.hpp b/include/internal/catch_section_info.hpp index f60896c4..6258a281 100644 --- a/include/internal/catch_section_info.hpp +++ b/include/internal/catch_section_info.hpp @@ -36,7 +36,7 @@ namespace Catch { RunningSection( std::string const& name ) : m_state( Root ), - m_parent( NULL ), + m_parent( CATCH_NULL ), m_name( name ) {} diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h index 402a6617..5f22ad67 100644 --- a/include/internal/catch_stream.h +++ b/include/internal/catch_stream.h @@ -9,28 +9,55 @@ #ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED -#include +#include "catch_compiler_capabilities.h" +#include "catch_streambuf.h" -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#endif +#include +#include +#include namespace Catch { - class Stream { - public: - Stream(); - Stream( std::streambuf* _streamBuf, bool _isOwned ); - void release(); - - std::streambuf* streamBuf; - - private: - bool isOwned; - }; - std::ostream& cout(); std::ostream& cerr(); + + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; } #endif // TWOBLUECUBES_CATCH_STREAM_H_INCLUDED diff --git a/include/internal/catch_stream.hpp b/include/internal/catch_stream.hpp index 30e9668b..2703df5d 100644 --- a/include/internal/catch_stream.hpp +++ b/include/internal/catch_stream.hpp @@ -10,7 +10,6 @@ #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED #include "catch_stream.h" -#include "catch_streambuf.h" #include "catch_debugger.h" #include @@ -57,6 +56,20 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////// + + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + struct OutputDebugWriter { void operator()( std::string const&str ) { @@ -64,20 +77,23 @@ namespace Catch { } }; - Stream::Stream() - : streamBuf( NULL ), isOwned( false ) + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) {} - Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) - : streamBuf( _streamBuf ), isOwned( _isOwned ) + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) {} - void Stream::release() { - if( isOwned ) { - delete streamBuf; - streamBuf = NULL; - isOwned = false; - } + std::ostream& CoutStream::stream() const { + return m_os; } #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions diff --git a/include/internal/catch_suppress_warnings.h b/include/internal/catch_suppress_warnings.h index e459dfcc..8f57b285 100644 --- a/include/internal/catch_suppress_warnings.h +++ b/include/internal/catch_suppress_warnings.h @@ -5,9 +5,6 @@ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ -#ifndef TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED -#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED - #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) @@ -22,6 +19,7 @@ # pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" @@ -29,5 +27,3 @@ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif - -#endif // TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED diff --git a/include/internal/catch_test_case_info.h b/include/internal/catch_test_case_info.h index 7520fd1c..6ab1f375 100644 --- a/include/internal/catch_test_case_info.h +++ b/include/internal/catch_test_case_info.h @@ -31,7 +31,7 @@ namespace Catch { MayFail = 1 << 3, Throws = 1 << 4 }; - + TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, @@ -40,6 +40,8 @@ namespace Catch { TestCaseInfo( TestCaseInfo const& other ); + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + bool isHidden() const; bool throws() const; bool okToFail() const; diff --git a/include/internal/catch_test_case_info.hpp b/include/internal/catch_test_case_info.hpp index 308ddc74..90f53411 100644 --- a/include/internal/catch_test_case_info.hpp +++ b/include/internal/catch_test_case_info.hpp @@ -93,6 +93,21 @@ namespace Catch { return TestCase( _testCase, info ); } + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, @@ -101,18 +116,10 @@ namespace Catch { : name( _name ), className( _className ), description( _description ), - tags( _tags ), lineInfo( _lineInfo ), properties( None ) { - std::ostringstream oss; - for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { - oss << "[" << *it << "]"; - std::string lcaseTag = toLower( *it ); - properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); - lcaseTags.insert( lcaseTag ); - } - tagsAsString = oss.str(); + setTags( *this, _tags ); } TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) diff --git a/include/internal/catch_test_case_registry_impl.hpp b/include/internal/catch_test_case_registry_impl.hpp index 4c575b68..728adcb0 100644 --- a/include/internal/catch_test_case_registry_impl.hpp +++ b/include/internal/catch_test_case_registry_impl.hpp @@ -21,14 +21,71 @@ namespace Catch { - class TestRegistry : public ITestCaseRegistry { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { public: TestRegistry() : m_unnamedCount( 0 ) {} virtual ~TestRegistry(); @@ -40,68 +97,27 @@ namespace Catch { oss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( oss.str() ) ); } - - if( m_functions.find( testCase ) == m_functions.end() ) { - m_functions.insert( testCase ); - m_functionsInOrder.push_back( testCase ); - if( !testCase.isHidden() ) - m_nonHiddenFunctions.push_back( testCase ); - } - else { - TestCase const& prev = *m_functions.find( testCase ); - { - Colour colourGuard( Colour::Red ); - Catch::cerr() << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; - } - exit(1); - } + m_functions.push_back( testCase ); } virtual std::vector const& getAllTests() const { - return m_functionsInOrder; + return m_functions; } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); - virtual std::vector const& getAllNonHiddenTests() const { - return m_nonHiddenFunctions; - } - - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { - - for( std::vector::const_iterator it = m_functionsInOrder.begin(), - itEnd = m_functionsInOrder.end(); - it != itEnd; - ++it ) { - bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); - if( includeTest != negated ) - matchingTestCases.push_back( *it ); + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); } - sortTests( config, matchingTestCases ); + return m_sortedFunctions; } private: - - static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); - break; - case RunTests::InRandomOrder: - { - RandomNumberGenerator rng; - std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); - } - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - } - std::set m_functions; - std::vector m_functionsInOrder; - std::vector m_nonHiddenFunctions; + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; size_t m_unnamedCount; std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised }; @@ -136,29 +152,38 @@ namespace Catch { return className; } + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + /////////////////////////////////////////////////////////////////////////// - AutoReg::AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { - registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); } AutoReg::~AutoReg() {} - void AutoReg::registerTestCase( ITestCase* testCase, - char const* classOrQualifiedMethodName, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - - getMutableRegistryHub().registerTest - ( makeTestCase( testCase, - extractClassName( classOrQualifiedMethodName ), - nameAndDesc.name, - nameAndDesc.description, - lineInfo ) ); - } - } // end namespace Catch diff --git a/include/internal/catch_test_case_tracker.hpp b/include/internal/catch_test_case_tracker.hpp index 86b6be50..505c3ab8 100644 --- a/include/internal/catch_test_case_tracker.hpp +++ b/include/internal/catch_test_case_tracker.hpp @@ -8,140 +8,308 @@ #ifndef TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED +#include "catch_compiler_capabilities.h" +#include "catch_ptr.hpp" + #include #include #include +#include namespace Catch { -namespace SectionTracking { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); + + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { - class TrackedSection { - - typedef std::map TrackedSections; - - public: enum RunState { NotStarted, Executing, - ExecutingChildren, - Completed + CompletedCycle }; - - TrackedSection( std::string const& name, TrackedSection* parent ) - : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) {} - - RunState runState() const { return m_runState; } - - TrackedSection* findChild( std::string const& childName ); - TrackedSection* acquireChild( std::string const& childName ); - void enter() { - if( m_runState == NotStarted ) - m_runState = Executing; - } - void leave(); - TrackedSection* getParent() { - return m_parent; + ITracker& startRun(); + + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; } - bool hasChildren() const { + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { return !m_children.empty(); } - - private: - std::string m_name; - RunState m_runState; - TrackedSections m_children; - TrackedSection* m_parent; - }; - - inline TrackedSection* TrackedSection::findChild( std::string const& childName ) { - TrackedSections::iterator it = m_children.find( childName ); - return it != m_children.end() - ? &it->second - : NULL; - } - inline TrackedSection* TrackedSection::acquireChild( std::string const& childName ) { - if( TrackedSection* child = findChild( childName ) ) - return child; - m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); - return findChild( childName ); - } - inline void TrackedSection::leave() { - for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); - it != itEnd; - ++it ) - if( it->second.runState() != Completed ) { + + + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { m_runState = ExecutingChildren; - return; + if( m_parent ) + m_parent->openChild(); } - m_runState = Completed; - } - - class TestCaseTracker { - public: - TestCaseTracker( std::string const& testCaseName ) - : m_testCase( testCaseName, NULL ), - m_currentSection( &m_testCase ), - m_completedASectionThisRun( false ) - {} - - bool enterSection( std::string const& name ) { - TrackedSection* child = m_currentSection->acquireChild( name ); - if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) - return false; - - m_currentSection = child; - m_currentSection->enter(); - return true; } - void leaveSection() { - m_currentSection->leave(); - m_currentSection = m_currentSection->getParent(); - assert( m_currentSection != NULL ); - m_completedASectionThisRun = true; + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); } - bool currentSectionHasChildren() const { - return m_currentSection->hasChildren(); - } - bool isCompleted() const { - return m_testCase.runState() == TrackedSection::Completed; - } + virtual void close() CATCH_OVERRIDE { - class Guard { - public: - Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { - m_tracker.enterTestCase(); + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); } - ~Guard() { - m_tracker.leaveTestCase(); - } - private: - Guard( Guard const& ); - void operator = ( Guard const& ); - TestCaseTracker& m_tracker; - }; - + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } private: - void enterTestCase() { - m_currentSection = &m_testCase; - m_completedASectionThisRun = false; - m_testCase.enter(); + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); } - void leaveTestCase() { - m_testCase.leave(); + void moveToThis() { + m_ctx.setCurrentTracker( this ); } - - TrackedSection m_testCase; - TrackedSection* m_currentSection; - bool m_completedASectionThisRun; }; -} // namespace SectionTracking + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); -using SectionTracking::TestCaseTracker; + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; } // namespace Catch diff --git a/include/internal/catch_test_registry.hpp b/include/internal/catch_test_registry.hpp index d12411d4..bd27ba0e 100644 --- a/include/internal/catch_test_registry.hpp +++ b/include/internal/catch_test_registry.hpp @@ -42,27 +42,32 @@ struct NameAndDesc { const char* description; }; +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + struct AutoReg { - AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); template - AutoReg( void (C::*method)(), - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - registerTestCase( new MethodTestCase( method ), - className, - nameAndDesc, - lineInfo ); - } + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { - void registerTestCase( ITestCase* testCase, - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ); + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } ~AutoReg(); @@ -71,6 +76,11 @@ private: void operator= ( AutoReg const& ); }; +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS @@ -94,6 +104,10 @@ private: } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ @@ -115,6 +129,9 @@ private: } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); #endif #endif // TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED diff --git a/include/internal/catch_test_spec.hpp b/include/internal/catch_test_spec.hpp index b5f70635..7e4ea9d1 100644 --- a/include/internal/catch_test_spec.hpp +++ b/include/internal/catch_test_spec.hpp @@ -13,6 +13,7 @@ #pragma clang diagnostic ignored "-Wpadded" #endif +#include "catch_wildcard_pattern.hpp" #include "catch_test_case_info.h" #include @@ -26,50 +27,18 @@ namespace Catch { virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; class NamePattern : public Pattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - public: - NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { - if( startsWith( m_name, "*" ) ) { - m_name = m_name.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_name, "*" ) ) { - m_name = m_name.substr( 0, m_name.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_name == toLower( testCase.name ); - case WildcardAtStart: - return endsWith( toLower( testCase.name ), m_name ); - case WildcardAtEnd: - return startsWith( toLower( testCase.name ), m_name ); - case WildcardAtBothEnds: - return contains( toLower( testCase.name ), m_name ); - } - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - throw std::logic_error( "Unknown enum" ); -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + return m_wildcardPattern.matches( toLower( testCase.name ) ); } private: - std::string m_name; - WildcardPosition m_wildcard; + WildcardPattern m_wildcardPattern; }; + class TagPattern : public Pattern { public: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} @@ -80,6 +49,7 @@ namespace Catch { private: std::string m_tag; }; + class ExcludedPattern : public Pattern { public: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} diff --git a/include/internal/catch_timer.hpp b/include/internal/catch_timer.hpp index 47d9536b..2ba709e3 100644 --- a/include/internal/catch_timer.hpp +++ b/include/internal/catch_timer.hpp @@ -37,7 +37,7 @@ namespace Catch { #else uint64_t getCurrentTicks() { timeval t; - gettimeofday(&t,NULL); + gettimeofday(&t,CATCH_NULL); return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h index 120619be..e6f7ec9d 100644 --- a/include/internal/catch_tostring.h +++ b/include/internal/catch_tostring.h @@ -52,6 +52,11 @@ std::string toString( char value ); std::string toString( signed char value ); std::string toString( unsigned char value ); +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif @@ -62,10 +67,10 @@ std::string toString( std::nullptr_t ); std::string toString( NSObject* const& nsObject ); #endif - + namespace Detail { - extern std::string unprintableString; + extern const std::string unprintableString; struct BorgType { template BorgType( T const& ); @@ -73,7 +78,7 @@ namespace Detail { struct TrueType { char sizer[1]; }; struct FalseType { char sizer[2]; }; - + TrueType& testStreamable( std::ostream& ); FalseType testStreamable( FalseType ); @@ -148,7 +153,7 @@ struct StringMaker { template static std::string convert( U* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } @@ -158,7 +163,7 @@ template struct StringMaker { static std::string convert( R C::* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } diff --git a/include/internal/catch_tostring.hpp b/include/internal/catch_tostring.hpp index 60f8f823..0a20ee2d 100644 --- a/include/internal/catch_tostring.hpp +++ b/include/internal/catch_tostring.hpp @@ -15,9 +15,11 @@ namespace Catch { namespace Detail { - std::string unprintableString = "{?}"; + const std::string unprintableString = "{?}"; namespace { + const int hexThreshold = 255; + struct Endianness { enum Arch { Big, Little }; @@ -99,7 +101,7 @@ std::string toString( wchar_t* const value ) std::string toString( int value ) { std::ostringstream oss; oss << value; - if( value >= 255 ) + if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } @@ -107,7 +109,7 @@ std::string toString( int value ) { std::string toString( unsigned long value ) { std::ostringstream oss; oss << value; - if( value >= 255 ) + if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } @@ -157,6 +159,23 @@ std::string toString( unsigned char value ) { return toString( static_cast( value ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ) { return "nullptr"; diff --git a/include/internal/catch_version.h b/include/internal/catch_version.h index b6a97077..1a79c5c5 100644 --- a/include/internal/catch_version.h +++ b/include/internal/catch_version.h @@ -27,7 +27,7 @@ namespace Catch { unsigned int const buildNumber; friend std::ostream& operator << ( std::ostream& os, Version const& version ); - + private: void operator=( Version const& ); }; diff --git a/include/internal/catch_version.hpp b/include/internal/catch_version.hpp index 46651b72..6194242f 100644 --- a/include/internal/catch_version.hpp +++ b/include/internal/catch_version.hpp @@ -37,7 +37,7 @@ namespace Catch { return os; } - Version libraryVersion( 1, 2, 1, "", 0 ); + Version libraryVersion( 1, 3, 0, "", 0 ); } diff --git a/include/internal/catch_wildcard_pattern.hpp b/include/internal/catch_wildcard_pattern.hpp new file mode 100644 index 00000000..cd8b07e1 --- /dev/null +++ b/include/internal/catch_wildcard_pattern.hpp @@ -0,0 +1,71 @@ +/* + * Created by Phil on 13/7/2015. + * Copyright 2015 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +#include "catch_common.h" + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + +#endif // TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED diff --git a/include/internal/catch_xmlwriter.hpp b/include/internal/catch_xmlwriter.hpp index 553c5a79..c59725b0 100644 --- a/include/internal/catch_xmlwriter.hpp +++ b/include/internal/catch_xmlwriter.hpp @@ -8,14 +8,72 @@ #ifndef TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED -#include "../internal/catch_stream.h" +#include "catch_stream.h" +#include "catch_compiler_capabilities.h" +#include "catch_suppress_warnings.h" #include #include #include +#include namespace Catch { + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + class XmlWriter { public: @@ -27,7 +85,7 @@ namespace Catch { ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ - other.m_writer = NULL; + other.m_writer = CATCH_NULL; } ~ScopedElement() { @@ -98,11 +156,8 @@ namespace Catch { } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) { - stream() << " " << name << "=\""; - writeEncodedText( attribute ); - stream() << "\""; - } + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; return *this; } @@ -113,9 +168,9 @@ namespace Catch { template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - if( !name.empty() ) - stream() << " " << name << "=\"" << attribute << "\""; - return *this; + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ) { @@ -124,7 +179,7 @@ namespace Catch { ensureTagClosed(); if( tagWasOpen && indent ) stream() << m_indent; - writeEncodedText( text ); + stream() << XmlEncode( text ); m_needsNewline = true; } return *this; @@ -169,30 +224,6 @@ namespace Catch { } } - void writeEncodedText( std::string const& text ) { - static const char* charsToEncode = "<&\""; - std::string mtext = text; - std::string::size_type pos = mtext.find_first_of( charsToEncode ); - while( pos != std::string::npos ) { - stream() << mtext.substr( 0, pos ); - - switch( mtext[pos] ) { - case '<': - stream() << "<"; - break; - case '&': - stream() << "&"; - break; - case '\"': - stream() << """; - break; - } - mtext = mtext.substr( pos+1 ); - pos = mtext.find_first_of( charsToEncode ); - } - stream() << mtext; - } - bool m_tagIsOpen; bool m_needsNewline; std::vector m_tags; @@ -201,4 +232,6 @@ namespace Catch { }; } +#include "catch_reenable_warnings.h" + #endif // TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp index 865dc29e..4fdeb195 100644 --- a/include/reporters/catch_reporter_bases.hpp +++ b/include/reporters/catch_reporter_bases.hpp @@ -19,47 +19,53 @@ namespace Catch { StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } - virtual ~StreamingReporterBase(); + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } - virtual void noMatchingTestCases( std::string const& ) {} + virtual ~StreamingReporterBase() CATCH_OVERRIDE; - virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { currentTestRunInfo = _testRunInfo; } - virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { currentGroupInfo = _groupInfo; } - virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { currentTestCaseInfo = _testInfo; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_sectionStack.push_back( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); } - virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { currentGroupInfo.reset(); } - virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } - virtual void skipTest( TestCaseInfo const& ) { + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } - Ptr m_config; + Ptr m_config; std::ostream& stream; LazyStat currentTestRunInfo; @@ -67,6 +73,7 @@ namespace Catch { LazyStat currentTestCaseInfo; std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; }; struct CumulativeReporterBase : SharedImpl { @@ -118,15 +125,21 @@ namespace Catch { CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } ~CumulativeReporterBase(); - virtual void testRunStarting( TestRunInfo const& ) {} - virtual void testGroupStarting( GroupInfo const& ) {} + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } - virtual void testCaseStarting( TestCaseInfo const& ) {} + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); Ptr node; if( m_sectionStack.empty() ) { @@ -151,7 +164,7 @@ namespace Catch { m_deepestSection = node; } - virtual void assertionStarting( AssertionInfo const& ) {} + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& assertionStats ) { assert( !m_sectionStack.empty() ); @@ -159,13 +172,13 @@ namespace Catch { sectionNode.assertions.push_back( assertionStats ); return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { Ptr node = new TestCaseNode( testCaseStats ); assert( m_sectionStack.size() == 0 ); node->children.push_back( m_rootSection ); @@ -176,12 +189,12 @@ namespace Catch { m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { Ptr node = new TestGroupNode( testGroupStats ); node->children.swap( m_testCases ); m_testGroups.push_back( node ); } - virtual void testRunEnded( TestRunStats const& testRunStats ) { + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { Ptr node = new TestRunNode( testRunStats ); node->children.swap( m_testGroups ); m_testRuns.push_back( node ); @@ -189,9 +202,9 @@ namespace Catch { } virtual void testRunEndedCumulative() = 0; - virtual void skipTest( TestCaseInfo const& ) {} + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} - Ptr m_config; + Ptr m_config; std::ostream& stream; std::vector m_assertions; std::vector > > m_sections; @@ -203,6 +216,7 @@ namespace Catch { Ptr m_rootSection; Ptr m_deepestSection; std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; }; @@ -216,6 +230,18 @@ namespace Catch { return line; } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + } // end namespace Catch #endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED diff --git a/include/reporters/catch_reporter_console.hpp b/include/reporters/catch_reporter_console.hpp index 150cf52a..e7367039 100644 --- a/include/reporters/catch_reporter_console.hpp +++ b/include/reporters/catch_reporter_console.hpp @@ -21,24 +21,19 @@ namespace Catch { m_headerPrinted( false ) {} - virtual ~ConsoleReporter(); + virtual ~ConsoleReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as plain lines of text"; } - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - virtual void noMatchingTestCases( std::string const& spec ) { + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { stream << "No test cases matched '" << spec << "'" << std::endl; } - virtual void assertionStarting( AssertionInfo const& ) { + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; @@ -58,11 +53,11 @@ namespace Catch { return true; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& _sectionStats ) { + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); @@ -84,11 +79,11 @@ namespace Catch { StreamingReporterBase::sectionEnded( _sectionStats ); } - virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } - virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; @@ -97,7 +92,7 @@ namespace Catch { } StreamingReporterBase::testGroupEnded( _testGroupStats ); } - virtual void testRunEnded( TestRunStats const& _testRunStats ) { + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; diff --git a/include/reporters/catch_reporter_junit.hpp b/include/reporters/catch_reporter_junit.hpp index f9524aaf..e656882f 100644 --- a/include/reporters/catch_reporter_junit.hpp +++ b/include/reporters/catch_reporter_junit.hpp @@ -23,28 +23,24 @@ namespace Catch { JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - ~JunitReporter(); + virtual ~JunitReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } - virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - - virtual void testRunStarting( TestRunInfo const& runInfo ) { + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { suiteTimer.start(); stdOutForSuite.str(""); stdErrForSuite.str(""); @@ -52,25 +48,25 @@ namespace Catch { CumulativeReporterBase::testGroupStarting( groupInfo ); } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { stdOutForSuite << testCaseStats.stdOut; stdErrForSuite << testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } - virtual void testRunEndedCumulative() { + virtual void testRunEndedCumulative() CATCH_OVERRIDE { xml.endElement(); } @@ -108,7 +104,7 @@ namespace Catch { SectionNode const& rootSection = *testCaseNode.children.front(); std::string className = stats.testInfo.className; - + if( className.empty() ) { if( rootSection.childSections.empty() ) className = "global"; @@ -122,7 +118,7 @@ namespace Catch { std::string name = trim( sectionNode.stats.sectionInfo.name ); if( !rootName.empty() ) name = rootName + "/" + name; - + if( !sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty() ) { @@ -191,7 +187,7 @@ namespace Catch { elementName = "internalError"; break; } - + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); xml.writeAttribute( "message", result.getExpandedExpression() ); @@ -220,7 +216,7 @@ namespace Catch { unsigned int unexpectedExceptions; }; - INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) } // end namespace Catch diff --git a/include/reporters/catch_reporter_multi.hpp b/include/reporters/catch_reporter_multi.hpp new file mode 100644 index 00000000..d3282666 --- /dev/null +++ b/include/reporters/catch_reporter_multi.hpp @@ -0,0 +1,147 @@ +/* + * Created by Phil on 5/08/2015. + * Copyright 2015 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +#include "../internal/catch_interfaces_reporter.h" + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED diff --git a/include/reporters/catch_reporter_teamcity.hpp b/include/reporters/catch_reporter_teamcity.hpp index 0647244f..1e633f1d 100644 --- a/include/reporters/catch_reporter_teamcity.hpp +++ b/include/reporters/catch_reporter_teamcity.hpp @@ -17,18 +17,22 @@ #include #ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" #endif namespace Catch { - + struct TeamCityReporter : StreamingReporterBase { TeamCityReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_headerPrintedForThisSection( false ) - {} - + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + static std::string escape( std::string const& str ) { std::string escaped = str; replaceInPlace( escaped, "|", "||" ); @@ -39,18 +43,13 @@ namespace Catch { replaceInPlace( escaped, "]", "|]" ); return escaped; } - virtual ~TeamCityReporter(); + virtual ~TeamCityReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as TeamCity service messages"; } - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - virtual void skipTest( TestCaseInfo const& testInfo ) { + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { stream << "##teamcity[testIgnored name='" << escape( testInfo.name ) << "'"; if( testInfo.isHidden() ) @@ -59,35 +58,35 @@ namespace Catch { stream << " message='test skipped because it didn|'t match the test spec'"; stream << "]\n"; } - - virtual void noMatchingTestCases( std::string const& /* spec */ ) {} - - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + + virtual void noMatchingTestCases( std::string const& /* spec */ ) CATCH_OVERRIDE {} + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { StreamingReporterBase::testGroupStarting( groupInfo ); stream << "##teamcity[testSuiteStarted name='" << escape( groupInfo.name ) << "']\n"; } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { StreamingReporterBase::testGroupEnded( testGroupStats ); stream << "##teamcity[testSuiteFinished name='" << escape( testGroupStats.groupInfo.name ) << "']\n"; } - - virtual void assertionStarting( AssertionInfo const& ) { + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = assertionStats.assertionResult; if( !result.isOk() ) { - + std::ostringstream msg; if( !m_headerPrintedForThisSection ) printSectionHeader( msg ); m_headerPrintedForThisSection = true; - + msg << result.getSourceInfo() << "\n"; - + switch( result.getResultType() ) { case ResultWas::ExpressionFailed: msg << "expression failed"; @@ -126,15 +125,15 @@ namespace Catch { it != itEnd; ++it ) msg << "\n \"" << it->message << "\""; - - + + if( result.hasExpression() ) { msg << "\n " << result.getExpressionInMacro() << "\n" "with expansion:\n" << " " << result.getExpandedExpression() << "\n"; } - + stream << "##teamcity[testFailed" << " name='" << escape( currentTestCaseInfo->name )<< "'" << " message='" << escape( msg.str() ) << "'" @@ -142,19 +141,19 @@ namespace Catch { } return true; } - - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { m_headerPrintedForThisSection = false; StreamingReporterBase::sectionStarting( sectionInfo ); } - virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting( testInfo ); stream << "##teamcity[testStarted name='" << escape( testInfo.name ) << "']\n"; } - - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( testCaseStats ); if( !testCaseStats.stdOut.empty() ) stream << "##teamcity[testStdOut name='" @@ -182,9 +181,9 @@ namespace Catch { printHeaderString( os, it->name ); os << getLineOfChars<'-'>() << "\n"; } - + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; - + if( !lineInfo.empty() ) os << lineInfo << "\n"; os << getLineOfChars<'.'>() << "\n\n"; @@ -204,19 +203,19 @@ namespace Catch { } private: bool m_headerPrintedForThisSection; - + }; - + #ifdef CATCH_IMPL TeamCityReporter::~TeamCityReporter() {} #endif - + INTERNAL_CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter ) - + } // end namespace Catch #ifdef __clang__ -#pragma clang diagnostic pop +# pragma clang diagnostic pop #endif #endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED diff --git a/include/reporters/catch_reporter_xml.hpp b/include/reporters/catch_reporter_xml.hpp index d8cb1dd1..bbe8780b 100644 --- a/include/reporters/catch_reporter_xml.hpp +++ b/include/reporters/catch_reporter_xml.hpp @@ -21,26 +21,23 @@ namespace Catch { XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_sectionDepth( 0 ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + virtual ~XmlReporter() CATCH_OVERRIDE; - virtual ~XmlReporter(); - static std::string getDescription() { return "Reports test results as an XML document"; } public: // StreamingReporterBase - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - virtual void noMatchingTestCases( std::string const& s ) { + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { StreamingReporterBase::noMatchingTestCases( s ); } - virtual void testRunStarting( TestRunInfo const& testInfo ) { + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testRunStarting( testInfo ); m_xml.setStream( stream ); m_xml.startElement( "Catch" ); @@ -48,13 +45,13 @@ namespace Catch { m_xml.writeAttribute( "name", m_config->name() ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } - virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); @@ -62,7 +59,7 @@ namespace Catch { m_testCaseTimer.start(); } - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) @@ -71,11 +68,11 @@ namespace Catch { } } - virtual void assertionStarting( AssertionInfo const& ) { } + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { const AssertionResult& assertionResult = assertionStats.assertionResult; - + // Print any info messages in tags. if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); @@ -137,14 +134,14 @@ namespace Catch { default: break; } - + if( assertionResult.hasExpression() ) m_xml.endElement(); - + return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); @@ -159,7 +156,7 @@ namespace Catch { } } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); @@ -170,7 +167,7 @@ namespace Catch { m_xml.endElement(); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) @@ -179,8 +176,8 @@ namespace Catch { .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); m_xml.endElement(); } - - virtual void testRunEnded( TestRunStats const& testRunStats ) { + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt index 240e1ebe..960d9fb1 100644 --- a/projects/CMake/CMakeLists.txt +++ b/projects/CMake/CMakeLists.txt @@ -22,7 +22,7 @@ set(SOURCES ${SELF_TEST_DIR}/GeneratorTests.cpp ${SELF_TEST_DIR}/MessageTests.cpp ${SELF_TEST_DIR}/MiscTests.cpp - ${SELF_TEST_DIR}/SectionTrackerTests.cpp + ${SELF_TEST_DIR}/PartTrackerTests.cpp ${SELF_TEST_DIR}/TestMain.cpp ${SELF_TEST_DIR}/TrickyTests.cpp ${SELF_TEST_DIR}/VariadicMacrosTests.cpp diff --git a/projects/SelfTest/ApproxTests.cpp b/projects/SelfTest/ApproxTests.cpp index 1df76155..53656596 100644 --- a/projects/SelfTest/ApproxTests.cpp +++ b/projects/SelfTest/ApproxTests.cpp @@ -16,7 +16,7 @@ TEST_CASE ) { double d = 1.23; - + REQUIRE( d == Approx( 1.23 ) ); REQUIRE( d != Approx( 1.22 ) ); REQUIRE( d != Approx( 1.24 ) ); @@ -34,7 +34,7 @@ TEST_CASE ) { double d = 1.23; - + REQUIRE( d != Approx( 1.231 ) ); REQUIRE( d == Approx( 1.231 ).epsilon( 0.1 ) ); } @@ -71,7 +71,7 @@ TEST_CASE 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 ).epsilon( 0.001 ) ); @@ -87,14 +87,14 @@ TEST_CASE ) { double d = 1.23; - + Approx approx = Approx::custom().epsilon( 0.005 ); - + 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 ); diff --git a/projects/SelfTest/BDDTests.cpp b/projects/SelfTest/BDDTests.cpp index 3b5c959d..2c8bc249 100644 --- a/projects/SelfTest/BDDTests.cpp +++ b/projects/SelfTest/BDDTests.cpp @@ -30,13 +30,13 @@ SCENARIO( "Vector resizing affects size and capacity", "[vector][bdd][size][capa GIVEN( "an empty vector" ) { std::vector 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" ) { @@ -46,7 +46,7 @@ SCENARIO( "Vector resizing affects size and capacity", "[vector][bdd][size][capa } } } - + WHEN( "we reserve more space" ) { v.reserve( 10 ); THEN( "The capacity is increased but the size remains the same" ) { @@ -76,19 +76,19 @@ struct Fixture : d_counter(0) { } - + int counter() { return d_counter++; } - + int d_counter; }; - + } SCENARIO_METHOD(Fixture, - "BDD tests requiring Fixtures to provide commonly-accessed data or methods", + "BDD tests requiring Fixtures to provide commonly-accessed data or methods", "[bdd][fixtures]") { const int before(counter()); GIVEN("No operations precede me") { diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 3fc76122..976a7105 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -356,7 +356,7 @@ due to unexpected exception with message: expected exception ------------------------------------------------------------------------------- -Unexpected custom exceptions can be translated +Non-std exceptions can be translated ------------------------------------------------------------------------------- ExceptionTests.cpp: ............................................................................... @@ -365,6 +365,16 @@ ExceptionTests.cpp:: FAILED: due to unexpected exception with message: custom exception +------------------------------------------------------------------------------- +Custom std-exceptions can be custom translated +------------------------------------------------------------------------------- +ExceptionTests.cpp: +............................................................................... + +ExceptionTests.cpp:: FAILED: +due to unexpected exception with message: + custom std exception + ------------------------------------------------------------------------------- Custom exceptions can be translated when testing for nothrow ------------------------------------------------------------------------------- @@ -397,6 +407,17 @@ ExceptionTests.cpp:: FAILED: due to unexpected exception with message: 3.14 +------------------------------------------------------------------------------- +Mismatching exception messages failing the test +------------------------------------------------------------------------------- +ExceptionTests.cpp: +............................................................................... + +ExceptionTests.cpp:: FAILED: + REQUIRE_THROWS_WITH( thisThrows(), "should fail" ) +with expansion: + expected exception + ------------------------------------------------------------------------------- INFO and WARN do not abort tests ------------------------------------------------------------------------------- @@ -696,6 +717,29 @@ MiscTests.cpp:: FAILED: with expansion: "this string contains 'abc' as a substring" equals: "something else" +------------------------------------------------------------------------------- +Matchers can be composed with both && and || - failing +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: FAILED: + CHECK_THAT( testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "random" ) ) +with expansion: + "this string contains 'abc' as a substring" ( ( contains: "string" or + contains: "different" ) and contains: "random" ) + +------------------------------------------------------------------------------- +Matchers can be negated (Not) with the ! operator - failing +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: FAILED: + CHECK_THAT( testStringForMatching() !Contains( "substring" ) ) +with expansion: + "this string contains 'abc' as a substring" not contains: "substring" + ------------------------------------------------------------------------------- Nice descriptive name ------------------------------------------------------------------------------- @@ -786,6 +830,6 @@ with expansion: "first" == "second" =============================================================================== -test cases: 155 | 116 passed | 38 failed | 1 failed as expected -assertions: 765 | 673 passed | 79 failed | 13 failed as expected +test cases: 167 | 124 passed | 42 failed | 1 failed as expected +assertions: 914 | 818 passed | 83 failed | 13 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 744fab67..4f3800b9 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -973,51 +973,51 @@ ConditionTests.cpp: ConditionTests.cpp:: PASSED: - REQUIRE( p == __null ) + REQUIRE( p == nullptr ) with expansion: - __null == 0 + NULL == nullptr ConditionTests.cpp:: PASSED: REQUIRE( p == pNULL ) with expansion: - __null == __null + NULL == NULL ConditionTests.cpp:: PASSED: - REQUIRE( p != __null ) + REQUIRE( p != nullptr ) with expansion: - 0x != 0 + 0x != nullptr ConditionTests.cpp:: PASSED: - REQUIRE( cp != __null ) + REQUIRE( cp != nullptr ) with expansion: - 0x != 0 + 0x != nullptr ConditionTests.cpp:: PASSED: - REQUIRE( cpc != __null ) + REQUIRE( cpc != nullptr ) with expansion: - 0x != 0 + 0x != nullptr ConditionTests.cpp:: PASSED: - REQUIRE( returnsNull() == __null ) + REQUIRE( returnsNull() == nullptr ) with expansion: - {null string} == 0 + {null string} == nullptr ConditionTests.cpp:: PASSED: - REQUIRE( returnsConstNull() == __null ) + REQUIRE( returnsConstNull() == nullptr ) with expansion: - {null string} == 0 + {null string} == nullptr ConditionTests.cpp:: PASSED: - REQUIRE( __null != p ) + REQUIRE( nullptr != p ) with expansion: - 0 != 0x + nullptr != 0x ------------------------------------------------------------------------------- 'Not' checks that should succeed @@ -1217,16 +1217,7 @@ due to unexpected exception with message: expected exception ------------------------------------------------------------------------------- -When unchecked exceptions are thrown, but caught, they do not affect the test -------------------------------------------------------------------------------- -ExceptionTests.cpp: -............................................................................... - - -No assertions in test case 'When unchecked exceptions are thrown, but caught, they do not affect the test' - -------------------------------------------------------------------------------- -Unexpected custom exceptions can be translated +Non-std exceptions can be translated ------------------------------------------------------------------------------- ExceptionTests.cpp: ............................................................................... @@ -1235,6 +1226,16 @@ ExceptionTests.cpp:: FAILED: due to unexpected exception with message: custom exception +------------------------------------------------------------------------------- +Custom std-exceptions can be custom translated +------------------------------------------------------------------------------- +ExceptionTests.cpp: +............................................................................... + +ExceptionTests.cpp:: FAILED: +due to unexpected exception with message: + custom std exception + ------------------------------------------------------------------------------- Custom exceptions can be translated when testing for nothrow ------------------------------------------------------------------------------- @@ -1277,6 +1278,66 @@ ExceptionTests.cpp:: PASSED: REQUIRE_THROWS( thisFunctionNotImplemented( 7 ) ) +------------------------------------------------------------------------------- +Exception messages can be tested for + exact match +------------------------------------------------------------------------------- +ExceptionTests.cpp: +............................................................................... + +ExceptionTests.cpp:: +PASSED: + REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ) + +------------------------------------------------------------------------------- +Exception messages can be tested for + different case +------------------------------------------------------------------------------- +ExceptionTests.cpp: +............................................................................... + +ExceptionTests.cpp:: +PASSED: + REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) ) + +------------------------------------------------------------------------------- +Exception messages can be tested for + wildcarded +------------------------------------------------------------------------------- +ExceptionTests.cpp: +............................................................................... + +ExceptionTests.cpp:: +PASSED: + REQUIRE_THROWS_WITH( thisThrows(), StartsWith( "expected" ) ) + +ExceptionTests.cpp:: +PASSED: + REQUIRE_THROWS_WITH( thisThrows(), EndsWith( "exception" ) ) + +ExceptionTests.cpp:: +PASSED: + REQUIRE_THROWS_WITH( thisThrows(), Contains( "except" ) ) + +ExceptionTests.cpp:: +PASSED: + REQUIRE_THROWS_WITH( thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) ) + +------------------------------------------------------------------------------- +Mismatching exception messages failing the test +------------------------------------------------------------------------------- +ExceptionTests.cpp: +............................................................................... + +ExceptionTests.cpp:: +PASSED: + REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ) + +ExceptionTests.cpp:: FAILED: + REQUIRE_THROWS_WITH( thisThrows(), "should fail" ) +with expansion: + expected exception + ------------------------------------------------------------------------------- Generators over two ranges ------------------------------------------------------------------------------- @@ -2608,9 +2669,6 @@ warning: this is a message this is a warning - -No assertions in test case 'INFO and WARN do not abort tests' - ------------------------------------------------------------------------------- SUCCEED counts as a test pass ------------------------------------------------------------------------------- @@ -2857,18 +2915,6 @@ MessageTests.cpp:: FAILED - but was ok: CHECK_NOFAIL( 1 == 2 ) - -No assertions in test case 'The NO_FAIL macro reports a failure but does not fail the test' - -------------------------------------------------------------------------------- -just info -------------------------------------------------------------------------------- -MessageTests.cpp: -............................................................................... - - -No assertions in test case 'just info' - ------------------------------------------------------------------------------- just failure ------------------------------------------------------------------------------- @@ -2905,9 +2951,6 @@ MessageTests.cpp:: warning: toString(p): 0x - -No assertions in test case 'Pointers can be converted to strings' - ------------------------------------------------------------------------------- random SECTION tests s1 @@ -2986,6 +3029,34 @@ MiscTests.cpp:: FAILED: with expansion: 1 == 2 +------------------------------------------------------------------------------- +more nested SECTION tests + s1 + s3 +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( a != b ) +with expansion: + 1 != 2 + +------------------------------------------------------------------------------- +more nested SECTION tests + s1 + s4 +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( a < b ) +with expansion: + 1 < 2 + ------------------------------------------------------------------------------- even more nested SECTION tests c @@ -2994,8 +3065,8 @@ even more nested SECTION tests MiscTests.cpp: ............................................................................... - -No assertions in section 'd (leaf)' +MiscTests.cpp:: +PASSED: ------------------------------------------------------------------------------- even more nested SECTION tests @@ -3005,8 +3076,8 @@ even more nested SECTION tests MiscTests.cpp: ............................................................................... - -No assertions in section 'e (leaf)' +MiscTests.cpp:: +PASSED: ------------------------------------------------------------------------------- even more nested SECTION tests @@ -3015,8 +3086,8 @@ even more nested SECTION tests MiscTests.cpp: ............................................................................... - -No assertions in section 'f (leaf)' +MiscTests.cpp:: +PASSED: ------------------------------------------------------------------------------- looped SECTION tests @@ -3096,15 +3167,6 @@ with message: A string sent directly to stdout A string sent directly to stderr -------------------------------------------------------------------------------- -Sends stuff to stdout and stderr -------------------------------------------------------------------------------- -MiscTests.cpp: -............................................................................... - - -No assertions in test case 'Sends stuff to stdout and stderr' - ------------------------------------------------------------------------------- null strings ------------------------------------------------------------------------------- @@ -3113,13 +3175,13 @@ MiscTests.cpp: MiscTests.cpp:: PASSED: - REQUIRE( makeString( false ) != static_cast(__null) ) + REQUIRE( makeString( false ) != static_cast(nullptr) ) with expansion: "valid string" != {null string} MiscTests.cpp:: PASSED: - REQUIRE( makeString( true ) == static_cast(__null) ) + REQUIRE( makeString( true ) == static_cast(nullptr) ) with expansion: {null string} == {null string} @@ -3198,8 +3260,8 @@ xmlentitycheck MiscTests.cpp: ............................................................................... - -No assertions in section 'embedded xml' +MiscTests.cpp:: +PASSED: ------------------------------------------------------------------------------- xmlentitycheck @@ -3208,8 +3270,8 @@ xmlentitycheck MiscTests.cpp: ............................................................................... - -No assertions in section 'encoded chars' +MiscTests.cpp:: +PASSED: ------------------------------------------------------------------------------- send a single char to INFO @@ -3316,7 +3378,7 @@ MiscTests.cpp: MiscTests.cpp:: PASSED: - REQUIRE_THAT( "" Equals(__null) ) + REQUIRE_THAT( "" Equals(nullptr) ) with expansion: "" equals: "" @@ -3366,6 +3428,87 @@ with expansion: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" +------------------------------------------------------------------------------- +Matchers can be (AllOf) composed with the && operator +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching() Contains( "string" ) && Contains( "abc" ) && Contains( "substring" ) && Contains( "contains" ) ) +with expansion: + "this string contains 'abc' as a substring" ( contains: "string" and + contains: "abc" and contains: "substring" and contains: "contains" ) + +------------------------------------------------------------------------------- +Matchers can be (AnyOf) composed with the || operator +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching() Contains( "string" ) || Contains( "different" ) || Contains( "random" ) ) +with expansion: + "this string contains 'abc' as a substring" ( contains: "string" or contains: + "different" or contains: "random" ) + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching2() Contains( "string" ) || Contains( "different" ) || Contains( "random" ) ) +with expansion: + "some completely different text that contains one common word" ( contains: + "string" or contains: "different" or contains: "random" ) + +------------------------------------------------------------------------------- +Matchers can be composed with both && and || +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "substring" ) ) +with expansion: + "this string contains 'abc' as a substring" ( ( contains: "string" or + contains: "different" ) and contains: "substring" ) + +------------------------------------------------------------------------------- +Matchers can be composed with both && and || - failing +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: FAILED: + CHECK_THAT( testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "random" ) ) +with expansion: + "this string contains 'abc' as a substring" ( ( contains: "string" or + contains: "different" ) and contains: "random" ) + +------------------------------------------------------------------------------- +Matchers can be negated (Not) with the ! operator +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + CHECK_THAT( testStringForMatching() !Contains( "different" ) ) +with expansion: + "this string contains 'abc' as a substring" not contains: "different" + +------------------------------------------------------------------------------- +Matchers can be negated (Not) with the ! operator - failing +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: FAILED: + CHECK_THAT( testStringForMatching() !Contains( "substring" ) ) +with expansion: + "this string contains 'abc' as a substring" not contains: "substring" + ------------------------------------------------------------------------------- Factorials are computed ------------------------------------------------------------------------------- @@ -3402,15 +3545,6 @@ PASSED: with expansion: 3628800 (0x) == 3628800 (0x) -------------------------------------------------------------------------------- -An empty test with no assertions -------------------------------------------------------------------------------- -MiscTests.cpp: -............................................................................... - - -No assertions in test case 'An empty test with no assertions' - ------------------------------------------------------------------------------- Nice descriptive name ------------------------------------------------------------------------------- @@ -3421,27 +3555,6 @@ MiscTests.cpp:: warning: This one ran - -No assertions in test case 'Nice descriptive name' - -------------------------------------------------------------------------------- -first tag -------------------------------------------------------------------------------- -MiscTests.cpp: -............................................................................... - - -No assertions in test case 'first tag' - -------------------------------------------------------------------------------- -second tag -------------------------------------------------------------------------------- -MiscTests.cpp: -............................................................................... - - -No assertions in test case 'second tag' - ------------------------------------------------------------------------------- vectors can be sized and resized ------------------------------------------------------------------------------- @@ -3702,6 +3815,142 @@ PASSED: with expansion: ""wide load"" == ""wide load"" +------------------------------------------------------------------------------- +XmlEncode + normal string +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( "normal string" ) == "normal string" ) +with expansion: + "normal string" == "normal string" + +------------------------------------------------------------------------------- +XmlEncode + empty string +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( "" ) == "" ) +with expansion: + "" == "" + +------------------------------------------------------------------------------- +XmlEncode + string with ampersand +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( "smith & jones" ) == "smith & jones" ) +with expansion: + "smith & jones" == "smith & jones" + +------------------------------------------------------------------------------- +XmlEncode + string with less-than +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( "smith < jones" ) == "smith < jones" ) +with expansion: + "smith < jones" == "smith < jones" + +------------------------------------------------------------------------------- +XmlEncode + string with greater-than +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( "smith > jones" ) == "smith > jones" ) +with expansion: + "smith > jones" == "smith > jones" + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( "smith ]]> jones" ) == "smith ]]> jones" ) +with expansion: + "smith ]]> jones" + == + "smith ]]> jones" + +------------------------------------------------------------------------------- +XmlEncode + string with quotes +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( stringWithQuotes ) == stringWithQuotes ) +with expansion: + "don't "quote" me on that" + == + "don't "quote" me on that" + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't "quote" me on that" ) +with expansion: + "don't "quote" me on that" + == + "don't "quote" me on that" + +------------------------------------------------------------------------------- +XmlEncode + string with control char (1) +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( "[\x01]" ) == "[]" ) +with expansion: + "[]" == "[]" + +------------------------------------------------------------------------------- +XmlEncode + string with control char (x7F) +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( encode( "[\x7F]" ) == "[]" ) +with expansion: + "[]" == "[]" + +------------------------------------------------------------------------------- +long long +------------------------------------------------------------------------------- +MiscTests.cpp: +............................................................................... + +MiscTests.cpp:: +PASSED: + REQUIRE( l == std::numeric_limits::max() ) +with expansion: + 9223372036854775807 (0x) + == + 9223372036854775807 (0x) + ------------------------------------------------------------------------------- Process can be configured on command line default - no arguments @@ -3733,7 +3982,7 @@ with expansion: TestMain.cpp:: PASSED: - CHECK( config.reporterName.empty() ) + CHECK( config.reporterNames.empty() ) with expansion: true @@ -3823,7 +4072,7 @@ PASSED: TestMain.cpp:: PASSED: - REQUIRE( config.reporterName == "console" ) + REQUIRE( config.reporterNames[0] == "console" ) with expansion: "console" == "console" @@ -3841,10 +4090,40 @@ PASSED: TestMain.cpp:: PASSED: - REQUIRE( config.reporterName == "xml" ) + REQUIRE( config.reporterNames[0] == "xml" ) with expansion: "xml" == "xml" +------------------------------------------------------------------------------- +Process can be configured on command line + reporter + -r xml and junit +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK_NOTHROW( parseIntoConfig( argv, config ) ) + +TestMain.cpp:: +PASSED: + REQUIRE( config.reporterNames.size() == 2 ) +with expansion: + 2 == 2 + +TestMain.cpp:: +PASSED: + REQUIRE( config.reporterNames[0] == "xml" ) +with expansion: + "xml" == "xml" + +TestMain.cpp:: +PASSED: + REQUIRE( config.reporterNames[1] == "junit" ) +with expansion: + "junit" == "junit" + ------------------------------------------------------------------------------- Process can be configured on command line reporter @@ -3859,7 +4138,7 @@ PASSED: TestMain.cpp:: PASSED: - REQUIRE( config.reporterName == "junit" ) + REQUIRE( config.reporterNames[0] == "junit" ) with expansion: "junit" == "junit" @@ -4691,15 +4970,6 @@ with expansion: hello hello -------------------------------------------------------------------------------- -Strings can be rendered with colour -------------------------------------------------------------------------------- -TestMain.cpp: -............................................................................... - - -No assertions in test case 'Strings can be rendered with colour' - ------------------------------------------------------------------------------- Text can be formatted using the Text class ------------------------------------------------------------------------------- @@ -5734,6 +6004,17 @@ with expansion: ************************ ... message truncated due to excessive size +------------------------------------------------------------------------------- +ManuallyRegistered +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: +with message: + was called + ------------------------------------------------------------------------------- Parsing a std::pair ------------------------------------------------------------------------------- @@ -5757,9 +6038,6 @@ warning: Uncomment the code in this test to check that it gives a sensible compiler error - -No assertions in test case 'Where there is more to the expression after the RHS' - ------------------------------------------------------------------------------- Where the LHS is not a simple value ------------------------------------------------------------------------------- @@ -5771,9 +6049,6 @@ warning: Uncomment the code in this test to check that it gives a sensible compiler error - -No assertions in test case 'Where the LHS is not a simple value' - ------------------------------------------------------------------------------- A failing expression with a non streamable type is still captured ------------------------------------------------------------------------------- @@ -5863,9 +6138,9 @@ TrickyTests.cpp: TrickyTests.cpp:: PASSED: - REQUIRE( obj.prop != __null ) + REQUIRE( obj.prop != nullptr ) with expansion: - 0x != 0 + 0x != nullptr ------------------------------------------------------------------------------- (unimplemented) static bools can be evaluated @@ -6106,7 +6381,7 @@ TrickyTests.cpp:: PASSED: REQUIRE( p == 0 ) with expansion: - __null == 0 + NULL == 0 ------------------------------------------------------------------------------- null_ptr @@ -6118,7 +6393,7 @@ TrickyTests.cpp:: PASSED: REQUIRE( ptr.get() == nullptr ) with expansion: - __null == nullptr + NULL == nullptr ------------------------------------------------------------------------------- X/level/0/a @@ -6238,6 +6513,1004 @@ with expansion: == "{ StringMaker }" +------------------------------------------------------------------------------- +Tracker +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isOpen() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker + successfully close one section +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isSuccessfullyCompleted() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( ctx.completedCycle() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isSuccessfullyCompleted() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isOpen() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker + fail one section +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isSuccessfullyCompleted() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( ctx.completedCycle() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isSuccessfullyCompleted() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + fail one section + re-enter after failed section +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isOpen() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( ctx.completedCycle() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isSuccessfullyCompleted() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isOpen() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker + fail one section +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isSuccessfullyCompleted() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( ctx.completedCycle() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isSuccessfullyCompleted() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + fail one section + re-enter after failed section and find next section +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isOpen() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( ctx.completedCycle() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isSuccessfullyCompleted() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isOpen() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker + successfully close one section, then find another +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isOpen() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + successfully close one section, then find another + Re-enter - skips S1 and enters S2 +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isOpen() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2b.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( ctx.completedCycle() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + successfully close one section, then find another + Re-enter - skips S1 and enters S2 + Successfully close S2 +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( ctx.completedCycle() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2b.isSuccessfullyCompleted() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isSuccessfullyCompleted() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isOpen() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker + successfully close one section, then find another +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isOpen() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + successfully close one section, then find another + Re-enter - skips S1 and enters S2 +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isOpen() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2b.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( ctx.completedCycle() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + successfully close one section, then find another + Re-enter - skips S1 and enters S2 + fail S2 +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( ctx.completedCycle() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2b.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2b.isSuccessfullyCompleted() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isSuccessfullyCompleted() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase3.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1c.isOpen() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2c.isOpen() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase3.isSuccessfullyCompleted() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isOpen() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker + open a nested section +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isOpen() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker + start a generator +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1.index() == 0 ) +with expansion: + 0 == 0 + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + start a generator + close outer section +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isSuccessfullyCompleted() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + start a generator + close outer section + Re-enter for second generation +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1b.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1b.index() == 1 ) +with expansion: + 1 == 1 + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1b.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isComplete() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isOpen() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker + start a generator +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1.index() == 0 ) +with expansion: + 0 == 0 + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + start a generator + Start a new inner section +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + start a generator + Start a new inner section + Re-enter for second generation +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1b.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1b.index() == 1 ) +with expansion: + 1 == 1 + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2b.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2b.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1b.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isComplete() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isOpen() ) +with expansion: + true + +------------------------------------------------------------------------------- +Tracker + start a generator +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1.index() == 0 ) +with expansion: + 0 == 0 + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + start a generator + Fail an inner section +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2.isSuccessfullyCompleted() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase.isComplete() == false ) +with expansion: + false == false + +------------------------------------------------------------------------------- +Tracker + start a generator + Fail an inner section + Re-enter for second generation +------------------------------------------------------------------------------- +PartTrackerTests.cpp: +............................................................................... + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1b.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1b.index() == 0 ) +with expansion: + 0 == 0 + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2b.isOpen() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1b.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1b.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase2.isComplete() == false ) +with expansion: + false == false + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase3.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1c.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1c.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1c.index() == 1 ) +with expansion: + 1 == 1 + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2c.isOpen() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s2c.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( g1c.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( s1c.isComplete() ) +with expansion: + true + +PartTrackerTests.cpp:: +PASSED: + REQUIRE( testCase3.isComplete() ) +with expansion: + true + ------------------------------------------------------------------------------- std::pair -> toString ------------------------------------------------------------------------------- @@ -7771,179 +9044,7 @@ PASSED: with expansion: 1 > 0 -------------------------------------------------------------------------------- -section tracking -------------------------------------------------------------------------------- -SectionTrackerTests.cpp: -............................................................................... - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.isCompleted() ) -with expansion: - !false - -------------------------------------------------------------------------------- -section tracking - test case with no sections -------------------------------------------------------------------------------- -SectionTrackerTests.cpp: -............................................................................... - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.isCompleted() ) -with expansion: - !false - -SectionTrackerTests.cpp:: -PASSED: - CHECK( testCaseTracker.isCompleted() ) -with expansion: - true - -------------------------------------------------------------------------------- -section tracking -------------------------------------------------------------------------------- -SectionTrackerTests.cpp: -............................................................................... - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.isCompleted() ) -with expansion: - !false - -------------------------------------------------------------------------------- -section tracking - test case with one section -------------------------------------------------------------------------------- -SectionTrackerTests.cpp: -............................................................................... - -SectionTrackerTests.cpp:: -PASSED: - CHECK( testCaseTracker.enterSection( section1Name ) ) -with expansion: - true - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.isCompleted() ) -with expansion: - !false - -SectionTrackerTests.cpp:: -PASSED: - CHECK( testCaseTracker.isCompleted() ) -with expansion: - true - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.enterSection( section1Name ) ) -with expansion: - !false - -------------------------------------------------------------------------------- -section tracking -------------------------------------------------------------------------------- -SectionTrackerTests.cpp: -............................................................................... - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.isCompleted() ) -with expansion: - !false - -------------------------------------------------------------------------------- -section tracking - test case with two consecutive sections -------------------------------------------------------------------------------- -SectionTrackerTests.cpp: -............................................................................... - -SectionTrackerTests.cpp:: -PASSED: - CHECK( testCaseTracker.enterSection( section1Name ) ) -with expansion: - true - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.enterSection( section2Name ) ) -with expansion: - !false - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.isCompleted() ) -with expansion: - !false - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.enterSection( section1Name ) ) -with expansion: - !false - -SectionTrackerTests.cpp:: -PASSED: - CHECK( testCaseTracker.enterSection( section2Name ) ) -with expansion: - true - -SectionTrackerTests.cpp:: -PASSED: - CHECK( testCaseTracker.isCompleted() ) -with expansion: - true - -------------------------------------------------------------------------------- -section tracking -------------------------------------------------------------------------------- -SectionTrackerTests.cpp: -............................................................................... - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.isCompleted() ) -with expansion: - !false - -------------------------------------------------------------------------------- -section tracking - test case with one section within another -------------------------------------------------------------------------------- -SectionTrackerTests.cpp: -............................................................................... - -SectionTrackerTests.cpp:: -PASSED: - CHECK( testCaseTracker.enterSection( section1Name ) ) -with expansion: - true - -SectionTrackerTests.cpp:: -PASSED: - CHECK( testCaseTracker.enterSection( section2Name ) ) -with expansion: - true - -SectionTrackerTests.cpp:: -PASSED: - CHECK_FALSE( testCaseTracker.isCompleted() ) -with expansion: - !false - -SectionTrackerTests.cpp:: -PASSED: - CHECK( testCaseTracker.isCompleted() ) -with expansion: - true - =============================================================================== -test cases: 155 | 100 passed | 54 failed | 1 failed as expected -assertions: 785 | 673 passed | 99 failed | 13 failed as expected +test cases: 167 | 123 passed | 43 failed | 1 failed as expected +assertions: 916 | 818 passed | 85 failed | 13 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index 48b84679..18792059 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,5 +1,5 @@ - + @@ -226,9 +226,15 @@ expected exception ExceptionTests.cpp: - + custom exception +ExceptionTests.cpp: + + + + +custom std exception ExceptionTests.cpp: @@ -251,6 +257,14 @@ ExceptionTests.cpp: + + + + + +ExceptionTests.cpp: + + @@ -333,6 +347,11 @@ MessageTests.cpp: MiscTests.cpp: + + + + + MiscTests.cpp: @@ -391,6 +410,8 @@ MiscTests.cpp: MiscTests.cpp: + + 3 @@ -423,6 +444,20 @@ MiscTests.cpp: + + + + + +MiscTests.cpp: + + + + + +MiscTests.cpp: + + @@ -455,12 +490,22 @@ MiscTests.cpp: + + + + + + + + + + @@ -502,6 +547,7 @@ hello + @@ -548,6 +594,23 @@ TrickyTests.cpp: + + + + + + + + + + + + + + + + + @@ -607,11 +670,6 @@ TrickyTests.cpp: - - - - - Message from section one Message from section two diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index c0a75b73..407c8928 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -1,20 +1,20 @@ - + - Catch::toString(e0) == "0" + Catch::toString(e0) == "0" - "0" == "0" + "0" == "0" - Catch::toString(e1) == "1" + Catch::toString(e1) == "1" - "1" == "1" + "1" == "1" @@ -22,18 +22,18 @@ - Catch::toString(e0) == "E2{0}" + Catch::toString(e0) == "E2{0}" - "E2{0}" == "E2{0}" + "E2{0}" == "E2{0}" - Catch::toString(e1) == "E2{1}" + Catch::toString(e1) == "E2{1}" - "E2{1}" == "E2{1}" + "E2{1}" == "E2{1}" @@ -41,18 +41,18 @@ - Catch::toString(e0) == "0" + Catch::toString(e0) == "0" - "0" == "0" + "0" == "0" - Catch::toString(e1) == "1" + Catch::toString(e1) == "1" - "1" == "1" + "1" == "1" @@ -60,28 +60,28 @@ - Catch::toString(e0) == "E2/V0" + Catch::toString(e0) == "E2/V0" - "E2/V0" == "E2/V0" + "E2/V0" == "E2/V0" - Catch::toString(e1) == "E2/V1" + Catch::toString(e1) == "E2/V1" - "E2/V1" == "E2/V1" + "E2/V1" == "E2/V1" - Catch::toString(e3) == "Unknown enum value 10" + Catch::toString(e3) == "Unknown enum value 10" - "Unknown enum value 10" + "Unknown enum value 10" == -"Unknown enum value 10" +"Unknown enum value 10" @@ -326,10 +326,10 @@ - s == "hello" + s == "hello" - "hello" == "hello" + "hello" == "hello" @@ -337,10 +337,10 @@ - s == "world" + s == "world" - "hello" == "world" + "hello" == "world" @@ -394,18 +394,18 @@ - data.str_hello == "hello" + data.str_hello == "hello" - "hello" == "hello" + "hello" == "hello" - "hello" == data.str_hello + "hello" == data.str_hello - "hello" == "hello" + "hello" == "hello" @@ -493,26 +493,26 @@ - data.str_hello == "goodbye" + data.str_hello == "goodbye" - "hello" == "goodbye" + "hello" == "goodbye" - data.str_hello == "hell" + data.str_hello == "hell" - "hello" == "hell" + "hello" == "hell" - data.str_hello == "hello1" + data.str_hello == "hello1" - "hello" == "hello1" + "hello" == "hello1" @@ -592,26 +592,26 @@ - data.str_hello != "goodbye" + data.str_hello != "goodbye" - "hello" != "goodbye" + "hello" != "goodbye" - data.str_hello != "hell" + data.str_hello != "hell" - "hello" != "hell" + "hello" != "hell" - data.str_hello != "hello1" + data.str_hello != "hello1" - "hello" != "hello1" + "hello" != "hello1" @@ -651,10 +651,10 @@ - data.str_hello != "hello" + data.str_hello != "hello" - "hello" != "hello" + "hello" != "hello" @@ -758,50 +758,50 @@ - data.str_hello <= "hello" + data.str_hello <= "hello" - "hello" <= "hello" + "hello" <= "hello" - data.str_hello >= "hello" + data.str_hello >= "hello" - "hello" >= "hello" + "hello" >= "hello" - data.str_hello < "hellp" + data.str_hello < "hellp" - "hello" < "hellp" + "hello" < "hellp" - data.str_hello < "zebra" + data.str_hello < "zebra" - "hello" < "zebra" + "hello" < "zebra" - data.str_hello > "hellm" + data.str_hello > "hellm" - "hello" > "hellm" + "hello" > "hellm" - data.str_hello > "a" + data.str_hello > "a" - "hello" > "a" + "hello" > "a" @@ -897,66 +897,66 @@ - data.str_hello > "hello" + data.str_hello > "hello" - "hello" > "hello" + "hello" > "hello" - data.str_hello < "hello" + data.str_hello < "hello" - "hello" < "hello" + "hello" < "hello" - data.str_hello > "hellp" + data.str_hello > "hellp" - "hello" > "hellp" + "hello" > "hellp" - data.str_hello > "z" + data.str_hello > "z" - "hello" > "z" + "hello" > "z" - data.str_hello < "hellm" + data.str_hello < "hellm" - "hello" < "hellm" + "hello" < "hellm" - data.str_hello < "a" + data.str_hello < "a" - "hello" < "a" + "hello" < "a" - data.str_hello >= "z" + data.str_hello >= "z" - "hello" >= "z" + "hello" >= "z" - data.str_hello <= "a" + data.str_hello <= "a" - "hello" <= "a" + "hello" <= "a" @@ -1205,10 +1205,10 @@ - p == __null + p == nullptr - __null == 0 + NULL == nullptr @@ -1216,55 +1216,55 @@ p == pNULL - __null == __null + NULL == NULL - p != __null + p != nullptr - 0x != 0 + 0x != nullptr - cp != __null + cp != nullptr - 0x != 0 + 0x != nullptr - cpc != __null + cpc != nullptr - 0x != 0 + 0x != nullptr - returnsNull() == __null + returnsNull() == nullptr - {null string} == 0 + {null string} == nullptr - returnsConstNull() == __null + returnsConstNull() == nullptr - {null string} == 0 + {null string} == nullptr - __null != p + nullptr != p - 0 != 0x + nullptr != 0x @@ -1543,14 +1543,20 @@ - + - + custom exception + + + custom std exception + + + @@ -1596,6 +1602,85 @@ + +
+ + + thisThrows(), "expected exception" + + + thisThrows(), "expected exception" + + + +
+
+ + + thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) + + + thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) + + + +
+
+ + + thisThrows(), StartsWith( "expected" ) + + + thisThrows(), StartsWith( "expected" ) + + + + + thisThrows(), EndsWith( "exception" ) + + + thisThrows(), EndsWith( "exception" ) + + + + + thisThrows(), Contains( "except" ) + + + thisThrows(), Contains( "except" ) + + + + + thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) + + + thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) + + + +
+ +
+ + + + thisThrows(), "expected exception" + + + thisThrows(), "expected exception" + + + + + thisThrows(), "should fail" + + + expected exception + + + + @@ -2777,7 +2862,7 @@ this is a warning - + @@ -2983,10 +3068,10 @@ 1 == 2 - + - + @@ -3018,7 +3103,7 @@ toString(p): 0x - +
@@ -3101,25 +3186,53 @@
+
+
+ + + a != b + + + 1 != 2 + + + +
+ +
+
+
+ + + a < b + + + 1 < 2 + + + +
+ +
- +
- +
- +
- +
- +
- +
@@ -3221,20 +3334,20 @@ - + - makeString( false ) != static_cast<char*>(__null) + makeString( false ) != static_cast<char*>(nullptr) - "valid string" != {null string} + "valid string" != {null string} - makeString( true ) == static_cast<char*>(__null) + makeString( true ) == static_cast<char*>(nullptr) {null string} == {null string} @@ -3320,12 +3433,12 @@
- +
- +
- +
@@ -3355,34 +3468,34 @@ - testStringForMatching() Contains( "string" ) + testStringForMatching() Contains( "string" ) - "this string contains 'abc' as a substring" contains: "string" + "this string contains 'abc' as a substring" contains: "string" - testStringForMatching() Contains( "abc" ) + testStringForMatching() Contains( "abc" ) - "this string contains 'abc' as a substring" contains: "abc" + "this string contains 'abc' as a substring" contains: "abc" - testStringForMatching() StartsWith( "this" ) + testStringForMatching() StartsWith( "this" ) - "this string contains 'abc' as a substring" starts with: "this" + "this string contains 'abc' as a substring" starts with: "this" - testStringForMatching() EndsWith( "substring" ) + testStringForMatching() EndsWith( "substring" ) - "this string contains 'abc' as a substring" ends with: "substring" + "this string contains 'abc' as a substring" ends with: "substring" @@ -3390,10 +3503,10 @@ - testStringForMatching() Contains( "not there" ) + testStringForMatching() Contains( "not there" ) - "this string contains 'abc' as a substring" contains: "not there" + "this string contains 'abc' as a substring" contains: "not there" @@ -3401,10 +3514,10 @@ - testStringForMatching() StartsWith( "string" ) + testStringForMatching() StartsWith( "string" ) - "this string contains 'abc' as a substring" starts with: "string" + "this string contains 'abc' as a substring" starts with: "string" @@ -3412,10 +3525,10 @@ - testStringForMatching() EndsWith( "this" ) + testStringForMatching() EndsWith( "this" ) - "this string contains 'abc' as a substring" ends with: "this" + "this string contains 'abc' as a substring" ends with: "this" @@ -3423,10 +3536,10 @@ - testStringForMatching() Equals( "something else" ) + testStringForMatching() Equals( "something else" ) - "this string contains 'abc' as a substring" equals: "something else" + "this string contains 'abc' as a substring" equals: "something else" @@ -3434,10 +3547,10 @@ - "" Equals(__null) + "" Equals(nullptr) - "" equals: "" + "" equals: "" @@ -3445,10 +3558,10 @@ - testStringForMatching() AllOf( Catch::Contains( "string" ), Catch::Contains( "abc" ) ) + testStringForMatching() AllOf( Catch::Contains( "string" ), Catch::Contains( "abc" ) ) - "this string contains 'abc' as a substring" ( contains: "string" and contains: "abc" ) + "this string contains 'abc' as a substring" ( contains: "string" and contains: "abc" ) @@ -3456,18 +3569,18 @@ - testStringForMatching() AnyOf( Catch::Contains( "string" ), Catch::Contains( "not there" ) ) + testStringForMatching() AnyOf( Catch::Contains( "string" ), Catch::Contains( "not there" ) ) - "this string contains 'abc' as a substring" ( contains: "string" or contains: "not there" ) + "this string contains 'abc' as a substring" ( contains: "string" or contains: "not there" ) - testStringForMatching() AnyOf( Catch::Contains( "not there" ), Catch::Contains( "string" ) ) + testStringForMatching() AnyOf( Catch::Contains( "not there" ), Catch::Contains( "string" ) ) - "this string contains 'abc' as a substring" ( contains: "not there" or contains: "string" ) + "this string contains 'abc' as a substring" ( contains: "not there" or contains: "string" ) @@ -3475,14 +3588,88 @@ - testStringForMatching() Equals( "this string contains 'abc' as a substring" ) + testStringForMatching() Equals( "this string contains 'abc' as a substring" ) - "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" + "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" + + + + testStringForMatching() Contains( "string" ) && Contains( "abc" ) && Contains( "substring" ) && Contains( "contains" ) + + + "this string contains 'abc' as a substring" ( contains: "string" and contains: "abc" and contains: "substring" and contains: "contains" ) + + + + + + + + testStringForMatching() Contains( "string" ) || Contains( "different" ) || Contains( "random" ) + + + "this string contains 'abc' as a substring" ( contains: "string" or contains: "different" or contains: "random" ) + + + + + testStringForMatching2() Contains( "string" ) || Contains( "different" ) || Contains( "random" ) + + + "some completely different text that contains one common word" ( contains: "string" or contains: "different" or contains: "random" ) + + + + + + + + testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "substring" ) + + + "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "substring" ) + + + + + + + + testStringForMatching() ( Contains( "string" ) || Contains( "different" ) ) && Contains( "random" ) + + + "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" ) + + + + + + + + testStringForMatching() !Contains( "different" ) + + + "this string contains 'abc' as a substring" not contains: "different" + + + + + + + + testStringForMatching() !Contains( "substring" ) + + + "this string contains 'abc' as a substring" not contains: "substring" + + + + @@ -3527,19 +3714,19 @@ - + This one ran - + - + - + @@ -3716,14 +3903,14 @@ s1 == s2 - "if ($b == 10) { + "if ($b == 10) { $a = 20; -}" +}" == -"if ($b == 10) { +"if ($b == 10) { $a = 20; } -" +" @@ -3731,10 +3918,10 @@ - result == "\"wide load\"" + result == "\"wide load\"" - ""wide load"" == ""wide load"" + ""wide load"" == ""wide load"" @@ -3742,10 +3929,10 @@ - result == "\"wide load\"" + result == "\"wide load\"" - ""wide load"" == ""wide load"" + ""wide load"" == ""wide load"" @@ -3753,10 +3940,10 @@ - result == "\"wide load\"" + result == "\"wide load\"" - ""wide load"" == ""wide load"" + ""wide load"" == ""wide load"" @@ -3764,10 +3951,136 @@ - result == "\"wide load\"" + result == "\"wide load\"" - ""wide load"" == ""wide load"" + ""wide load"" == ""wide load"" + + + + + +
+ + + encode( "normal string" ) == "normal string" + + + "normal string" == "normal string" + + + +
+
+ + + encode( "" ) == "" + + + "" == "" + + + +
+
+ + + encode( "smith & jones" ) == "smith &amp; jones" + + + "smith &amp; jones" == "smith &amp; jones" + + + +
+
+ + + encode( "smith < jones" ) == "smith &lt; jones" + + + "smith &lt; jones" == "smith &lt; jones" + + + +
+
+ + + encode( "smith > jones" ) == "smith > jones" + + + "smith > jones" == "smith > jones" + + + + + encode( "smith ]]> jones" ) == "smith ]]&gt; jones" + + + "smith ]]&gt; jones" +== +"smith ]]&gt; jones" + + + +
+
+ + + encode( stringWithQuotes ) == stringWithQuotes + + + "don't "quote" me on that" +== +"don't "quote" me on that" + + + + + encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't &quot;quote&quot; me on that" + + + "don't &quot;quote&quot; me on that" +== +"don't &quot;quote&quot; me on that" + + + +
+
+ + + encode( "[\x01]" ) == "[&#x1]" + + + "[&#x1]" == "[&#x1]" + + + +
+
+ + + encode( "[\x7F]" ) == "[&#x7F]" + + + "[&#x7F]" == "[&#x7F]" + + + +
+ +
+ + + + l == std::numeric_limits<long long>::max() + + + 9223372036854775807 (0x) +== +9223372036854775807 (0x) @@ -3808,7 +4121,7 @@ - config.reporterName.empty() + config.reporterNames.empty() true @@ -3828,7 +4141,7 @@ - cfg.testSpec().matches( fakeTestCase( "notIncluded" ) ) == false + cfg.testSpec().matches( fakeTestCase( "notIncluded" ) ) == false false == false @@ -3836,7 +4149,7 @@ - cfg.testSpec().matches( fakeTestCase( "test1" ) ) + cfg.testSpec().matches( fakeTestCase( "test1" ) ) true @@ -3858,7 +4171,7 @@ - cfg.testSpec().matches( fakeTestCase( "test1" ) ) == false + cfg.testSpec().matches( fakeTestCase( "test1" ) ) == false false == false @@ -3866,7 +4179,7 @@ - cfg.testSpec().matches( fakeTestCase( "alwaysIncluded" ) ) + cfg.testSpec().matches( fakeTestCase( "alwaysIncluded" ) ) true @@ -3888,7 +4201,7 @@ - cfg.testSpec().matches( fakeTestCase( "test1" ) ) == false + cfg.testSpec().matches( fakeTestCase( "test1" ) ) == false false == false @@ -3896,7 +4209,7 @@ - cfg.testSpec().matches( fakeTestCase( "alwaysIncluded" ) ) + cfg.testSpec().matches( fakeTestCase( "alwaysIncluded" ) ) true @@ -3918,10 +4231,10 @@ - config.reporterName == "console" + config.reporterNames[0] == "console" - "console" == "console" + "console" == "console" @@ -3940,16 +4253,54 @@ - config.reporterName == "xml" + config.reporterNames[0] == "xml" - "xml" == "xml" + "xml" == "xml"
+
+
+ + + parseIntoConfig( argv, config ) + + + parseIntoConfig( argv, config ) + + + + + config.reporterNames.size() == 2 + + + 2 == 2 + + + + + config.reporterNames[0] == "xml" + + + "xml" == "xml" + + + + + config.reporterNames[1] == "junit" + + + "junit" == "junit" + + + +
+ +
@@ -3962,10 +4313,10 @@ - config.reporterName == "junit" + config.reporterNames[0] == "junit" - "junit" == "junit" + "junit" == "junit" @@ -4064,11 +4415,11 @@
- parseIntoConfigAndReturnError( argv, config ) Contains( "greater than zero" ) + parseIntoConfigAndReturnError( argv, config ) Contains( "greater than zero" ) - "Value after -x or --abortAfter must be greater than zero -- while parsing: (-x, --abortx <no. failures>)" contains: "greater than zero" + "Value after -x or --abortAfter must be greater than zero +- while parsing: (-x, --abortx <no. failures>)" contains: "greater than zero" @@ -4079,11 +4430,11 @@
- parseIntoConfigAndReturnError( argv, config ) Contains( "-x" ) + parseIntoConfigAndReturnError( argv, config ) Contains( "-x" ) - "Unable to convert oops to destination type -- while parsing: (-x, --abortx <no. failures>)" contains: "-x" + "Unable to convert oops to destination type +- while parsing: (-x, --abortx <no. failures>)" contains: "-x" @@ -4146,10 +4497,10 @@ - config.outputFilename == "filename.ext" + config.outputFilename == "filename.ext" - "filename.ext" == "filename.ext" + "filename.ext" == "filename.ext" @@ -4168,10 +4519,10 @@ - config.outputFilename == "filename.ext" + config.outputFilename == "filename.ext" - "filename.ext" == "filename.ext" + "filename.ext" == "filename.ext" @@ -4270,9 +4621,9 @@ Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString - "one two three four" + "one two three four" == -"one two three four" +"one two three four" @@ -4280,9 +4631,9 @@ Text( testString, TextAttributes().setWidth( 18 ) ).toString() == testString - "one two three four" + "one two three four" == -"one two three four" +"one two three four" @@ -4293,62 +4644,62 @@
- Text( testString, TextAttributes().setWidth( 17 ) ).toString() == "one two three\nfour" + Text( testString, TextAttributes().setWidth( 17 ) ).toString() == "one two three\nfour" - "one two three -four" + "one two three +four" == -"one two three -four" +"one two three +four" - Text( testString, TextAttributes().setWidth( 16 ) ).toString() == "one two three\nfour" + Text( testString, TextAttributes().setWidth( 16 ) ).toString() == "one two three\nfour" - "one two three -four" + "one two three +four" == -"one two three -four" +"one two three +four" - Text( testString, TextAttributes().setWidth( 14 ) ).toString() == "one two three\nfour" + Text( testString, TextAttributes().setWidth( 14 ) ).toString() == "one two three\nfour" - "one two three -four" + "one two three +four" == -"one two three -four" +"one two three +four" - Text( testString, TextAttributes().setWidth( 13 ) ).toString() == "one two three\nfour" + Text( testString, TextAttributes().setWidth( 13 ) ).toString() == "one two three\nfour" - "one two three -four" + "one two three +four" == -"one two three -four" +"one two three +four" - Text( testString, TextAttributes().setWidth( 12 ) ).toString() == "one two\nthree four" + Text( testString, TextAttributes().setWidth( 12 ) ).toString() == "one two\nthree four" - "one two -three four" + "one two +three four" == -"one two -three four" +"one two +three four" @@ -4359,44 +4710,44 @@ three four"
- Text( testString, TextAttributes().setWidth( 9 ) ).toString() == "one two\nthree\nfour" + Text( testString, TextAttributes().setWidth( 9 ) ).toString() == "one two\nthree\nfour" - "one two + "one two three -four" +four" == -"one two +"one two three -four" +four" - Text( testString, TextAttributes().setWidth( 8 ) ).toString() == "one two\nthree\nfour" + Text( testString, TextAttributes().setWidth( 8 ) ).toString() == "one two\nthree\nfour" - "one two + "one two three -four" +four" == -"one two +"one two three -four" +four" - Text( testString, TextAttributes().setWidth( 7 ) ).toString() == "one two\nthree\nfour" + Text( testString, TextAttributes().setWidth( 7 ) ).toString() == "one two\nthree\nfour" - "one two + "one two three -four" +four" == -"one two +"one two three -four" +four" @@ -4407,34 +4758,34 @@ four"
- Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one\ntwo\nthree\nfour" + Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one\ntwo\nthree\nfour" - "one + "one two three -four" +four" == -"one +"one two three -four" +four" - Text( testString, TextAttributes().setWidth( 5 ) ).toString() == "one\ntwo\nthree\nfour" + Text( testString, TextAttributes().setWidth( 5 ) ).toString() == "one\ntwo\nthree\nfour" - "one + "one two three -four" +four" == -"one +"one two three -four" +four" @@ -4445,78 +4796,78 @@ four"
- Text( "abcdef", TextAttributes().setWidth( 4 ) ).toString() == "abc-\ndef" + Text( "abcdef", TextAttributes().setWidth( 4 ) ).toString() == "abc-\ndef" - "abc- -def" + "abc- +def" == -"abc- -def" +"abc- +def" - Text( "abcdefg", TextAttributes().setWidth( 4 ) ).toString() == "abc-\ndefg" + Text( "abcdefg", TextAttributes().setWidth( 4 ) ).toString() == "abc-\ndefg" - "abc- -defg" + "abc- +defg" == -"abc- -defg" +"abc- +defg" - Text( "abcdefgh", TextAttributes().setWidth( 4 ) ).toString() == "abc-\ndef-\ngh" + Text( "abcdefgh", TextAttributes().setWidth( 4 ) ).toString() == "abc-\ndef-\ngh" - "abc- + "abc- def- -gh" +gh" == -"abc- +"abc- def- -gh" +gh" - Text( testString, TextAttributes().setWidth( 4 ) ).toString() == "one\ntwo\nthr-\nee\nfour" + Text( testString, TextAttributes().setWidth( 4 ) ).toString() == "one\ntwo\nthr-\nee\nfour" - "one + "one two thr- ee -four" +four" == -"one +"one two thr- ee -four" +four" - Text( testString, TextAttributes().setWidth( 3 ) ).toString() == "one\ntwo\nth-\nree\nfo-\nur" + Text( testString, TextAttributes().setWidth( 3 ) ).toString() == "one\ntwo\nth-\nree\nfo-\nur" - "one + "one two th- ree fo- -ur" +ur" == -"one +"one two th- ree fo- -ur" +ur" @@ -4535,34 +4886,34 @@ ur" - text[0] == "one" + text[0] == "one" - "one" == "one" + "one" == "one" - text[1] == "two" + text[1] == "two" - "two" == "two" + "two" == "two" - text[2] == "three" + text[2] == "three" - "three" == "three" + "three" == "three" - text[3] == "four" + text[3] == "four" - "four" == "four" + "four" == "four" @@ -4573,16 +4924,16 @@ ur"
- text.toString() == " one two\n three\n four" + text.toString() == " one two\n three\n four" - " one two + " one two three - four" + four" == -" one two +" one two three - four" + four" @@ -4596,11 +4947,11 @@ ur" Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString - "one two -three four" + "one two +three four" == -"one two -three four" +"one two +three four" @@ -4608,11 +4959,11 @@ three four" Text( testString, TextAttributes().setWidth( 18 ) ).toString() == testString - "one two -three four" + "one two +three four" == -"one two -three four" +"one two +three four" @@ -4620,11 +4971,11 @@ three four" Text( testString, TextAttributes().setWidth( 10 ) ).toString() == testString - "one two -three four" + "one two +three four" == -"one two -three four" +"one two +three four" @@ -4635,34 +4986,34 @@ three four"
- Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef\n" + Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef\n" - "abcdef -" + "abcdef +" == -"abcdef -" +"abcdef +" - Text( "abcdef", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" + Text( "abcdef", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" - "abcdef" == "abcdef" + "abcdef" == "abcdef" - Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef\n" + Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef\n" - "abcdef -" + "abcdef +" == -"abcdef -" +"abcdef +" @@ -4673,44 +5024,44 @@ three four"
- Text( testString, TextAttributes().setWidth( 9 ) ).toString() == "one two\nthree\nfour" + Text( testString, TextAttributes().setWidth( 9 ) ).toString() == "one two\nthree\nfour" - "one two + "one two three -four" +four" == -"one two +"one two three -four" +four" - Text( testString, TextAttributes().setWidth( 8 ) ).toString() == "one two\nthree\nfour" + Text( testString, TextAttributes().setWidth( 8 ) ).toString() == "one two\nthree\nfour" - "one two + "one two three -four" +four" == -"one two +"one two three -four" +four" - Text( testString, TextAttributes().setWidth( 7 ) ).toString() == "one two\nthree\nfour" + Text( testString, TextAttributes().setWidth( 7 ) ).toString() == "one two\nthree\nfour" - "one two + "one two three -four" +four" == -"one two +"one two three -four" +four" @@ -4721,18 +5072,18 @@ four"
- Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one\ntwo\nthree\nfour" + Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one\ntwo\nthree\nfour" - "one + "one two three -four" +four" == -"one +"one two three -four" +four" @@ -4742,18 +5093,18 @@ four"
- Text( testString, TextAttributes().setWidth( 15 ) ).toString() == "one two three\n four\n five\n six" + Text( testString, TextAttributes().setWidth( 15 ) ).toString() == "one two three\n four\n five\n six" - "one two three + "one two three four five - six" + six" == -"one two three +"one two three four five - six" + six" @@ -4764,7 +5115,7 @@ four"
- replaceInPlace( letters, "b", "z" ) + replaceInPlace( letters, "b", "z" ) true @@ -4772,10 +5123,10 @@ four" - letters == "azcdefcg" + letters == "azcdefcg" - "azcdefcg" == "azcdefcg" + "azcdefcg" == "azcdefcg" @@ -4783,7 +5134,7 @@ four"
- replaceInPlace( letters, "c", "z" ) + replaceInPlace( letters, "c", "z" ) true @@ -4791,10 +5142,10 @@ four" - letters == "abzdefzg" + letters == "abzdefzg" - "abzdefzg" == "abzdefzg" + "abzdefzg" == "abzdefzg" @@ -4802,7 +5153,7 @@ four"
- replaceInPlace( letters, "a", "z" ) + replaceInPlace( letters, "a", "z" ) true @@ -4810,10 +5161,10 @@ four" - letters == "zbcdefcg" + letters == "zbcdefcg" - "zbcdefcg" == "zbcdefcg" + "zbcdefcg" == "zbcdefcg" @@ -4821,7 +5172,7 @@ four"
- replaceInPlace( letters, "g", "z" ) + replaceInPlace( letters, "g", "z" ) true @@ -4829,10 +5180,10 @@ four" - letters == "abcdefcz" + letters == "abcdefcz" - "abcdefcz" == "abcdefcz" + "abcdefcz" == "abcdefcz" @@ -4840,7 +5191,7 @@ four"
- replaceInPlace( letters, letters, "replaced" ) + replaceInPlace( letters, letters, "replaced" ) true @@ -4848,10 +5199,10 @@ four" - letters == "replaced" + letters == "replaced" - "replaced" == "replaced" + "replaced" == "replaced" @@ -4859,7 +5210,7 @@ four"
- !replaceInPlace( letters, "x", "z" ) + !replaceInPlace( letters, "x", "z" ) !false @@ -4870,7 +5221,7 @@ four" letters == letters - "abcdefcg" == "abcdefcg" + "abcdefcg" == "abcdefcg" @@ -4878,7 +5229,7 @@ four"
- replaceInPlace( s, "'", "|'" ) + replaceInPlace( s, "'", "|'" ) true @@ -4886,10 +5237,10 @@ four" - s == "didn|'t" + s == "didn|'t" - "didn|'t" == "didn|'t" + "didn|'t" == "didn|'t" @@ -4897,27 +5248,27 @@ four" - + - Text( "hi there" ).toString() == "hi there" + Text( "hi there" ).toString() == "hi there" - "hi there" == "hi there" + "hi there" == "hi there" - Text( "hi there", narrow ).toString() == "hi\nthere" + Text( "hi there", narrow ).toString() == "hi\nthere" - "hi -there" + "hi +there" == -"hi -there" +"hi +there" @@ -4925,10 +5276,10 @@ there" - t.toString() EndsWith( "... message truncated due to excessive size" ) + t.toString() EndsWith( "... message truncated due to excessive size" ) - "******************************************************************************- + "******************************************************************************- ******************************************************************************- ************************ ******************************************************************************- @@ -5928,11 +6279,14 @@ there" ******************************************************************************- ************************ ******************************************************************************- -... message truncated due to excessive size" ends with: "... message truncated due to excessive size" +... message truncated due to excessive size" ends with: "... message truncated due to excessive size" + + + @@ -5948,13 +6302,13 @@ there" Uncomment the code in this test to check that it gives a sensible compiler error - + Uncomment the code in this test to check that it gives a sensible compiler error - + @@ -5978,10 +6332,10 @@ there" - std::string( "first" ) == "second" + std::string( "first" ) == "second" - "first" == "second" + "first" == "second" @@ -6041,10 +6395,10 @@ there" - obj.prop != __null + obj.prop != nullptr - 0x != 0 + 0x != nullptr @@ -6224,10 +6578,10 @@ there" - s == "7" + s == "7" - "7" == "7" + "7" == "7" @@ -6270,7 +6624,7 @@ there" p == 0 - __null == 0 + NULL == 0 @@ -6281,7 +6635,7 @@ there" ptr.get() == nullptr - __null == nullptr + NULL == nullptr @@ -6301,12 +6655,12 @@ there" - Catch::toString( item ) == "toString( has_toString )" + Catch::toString( item ) == "toString( has_toString )" - "toString( has_toString )" + "toString( has_toString )" == -"toString( has_toString )" +"toString( has_toString )" @@ -6314,12 +6668,12 @@ there" - Catch::toString( item ) == "StringMaker<has_maker>" + Catch::toString( item ) == "StringMaker<has_maker>" - "StringMaker<has_maker>" + "StringMaker<has_maker>" == -"StringMaker<has_maker>" +"StringMaker<has_maker>" @@ -6327,12 +6681,12 @@ there" - Catch::toString( item ) == "toString( has_maker_and_toString )" + Catch::toString( item ) == "toString( has_maker_and_toString )" - "toString( has_maker_and_toString )" + "toString( has_maker_and_toString )" == -"toString( has_maker_and_toString )" +"toString( has_maker_and_toString )" @@ -6340,10 +6694,10 @@ there" - Catch::toString( v ) == "{ {?} }" + Catch::toString( v ) == "{ {?} }" - "{ {?} }" == "{ {?} }" + "{ {?} }" == "{ {?} }" @@ -6351,12 +6705,12 @@ there" - Catch::toString( v ) == "{ StringMaker<has_maker> }" + Catch::toString( v ) == "{ StringMaker<has_maker> }" - "{ StringMaker<has_maker> }" + "{ StringMaker<has_maker> }" == -"{ StringMaker<has_maker> }" +"{ StringMaker<has_maker> }" @@ -6364,23 +6718,1129 @@ there" - Catch::toString( v ) == "{ StringMaker<has_maker_and_toString> }" + Catch::toString( v ) == "{ StringMaker<has_maker_and_toString> }" - "{ StringMaker<has_maker_and_toString> }" + "{ StringMaker<has_maker_and_toString> }" == -"{ StringMaker<has_maker_and_toString> }" +"{ StringMaker<has_maker_and_toString> }" + + + + testCase.isOpen() + + + true + + + + + s1.isOpen() + + + true + + +
+ + + s1.isSuccessfullyCompleted() + + + true + + + + + testCase.isComplete() == false + + + false == false + + + + + ctx.completedCycle() + + + true + + + + + testCase.isSuccessfullyCompleted() + + + true + + + +
+ + + testCase.isOpen() + + + true + + + + + s1.isOpen() + + + true + + +
+ + + s1.isComplete() + + + true + + + + + s1.isSuccessfullyCompleted() == false + + + false == false + + + + + testCase.isComplete() == false + + + false == false + + + + + ctx.completedCycle() + + + true + + + + + testCase.isSuccessfullyCompleted() == false + + + false == false + + +
+ + + testCase2.isOpen() + + + true + + + + + s1b.isOpen() == false + + + false == false + + + + + ctx.completedCycle() + + + true + + + + + testCase.isComplete() + + + true + + + + + testCase.isSuccessfullyCompleted() + + + true + + + +
+ +
+ + + testCase.isOpen() + + + true + + + + + s1.isOpen() + + + true + + +
+ + + s1.isComplete() + + + true + + + + + s1.isSuccessfullyCompleted() == false + + + false == false + + + + + testCase.isComplete() == false + + + false == false + + + + + ctx.completedCycle() + + + true + + + + + testCase.isSuccessfullyCompleted() == false + + + false == false + + +
+ + + testCase2.isOpen() + + + true + + + + + s1b.isOpen() == false + + + false == false + + + + + s2.isOpen() + + + true + + + + + ctx.completedCycle() + + + true + + + + + testCase.isComplete() + + + true + + + + + testCase.isSuccessfullyCompleted() + + + true + + + +
+ +
+ + + testCase.isOpen() + + + true + + + + + s1.isOpen() + + + true + + +
+ + + s2.isOpen() == false + + + false == false + + + + + testCase.isComplete() == false + + + false == false + + +
+ + + testCase2.isOpen() + + + true + + + + + s1b.isOpen() == false + + + false == false + + + + + s2b.isOpen() + + + true + + + + + ctx.completedCycle() == false + + + false == false + + +
+ + + ctx.completedCycle() + + + true + + + + + s2b.isSuccessfullyCompleted() + + + true + + + + + testCase2.isComplete() == false + + + false == false + + + + + testCase2.isSuccessfullyCompleted() + + + true + + + +
+ +
+ +
+ + + testCase.isOpen() + + + true + + + + + s1.isOpen() + + + true + + +
+ + + s2.isOpen() == false + + + false == false + + + + + testCase.isComplete() == false + + + false == false + + +
+ + + testCase2.isOpen() + + + true + + + + + s1b.isOpen() == false + + + false == false + + + + + s2b.isOpen() + + + true + + + + + ctx.completedCycle() == false + + + false == false + + +
+ + + ctx.completedCycle() + + + true + + + + + s2b.isComplete() + + + true + + + + + s2b.isSuccessfullyCompleted() == false + + + false == false + + + + + testCase2.isSuccessfullyCompleted() == false + + + false == false + + + + + testCase3.isOpen() + + + true + + + + + s1c.isOpen() == false + + + false == false + + + + + s2c.isOpen() == false + + + false == false + + + + + testCase3.isSuccessfullyCompleted() + + + true + + + +
+ +
+ +
+ + + testCase.isOpen() + + + true + + + + + s1.isOpen() + + + true + + +
+ + + s2.isOpen() + + + true + + + + + s2.isComplete() + + + true + + + + + s1.isComplete() == false + + + false == false + + + + + s1.isComplete() + + + true + + + + + testCase.isComplete() == false + + + false == false + + + + + testCase.isComplete() + + + true + + + +
+ + + testCase.isOpen() + + + true + + + + + s1.isOpen() + + + true + + +
+ + + g1.isOpen() + + + true + + + + + g1.index() == 0 + + + 0 == 0 + + + + + g1.isComplete() == false + + + false == false + + + + + s1.isComplete() == false + + + false == false + + +
+ + + s1.isComplete() == false + + + false == false + + + + + testCase.isSuccessfullyCompleted() == false + + + false == false + + +
+ + + testCase2.isOpen() + + + true + + + + + s1b.isOpen() + + + true + + + + + g1b.isOpen() + + + true + + + + + g1b.index() == 1 + + + 1 == 1 + + + + + s1.isComplete() == false + + + false == false + + + + + s1b.isComplete() + + + true + + + + + g1b.isComplete() + + + true + + + + + testCase2.isComplete() + + + true + + + +
+ +
+ +
+ + + testCase.isOpen() + + + true + + + + + s1.isOpen() + + + true + + +
+ + + g1.isOpen() + + + true + + + + + g1.index() == 0 + + + 0 == 0 + + + + + g1.isComplete() == false + + + false == false + + + + + s1.isComplete() == false + + + false == false + + +
+ + + s2.isOpen() + + + true + + + + + s2.isComplete() + + + true + + + + + s1.isComplete() == false + + + false == false + + + + + testCase.isComplete() == false + + + false == false + + +
+ + + testCase2.isOpen() + + + true + + + + + s1b.isOpen() + + + true + + + + + g1b.isOpen() + + + true + + + + + g1b.index() == 1 + + + 1 == 1 + + + + + s2b.isOpen() + + + true + + + + + s2b.isComplete() + + + true + + + + + g1b.isComplete() + + + true + + + + + s1b.isComplete() + + + true + + + + + testCase2.isComplete() + + + true + + + +
+ +
+ +
+ + + testCase.isOpen() + + + true + + + + + s1.isOpen() + + + true + + +
+ + + g1.isOpen() + + + true + + + + + g1.index() == 0 + + + 0 == 0 + + + + + g1.isComplete() == false + + + false == false + + + + + s1.isComplete() == false + + + false == false + + +
+ + + s2.isOpen() + + + true + + + + + s2.isComplete() + + + true + + + + + s2.isSuccessfullyCompleted() == false + + + false == false + + + + + s1.isComplete() == false + + + false == false + + + + + testCase.isComplete() == false + + + false == false + + +
+ + + testCase2.isOpen() + + + true + + + + + s1b.isOpen() + + + true + + + + + g1b.isOpen() + + + true + + + + + g1b.index() == 0 + + + 0 == 0 + + + + + s2b.isOpen() == false + + + false == false + + + + + g1b.isComplete() == false + + + false == false + + + + + s1b.isComplete() == false + + + false == false + + + + + testCase2.isComplete() == false + + + false == false + + + + + testCase3.isOpen() + + + true + + + + + s1c.isOpen() + + + true + + + + + g1c.isOpen() + + + true + + + + + g1c.index() == 1 + + + 1 == 1 + + + + + s2c.isOpen() + + + true + + + + + s2c.isComplete() + + + true + + + + + g1c.isComplete() + + + true + + + + + s1c.isComplete() + + + true + + + + + testCase3.isComplete() + + + true + + + +
+ +
+ +
+ +
- Catch::toString( value ) == "{ 34, \"xyzzy\" }" + Catch::toString( value ) == "{ 34, \"xyzzy\" }" - "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" + "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" @@ -6388,10 +7848,10 @@ there" - Catch::toString(value) == "{ 34, \"xyzzy\" }" + Catch::toString(value) == "{ 34, \"xyzzy\" }" - "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" + "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" @@ -6399,12 +7859,12 @@ there" - Catch::toString( pr ) == "{ { \"green\", 55 } }" + Catch::toString( pr ) == "{ { \"green\", 55 } }" - "{ { "green", 55 } }" + "{ { "green", 55 } }" == -"{ { "green", 55 } }" +"{ { "green", 55 } }" @@ -6412,12 +7872,12 @@ there" - Catch::toString( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" + Catch::toString( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" - "{ { 42, "Arthur" }, { "Ford", 24 } }" + "{ { 42, "Arthur" }, { "Ford", 24 } }" == -"{ { 42, "Arthur" }, { "Ford", 24 } }" +"{ { 42, "Arthur" }, { "Ford", 24 } }" @@ -6425,26 +7885,26 @@ there" - Catch::toString(vv) == "{ }" + Catch::toString(vv) == "{ }" - "{ }" == "{ }" + "{ }" == "{ }" - Catch::toString(vv) == "{ 42 }" + Catch::toString(vv) == "{ 42 }" - "{ 42 }" == "{ 42 }" + "{ 42 }" == "{ 42 }" - Catch::toString(vv) == "{ 42, 250 }" + Catch::toString(vv) == "{ 42, 250 }" - "{ 42, 250 }" == "{ 42, 250 }" + "{ 42, 250 }" == "{ 42, 250 }" @@ -6452,28 +7912,28 @@ there" - Catch::toString(vv) == "{ }" + Catch::toString(vv) == "{ }" - "{ }" == "{ }" + "{ }" == "{ }" - Catch::toString(vv) == "{ \"hello\" }" + Catch::toString(vv) == "{ \"hello\" }" - "{ "hello" }" == "{ "hello" }" + "{ "hello" }" == "{ "hello" }" - Catch::toString(vv) == "{ \"hello\", \"world\" }" + Catch::toString(vv) == "{ \"hello\", \"world\" }" - "{ "hello", "world" }" + "{ "hello", "world" }" == -"{ "hello", "world" }" +"{ "hello", "world" }" @@ -6481,26 +7941,26 @@ there" - Catch::toString(vv) == "{ }" + Catch::toString(vv) == "{ }" - "{ }" == "{ }" + "{ }" == "{ }" - Catch::toString(vv) == "{ 42 }" + Catch::toString(vv) == "{ 42 }" - "{ 42 }" == "{ 42 }" + "{ 42 }" == "{ 42 }" - Catch::toString(vv) == "{ 42, 250 }" + Catch::toString(vv) == "{ 42, 250 }" - "{ 42, 250 }" == "{ 42, 250 }" + "{ 42, 250 }" == "{ 42, 250 }" @@ -6508,20 +7968,20 @@ there" - Catch::toString(v) == "{ }" + Catch::toString(v) == "{ }" - "{ }" == "{ }" + "{ }" == "{ }" - Catch::toString(v) == "{ { \"hello\" }, { \"world\" } }" + Catch::toString(v) == "{ { \"hello\" }, { \"world\" } }" - "{ { "hello" }, { "world" } }" + "{ { "hello" }, { "world" } }" == -"{ { "hello" }, { "world" } }" +"{ { "hello" }, { "world" } }" @@ -6740,7 +8200,7 @@ there" - parseTestSpec( "*a" ).matches( tcA ) == true + parseTestSpec( "*a" ).matches( tcA ) == true true == true @@ -6791,7 +8251,7 @@ there" - parseTestSpec( "a*" ).matches( tcA ) == true + parseTestSpec( "a*" ).matches( tcA ) == true true == true @@ -6842,7 +8302,7 @@ there" - parseTestSpec( "*a*" ).matches( tcA ) == true + parseTestSpec( "*a*" ).matches( tcA ) == true true == true @@ -7705,18 +9165,18 @@ there" - "{ }" == Catch::toString(type{}) + "{ }" == Catch::toString(type{}) - "{ }" == "{ }" + "{ }" == "{ }" - "{ }" == Catch::toString(value) + "{ }" == Catch::toString(value) - "{ }" == "{ }" + "{ }" == "{ }" @@ -7724,10 +9184,10 @@ there" - "{ 0 }" == Catch::toString(type{0}) + "{ 0 }" == Catch::toString(type{0}) - "{ 0 }" == "{ 0 }" + "{ 0 }" == "{ 0 }" @@ -7735,18 +9195,18 @@ there" - "1.2f" == Catch::toString(float(1.2)) + "1.2f" == Catch::toString(float(1.2)) - "1.2f" == "1.2f" + "1.2f" == "1.2f" - "{ 1.2f, 0 }" == Catch::toString(type{1.2,0}) + "{ 1.2f, 0 }" == Catch::toString(type{1.2,0}) - "{ 1.2f, 0 }" == "{ 1.2f, 0 }" + "{ 1.2f, 0 }" == "{ 1.2f, 0 }" @@ -7754,12 +9214,12 @@ there" - "{ \"hello\", \"world\" }" == Catch::toString(type{"hello","world"}) + "{ \"hello\", \"world\" }" == Catch::toString(type{"hello","world"}) - "{ "hello", "world" }" + "{ "hello", "world" }" == -"{ "hello", "world" }" +"{ "hello", "world" }" @@ -7767,12 +9227,12 @@ there" - "{ { 42 }, { }, 1.2f }" == Catch::toString(value) + "{ { 42 }, { }, 1.2f }" == Catch::toString(value) - "{ { 42 }, { }, 1.2f }" + "{ { 42 }, { }, 1.2f }" == -"{ { 42 }, { }, 1.2f }" +"{ { 42 }, { }, 1.2f }" @@ -7780,12 +9240,12 @@ there" - "{ nullptr, 42, \"Catch me\" }" == Catch::toString(value) + "{ nullptr, 42, \"Catch me\" }" == Catch::toString(value) - "{ nullptr, 42, "Catch me" }" + "{ nullptr, 42, "Catch me" }" == -"{ nullptr, 42, "Catch me" }" +"{ nullptr, 42, "Catch me" }" @@ -7794,42 +9254,42 @@ there"
- what Contains( "[@zzz]" ) + what Contains( "[@zzz]" ) - "error: tag alias, "[@zzz]" already registered. + "error: tag alias, "[@zzz]" already registered. First seen at file:2 - Redefined at file:10" contains: "[@zzz]" + Redefined at file:10" contains: "[@zzz]" - what Contains( "file" ) + what Contains( "file" ) - "error: tag alias, "[@zzz]" already registered. + "error: tag alias, "[@zzz]" already registered. First seen at file:2 - Redefined at file:10" contains: "file" + Redefined at file:10" contains: "file" - what Contains( "2" ) + what Contains( "2" ) - "error: tag alias, "[@zzz]" already registered. + "error: tag alias, "[@zzz]" already registered. First seen at file:2 - Redefined at file:10" contains: "2" + Redefined at file:10" contains: "2" - what Contains( "10" ) + what Contains( "10" ) - "error: tag alias, "[@zzz]" already registered. + "error: tag alias, "[@zzz]" already registered. First seen at file:2 - Redefined at file:10" contains: "10" + Redefined at file:10" contains: "10" @@ -7837,34 +9297,34 @@ there"
- registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) ) + registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) ) - registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) ) + registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) ) - registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) ) + registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) ) - registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) ) + registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) ) - registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) ) + registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) ) - registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) ) + registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) ) - registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) + registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) - registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) + registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) @@ -8045,182 +9505,7 @@ there"
- - - - !testCaseTracker.isCompleted() - - - !false - - -
- - - !testCaseTracker.isCompleted() - - - !false - - - - - testCaseTracker.isCompleted() - - - true - - - -
- - - !testCaseTracker.isCompleted() - - - !false - - -
- - - testCaseTracker.enterSection( section1Name ) - - - true - - - - - !testCaseTracker.isCompleted() - - - !false - - - - - testCaseTracker.isCompleted() - - - true - - - - - !testCaseTracker.enterSection( section1Name ) - - - !false - - - -
- - - !testCaseTracker.isCompleted() - - - !false - - -
- - - testCaseTracker.enterSection( section1Name ) - - - true - - - - - !testCaseTracker.enterSection( section2Name ) - - - !false - - - - - !testCaseTracker.isCompleted() - - - !false - - - - - !testCaseTracker.enterSection( section1Name ) - - - !false - - - - - testCaseTracker.enterSection( section2Name ) - - - true - - - - - testCaseTracker.isCompleted() - - - true - - - -
- - - !testCaseTracker.isCompleted() - - - !false - - -
- - - testCaseTracker.enterSection( section1Name ) - - - true - - - - - testCaseTracker.enterSection( section2Name ) - - - true - - - - - !testCaseTracker.isCompleted() - - - !false - - - - - testCaseTracker.isCompleted() - - - true - - - -
- -
- + - + diff --git a/projects/SelfTest/ClassTests.cpp b/projects/SelfTest/ClassTests.cpp index e22f3d24..a4707849 100644 --- a/projects/SelfTest/ClassTests.cpp +++ b/projects/SelfTest/ClassTests.cpp @@ -13,18 +13,18 @@ namespace class TestClass { std::string s; - + public: TestClass() : s( "hello" ) {} - + void succeedingCase() - { + { REQUIRE( s == "hello" ); } void failingCase() - { + { REQUIRE( s == "world" ); } }; @@ -38,20 +38,20 @@ METHOD_AS_TEST_CASE( TestClass::failingCase, "A METHOD_AS_TEST_CASE based test r struct Fixture { Fixture() : m_a( 1 ) {} - + int m_a; }; TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that succeeds", "[class]" ) -{ - REQUIRE( m_a == 1 ); +{ + REQUIRE( 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 ); + { + REQUIRE( m_a == 2 ); } } diff --git a/projects/SelfTest/CmdLineTests.cpp b/projects/SelfTest/CmdLineTests.cpp index 46aecfd0..719c89b8 100644 --- a/projects/SelfTest/CmdLineTests.cpp +++ b/projects/SelfTest/CmdLineTests.cpp @@ -9,8 +9,11 @@ #include "catch.hpp" #include "catch_test_spec_parser.hpp" +#ifdef __clang__ +# pragma clang diagnostic ignored "-Wc++98-compat" +#endif -inline Catch::TestCase fakeTestCase( const char* name, const char* desc = "" ){ return Catch::makeTestCase( NULL, "", name, desc, CATCH_INTERNAL_LINEINFO ); } +inline Catch::TestCase fakeTestCase( const char* name, const char* desc = "" ){ return Catch::makeTestCase( CATCH_NULL, "", name, desc, CATCH_INTERNAL_LINEINFO ); } TEST_CASE( "Parse test names and tags", "" ) { diff --git a/projects/SelfTest/ConditionTests.cpp b/projects/SelfTest/ConditionTests.cpp index 097c3f33..d1b7ed24 100644 --- a/projects/SelfTest/ConditionTests.cpp +++ b/projects/SelfTest/ConditionTests.cpp @@ -6,7 +6,8 @@ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" #endif #include "catch.hpp" @@ -21,7 +22,7 @@ struct TestData { float_nine_point_one( 9.1f ), double_pi( 3.1415926535 ) {} - + int int_seven; std::string str_hello; float float_nine_point_one; @@ -36,7 +37,7 @@ struct TestDef { TestDef& operator[]( const std::string& ) { return *this; } - + }; // The "failing" tests all use the CHECK macro, which continues if the specific test fails. @@ -48,14 +49,14 @@ TEST_CASE( "Equality checks that should succeed", "" ) TestDef td; td + "hello" + "hello"; - + 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( "hello" == data.str_hello ); REQUIRE( data.str_hello.size() == 5 ); double x = 1.1 + 0.1 + 0.1; @@ -65,7 +66,7 @@ TEST_CASE( "Equality checks that should succeed", "" ) 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 ); @@ -86,7 +87,7 @@ TEST_CASE( "Equality checks that should fail", "[.][failing][!mayfail]" ) 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 ) ); @@ -103,7 +104,7 @@ TEST_CASE( "Inequality checks that should succeed", "" ) TEST_CASE( "Inequality checks that should fail", "[.][failing]" ) { TestData data; - + CHECK( data.int_seven != 7 ); CHECK( data.float_nine_point_one != Approx( 9.1f ) ); CHECK( data.double_pi != Approx( 3.1415926535 ) ); @@ -115,7 +116,7 @@ TEST_CASE( "Inequality checks that should fail", "[.][failing]" ) 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 ); @@ -125,14 +126,14 @@ TEST_CASE( "Ordering comparison checks that should succeed", "" ) 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" ); @@ -142,7 +143,7 @@ TEST_CASE( "Ordering comparison checks that should succeed", "" ) 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 ); @@ -152,11 +153,11 @@ TEST_CASE( "Ordering comparison checks that should fail", "[.][failing]" ) 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" ); @@ -177,7 +178,7 @@ TEST_CASE( "Comparisons with int literals don't warn when mixing signed/ unsigne unsigned long ul = 4; char c = 5; unsigned char uc = 6; - + REQUIRE( i == 1 ); REQUIRE( ui == 2 ); REQUIRE( l == 3 ); @@ -214,7 +215,7 @@ TEST_CASE( "comparisons between int variables", "" ) 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 ); @@ -251,7 +252,7 @@ template struct Ex { Ex( T ){} - + bool operator == ( const T& ) const { return true; } T operator * ( const T& ) const { return T(); } }; @@ -265,32 +266,32 @@ TEST_CASE( "Comparisons between ints where one side is computed", "" ) #pragma GCC diagnostic pop #endif -inline const char* returnsConstNull(){ return NULL; } -inline char* returnsNull(){ return NULL; } +inline const char* returnsConstNull(){ return CATCH_NULL; } +inline char* returnsNull(){ return CATCH_NULL; } TEST_CASE( "Pointers can be compared to null", "" ) { - TestData* p = NULL; - TestData* pNULL = NULL; - - REQUIRE( p == NULL ); + TestData* p = CATCH_NULL; + TestData* pNULL = CATCH_NULL; + + REQUIRE( p == CATCH_NULL ); REQUIRE( p == pNULL ); - + TestData data; p = &data; - - REQUIRE( p != NULL ); + + REQUIRE( p != CATCH_NULL ); const TestData* cp = p; - REQUIRE( cp != NULL ); + REQUIRE( cp != CATCH_NULL ); const TestData* const cpc = p; - REQUIRE( cpc != NULL ); + REQUIRE( cpc != CATCH_NULL ); - REQUIRE( returnsNull() == NULL ); - REQUIRE( returnsConstNull() == NULL ); - - REQUIRE( NULL != p ); + REQUIRE( returnsNull() == CATCH_NULL ); + REQUIRE( returnsConstNull() == CATCH_NULL ); + + REQUIRE( CATCH_NULL != p ); } // Not (!) tests @@ -303,7 +304,7 @@ TEST_CASE( "Pointers can be compared to null", "" ) TEST_CASE( "'Not' checks that should succeed", "" ) { bool falseValue = false; - + REQUIRE( false == false ); REQUIRE( true == true ); REQUIRE( !false ); @@ -319,15 +320,15 @@ TEST_CASE( "'Not' checks that should succeed", "" ) 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 ); } diff --git a/projects/SelfTest/ExceptionTests.cpp b/projects/SelfTest/ExceptionTests.cpp index 7de1d179..dfcaa4b8 100644 --- a/projects/SelfTest/ExceptionTests.cpp +++ b/projects/SelfTest/ExceptionTests.cpp @@ -96,6 +96,23 @@ public: CustomException( const std::string& msg ) : m_msg( msg ) {} + + std::string getMessage() const + { + return m_msg; + } + +private: + std::string m_msg; +}; + +class CustomStdException : public std::exception +{ +public: + CustomStdException( const std::string& msg ) + : m_msg( msg ) + {} + ~CustomStdException() CATCH_NOEXCEPT {} std::string getMessage() const { @@ -106,22 +123,34 @@ private: std::string m_msg; }; + CATCH_TRANSLATE_EXCEPTION( CustomException& ex ) { return ex.getMessage(); } +CATCH_TRANSLATE_EXCEPTION( CustomStdException& ex ) +{ + return ex.getMessage(); +} + CATCH_TRANSLATE_EXCEPTION( double& ex ) { return Catch::toString( ex ); } -TEST_CASE("Unexpected custom exceptions can be translated", "[.][failing]" ) +TEST_CASE("Non-std exceptions can be translated", "[.][failing]" ) { if( Catch::alwaysTrue() ) throw CustomException( "custom exception" ); } +TEST_CASE("Custom std-exceptions can be custom translated", "[.][failing]" ) +{ + if( Catch::alwaysTrue() ) + throw CustomException( "custom std exception" ); +} + inline void throwCustom() { if( Catch::alwaysTrue() ) throw CustomException( "custom exception - not std" ); @@ -152,3 +181,23 @@ TEST_CASE( "NotImplemented exception", "" ) { REQUIRE_THROWS( thisFunctionNotImplemented( 7 ) ); } + +TEST_CASE( "Exception messages can be tested for", "" ) { + 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(), Contains( "except" ) ); + REQUIRE_THROWS_WITH( thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) ); + } +} + +TEST_CASE( "Mismatching exception messages failing the test", "[.][failing]" ) { + REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ); + REQUIRE_THROWS_WITH( thisThrows(), "should fail" ); + REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ); +} diff --git a/projects/SelfTest/GeneratorTests.cpp b/projects/SelfTest/GeneratorTests.cpp index a961b698..af08b1d3 100644 --- a/projects/SelfTest/GeneratorTests.cpp +++ b/projects/SelfTest/GeneratorTests.cpp @@ -19,10 +19,10 @@ inline int multiply( int a, int b ) CATCH_TEST_CASE( "Generators over two ranges", "[generators]" ) { using namespace Catch::Generators; - + int i = CATCH_GENERATE( between( 1, 5 ).then( values( 15, 20, 21 ).then( 36 ) ) ); int j = CATCH_GENERATE( between( 100, 107 ) ); - + CATCH_REQUIRE( multiply( i, 2 ) == i*2 ); CATCH_REQUIRE( multiply( j, 2 ) == j*2 ); } @@ -32,11 +32,11 @@ struct IntPair { int first, second; }; CATCH_TEST_CASE( "Generator over a range of pairs", "[generators]" ) { using namespace Catch::Generators; - + IntPair p[] = { { 0, 1 }, { 2, 3 } }; - + IntPair* i = CATCH_GENERATE( between( p, &p[1] ) ); - + CATCH_REQUIRE( i->first == i->second-1 ); - + } diff --git a/projects/SelfTest/MessageTests.cpp b/projects/SelfTest/MessageTests.cpp index 69ef03dd..87a85a82 100644 --- a/projects/SelfTest/MessageTests.cpp +++ b/projects/SelfTest/MessageTests.cpp @@ -38,7 +38,7 @@ TEST_CASE( "INFO gets logged on failure, even if captured before successful asse CHECK( a == 2 ); INFO( "this message should be logged" ); - + CHECK( a == 1 ); INFO( "and this, but later" ); @@ -85,7 +85,7 @@ TEST_CASE( "Standard output from all sections is reported", "[messages][.]" ) { std::cout << "Message from section one" << std::endl; } - + SECTION( "two", "" ) { std::cout << "Message from section two" << std::endl; diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index 86bd4f39..cf7f48cf 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -8,17 +8,20 @@ #include "catch.hpp" -#include - #ifdef __clang__ -#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" #endif +#include "../include/internal/catch_xmlwriter.hpp" + +#include + TEST_CASE( "random SECTION tests", "[.][sections][failing]" ) { int a = 1; int b = 2; - + SECTION( "s1", "doesn't equal" ) { REQUIRE( a != b ); @@ -35,7 +38,7 @@ TEST_CASE( "nested SECTION tests", "[.][sections][failing]" ) { int a = 1; int b = 2; - + SECTION( "s1", "doesn't equal" ) { REQUIRE( a != b ); @@ -52,7 +55,7 @@ TEST_CASE( "more nested SECTION tests", "[sections][failing][.]" ) { int a = 1; int b = 2; - + SECTION( "s1", "doesn't equal" ) { SECTION( "s2", "equal" ) @@ -77,29 +80,32 @@ TEST_CASE( "even more nested SECTION tests", "[sections]" ) { 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 ) { std::ostringstream oss; oss << "b is currently: " << b; SECTION( "s1", oss.str() ) { - CHECK( b > a ); + CHECK( b > a ); } } } @@ -107,30 +113,30 @@ TEST_CASE( "looped SECTION tests", "[.][failing][sections]" ) TEST_CASE( "looped tests", "[.][failing]" ) { static const int fib[] = { 1, 1, 2, 3, 5, 8, 13, 21 }; - + for( size_t i=0; i < sizeof(fib)/sizeof(int); ++i ) { INFO( "Testing if fib[" << i << "] (" << fib[i] << ") is even" ); - CHECK( ( fib[i] % 2 ) == 0 ); + CHECK( ( fib[i] % 2 ) == 0 ); } } TEST_CASE( "Sends stuff to stdout and stderr", "[.]" ) { std::cout << "A string sent directly to stdout" << std::endl; - + std::cerr << "A string sent directly to stderr" << std::endl; } inline const char* makeString( bool makeNull ) { - return makeNull ? NULL : "valid string"; + return makeNull ? CATCH_NULL : "valid string"; } TEST_CASE( "null strings", "" ) { - REQUIRE( makeString( false ) != static_cast(NULL)); - REQUIRE( makeString( true ) == static_cast(NULL)); + REQUIRE( makeString( false ) != static_cast(CATCH_NULL)); + REQUIRE( makeString( true ) == static_cast(CATCH_NULL)); } @@ -156,7 +162,7 @@ inline bool testCheckedElse( bool flag ) { CHECKED_ELSE( flag ) return false; - + return true; } @@ -174,24 +180,24 @@ TEST_CASE( "xmlentitycheck", "" ) { SECTION( "embedded xml", "it should be possible to embed xml characters, such as <, \" or &, or even whole documents within an attribute" ) { - // No test + SUCCEED(""); // We need this here to stop it failing due to no tests } SECTION( "encoded chars", "these should all be encoded: &&&\"\"\"<<<&\"<<&\"" ) { - // No test + 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); + REQUIRE(false); } TEST_CASE( "atomic if", "[failing][0]") { size_t x = 0; - + if( x ) REQUIRE(x > 0); else @@ -202,10 +208,16 @@ inline const char* testStringForMatching() { return "this string contains 'abc' as a substring"; } +inline const char* testStringForMatching2() +{ + return "some completely different text that contains one common word"; +} + +using namespace Catch::Matchers; TEST_CASE("String matchers", "[matchers]" ) { - REQUIRE_THAT( testStringForMatching(), Contains( "string" ) ); + REQUIRE_THAT( testStringForMatching(), Contains( "string" ) ); CHECK_THAT( testStringForMatching(), Contains( "abc" ) ); CHECK_THAT( testStringForMatching(), StartsWith( "this" ) ); @@ -233,7 +245,7 @@ TEST_CASE("Equals string matcher", "[.][failing][matchers]") } TEST_CASE("Equals string matcher, with NULL", "[matchers]") { - REQUIRE_THAT("", Equals(NULL)); + REQUIRE_THAT("", Equals(CATCH_NULL)); } TEST_CASE("AllOf matcher", "[matchers]") { @@ -250,6 +262,42 @@ TEST_CASE("Equals", "[matchers]") CHECK_THAT( testStringForMatching(), Equals( "this string contains 'abc' as a substring" ) ); } +TEST_CASE("Matchers can be (AllOf) composed with the && operator", "[matchers][operators][operator&&]") +{ + CHECK_THAT( testStringForMatching(), + Contains( "string" ) && + Contains( "abc" ) && + Contains( "substring" ) && + Contains( "contains" ) ); +} + +TEST_CASE("Matchers can be (AnyOf) composed with the || operator", "[matchers][operators][operator||]") +{ + CHECK_THAT( testStringForMatching(), Contains( "string" ) || Contains( "different" ) || Contains( "random" ) ); + CHECK_THAT( testStringForMatching2(), Contains( "string" ) || Contains( "different" ) || Contains( "random" ) ); +} + +TEST_CASE("Matchers can be composed with both && and ||", "[matchers][operators][operator||][operator&&]") +{ + CHECK_THAT( testStringForMatching(), ( Contains( "string" ) || Contains( "different" ) ) && Contains( "substring" ) ); +} + +TEST_CASE("Matchers can be composed with both && and || - failing", "[matchers][operators][operator||][operator&&][.failing]") +{ + CHECK_THAT( testStringForMatching(), ( Contains( "string" ) || Contains( "different" ) ) && Contains( "random" ) ); +} + +TEST_CASE("Matchers can be negated (Not) with the ! operator", "[matchers][operators][not]") +{ + CHECK_THAT( testStringForMatching(), !Contains( "different" ) ); +} + +TEST_CASE("Matchers can be negated (Not) with the ! operator - failing", "[matchers][operators][not][.failing]") +{ + CHECK_THAT( testStringForMatching(), !Contains( "substring" ) ); +} + + inline unsigned int Factorial( unsigned int number ) { // return number <= 1 ? number : Factorial(number-1)*number; @@ -291,38 +339,38 @@ TEST_CASE( "second tag", "[tag2]" ) TEST_CASE( "vectors can be sized and resized", "[vector]" ) { 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( "We can use the 'swap trick' to reset the capacity", "" ) { std::vector 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 ); } @@ -381,6 +429,50 @@ TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) { CHECK( result == "\"wide load\"" ); } +inline std::string encode( std::string const& str, Catch::XmlEncode::ForWhat forWhat = Catch::XmlEncode::ForTextNodes ) { + std::ostringstream oss; + oss << Catch::XmlEncode( str, forWhat ); + return oss.str(); +} + +TEST_CASE( "XmlEncode" ) { + SECTION( "normal string" ) { + REQUIRE( encode( "normal string" ) == "normal string" ); + } + SECTION( "empty string" ) { + REQUIRE( encode( "" ) == "" ); + } + SECTION( "string with ampersand" ) { + REQUIRE( encode( "smith & jones" ) == "smith & jones" ); + } + SECTION( "string with less-than" ) { + REQUIRE( encode( "smith < jones" ) == "smith < jones" ); + } + SECTION( "string with greater-than" ) { + REQUIRE( encode( "smith > jones" ) == "smith > jones" ); + REQUIRE( encode( "smith ]]> jones" ) == "smith ]]> jones" ); + } + SECTION( "string with quotes" ) { + std::string stringWithQuotes = "don't \"quote\" me on that"; + REQUIRE( encode( stringWithQuotes ) == stringWithQuotes ); + REQUIRE( encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't "quote" me on that" ); + } + SECTION( "string with control char (1)" ) { + REQUIRE( encode( "[\x01]" ) == "[]" ); + } + SECTION( "string with control char (x7F)" ) { + REQUIRE( encode( "[\x7F]" ) == "[]" ); + } +} + +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +TEST_CASE( "long long" ) { + long long l = std::numeric_limits::max(); + + REQUIRE( l == std::numeric_limits::max() ); +} +#endif + //TEST_CASE( "Divide by Zero signal handler", "[.][sig]" ) { // int i = 0; // int x = 10/i; // This should cause the signal to fire diff --git a/projects/SelfTest/PartTrackerTests.cpp b/projects/SelfTest/PartTrackerTests.cpp new file mode 100644 index 00000000..29256351 --- /dev/null +++ b/projects/SelfTest/PartTrackerTests.cpp @@ -0,0 +1,328 @@ +/* + * Created by Phil on 1/10/2015. + * Copyright 2015 Two Blue Cubes Ltd + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#include "internal/catch_suppress_warnings.h" +#include "internal/catch_test_case_tracker.hpp" + + +namespace Catch +{ + class LocalContext { + + public: + TrackerContext& operator()() const { + return TrackerContext::instance(); + } + }; + +} // namespace Catch + +inline Catch::TrackerContext& C_A_T_C_H_Context() { + return Catch::TrackerContext::instance(); +} + +// ------------------- + +#include "catch.hpp" + +using namespace Catch; + +//inline void testCase( Catch::LocalContext const& C_A_T_C_H_Context ) { +// +// REQUIRE( C_A_T_C_H_Context().i() == 42 ); +//} + +TEST_CASE( "Tracker", "" ) { + + TrackerContext ctx; + ctx.startRun(); + ctx.startCycle(); + + ITracker& testCase = SectionTracker::acquire( ctx, "Testcase" ); + REQUIRE( testCase.isOpen() ); + + ITracker& s1 = SectionTracker::acquire( ctx, "S1" ); + REQUIRE( s1.isOpen() ); + + SECTION( "successfully close one section", "" ) { + s1.close(); + REQUIRE( s1.isSuccessfullyCompleted() ); + REQUIRE( testCase.isComplete() == false ); + + testCase.close(); + REQUIRE( ctx.completedCycle() ); + REQUIRE( testCase.isSuccessfullyCompleted() ); + } + + SECTION( "fail one section", "" ) { + s1.fail(); + REQUIRE( s1.isComplete() ); + REQUIRE( s1.isSuccessfullyCompleted() == false ); + REQUIRE( testCase.isComplete() == false ); + + testCase.close(); + REQUIRE( ctx.completedCycle() ); + REQUIRE( testCase.isSuccessfullyCompleted() == false ); + + SECTION( "re-enter after failed section", "" ) { + ctx.startCycle(); + ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" ); + REQUIRE( testCase2.isOpen() ); + + ITracker& s1b = SectionTracker::acquire( ctx, "S1" ); + REQUIRE( s1b.isOpen() == false ); + + testCase2.close(); + REQUIRE( ctx.completedCycle() ); + REQUIRE( testCase.isComplete() ); + REQUIRE( testCase.isSuccessfullyCompleted() ); + } + SECTION( "re-enter after failed section and find next section", "" ) { + ctx.startCycle(); + ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" ); + REQUIRE( testCase2.isOpen() ); + + ITracker& s1b = SectionTracker::acquire( ctx, "S1" ); + REQUIRE( s1b.isOpen() == false ); + + ITracker& s2 = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2.isOpen() ); + + s2.close(); + REQUIRE( ctx.completedCycle() ); + + testCase2.close(); + REQUIRE( testCase.isComplete() ); + REQUIRE( testCase.isSuccessfullyCompleted() ); + } + } + + SECTION( "successfully close one section, then find another", "" ) { + s1.close(); + + ITracker& s2 = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2.isOpen() == false ); + + testCase.close(); + REQUIRE( testCase.isComplete() == false ); + + SECTION( "Re-enter - skips S1 and enters S2", "" ) { + ctx.startCycle(); + ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" ); + REQUIRE( testCase2.isOpen() ); + + ITracker& s1b = SectionTracker::acquire( ctx, "S1" ); + REQUIRE( s1b.isOpen() == false ); + + ITracker& s2b = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2b.isOpen() ); + + REQUIRE( ctx.completedCycle() == false ); + + SECTION ("Successfully close S2") { + s2b.close(); + REQUIRE( ctx.completedCycle() ); + + REQUIRE( s2b.isSuccessfullyCompleted() ); + REQUIRE( testCase2.isComplete() == false ); + + testCase2.close(); + REQUIRE( testCase2.isSuccessfullyCompleted() ); + } + SECTION ("fail S2") { + s2b.fail(); + REQUIRE( ctx.completedCycle() ); + + REQUIRE( s2b.isComplete() ); + REQUIRE( s2b.isSuccessfullyCompleted() == false ); + + testCase2.close(); + REQUIRE( testCase2.isSuccessfullyCompleted() == false ); + + // Need a final cycle + ctx.startCycle(); + ITracker& testCase3 = SectionTracker::acquire( ctx, "Testcase" ); + REQUIRE( testCase3.isOpen() ); + + ITracker& s1c = SectionTracker::acquire( ctx, "S1" ); + REQUIRE( s1c.isOpen() == false ); + + ITracker& s2c = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2c.isOpen() == false ); + + testCase3.close(); + REQUIRE( testCase3.isSuccessfullyCompleted() ); + } + } + } + + SECTION( "open a nested section", "" ) { + ITracker& s2 = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2.isOpen() ); + + s2.close(); + REQUIRE( s2.isComplete() ); + REQUIRE( s1.isComplete() == false ); + + s1.close(); + REQUIRE( s1.isComplete() ); + REQUIRE( testCase.isComplete() == false ); + + testCase.close(); + REQUIRE( testCase.isComplete() ); + } + + SECTION( "start a generator", "" ) { + IndexTracker& g1 = IndexTracker::acquire( ctx, "G1", 2 ); + REQUIRE( g1.isOpen() ); + REQUIRE( g1.index() == 0 ); + + REQUIRE( g1.isComplete() == false ); + REQUIRE( s1.isComplete() == false ); + + SECTION( "close outer section" ) + { + s1.close(); + REQUIRE( s1.isComplete() == false ); + testCase.close(); + REQUIRE( testCase.isSuccessfullyCompleted() == false ); + + SECTION( "Re-enter for second generation", "" ) { + ctx.startCycle(); + ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" ); + REQUIRE( testCase2.isOpen() ); + + ITracker& s1b = SectionTracker::acquire( ctx, "S1" ); + REQUIRE( s1b.isOpen() ); + + + IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 ); + REQUIRE( g1b.isOpen() ); + REQUIRE( g1b.index() == 1 ); + + REQUIRE( s1.isComplete() == false ); + + s1b.close(); + REQUIRE( s1b.isComplete() ); + REQUIRE( g1b.isComplete() ); + testCase2.close(); + REQUIRE( testCase2.isComplete() ); + } + } + SECTION( "Start a new inner section", "" ) { + ITracker& s2 = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2.isOpen() ); + + s2.close(); + REQUIRE( s2.isComplete() ); + + s1.close(); + REQUIRE( s1.isComplete() == false ); + + testCase.close(); + REQUIRE( testCase.isComplete() == false ); + + SECTION( "Re-enter for second generation", "" ) { + ctx.startCycle(); + ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" ); + REQUIRE( testCase2.isOpen() ); + + ITracker& s1b = SectionTracker::acquire( ctx, "S1" ); + REQUIRE( s1b.isOpen() ); + + // generator - next value + IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 ); + REQUIRE( g1b.isOpen() ); + REQUIRE( g1b.index() == 1 ); + + // inner section again + ITracker& s2b = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2b.isOpen() ); + + s2b.close(); + REQUIRE( s2b.isComplete() ); + + s1b.close(); + REQUIRE( g1b.isComplete() ); + REQUIRE( s1b.isComplete() ); + + testCase2.close(); + REQUIRE( testCase2.isComplete() ); + } + } + + SECTION( "Fail an inner section", "" ) { + ITracker& s2 = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2.isOpen() ); + + s2.fail(); + REQUIRE( s2.isComplete() ); + REQUIRE( s2.isSuccessfullyCompleted() == false ); + + s1.close(); + REQUIRE( s1.isComplete() == false ); + + testCase.close(); + REQUIRE( testCase.isComplete() == false ); + + SECTION( "Re-enter for second generation", "" ) { + ctx.startCycle(); + ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" ); + REQUIRE( testCase2.isOpen() ); + + ITracker& s1b = SectionTracker::acquire( ctx, "S1" ); + REQUIRE( s1b.isOpen() ); + + // generator - still same value + IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 ); + REQUIRE( g1b.isOpen() ); + REQUIRE( g1b.index() == 0 ); + + // inner section again - this time won't open + ITracker& s2b = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2b.isOpen() == false ); + + s1b.close(); + REQUIRE( g1b.isComplete() == false ); + REQUIRE( s1b.isComplete() == false ); + + testCase2.close(); + REQUIRE( testCase2.isComplete() == false ); + + // Another cycle - now should complete + ctx.startCycle(); + ITracker& testCase3 = SectionTracker::acquire( ctx, "Testcase" ); + REQUIRE( testCase3.isOpen() ); + + ITracker& s1c = SectionTracker::acquire( ctx, "S1" ); + REQUIRE( s1c.isOpen() ); + + // generator - now next value + IndexTracker& g1c = IndexTracker::acquire( ctx, "G1", 2 ); + REQUIRE( g1c.isOpen() ); + REQUIRE( g1c.index() == 1 ); + + // inner section - now should open again + ITracker& s2c = SectionTracker::acquire( ctx, "S2" ); + REQUIRE( s2c.isOpen() ); + + s2c.close(); + REQUIRE( s2c.isComplete() ); + + s1c.close(); + REQUIRE( g1c.isComplete() ); + REQUIRE( s1c.isComplete() ); + + testCase3.close(); + REQUIRE( testCase3.isComplete() ); + } + } + // !TBD" + // nested generator + // two sections within a generator + } +} diff --git a/projects/SelfTest/SectionTrackerTests.cpp b/projects/SelfTest/SectionTrackerTests.cpp deleted file mode 100644 index 03d856d8..00000000 --- a/projects/SelfTest/SectionTrackerTests.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Created by Phil on 20/07/2013. - * Copyright 2013 Two Blue Cubes Ltd - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#endif - -#include "internal/catch_test_case_tracker.hpp" - -#include "catch.hpp" - -TEST_CASE( "section tracking", "" ) { - - using namespace Catch; - TestCaseTracker testCaseTracker( "test case" ); - - const std::string section1Name = "section 1"; - const std::string section2Name = "section 2"; - - CHECK_FALSE( testCaseTracker.isCompleted() ); - - SECTION( "test case with no sections", "" ) { - - { - TestCaseTracker::Guard guard( testCaseTracker ); - CHECK_FALSE( testCaseTracker.isCompleted() ); - } - CHECK( testCaseTracker.isCompleted() ); - } - - SECTION( "test case with one section", "" ) { - - { - TestCaseTracker::Guard guard( testCaseTracker ); - - // Enter section? - yes - CHECK( testCaseTracker.enterSection( section1Name ) ); - CHECK_FALSE( testCaseTracker.isCompleted() ); - testCaseTracker.leaveSection(); - - // Leave test case - now complete - } - CHECK( testCaseTracker.isCompleted() ); - - // ... - - // Enter test case again - { - TestCaseTracker::Guard guard( testCaseTracker ); - - // Enter section? - no - now complete - CHECK_FALSE( testCaseTracker.enterSection( section1Name ) ); - } - } - - SECTION( "test case with two consecutive sections", "" ) { - - // Enter test case - { - TestCaseTracker::Guard guard( testCaseTracker ); - - // Enter section 1? - yes - CHECK( testCaseTracker.enterSection( section1Name ) ); - testCaseTracker.leaveSection(); - - // Enter section 2? - no - we just exected section 1 - CHECK_FALSE( testCaseTracker.enterSection( section2Name ) ); - - // Leave test case - incomplete (still need to visit section 2) - } - CHECK_FALSE( testCaseTracker.isCompleted() ); - - // ... - - // Enter test case again - { - TestCaseTracker::Guard guard( testCaseTracker ); - - // Enter section 1? - no, already done now - CHECK_FALSE( testCaseTracker.enterSection( section1Name ) ); - - // Enter section 2? - yes - CHECK( testCaseTracker.enterSection( section2Name ) ); - testCaseTracker.leaveSection(); - - // Leave test case - now complete - } - CHECK( testCaseTracker.isCompleted() ); - } - - SECTION( "test case with one section within another", "" ) { - - // Enter test case again - { - TestCaseTracker::Guard guard( testCaseTracker ); - - // Enter section 1? - yes - CHECK( testCaseTracker.enterSection( section1Name ) ); - - // Enter section 2? - yes - CHECK( testCaseTracker.enterSection( section2Name ) ); - - CHECK_FALSE( testCaseTracker.isCompleted() ); - - testCaseTracker.leaveSection(); // section 2 - testCaseTracker.leaveSection(); // section 1 - - // Leave test case - now complete - } - CHECK( testCaseTracker.isCompleted() ); - } -} diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_exception.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_exception.cpp index 65709351..183d87d9 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_exception.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_exception.cpp @@ -1 +1,2 @@ +#include "catch_suppress_warnings.h" #include "catch_interfaces_exception.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_interfaces_registry_hub.cpp b/projects/SelfTest/SurrogateCpps/catch_interfaces_registry_hub.cpp index 9446c5cf..ffece3b4 100644 --- a/projects/SelfTest/SurrogateCpps/catch_interfaces_registry_hub.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_interfaces_registry_hub.cpp @@ -1,2 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header +#include "catch_suppress_warnings.h" #include "catch_interfaces_registry_hub.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_stream.cpp b/projects/SelfTest/SurrogateCpps/catch_stream.cpp index 9911aec6..7aaffa1e 100644 --- a/projects/SelfTest/SurrogateCpps/catch_stream.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_stream.cpp @@ -1,2 +1,3 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header +#include "catch_suppress_warnings.h" #include "catch_stream.h" diff --git a/projects/SelfTest/SurrogateCpps/catch_xmlwriter.cpp b/projects/SelfTest/SurrogateCpps/catch_xmlwriter.cpp index ca853847..15328efe 100644 --- a/projects/SelfTest/SurrogateCpps/catch_xmlwriter.cpp +++ b/projects/SelfTest/SurrogateCpps/catch_xmlwriter.cpp @@ -1,2 +1,4 @@ // This file is only here to verify (to the extent possible) the self sufficiency of the header +#include "catch_suppress_warnings.h" #include "catch_xmlwriter.hpp" +#include "catch_reenable_warnings.h" diff --git a/projects/SelfTest/TagAliasTests.cpp b/projects/SelfTest/TagAliasTests.cpp index b95ad009..002a93c0 100644 --- a/projects/SelfTest/TagAliasTests.cpp +++ b/projects/SelfTest/TagAliasTests.cpp @@ -11,6 +11,8 @@ TEST_CASE( "Tag alias can be registered against tag patterns", "" ) { + using namespace Catch::Matchers; + Catch::TagAliasRegistry registry; registry.add( "[@zzz]", "[one][two]", Catch::SourceLineInfo( "file", 2 ) ); diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index 7cb7ca42..1713b51a 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -8,7 +8,7 @@ #define CATCH_CONFIG_MAIN #include "catch.hpp" -#include "reporters/catch_reporter_teamcity.hpp" +#include "../include/reporters/catch_reporter_teamcity.hpp" // Some example tag aliases CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" ) @@ -16,8 +16,9 @@ CATCH_REGISTER_TAG_ALIAS( "[@tricky]", "[tricky]~[.]" ) #ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#pragma clang diagnostic ignored "-Wweak-vtables" +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wweak-vtables" +# pragma clang diagnostic ignored "-Wc++98-compat" #endif @@ -39,22 +40,24 @@ std::string parseIntoConfigAndReturnError( const char * (&argv)[size], Catch::Co return ""; } -inline Catch::TestCase fakeTestCase( const char* name, const char* desc = "" ){ return Catch::makeTestCase( NULL, "", name, desc, CATCH_INTERNAL_LINEINFO ); } +inline Catch::TestCase fakeTestCase( const char* name, const char* desc = "" ){ return Catch::makeTestCase( CATCH_NULL, "", name, desc, CATCH_INTERNAL_LINEINFO ); } TEST_CASE( "Process can be configured on command line", "[config][command-line]" ) { + using namespace Catch::Matchers; + Catch::ConfigData config; SECTION( "default - no arguments", "" ) { const char* argv[] = { "test" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - + CHECK( config.shouldDebugBreak == false ); CHECK( config.abortAfter == -1 ); CHECK( config.noThrow == false ); - CHECK( config.reporterName.empty() ); + CHECK( config.reporterNames.empty() ); } - + SECTION( "test lists", "" ) { SECTION( "1 test", "Specify one test case using" ) { const char* argv[] = { "test", "test1" }; @@ -83,43 +86,51 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" } } - + SECTION( "reporter", "" ) { SECTION( "-r/console", "" ) { const char* argv[] = { "test", "-r", "console" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - - REQUIRE( config.reporterName == "console" ); + + REQUIRE( config.reporterNames[0] == "console" ); } SECTION( "-r/xml", "" ) { const char* argv[] = { "test", "-r", "xml" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - - REQUIRE( config.reporterName == "xml" ); + + REQUIRE( config.reporterNames[0] == "xml" ); + } + SECTION( "-r xml and junit", "" ) { + const char* argv[] = { "test", "-r", "xml", "-r", "junit" }; + CHECK_NOTHROW( parseIntoConfig( argv, config ) ); + + REQUIRE( config.reporterNames.size() == 2 ); + REQUIRE( config.reporterNames[0] == "xml" ); + REQUIRE( config.reporterNames[1] == "junit" ); } SECTION( "--reporter/junit", "" ) { const char* argv[] = { "test", "--reporter", "junit" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - - REQUIRE( config.reporterName == "junit" ); + + REQUIRE( config.reporterNames[0] == "junit" ); } } - + SECTION( "debugger", "" ) { SECTION( "-b", "" ) { const char* argv[] = { "test", "-b" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - + REQUIRE( config.shouldDebugBreak == true ); } SECTION( "--break", "" ) { const char* argv[] = { "test", "--break" }; CHECK_NOTHROW( parseIntoConfig( argv, config ) ); - + REQUIRE( config.shouldDebugBreak ); } } - + SECTION( "abort", "" ) { SECTION( "-a aborts after first failure", "" ) { const char* argv[] = { "test", "-a" }; @@ -142,7 +153,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "-x" ) ); } } - + SECTION( "nothrow", "" ) { SECTION( "-e", "" ) { const char* argv[] = { "test", "-e" }; @@ -208,7 +219,7 @@ TEST_CASE( "Long strings can be wrapped", "[wrap]" ) { SECTION( "plain string", "" ) { // guide: 123456789012345678 std::string testString = "one two three four"; - + SECTION( "No wrapping", "" ) { CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString ); CHECK( Text( testString, TextAttributes().setWidth( 18 ) ).toString() == testString ); @@ -252,14 +263,14 @@ TEST_CASE( "Long strings can be wrapped", "[wrap]" ) { .setInitialIndent( 1 ) ); CHECK( text.toString() == " one two\n three\n four" ); } - + } - + SECTION( "With newlines", "" ) { - + // guide: 1234567890123456789 std::string testString = "one two\nthree four"; - + SECTION( "No wrapping" , "" ) { CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString ); CHECK( Text( testString, TextAttributes().setWidth( 18 ) ).toString() == testString ); @@ -279,17 +290,17 @@ TEST_CASE( "Long strings can be wrapped", "[wrap]" ) { CHECK( Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one\ntwo\nthree\nfour" ); } } - + SECTION( "With tabs", "" ) { // guide: 1234567890123456789 std::string testString = "one two \tthree four five six"; - + CHECK( Text( testString, TextAttributes().setWidth( 15 ) ).toString() == "one two three\n four\n five\n six" ); } - - + + } using namespace Catch; @@ -315,7 +326,7 @@ public: ColourString( std::string const& _string, std::vector const& _colours ) : string( _string ), colours( _colours ) {} - + ColourString& addColour( Colour::Code colour, int _index ) { colours.push_back( ColourIndex( colour, resolveRelativeIndex( _index ), @@ -328,7 +339,7 @@ public: resolveLastRelativeIndex( _toIndex ) ) ); return *this; } - + void writeToStream( std::ostream& _stream ) const { std::size_t last = 0; for( std::size_t i = 0; i < colours.size(); ++i ) { @@ -342,7 +353,7 @@ public: last = index.toIndex; } if( last < string.size() ) - _stream << string.substr( last ); + _stream << string.substr( last ); } friend std::ostream& operator << ( std::ostream& _stream, ColourString const& _colourString ) { _colourString.writeToStream( _stream ); @@ -399,7 +410,7 @@ TEST_CASE( "replaceInPlace", "" ) { // !TBD: This will be folded into Text class TEST_CASE( "Strings can be rendered with colour", "[.colour]" ) { - + { ColourString cs( "hello" ); cs .addColour( Colour::Red, 0 ) @@ -411,19 +422,19 @@ TEST_CASE( "Strings can be rendered with colour", "[.colour]" ) { { ColourString cs( "hello" ); cs .addColour( Colour::Blue, 1, -2 ); - + Catch::cout() << cs << std::endl; } - + } TEST_CASE( "Text can be formatted using the Text class", "" ) { - + CHECK( Text( "hi there" ).toString() == "hi there" ); - + TextAttributes narrow; narrow.setWidth( 6 ); - + CHECK( Text( "hi there", narrow ).toString() == "hi\nthere" ); } @@ -436,5 +447,15 @@ TEST_CASE( "Long text is truncted", "[Text][Truncated]" ) { oss << longLine << longLine << "\n"; Text t( oss.str() ); CHECK_THAT( t.toString(), EndsWith( "... message truncated due to excessive size" ) ); - + } + +inline void manuallyRegisteredTestFunction() { + SUCCEED( "was called" ); +} +struct AutoTestReg { + AutoTestReg() { + REGISTER_TEST_CASE( manuallyRegisteredTestFunction, "ManuallyRegistered", "" ); + } +}; +AutoTestReg autoTestReg; diff --git a/projects/SelfTest/ToStringTuple.cpp b/projects/SelfTest/ToStringTuple.cpp index d1ab02f2..80e54530 100644 --- a/projects/SelfTest/ToStringTuple.cpp +++ b/projects/SelfTest/ToStringTuple.cpp @@ -42,12 +42,14 @@ TEST_CASE( "tuple,tuple<>,float>", "[toString][tuple]" ) CHECK( "{ { 42 }, { }, 1.2f }" == Catch::toString(value) ); } +#ifdef CATCH_CONFIG_CPP11_NULLPTR TEST_CASE( "tuple", "[toString][tuple]" ) { typedef std::tuple type; type value { nullptr, 42, "Catch me" }; CHECK( "{ nullptr, 42, \"Catch me\" }" == Catch::toString(value) ); } +#endif #ifdef __clang__ #pragma clang diagnostic pop diff --git a/projects/SelfTest/TrickyTests.cpp b/projects/SelfTest/TrickyTests.cpp index 462718db..eb53e420 100644 --- a/projects/SelfTest/TrickyTests.cpp +++ b/projects/SelfTest/TrickyTests.cpp @@ -25,7 +25,7 @@ namespace Catch std::ostringstream oss; oss << "std::pair( " << value.first << ", " << value.second << " )"; return oss.str(); - + } } @@ -38,7 +38,7 @@ TEST_CASE { std::pair aNicePair( 1, 2 ); - REQUIRE( (std::pair( 1, 2 )) == aNicePair ); + REQUIRE( (std::pair( 1, 2 )) == aNicePair ); } /////////////////////////////////////////////////////////////////////////////// @@ -62,7 +62,7 @@ TEST_CASE /* int a = 1; int b = 2; - + // This only captures part of the expression, but issues a warning about the rest REQUIRE( a+1 == b-1 ); */ @@ -85,38 +85,38 @@ TEST_CASE "[Tricky][failing][.]" ) { - + Opaque o1, o2; o1.val = 7; o2.val = 8; - + CHECK( &o1 == &o2 ); CHECK( o1 == o2 ); } /////////////////////////////////////////////////////////////////////////////// TEST_CASE -( +( "string literals of different sizes can be compared", "[Tricky][failing][.]" ) { REQUIRE( std::string( "first" ) == "second" ); - + } /////////////////////////////////////////////////////////////////////////////// TEST_CASE -( +( "An expression with side-effects should only be evaluated once", "[Tricky]" ) { int i = 7; - + REQUIRE( i++ == 7 ); REQUIRE( i++ == 8 ); - + } namespace A { @@ -167,8 +167,8 @@ TEST_CASE */ namespace ObjectWithConversions -{ - struct Object +{ + struct Object { operator unsigned int() {return 0xc0000000;} }; @@ -179,31 +179,31 @@ namespace ObjectWithConversions "Operators at different namespace levels not hijacked by Koenig lookup", "[Tricky]" ) - { + { Object o; REQUIRE(0xc0000000 == o ); } } -namespace ObjectWithNonConstEqualityOperator +namespace ObjectWithNonConstEqualityOperator { struct Test { Test( unsigned int v ) - : m_value(v) + : m_value(v) {} - + bool operator==( const Test&rhs ) - { + { return (m_value == rhs.m_value); } bool operator==( const Test&rhs ) const - { + { return (m_value != rhs.m_value); } unsigned int m_value; }; - + TEST_CASE("Demonstrate that a non-const == is not used", "[Tricky]" ) { Test t( 1 ); @@ -226,7 +226,7 @@ namespace EnumBitFieldTests struct Obj { Obj():prop(&p){} - + int p; int* prop; }; @@ -234,7 +234,7 @@ struct Obj TEST_CASE("boolean member", "[Tricky]") { Obj obj; - REQUIRE( obj.prop != NULL ); + REQUIRE( obj.prop != CATCH_NULL ); } // Tests for a problem submitted by Ralph McArdell @@ -284,11 +284,11 @@ TEST_CASE( "(unimplemented) static bools can be evaluated", "[Tricky]" ) /* TEST_CASE( "Tests with the same name are not allowed", "[Tricky]" ) { - + } TEST_CASE( "Tests with the same name are not allowed", "[Tricky]" ) { - + } */ @@ -317,13 +317,13 @@ TEST_CASE( "Assertions then sections", "[Tricky]" ) { // This was causing a failure due to the way the console reporter was handling // the current section - + REQUIRE( Catch::alwaysTrue() ); - + SECTION( "A section", "" ) { REQUIRE( Catch::alwaysTrue() ); - + SECTION( "Another section", "" ) { REQUIRE( Catch::alwaysTrue() ); diff --git a/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj index b64ceef1..8947e38e 100644 --- a/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj +++ b/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 26059AF21BD4B94C003D575C /* PartTrackerTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26059AF11BD4B94C003D575C /* PartTrackerTests.cpp */; }; 263F7A4719B6FCBF009474C2 /* EnumToString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4619B6FCBF009474C2 /* EnumToString.cpp */; }; 263F7A4B19B6FE1E009474C2 /* ToStringPair.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4819B6FE1E009474C2 /* ToStringPair.cpp */; }; 263F7A4C19B6FE1E009474C2 /* ToStringVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4919B6FE1E009474C2 /* ToStringVector.cpp */; }; @@ -17,7 +18,6 @@ 26711C8F195D465C0033EDA2 /* TagAliasTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26711C8D195D465C0033EDA2 /* TagAliasTests.cpp */; }; 26847E5F16BBADB40043B9C1 /* catch_message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26847E5D16BBADB40043B9C1 /* catch_message.cpp */; }; 2691574C1A532A280054F1ED /* ToStringTuple.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2691574B1A532A280054F1ED /* ToStringTuple.cpp */; }; - 26948286179A9AB900ED166E /* SectionTrackerTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */; }; 2694A1FD16A0000E004816E3 /* catch_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2694A1FB16A0000E004816E3 /* catch_text.cpp */; }; 26E1B7D319213BC900812682 /* CmdLineTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E1B7D119213BC900812682 /* CmdLineTests.cpp */; }; 4A45DA2416161EF9004F8D6B /* catch_console_colour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A45DA2316161EF9004F8D6B /* catch_console_colour.cpp */; }; @@ -62,6 +62,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 26059AF11BD4B94C003D575C /* PartTrackerTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PartTrackerTests.cpp; path = ../../../SelfTest/PartTrackerTests.cpp; sourceTree = ""; }; 261488FA184C81130041FBEB /* catch_test_spec.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_spec.hpp; sourceTree = ""; }; 261488FC184D1DC10041FBEB /* catch_stream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_stream.h; sourceTree = ""; }; 261488FD184D21290041FBEB /* catch_section_info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_section_info.h; sourceTree = ""; }; @@ -91,7 +92,6 @@ 26711C91195D47820033EDA2 /* catch_tag_alias.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_tag_alias.h; sourceTree = ""; }; 26711C92195D48F60033EDA2 /* catch_tag_alias_registry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_tag_alias_registry.hpp; sourceTree = ""; }; 26711C94195D4B120033EDA2 /* catch_tag_alias_registry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_tag_alias_registry.h; sourceTree = ""; }; - 26759472171C72A400A84BD1 /* catch_sfinae.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_sfinae.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 26759473171C74C200A84BD1 /* catch_compiler_capabilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = catch_compiler_capabilities.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 26847E5B16BBAB790043B9C1 /* catch_message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_message.h; sourceTree = ""; }; 26847E5C16BBACB60043B9C1 /* catch_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_message.hpp; sourceTree = ""; }; @@ -101,7 +101,6 @@ 2691574B1A532A280054F1ED /* ToStringTuple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringTuple.cpp; path = ../../../SelfTest/ToStringTuple.cpp; sourceTree = ""; }; 26926E8318D7777D004E10F2 /* clara.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = clara.h; path = ../../../../include/external/clara.h; sourceTree = ""; }; 26926E8418D77809004E10F2 /* tbc_text_format.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tbc_text_format.h; path = ../../../../include/external/tbc_text_format.h; sourceTree = ""; }; - 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SectionTrackerTests.cpp; path = ../../../SelfTest/SectionTrackerTests.cpp; sourceTree = ""; }; 26948287179EF7F900ED166E /* catch_test_case_tracker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_tracker.hpp; sourceTree = ""; }; 2694A1FB16A0000E004816E3 /* catch_text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catch_text.cpp; sourceTree = ""; }; 269831E519078C1600BB0CE0 /* catch_tostring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_tostring.h; sourceTree = ""; }; @@ -109,7 +108,9 @@ 269831E719121CA500BB0CE0 /* catch_reporter_compact.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_compact.hpp; sourceTree = ""; }; 26AEAF1617BEA18E009E32C9 /* catch_platform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_platform.h; sourceTree = ""; }; 26DACF2F17206D3400A21326 /* catch_text.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_text.h; sourceTree = ""; }; + 26DFD3B11B53F84700FD6F16 /* catch_wildcard_pattern.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_wildcard_pattern.hpp; sourceTree = ""; }; 26E1B7D119213BC900812682 /* CmdLineTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CmdLineTests.cpp; path = ../../../SelfTest/CmdLineTests.cpp; sourceTree = ""; }; + 26EDFBD91B72011F00B1873C /* catch_reporter_multi.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_multi.hpp; sourceTree = ""; }; 4A084F1C15DACEEA0027E631 /* catch_test_case_info.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_info.hpp; sourceTree = ""; }; 4A3D7DD01503869D005F9203 /* catch_matchers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_matchers.hpp; sourceTree = ""; }; 4A45DA2316161EF9004F8D6B /* catch_console_colour.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_console_colour.cpp; path = ../../../SelfTest/SurrogateCpps/catch_console_colour.cpp; sourceTree = ""; }; @@ -136,7 +137,7 @@ 4A6D0C34149B3D9E00DB3EAA /* MiscTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MiscTests.cpp; path = ../../../SelfTest/MiscTests.cpp; sourceTree = ""; }; 4A6D0C35149B3D9E00DB3EAA /* TestMain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestMain.cpp; path = ../../../SelfTest/TestMain.cpp; sourceTree = ""; }; 4A6D0C36149B3D9E00DB3EAA /* TrickyTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TrickyTests.cpp; path = ../../../SelfTest/TrickyTests.cpp; sourceTree = ""; }; - 4A6D0C42149B3E1500DB3EAA /* catch_runner.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = catch_runner.hpp; path = ../../../../include/catch_runner.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + 4A6D0C42149B3E1500DB3EAA /* catch_session.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = catch_session.hpp; path = ../../../../include/catch_session.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 4A6D0C43149B3E1500DB3EAA /* catch_with_main.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_with_main.hpp; path = ../../../../include/catch_with_main.hpp; sourceTree = ""; }; 4A6D0C44149B3E1500DB3EAA /* catch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch.hpp; path = ../../../../include/catch.hpp; sourceTree = ""; }; 4A6D0C46149B3E3D00DB3EAA /* catch_approx.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_approx.hpp; sourceTree = ""; }; @@ -163,7 +164,7 @@ 4A6D0C5B149B3E3D00DB3EAA /* catch_reporter_registry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_registry.hpp; sourceTree = ""; }; 4A6D0C5C149B3E3D00DB3EAA /* catch_result_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_result_type.h; sourceTree = ""; }; 4A6D0C5D149B3E3D00DB3EAA /* catch_assertionresult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = catch_assertionresult.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 4A6D0C5E149B3E3D00DB3EAA /* catch_runner_impl.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_runner_impl.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + 4A6D0C5E149B3E3D00DB3EAA /* catch_run_context.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_run_context.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 4A6D0C5F149B3E3D00DB3EAA /* catch_section.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_section.hpp; sourceTree = ""; }; 4A6D0C60149B3E3D00DB3EAA /* catch_stream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_stream.hpp; sourceTree = ""; }; 4A6D0C61149B3E3D00DB3EAA /* catch_test_case_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_test_case_info.h; sourceTree = ""; }; @@ -211,7 +212,7 @@ 266E9AD317290E710061DAB2 /* Introspective Tests */ = { isa = PBXGroup; children = ( - 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */, + 26059AF11BD4B94C003D575C /* PartTrackerTests.cpp */, 26E1B7D119213BC900812682 /* CmdLineTests.cpp */, 26711C8D195D465C0033EDA2 /* TagAliasTests.cpp */, ); @@ -285,7 +286,7 @@ 4AA7B8B4165428BA003155F6 /* catch_version.hpp */, 4A8E4DCF160A34E200194CBD /* SurrogateCpps */, 4A6D0C44149B3E1500DB3EAA /* catch.hpp */, - 4A6D0C42149B3E1500DB3EAA /* catch_runner.hpp */, + 4A6D0C42149B3E1500DB3EAA /* catch_session.hpp */, 4A6D0C43149B3E1500DB3EAA /* catch_with_main.hpp */, 4A6D0C45149B3E3D00DB3EAA /* internal */, 4A6D0C65149B3E3D00DB3EAA /* reporters */, @@ -318,6 +319,7 @@ 4A6D0C68149B3E3D00DB3EAA /* catch_reporter_xml.hpp */, 4AB42F84166F3E1A0099F2C8 /* catch_reporter_console.hpp */, 2691574A1A4480C50054F1ED /* catch_reporter_teamcity.hpp */, + 26EDFBD91B72011F00B1873C /* catch_reporter_multi.hpp */, ); name = reporters; path = ../../../../include/reporters; @@ -358,7 +360,7 @@ 4A4B0F9715CE6CFB00AE2392 /* catch_registry_hub.hpp */, 4A6D0C50149B3E3D00DB3EAA /* catch_generators_impl.hpp */, 4A6D0C52149B3E3D00DB3EAA /* catch_context_impl.hpp */, - 4A6D0C5E149B3E3D00DB3EAA /* catch_runner_impl.hpp */, + 4A6D0C5E149B3E3D00DB3EAA /* catch_run_context.hpp */, 4A6D0C62149B3E3D00DB3EAA /* catch_test_case_registry_impl.hpp */, 4AB1C73514F97BDA00F31DF7 /* catch_console_colour_impl.hpp */, 4A4B0F9B15CEF8C400AE2392 /* catch_notimplemented_exception.hpp */, @@ -453,6 +455,7 @@ 266ECD8C1713614B0030D735 /* catch_legacy_reporter_adapter.hpp */, 266ECD8D1713614B0030D735 /* catch_legacy_reporter_adapter.h */, 4A6D0C49149B3E3D00DB3EAA /* catch_common.h */, + 262E739A1846759000CAC268 /* catch_common.hpp */, 4A6D0C4B149B3E3D00DB3EAA /* catch_debugger.hpp */, 261488FF184DC4A20041FBEB /* catch_debugger.h */, 4A6D0C60149B3E3D00DB3EAA /* catch_stream.hpp */, @@ -461,17 +464,16 @@ 4AB77CB51551AEA200857BF0 /* catch_ptr.hpp */, 4AEE0326161431070071E950 /* catch_streambuf.h */, 4ACE21C8166CA19700FB5509 /* catch_option.hpp */, - 26759472171C72A400A84BD1 /* catch_sfinae.hpp */, 26759473171C74C200A84BD1 /* catch_compiler_capabilities.h */, 26DACF2F17206D3400A21326 /* catch_text.h */, 263FD06117AF8DF200988A20 /* catch_timer.h */, 26AEAF1617BEA18E009E32C9 /* catch_platform.h */, - 262E739A1846759000CAC268 /* catch_common.hpp */, 261488FC184D1DC10041FBEB /* catch_stream.h */, 268F47B018A93F7800D8C14F /* catch_clara.h */, 2656C226192A77EF0040DB02 /* catch_suppress_warnings.h */, 2656C227192A78410040DB02 /* catch_reenable_warnings.h */, 263F7A4519A66608009474C2 /* catch_fatal_condition.hpp */, + 26DFD3B11B53F84700FD6F16 /* catch_wildcard_pattern.hpp */, ); name = Infrastructure; sourceTree = ""; @@ -546,6 +548,7 @@ 4A6D0C3E149B3D9E00DB3EAA /* TestMain.cpp in Sources */, 4A6D0C3F149B3D9E00DB3EAA /* TrickyTests.cpp in Sources */, 263F7A4D19B6FE1E009474C2 /* ToStringWhich.cpp in Sources */, + 26059AF21BD4B94C003D575C /* PartTrackerTests.cpp in Sources */, 263F7A4B19B6FE1E009474C2 /* ToStringPair.cpp in Sources */, 4AEE032016142F910071E950 /* catch_common.cpp in Sources */, 263F7A4C19B6FE1E009474C2 /* ToStringVector.cpp in Sources */, @@ -572,7 +575,6 @@ 26847E5F16BBADB40043B9C1 /* catch_message.cpp in Sources */, 266B06B816F3A60A004ED264 /* VariadicMacrosTests.cpp in Sources */, 266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */, - 26948286179A9AB900ED166E /* SectionTrackerTests.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/projects/XCode/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.xcworkspace/xcshareddata/CatchSelfTestSingle.xccheckout b/projects/XCode/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.xcworkspace/xcshareddata/CatchSelfTestSingle.xccheckout index fd24e72b..cce7052b 100644 --- a/projects/XCode/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.xcworkspace/xcshareddata/CatchSelfTestSingle.xccheckout +++ b/projects/XCode/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.xcworkspace/xcshareddata/CatchSelfTestSingle.xccheckout @@ -10,31 +10,31 @@ CatchSelfTestSingle IDESourceControlProjectOriginsDictionary - 01DD8CA9-7DC3-46BC-B998-EFF40EA3485F - ssh://github.com/philsquared/Catch.git + 90C00904F36E6ADB57A7313E998815D255B0DEAF + https://github.com/philsquared/Catch.git IDESourceControlProjectPath - projects/XCode4/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.xcworkspace + projects/XCode/CatchSelfTest/CatchSelfTestSingle.xcodeproj IDESourceControlProjectRelativeInstallPathDictionary - 01DD8CA9-7DC3-46BC-B998-EFF40EA3485F + 90C00904F36E6ADB57A7313E998815D255B0DEAF ../../../../.. IDESourceControlProjectURL - ssh://github.com/philsquared/Catch.git + https://github.com/philsquared/Catch.git IDESourceControlProjectVersion - 110 + 111 IDESourceControlProjectWCCIdentifier - 01DD8CA9-7DC3-46BC-B998-EFF40EA3485F + 90C00904F36E6ADB57A7313E998815D255B0DEAF IDESourceControlProjectWCConfigurations IDESourceControlRepositoryExtensionIdentifierKey public.vcs.git IDESourceControlWCCIdentifierKey - 01DD8CA9-7DC3-46BC-B998-EFF40EA3485F + 90C00904F36E6ADB57A7313E998815D255B0DEAF IDESourceControlWCCName - Catch + Catch-Develop diff --git a/projects/runners/iTchRunner/internal/iTchRunnerAppDelegate.h b/projects/runners/iTchRunner/internal/iTchRunnerAppDelegate.h index a98b45d5..522291a9 100644 --- a/projects/runners/iTchRunner/internal/iTchRunnerAppDelegate.h +++ b/projects/runners/iTchRunner/internal/iTchRunnerAppDelegate.h @@ -13,7 +13,7 @@ -@interface iTchRunnerAppDelegate : NSObject +@interface iTchRunnerAppDelegate : NSObject { UIWindow *window; } @@ -25,15 +25,15 @@ /////////////////////////////////////////////////////////////////////////////// -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; [window setUserInteractionEnabled:YES]; [window setMultipleTouchEnabled:YES]; - + CGRect screenRect = [[UIScreen mainScreen] applicationFrame]; iTchRunnerMainView* view = [[iTchRunnerMainView alloc] initWithFrame:screenRect]; - + [window addSubview:view]; [window makeKeyAndVisible]; arcSafeRelease( view ); @@ -42,7 +42,7 @@ } /////////////////////////////////////////////////////////////////////////////// -- (void)dealloc +- (void)dealloc { #if !CATCH_ARC_ENABLED [window release]; @@ -52,7 +52,7 @@ /////////////////////////////////////////////////////////////////////////////// -- (void)applicationWillResignActive:(UIApplication *)application +- (void)applicationWillResignActive:(UIApplication *)application { /* Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. @@ -62,17 +62,17 @@ /////////////////////////////////////////////////////////////////////////////// -- (void)applicationDidEnterBackground:(UIApplication *)application +- (void)applicationDidEnterBackground:(UIApplication *)application { /* - Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. If your application supports background execution, called instead of applicationWillTerminate: when the user quits. */ } /////////////////////////////////////////////////////////////////////////////// -- (void)applicationWillEnterForeground:(UIApplication *)application +- (void)applicationWillEnterForeground:(UIApplication *)application { /* Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background. @@ -81,7 +81,7 @@ /////////////////////////////////////////////////////////////////////////////// -- (void)applicationDidBecomeActive:(UIApplication *)application +- (void)applicationDidBecomeActive:(UIApplication *)application { /* Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. @@ -90,7 +90,7 @@ /////////////////////////////////////////////////////////////////////////////// -- (void)applicationWillTerminate:(UIApplication *)application +- (void)applicationWillTerminate:(UIApplication *)application { /* Called when the application is about to terminate. @@ -100,7 +100,7 @@ /////////////////////////////////////////////////////////////////////////////// -- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application +- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { /* Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. diff --git a/projects/runners/iTchRunner/internal/iTchRunnerMainView.h b/projects/runners/iTchRunner/internal/iTchRunnerMainView.h index ee78004c..c6a6394e 100644 --- a/projects/runners/iTchRunner/internal/iTchRunnerMainView.h +++ b/projects/runners/iTchRunner/internal/iTchRunnerMainView.h @@ -33,7 +33,7 @@ /////////////////////////////////////////////////////////////////////////////// -(id) initWithFrame:(CGRect)frame { - if ((self = [super initWithFrame:frame])) + if ((self = [super initWithFrame:frame])) { // Initialization code self.backgroundColor = [UIColor blackColor]; @@ -64,7 +64,7 @@ /////////////////////////////////////////////////////////////////////////////// -(void) showAlert -{ +{ UIActionSheet* menu = [[UIActionSheet alloc] initWithTitle:@"Options" delegate:self cancelButtonTitle:nil @@ -72,7 +72,7 @@ otherButtonTitles:@"Run all tests", nil]; [menu showInView: self]; arcSafeRelease( menu ); - + } // This is a copy & paste from Catch::Runner2 to get us bootstrapped (this is due to all be @@ -144,7 +144,7 @@ inline Catch::Totals runTestsForGroup( Catch::RunContext& context, const Catch:: { const Catch::AssertionResult& resultInfo = *pResultInfo; std::ostringstream oss; - + if( resultInfo.hasExpression() ) { oss << resultInfo.getExpression(); @@ -174,7 +174,7 @@ inline Catch::Totals runTestsForGroup( Catch::RunContext& context, const Catch:: default: break; } - + if( resultInfo.hasExpression() ) { oss << " for: " << resultInfo.getExpandedExpression(); diff --git a/projects/runners/iTchRunner/internal/iTchRunnerReporter.h b/projects/runners/iTchRunner/internal/iTchRunnerReporter.h index a7adf866..d2628861 100644 --- a/projects/runners/iTchRunner/internal/iTchRunnerReporter.h +++ b/projects/runners/iTchRunner/internal/iTchRunnerReporter.h @@ -13,7 +13,7 @@ @protocol iTchRunnerDelegate --(void) testWasRun: (const Catch::AssertionResult*) result; +-(void) testWasRun: (const Catch::AssertionResult*) result; @end @@ -38,14 +38,14 @@ namespace Catch { return true; } - + /////////////////////////////////////////////////////////////////////////// static std::string getDescription () { return "Captures results for iOS runner"; } - + /////////////////////////////////////////////////////////////////////////// size_t getSucceeded () @@ -53,7 +53,7 @@ namespace Catch { return m_totals.assertions.passed; } - + /////////////////////////////////////////////////////////////////////////// size_t getFailed () @@ -61,20 +61,20 @@ namespace Catch { return m_totals.assertions.failed; } - + /////////////////////////////////////////////////////////////////////////// void reset() { m_totals = Totals(); } - + private: // IReporter - + /////////////////////////////////////////////////////////////////////////// virtual void StartTesting () {} - + /////////////////////////////////////////////////////////////////////////// virtual void EndTesting ( @@ -83,7 +83,7 @@ namespace Catch { m_totals = totals; } - + /////////////////////////////////////////////////////////////////////////// virtual void Result ( @@ -92,7 +92,7 @@ namespace Catch { [m_delegate testWasRun: &result]; } - + /////////////////////////////////////////////////////////////////////////// // Deliberately unimplemented: virtual void StartGroup( const std::string& ){} @@ -107,7 +107,7 @@ namespace Catch private: Totals m_totals; - + id m_delegate; }; } diff --git a/scripts/approvalTests.py b/scripts/approvalTests.py index 92e2876c..618812f8 100644 --- a/scripts/approvalTests.py +++ b/scripts/approvalTests.py @@ -15,7 +15,8 @@ pathParser = re.compile( r'(.*?)/(.*\..pp)(.*)' ) lineNumberParser = re.compile( r'(.*)line="[0-9]*"(.*)' ) hexParser = re.compile( r'(.*)\b(0[xX][0-9a-fA-F]+)\b(.*)' ) durationsParser = re.compile( r'(.*)time="[0-9]*\.[0-9]*"(.*)' ) -versionParser = re.compile( r'(.*?)Catch v[0-9]*\.[0-9]*\.[0-9].?( .*)' ) +versionParser = re.compile( r'(.*?)Catch v[0-9]*\.[0-9]*\.[0-9]*(.*)' ) +devVersionParser = re.compile( r'(.*?)Catch v[0-9]*\.[0-9]*\.[0-9]*-develop\.[0-9]*(.*)' ) if len(sys.argv) == 2: cmdPath = sys.argv[1] @@ -41,9 +42,13 @@ def filterLine( line ): if path.startswith( catchPath ): path = path[1+len(catchPath):] line = m.group(1) + path + m.group(3) - m = versionParser.match( line ) + m = devVersionParser.match( line ) if m: line = m.group(1) + "" + m.group(2) + else: + m = versionParser.match( line ) + if m: + line = m.group(1) + "" + m.group(2) while True: m = hexParser.match( line ) diff --git a/scripts/fixTrailingWhitespace.py b/scripts/fixTrailingWhitespace.py new file mode 100644 index 00000000..a1b6bbe8 --- /dev/null +++ b/scripts/fixTrailingWhitespace.py @@ -0,0 +1,46 @@ +from __future__ import print_function +import os +from scriptCommon import catchPath + +changedFiles = 0 + +def isSourceFile( path ): + return path.endswith( ".cpp" ) or path.endswith( ".h" ) or path.endswith( ".hpp" ) + +def fixAllFilesInDir( dir ): + for f in os.listdir( dir ): + path = os.path.join( dir,f ) + if os.path.isfile( path ): + if isSourceFile( path ): + fixFile( path ) + else: + fixAllFilesInDir( path ) + +def fixFile( path ): + f = open( path, 'r' ) + lines = [] + changed = 0 + for line in f: + trimmed = line.rstrip() + "\n" + if trimmed != line: + changed = changed +1 + lines.append( trimmed ) + f.close() + if changed > 0: + global changedFiles + changedFiles = changedFiles + 1 + print( path + ":" ) + print( " - fixed " + str(changed) + " line(s)" ) + altPath = path + ".backup" + os.rename( path, altPath ) + f2 = open( path, 'w' ) + for line in lines: + f2.write( line ) + f2.close() + os.remove( altPath ) + +fixAllFilesInDir(catchPath) +if changedFiles > 0: + print( "Fixed " + str(changedFiles) + " file(s)" ) +else: + print( "No trailing whitespace found" ) diff --git a/single_include/catch.hpp b/single_include/catch.hpp index de61226c..1d0d8085 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v1.2.1 - * Generated: 2015-06-30 18:23:27.961086 + * Catch v1.3.0 + * Generated: 2015-12-04 10:18:17.055188 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -21,8 +21,6 @@ // #included from: internal/catch_suppress_warnings.h -#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED - #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) @@ -37,6 +35,7 @@ # pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" @@ -44,7 +43,6 @@ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif - #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL #endif @@ -84,11 +82,19 @@ // CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? // CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they @@ -130,10 +136,13 @@ // GCC #ifdef __GNUC__ -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR #endif +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + #endif // __GNUC__ //////////////////////////////////////////////////////////////////////////////// @@ -142,6 +151,7 @@ #if (_MSC_VER >= 1600) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) @@ -151,6 +161,8 @@ #endif // _MSC_VER +//////////////////////////////////////////////////////////////////////////////// + // Use variadic macros if the compiler supports them #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ @@ -165,7 +177,7 @@ // C++ language feature support // catch all support for C++11 -#if (__cplusplus >= 201103L) +#if defined(__cplusplus) && __cplusplus >= 201103L # define CATCH_CPP11_OR_GREATER @@ -193,6 +205,17 @@ # define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + #endif // __cplusplus >= 201103L // Now set the actual defines based on the above + anything the user has configured @@ -212,7 +235,16 @@ # define CATCH_CONFIG_CPP11_TUPLE #endif #if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) -#define CATCH_CONFIG_VARIADIC_MACROS +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif // noexcept support: @@ -224,8 +256,36 @@ # define CATCH_NOEXCEPT_IS(x) #endif +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + namespace Catch { + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + class NonCopyable { #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; @@ -312,6 +372,9 @@ namespace Catch { void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as @@ -397,7 +460,7 @@ namespace Catch { template class Ptr { public: - Ptr() : m_p( NULL ){} + Ptr() : m_p( CATCH_NULL ){} Ptr( T* p ) : m_p( p ){ if( m_p ) m_p->addRef(); @@ -413,7 +476,7 @@ namespace Catch { void reset() { if( m_p ) m_p->release(); - m_p = NULL; + m_p = CATCH_NULL; } Ptr& operator = ( T* p ){ Ptr temp( p ); @@ -426,12 +489,11 @@ namespace Catch { return *this; } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() { return m_p; } - const T* get() const{ return m_p; } + T* get() const{ return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } - bool operator !() const { return m_p == NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } private: T* m_p; @@ -528,9 +590,13 @@ namespace Catch { struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; - + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + } namespace Catch { @@ -563,27 +629,32 @@ struct NameAndDesc { const char* description; }; +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + struct AutoReg { - AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); template - AutoReg( void (C::*method)(), - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - registerTestCase( new MethodTestCase( method ), - className, - nameAndDesc, - lineInfo ); - } + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { - void registerTestCase( ITestCase* testCase, - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ); + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } ~AutoReg(); @@ -592,6 +663,11 @@ private: void operator= ( AutoReg const& ); }; +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS @@ -615,6 +691,10 @@ private: } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ @@ -636,6 +716,9 @@ private: } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); #endif // #included from: internal/catch_capture.hpp @@ -758,6 +841,323 @@ namespace Catch { } // end namespace Catch +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) == 0; + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) == expr.size() - m_data.m_str.size(); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + namespace Catch { struct TestFailureException{}; @@ -784,7 +1184,8 @@ namespace Catch { ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, - ResultDisposition::Flags resultDisposition ); + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); template ExpressionLhs operator <= ( T const& operand ); @@ -813,6 +1214,9 @@ namespace Catch { void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void captureResult( ResultWas::OfType resultType ); void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; bool allowThrows() const; @@ -991,13 +1395,51 @@ namespace Internal { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + #ifdef CATCH_CONFIG_CPP11_NULLPTR // pointer to nullptr_t (when comparing against nullptr) template bool compare( std::nullptr_t, T* rhs ) { - return Evaluator::evaluate( NULL, rhs ); + return Evaluator::evaluate( nullptr, rhs ); } template bool compare( T* lhs, std::nullptr_t ) { - return Evaluator::evaluate( lhs, NULL ); + return Evaluator::evaluate( lhs, nullptr ); } #endif // CATCH_CONFIG_CPP11_NULLPTR @@ -1095,6 +1537,11 @@ std::string toString( char value ); std::string toString( signed char value ); std::string toString( unsigned char value ); +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif @@ -1107,7 +1554,7 @@ std::string toString( std::nullptr_t ); namespace Detail { - extern std::string unprintableString; + extern const std::string unprintableString; struct BorgType { template BorgType( T const& ); @@ -1190,7 +1637,7 @@ struct StringMaker { template static std::string convert( U* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } @@ -1200,7 +1647,7 @@ template struct StringMaker { static std::string convert( R C::* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } @@ -1472,6 +1919,7 @@ namespace Catch { class AssertionResult; struct AssertionInfo; struct SectionInfo; + struct SectionEndInfo; struct MessageInfo; class ScopedMessageBuilder; struct Counts; @@ -1483,7 +1931,8 @@ namespace Catch { virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; - virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; @@ -1604,16 +2053,16 @@ namespace Catch { } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + __catchResult.captureExpectedException( matcher ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ @@ -1668,12 +2117,12 @@ namespace Catch { do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ try { \ - std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + std::string matcherAsString = (matcher).toString(); \ __catchResult \ .setLhs( Catch::toString( arg ) ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setOp( "matches" ) \ - .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + .setResultType( (matcher).match( arg ) ); \ __catchResult.captureExpression(); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ @@ -1687,21 +2136,6 @@ namespace Catch { // #included from: catch_section_info.h #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED -namespace Catch { - - struct SectionInfo { - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description = std::string() ); - - std::string name; - std::string description; - SourceLineInfo lineInfo; - }; - -} // end namespace Catch - // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED @@ -1772,6 +2206,31 @@ namespace Catch { }; } +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + // #included from: catch_timer.h #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED @@ -2012,6 +2471,8 @@ using namespace Generators; #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include +#include + // #included from: catch_interfaces_registry_hub.h #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED @@ -2036,7 +2497,8 @@ namespace Catch { struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; }; @@ -2048,14 +2510,16 @@ namespace Catch { } - namespace Catch { typedef std::string(*exceptionTranslateFunction)(); + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + struct IExceptionTranslator { virtual ~IExceptionTranslator(); - virtual std::string translate() const = 0; + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; }; struct IExceptionTranslatorRegistry { @@ -2073,9 +2537,12 @@ namespace Catch { : m_translateFunction( translateFunction ) {} - virtual std::string translate() const { + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { try { - throw; + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); } catch( T& ex ) { return m_translateFunction( ex ); @@ -2182,231 +2649,6 @@ inline std::string toString( Detail::Approx const& value ) { } // end namespace Catch -// #included from: internal/catch_matchers.hpp -#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED - -namespace Catch { -namespace Matchers { - namespace Impl { - - template - struct Matcher : SharedImpl - { - typedef ExpressionT ExpressionType; - - virtual ~Matcher() {} - virtual Ptr clone() const = 0; - virtual bool match( ExpressionT const& expr ) const = 0; - virtual std::string toString() const = 0; - }; - - template - struct MatcherImpl : Matcher { - - virtual Ptr > clone() const { - return Ptr >( new DerivedT( static_cast( *this ) ) ); - } - }; - - namespace Generic { - - template - class AllOf : public MatcherImpl, ExpressionT> { - public: - - AllOf() {} - AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} - - AllOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( !m_matchers[i]->match( expr ) ) - return false; - return true; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " and "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - template - class AnyOf : public MatcherImpl, ExpressionT> { - public: - - AnyOf() {} - AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} - - AnyOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( m_matchers[i]->match( expr ) ) - return true; - return false; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " or "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - } - - namespace StdString { - - inline std::string makeString( std::string const& str ) { return str; } - inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } - - struct Equals : MatcherImpl { - Equals( std::string const& str ) : m_str( str ){} - Equals( Equals const& other ) : m_str( other.m_str ){} - - virtual ~Equals(); - - virtual bool match( std::string const& expr ) const { - return m_str == expr; - } - virtual std::string toString() const { - return "equals: \"" + m_str + "\""; - } - - std::string m_str; - }; - - struct Contains : MatcherImpl { - Contains( std::string const& substr ) : m_substr( substr ){} - Contains( Contains const& other ) : m_substr( other.m_substr ){} - - virtual ~Contains(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) != std::string::npos; - } - virtual std::string toString() const { - return "contains: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct StartsWith : MatcherImpl { - StartsWith( std::string const& substr ) : m_substr( substr ){} - StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~StartsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == 0; - } - virtual std::string toString() const { - return "starts with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct EndsWith : MatcherImpl { - EndsWith( std::string const& substr ) : m_substr( substr ){} - EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~EndsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == expr.size() - m_substr.size(); - } - virtual std::string toString() const { - return "ends with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - } // namespace StdString - } // namespace Impl - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); - } - - inline Impl::StdString::Equals Equals( std::string const& str ) { - return Impl::StdString::Equals( str ); - } - inline Impl::StdString::Equals Equals( const char* str ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); - } - inline Impl::StdString::Contains Contains( std::string const& substr ) { - return Impl::StdString::Contains( substr ); - } - inline Impl::StdString::Contains Contains( const char* substr ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { - return Impl::StdString::StartsWith( substr ); - } - inline Impl::StdString::StartsWith StartsWith( const char* substr ) { - return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { - return Impl::StdString::EndsWith( substr ); - } - inline Impl::StdString::EndsWith EndsWith( const char* substr ) { - return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); - } - -} // namespace Matchers - -using namespace Matchers; - -} // namespace Catch - // #included from: internal/catch_interfaces_tag_alias_registry.h #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED @@ -2440,12 +2682,12 @@ namespace Catch { template class Option { public: - Option() : nullableValue( NULL ) {} + Option() : nullableValue( CATCH_NULL ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) {} ~Option() { @@ -2469,7 +2711,7 @@ namespace Catch { void reset() { if( nullableValue ) nullableValue->~T(); - nullableValue = NULL; + nullableValue = CATCH_NULL; } T& operator*() { return *nullableValue; } @@ -2481,10 +2723,10 @@ namespace Catch { return nullableValue ? *nullableValue : defaultValue; } - bool some() const { return nullableValue != NULL; } - bool none() const { return nullableValue == NULL; } + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } - bool operator !() const { return nullableValue == NULL; } + bool operator !() const { return nullableValue == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( some() ); } @@ -2542,6 +2784,8 @@ namespace Catch { TestCaseInfo( TestCaseInfo const& other ); + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + bool isHidden() const; bool throws() const; bool okToFail() const; @@ -2654,7 +2898,7 @@ namespace Catch { inline size_t registerTestMethods() { size_t noTestMethods = 0; - int noClasses = objc_getClassList( NULL, 0 ); + int noClasses = objc_getClassList( CATCH_NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); @@ -2796,7 +3040,7 @@ return @ desc; \ #pragma clang diagnostic ignored "-Wweak-vtables" #endif -// #included from: ../catch_runner.hpp +// #included from: ../catch_session.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp @@ -2821,6 +3065,67 @@ return @ desc; \ #pragma clang diagnostic ignored "-Wpadded" #endif +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + #include #include @@ -2832,50 +3137,18 @@ namespace Catch { virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; class NamePattern : public Pattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - public: - NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { - if( startsWith( m_name, "*" ) ) { - m_name = m_name.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_name, "*" ) ) { - m_name = m_name.substr( 0, m_name.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_name == toLower( testCase.name ); - case WildcardAtStart: - return endsWith( toLower( testCase.name ), m_name ); - case WildcardAtEnd: - return startsWith( toLower( testCase.name ), m_name ); - case WildcardAtBothEnds: - return contains( toLower( testCase.name ), m_name ); - } - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - throw std::logic_error( "Unknown enum" ); -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + return m_wildcardPattern.matches( toLower( testCase.name ) ); } private: - std::string m_name; - WildcardPosition m_wildcard; + WildcardPattern m_wildcardPattern; }; + class TagPattern : public Pattern { public: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} @@ -2886,6 +3159,7 @@ namespace Catch { private: std::string m_tag; }; + class ExcludedPattern : public Pattern { public: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} @@ -3083,28 +3357,62 @@ namespace Catch { // #included from: catch_stream.h #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED -#include +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#endif +#include namespace Catch { - class Stream { + class StreamBufBase : public std::streambuf { public: - Stream(); - Stream( std::streambuf* _streamBuf, bool _isOwned ); - void release(); - - std::streambuf* streamBuf; - - private: - bool isOwned; + virtual ~StreamBufBase() CATCH_NOEXCEPT; }; +} + +#include +#include +#include + +namespace Catch { std::ostream& cout(); std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; } #include @@ -3132,6 +3440,7 @@ namespace Catch { showHelp( false ), showInvisibles( false ), forceColour( false ), + filenamesAsTags( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), @@ -3151,6 +3460,7 @@ namespace Catch { bool showHelp; bool showInvisibles; bool forceColour; + bool filenamesAsTags; int abortAfter; unsigned int rngSeed; @@ -3160,11 +3470,11 @@ namespace Catch { ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; - std::string reporterName; std::string outputFilename; std::string name; std::string processName; + std::vector reporterNames; std::vector testsOrTags; }; @@ -3176,12 +3486,11 @@ namespace Catch { public: Config() - : m_os( Catch::cout().rdbuf() ) {} Config( ConfigData const& data ) : m_data( data ), - m_os( Catch::cout().rdbuf() ) + m_stream( openStream() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); @@ -3192,12 +3501,6 @@ namespace Catch { } virtual ~Config() { - m_os.rdbuf( Catch::cout().rdbuf() ); - m_stream.release(); - } - - void setFilename( std::string const& filename ) { - m_data.outputFilename = filename; } std::string const& getFilename() const { @@ -3213,18 +3516,7 @@ namespace Catch { bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } - void setStreamBuf( std::streambuf* buf ) { - m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); - } - - void useStream( std::string const& streamName ) { - Stream stream = createStream( streamName ); - setStreamBuf( stream.streamBuf ); - m_stream.release(); - m_stream = stream; - } - - std::string getReporterName() const { return m_data.reporterName; } + std::vector getReporterNames() const { return m_data.reporterNames; } int abortAfter() const { return m_data.abortAfter; } @@ -3235,7 +3527,7 @@ namespace Catch { // IConfig interface virtual bool allowThrows() const { return !m_data.noThrow; } - virtual std::ostream& stream() const { return m_os; } + virtual std::ostream& stream() const { return m_stream->stream(); } virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } @@ -3245,10 +3537,22 @@ namespace Catch { virtual bool forceColour() const { return m_data.forceColour; } private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } ConfigData m_data; - Stream m_stream; - mutable std::ostream m_os; + std::auto_ptr m_stream; TestSpec m_testSpec; }; @@ -3517,11 +3821,11 @@ namespace Clara { template class BoundArgFunction { public: - BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction() : functionObj( CATCH_NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CATCH_NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL; delete functionObj; functionObj = newFunctionObj; return *this; @@ -3537,7 +3841,7 @@ namespace Clara { bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { - return functionObj != NULL; + return functionObj != CATCH_NULL; } private: IArgFunction* functionObj; @@ -3755,12 +4059,7 @@ namespace Clara { } }; - // NOTE: std::auto_ptr is deprecated in c++11/c++0x -#if defined(__cplusplus) && __cplusplus > 199711L - typedef std::unique_ptr ArgAutoPtr; -#else - typedef std::auto_ptr ArgAutoPtr; -#endif + typedef CATCH_AUTO_PTR( Arg ) ArgAutoPtr; friend void addOptName( Arg& arg, std::string const& optName ) { @@ -3836,8 +4135,8 @@ namespace Clara { m_arg->description = description; return *this; } - ArgBuilder& detail( std::string const& detail ) { - m_arg->detail = detail; + ArgBuilder& detail( std::string const& _detail ) { + m_arg->detail = _detail; return *this; } @@ -3920,14 +4219,14 @@ namespace Clara { maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usage( it->commands(), Detail::TextAttributes() + Detail::Text usageText( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); - for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { - std::string usageCol = i < usage.size() ? usage[i] : ""; + for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) { + std::string usageCol = i < usageText.size() ? usageText[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) @@ -4133,6 +4432,7 @@ namespace Catch { config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) @@ -4226,7 +4526,7 @@ namespace Catch { cli["-r"]["--reporter"] // .placeholder( "name[:filename]" ) .describe( "reporter to use (defaults to console)" ) - .bind( &ConfigData::reporterName, "name" ); + .bind( &addReporterName, "name" ); cli["-n"]["--name"] .describe( "suite name" ) @@ -4263,6 +4563,10 @@ namespace Catch { .describe( "load test names to run from a file" ) .bind( &loadTestNamesFromFile, "filename" ); + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) @@ -4520,18 +4824,18 @@ namespace Catch { namespace Catch { struct ReporterConfig { - explicit ReporterConfig( Ptr const& _fullConfig ) + explicit ReporterConfig( Ptr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& stream() const { return *m_stream; } - Ptr fullConfig() const { return m_fullConfig; } + Ptr fullConfig() const { return m_fullConfig; } private: std::ostream* m_stream; - Ptr m_fullConfig; + Ptr m_fullConfig; }; struct ReporterPreferences { @@ -4733,6 +5037,7 @@ namespace Catch // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; @@ -4741,20 +5046,24 @@ namespace Catch virtual void skipTest( TestCaseInfo const& testInfo ) = 0; }; - struct IReporterFactory { + struct IReporterFactory : IShared { virtual ~IReporterFactory(); virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { - typedef std::map FactoryMap; + typedef std::map > FactoryMap; + typedef std::vector > Listeners; virtual ~IReporterRegistry(); - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; }; + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + } #include @@ -4777,8 +5086,7 @@ namespace Catch { nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4806,8 +5114,7 @@ namespace Catch { if( !config.testSpec().hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4847,8 +5154,7 @@ namespace Catch { std::map tagCounts; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4919,7 +5225,7 @@ namespace Catch { } // end namespace Catch -// #included from: internal/catch_runner_impl.hpp +// #included from: internal/catch_run_context.hpp #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED // #included from: catch_test_case_tracker.hpp @@ -4928,137 +5234,300 @@ namespace Catch { #include #include #include +#include namespace Catch { -namespace SectionTracking { +namespace TestCaseTracking { - class TrackedSection { + struct ITracker : SharedImpl<> { + virtual ~ITracker(); - typedef std::map TrackedSections; + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { - public: enum RunState { NotStarted, Executing, - ExecutingChildren, - Completed + CompletedCycle }; - TrackedSection( std::string const& name, TrackedSection* parent ) - : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) {} - RunState runState() const { return m_runState; } + ITracker& startRun(); - TrackedSection* findChild( std::string const& childName ); - TrackedSection* acquireChild( std::string const& childName ); - - void enter() { - if( m_runState == NotStarted ) - m_runState = Executing; + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; } - void leave(); - TrackedSection* getParent() { - return m_parent; + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; } - bool hasChildren() const { + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { return !m_children.empty(); } - private: - std::string m_name; - RunState m_runState; - TrackedSections m_children; - TrackedSection* m_parent; - }; + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } - inline TrackedSection* TrackedSection::findChild( std::string const& childName ) { - TrackedSections::iterator it = m_children.find( childName ); - return it != m_children.end() - ? &it->second - : NULL; - } - inline TrackedSection* TrackedSection::acquireChild( std::string const& childName ) { - if( TrackedSection* child = findChild( childName ) ) - return child; - m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); - return findChild( childName ); - } - inline void TrackedSection::leave() { - for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); - it != itEnd; - ++it ) - if( it->second.runState() != Completed ) { + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { m_runState = ExecutingChildren; - return; + if( m_parent ) + m_parent->openChild(); } - m_runState = Completed; - } - - class TestCaseTracker { - public: - TestCaseTracker( std::string const& testCaseName ) - : m_testCase( testCaseName, NULL ), - m_currentSection( &m_testCase ), - m_completedASectionThisRun( false ) - {} - - bool enterSection( std::string const& name ) { - TrackedSection* child = m_currentSection->acquireChild( name ); - if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) - return false; - - m_currentSection = child; - m_currentSection->enter(); - return true; } - void leaveSection() { - m_currentSection->leave(); - m_currentSection = m_currentSection->getParent(); - assert( m_currentSection != NULL ); - m_completedASectionThisRun = true; + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); } - bool currentSectionHasChildren() const { - return m_currentSection->hasChildren(); - } - bool isCompleted() const { - return m_testCase.runState() == TrackedSection::Completed; - } + virtual void close() CATCH_OVERRIDE { - class Guard { - public: - Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { - m_tracker.enterTestCase(); + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); } - ~Guard() { - m_tracker.leaveTestCase(); - } - private: - Guard( Guard const& ); - void operator = ( Guard const& ); - TestCaseTracker& m_tracker; - }; - + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } private: - void enterTestCase() { - m_currentSection = &m_testCase; - m_completedASectionThisRun = false; - m_testCase.enter(); + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); } - void leaveTestCase() { - m_testCase.leave(); + void moveToThis() { + m_ctx.setCurrentTracker( this ); } - - TrackedSection m_testCase; - TrackedSection* m_currentSection; - bool m_completedASectionThisRun; }; -} // namespace SectionTracking + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); -using SectionTracking::TestCaseTracker; + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; } // namespace Catch @@ -5174,15 +5643,12 @@ namespace Catch { public: - explicit RunContext( Ptr const& config, Ptr const& reporter ) - : m_runInfo( config->name() ), + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), m_context( getCurrentMutableContext() ), - m_activeTestCase( NULL ), - m_config( config ), - m_reporter( reporter ), - m_prevRunner( m_context.getRunner() ), - m_prevResultCapture( m_context.getResultCapture() ), - m_prevConfig( m_context.getConfig() ) + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) { m_context.setRunner( this ); m_context.setConfig( m_config ); @@ -5192,10 +5658,6 @@ namespace Catch { virtual ~RunContext() { m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); - m_context.setRunner( m_prevRunner ); - m_context.setConfig( NULL ); - m_context.setResultCapture( m_prevResultCapture ); - m_context.setConfig( m_prevConfig ); } void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { @@ -5216,14 +5678,17 @@ namespace Catch { m_reporter->testCaseStarting( testInfo ); m_activeTestCase = &testCase; - m_testCaseTracker = TestCaseTracker( testInfo.name ); do { + m_trackerContext.startRun(); do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); runCurrentTest( redirectedCout, redirectedCerr ); } - while( !m_testCaseTracker->isCompleted() && !aborting() ); + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); } + // !TBD: deprecated - this will be replaced by indexed trackers while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); @@ -5234,8 +5699,8 @@ namespace Catch { redirectedCerr, aborting() ) ); - m_activeTestCase = NULL; - m_testCaseTracker.reset(); + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; return deltaTotals; } @@ -5270,8 +5735,10 @@ namespace Catch { std::ostringstream oss; oss << sectionInfo.name << "@" << sectionInfo.lineInfo; - if( !m_testCaseTracker->enterSection( oss.str() ) ) + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) return false; + m_activeSections.push_back( §ionTracker ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; @@ -5282,30 +5749,40 @@ namespace Catch { return true; } bool testForMissingAssertions( Counts& assertions ) { - if( assertions.total() != 0 || - !m_config->warnAboutMissingAssertions() || - m_testCaseTracker->currentSectionHasChildren() ) + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) return false; m_totals.assertions.failed++; assertions.failed++; return true; } - virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { - if( std::uncaught_exception() ) { - m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); - return; - } - - Counts assertions = m_totals.assertions - prevAssertions; + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); - m_testCaseTracker->leaveSection(); + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } - m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); m_messages.clear(); } + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + virtual void pushScopedMessage( MessageInfo const& message ) { m_messages.push_back( message ); } @@ -5371,7 +5848,8 @@ namespace Catch { double duration = 0; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); - TestCaseTracker::Guard guard( *m_testCaseTracker ); + + seedRng( *m_config ); Timer timer; timer.start(); @@ -5391,6 +5869,7 @@ namespace Catch { catch(...) { makeUnexpectedResultBuilder().useActiveException(); } + m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); @@ -5425,39 +5904,29 @@ namespace Catch { void handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. - for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it ) - sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + sectionEnded( *it ); m_unfinishedSections.clear(); } - struct UnfinishedSections { - UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) - : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - - SectionInfo info; - Counts prevAssertions; - double durationInSeconds; - }; - TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase; - Option m_testCaseTracker; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; AssertionResult m_lastResult; Ptr m_config; Totals m_totals; Ptr m_reporter; std::vector m_messages; - IRunner* m_prevRunner; - IResultCapture* m_prevResultCapture; - Ptr m_prevConfig; AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; }; IResultCapture& getResultCapture() { @@ -5505,89 +5974,87 @@ namespace Catch { namespace Catch { - class Runner { + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } - public: - Runner( Ptr const& config ) - : m_config( config ) - { - openStream(); - makeReporter(); + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); } - Totals runTests() { + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } - RunContext context( m_config.get(), m_reporter ); + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; - Totals totals; + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); - context.testGroupStarting( "all tests", 1, 1 ); // deprecated? + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); - TestSpec testSpec = m_config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests - - std::vector testCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); - - int testsRunForGroup = 0; - for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); - it != itEnd; - ++it ) { - testsRunForGroup++; - if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { - - if( context.aborting() ) - break; - - totals += context.runTest( *it ); - m_testsAlreadyRun.insert( *it ); - } - } - std::vector skippedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); - - for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); - it != itEnd; - ++it ) - m_reporter->skipTest( *it ); - - context.testGroupEnded( "all tests", totals, 1, 1 ); - return totals; + tags.insert( "#" + filename ); + setTags( test, tags ); } - - private: - void openStream() { - // Open output file, if specified - if( !m_config->getFilename().empty() ) { - m_ofs.open( m_config->getFilename().c_str() ); - if( m_ofs.fail() ) { - std::ostringstream oss; - oss << "Unable to open file: '" << m_config->getFilename() << "'"; - throw std::domain_error( oss.str() ); - } - m_config->setStreamBuf( m_ofs.rdbuf() ); - } - } - void makeReporter() { - std::string reporterName = m_config->getReporterName().empty() - ? "console" - : m_config->getReporterName(); - - m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); - if( !m_reporter ) { - std::ostringstream oss; - oss << "No reporter registered with name: '" << reporterName << "'"; - throw std::domain_error( oss.str() ); - } - } - - private: - Ptr m_config; - std::ofstream m_ofs; - Ptr m_reporter; - std::set m_testsAlreadyRun; - }; + } class Session : NonCopyable { static bool alreadyInstantiated; @@ -5616,7 +6083,7 @@ namespace Catch { Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } - int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + int applyCommandLine( int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); @@ -5643,7 +6110,7 @@ namespace Catch { m_config.reset(); } - int run( int argc, char* const argv[] ) { + int run( int argc, char const* const argv[] ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) @@ -5659,15 +6126,16 @@ namespace Catch { { config(); // Force config to be constructed - std::srand( m_configData.rngSeed ); + seedRng( *m_config ); - Runner runner( m_config ); + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); - return static_cast( runner.runTests().assertions.failed ); + return static_cast( runTests( m_config ).assertions.failed ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; @@ -5689,7 +6157,6 @@ namespace Catch { m_config = new Config( m_configData ); return *m_config; } - private: Clara::CommandLine m_cli; std::vector m_unusedTokens; @@ -5715,14 +6182,71 @@ namespace Catch { namespace Catch { - class TestRegistry : public ITestCaseRegistry { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { public: TestRegistry() : m_unnamedCount( 0 ) {} virtual ~TestRegistry(); @@ -5734,69 +6258,29 @@ namespace Catch { oss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( oss.str() ) ); } - - if( m_functions.find( testCase ) == m_functions.end() ) { - m_functions.insert( testCase ); - m_functionsInOrder.push_back( testCase ); - if( !testCase.isHidden() ) - m_nonHiddenFunctions.push_back( testCase ); - } - else { - TestCase const& prev = *m_functions.find( testCase ); - { - Colour colourGuard( Colour::Red ); - Catch::cerr() << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; - } - exit(1); - } + m_functions.push_back( testCase ); } virtual std::vector const& getAllTests() const { - return m_functionsInOrder; + return m_functions; } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); - virtual std::vector const& getAllNonHiddenTests() const { - return m_nonHiddenFunctions; - } - - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { - - for( std::vector::const_iterator it = m_functionsInOrder.begin(), - itEnd = m_functionsInOrder.end(); - it != itEnd; - ++it ) { - bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); - if( includeTest != negated ) - matchingTestCases.push_back( *it ); + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); } - sortTests( config, matchingTestCases ); + return m_sortedFunctions; } private: - - static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); - break; - case RunTests::InRandomOrder: - { - RandomNumberGenerator rng; - std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); - } - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - } - std::set m_functions; - std::vector m_functionsInOrder; - std::vector m_nonHiddenFunctions; + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised }; /////////////////////////////////////////////////////////////////////////// @@ -5829,29 +6313,38 @@ namespace Catch { return className; } - /////////////////////////////////////////////////////////////////////////// + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { - AutoReg::AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); } - AutoReg::~AutoReg() {} + /////////////////////////////////////////////////////////////////////////// - void AutoReg::registerTestCase( ITestCase* testCase, - char const* classOrQualifiedMethodName, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - - getMutableRegistryHub().registerTest - ( makeTestCase( testCase, - extractClassName( classOrQualifiedMethodName ), - nameAndDesc.name, - nameAndDesc.description, - lineInfo ) ); + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); } + AutoReg::~AutoReg() {} + } // end namespace Catch // #included from: catch_reporter_registry.hpp @@ -5865,27 +6358,32 @@ namespace Catch { public: - virtual ~ReporterRegistry() { - deleteAllValues( m_factories ); - } + virtual ~ReporterRegistry() CATCH_OVERRIDE {} - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { FactoryMap::const_iterator it = m_factories.find( name ); if( it == m_factories.end() ) - return NULL; + return CATCH_NULL; return it->second->create( ReporterConfig( config ) ); } - void registerReporter( std::string const& name, IReporterFactory* factory ) { + void registerReporter( std::string const& name, Ptr const& factory ) { m_factories.insert( std::make_pair( name, factory ) ); } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } - FactoryMap const& getFactories() const { + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { return m_factories; } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } private: FactoryMap m_factories; + Listeners m_listeners; }; } @@ -5913,13 +6411,13 @@ namespace Catch { #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { - throw; + return tryTranslators(); } @catch (NSException *exception) { return Catch::toString( [exception description] ); } #else - throw; + return tryTranslators(); #endif } catch( TestFailureException& ) { @@ -5935,20 +6433,15 @@ namespace Catch { return msg; } catch(...) { - return tryTranslators( m_translators.begin() ); + return "Unknown exception"; } } - std::string tryTranslators( std::vector::const_iterator it ) const { - if( it == m_translators.end() ) - return "Unknown exception"; - - try { - return (*it)->translate(); - } - catch(...) { - return tryTranslators( it+1 ); - } + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); } private: @@ -5968,24 +6461,27 @@ namespace Catch { public: // IRegistryHub RegistryHub() { } - virtual IReporterRegistry const& getReporterRegistry() const { + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { return m_reporterRegistry; } - virtual ITestCaseRegistry const& getTestCaseRegistry() const { + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { return m_testCaseRegistry; } - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { return m_exceptionTranslatorRegistry; } public: // IMutableRegistryHub - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerReporter( name, factory ); } - virtual void registerTest( TestCase const& testInfo ) { + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { m_testCaseRegistry.registerTest( testInfo ); } - virtual void registerTranslator( const IExceptionTranslator* translator ) { + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { m_exceptionTranslatorRegistry.registerTranslator( translator ); } @@ -5997,7 +6493,7 @@ namespace Catch { // Single, global, instance inline RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = NULL; + static RegistryHub* theRegistryHub = CATCH_NULL; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; @@ -6012,7 +6508,7 @@ namespace Catch { } void cleanUp() { delete getTheRegistryHub(); - getTheRegistryHub() = NULL; + getTheRegistryHub() = CATCH_NULL; cleanUpContext(); } std::string translateActiveException() { @@ -6048,19 +6544,6 @@ namespace Catch { // #included from: catch_stream.hpp #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED -// #included from: catch_streambuf.h -#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED - -#include - -namespace Catch { - - class StreamBufBase : public std::streambuf { - public: - virtual ~StreamBufBase() CATCH_NOEXCEPT; - }; -} - #include #include #include @@ -6105,6 +6588,19 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////// + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + struct OutputDebugWriter { void operator()( std::string const&str ) { @@ -6112,23 +6608,26 @@ namespace Catch { } }; - Stream::Stream() - : streamBuf( NULL ), isOwned( false ) + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) {} - Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) - : streamBuf( _streamBuf ), isOwned( _isOwned ) - {} - - void Stream::release() { - if( isOwned ) { - delete streamBuf; - streamBuf = NULL; - isOwned = false; - } + std::ostream& DebugOutStream::stream() const { + return m_os; } -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions std::ostream& cout() { return std::cout; } @@ -6142,7 +6641,7 @@ namespace Catch { class Context : public IMutableContext { - Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} Context( Context const& ); void operator=( Context const& ); @@ -6188,7 +6687,7 @@ namespace Catch { m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second - : NULL; + : CATCH_NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { @@ -6209,7 +6708,7 @@ namespace Catch { }; namespace { - Context* currentContext = NULL; + Context* currentContext = CATCH_NULL; } IMutableContext& getCurrentMutableContext() { if( !currentContext ) @@ -6220,17 +6719,9 @@ namespace Catch { return getCurrentMutableContext(); } - Stream createStream( std::string const& streamName ) { - if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); - if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); - if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); - - throw std::domain_error( "Unknown stream: " + streamName ); - } - void cleanUpContext() { delete currentContext; - currentContext = NULL; + currentContext = CATCH_NULL; } } @@ -6286,12 +6777,13 @@ namespace { { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalAttributes = csbiInfo.wAttributes; + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); @@ -6311,10 +6803,11 @@ namespace { private: void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); } HANDLE stdoutHandle; - WORD originalAttributes; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; }; IColourImpl* platformColourInstance() { @@ -6640,6 +7133,21 @@ namespace Catch { return TestCase( _testCase, info ); } + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, @@ -6648,18 +7156,10 @@ namespace Catch { : name( _name ), className( _className ), description( _description ), - tags( _tags ), lineInfo( _lineInfo ), properties( None ) { - std::ostringstream oss; - for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { - oss << "[" << *it << "]"; - std::string lcaseTag = toLower( *it ); - properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); - lcaseTags.insert( lcaseTag ); - } - tagsAsString = oss.str(); + setTags( *this, _tags ); } TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) @@ -6767,7 +7267,7 @@ namespace Catch { return os; } - Version libraryVersion( 1, 2, 1, "", 0 ); + Version libraryVersion( 1, 3, 0, "", 0 ); } @@ -6960,7 +7460,7 @@ namespace Catch { #else uint64_t getCurrentTicks() { timeval t; - gettimeofday(&t,NULL); + gettimeofday(&t,CATCH_NULL); return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif @@ -7059,6 +7559,14 @@ namespace Catch { return line < other.line || ( line == other.line && file < other.file ); } + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << "(" << info.line << ")"; @@ -7098,8 +7606,13 @@ namespace Catch { } Section::~Section() { - if( m_sectionIncluded ) - getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } } // This indicates whether the section should be executed or not @@ -7151,7 +7664,7 @@ namespace Catch { // Call sysctl. size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } @@ -7205,9 +7718,11 @@ namespace Catch { namespace Detail { - std::string unprintableString = "{?}"; + const std::string unprintableString = "{?}"; namespace { + const int hexThreshold = 255; + struct Endianness { enum Arch { Big, Little }; @@ -7289,7 +7804,7 @@ std::string toString( wchar_t* const value ) std::string toString( int value ) { std::ostringstream oss; oss << value; - if( value >= 255 ) + if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } @@ -7297,7 +7812,7 @@ std::string toString( int value ) { std::string toString( unsigned long value ) { std::ostringstream oss; oss << value; - if( value >= 255 ) + if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } @@ -7347,6 +7862,23 @@ std::string toString( unsigned char value ) { return toString( static_cast( value ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ) { return "nullptr"; @@ -7376,11 +7908,17 @@ std::string toString( std::nullptr_t ) { namespace Catch { + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), m_shouldDebugBreak( false ), m_shouldThrow( false ) {} @@ -7421,9 +7959,35 @@ namespace Catch { setResultType( resultType ); captureExpression(); } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } void ResultBuilder::captureExpression() { AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { getResultCapture().assertionEnded( result ); if( !result.isOk() ) { @@ -7576,6 +8140,137 @@ namespace Catch { } // end namespace Catch +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + // #included from: ../reporters/catch_reporter_xml.hpp #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED @@ -7591,47 +8286,53 @@ namespace Catch { StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } - virtual ~StreamingReporterBase(); + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } - virtual void noMatchingTestCases( std::string const& ) {} + virtual ~StreamingReporterBase() CATCH_OVERRIDE; - virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { currentTestRunInfo = _testRunInfo; } - virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { currentGroupInfo = _groupInfo; } - virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { currentTestCaseInfo = _testInfo; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_sectionStack.push_back( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); } - virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { currentGroupInfo.reset(); } - virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } - virtual void skipTest( TestCaseInfo const& ) { + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } - Ptr m_config; + Ptr m_config; std::ostream& stream; LazyStat currentTestRunInfo; @@ -7639,6 +8340,7 @@ namespace Catch { LazyStat currentTestCaseInfo; std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; }; struct CumulativeReporterBase : SharedImpl { @@ -7689,15 +8391,21 @@ namespace Catch { CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } ~CumulativeReporterBase(); - virtual void testRunStarting( TestRunInfo const& ) {} - virtual void testGroupStarting( GroupInfo const& ) {} + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } - virtual void testCaseStarting( TestCaseInfo const& ) {} + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); Ptr node; if( m_sectionStack.empty() ) { @@ -7722,7 +8430,7 @@ namespace Catch { m_deepestSection = node; } - virtual void assertionStarting( AssertionInfo const& ) {} + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& assertionStats ) { assert( !m_sectionStack.empty() ); @@ -7730,13 +8438,13 @@ namespace Catch { sectionNode.assertions.push_back( assertionStats ); return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { Ptr node = new TestCaseNode( testCaseStats ); assert( m_sectionStack.size() == 0 ); node->children.push_back( m_rootSection ); @@ -7747,12 +8455,12 @@ namespace Catch { m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { Ptr node = new TestGroupNode( testGroupStats ); node->children.swap( m_testCases ); m_testGroups.push_back( node ); } - virtual void testRunEnded( TestRunStats const& testRunStats ) { + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { Ptr node = new TestRunNode( testRunStats ); node->children.swap( m_testGroups ); m_testRuns.push_back( node ); @@ -7760,9 +8468,9 @@ namespace Catch { } virtual void testRunEndedCumulative() = 0; - virtual void skipTest( TestCaseInfo const& ) {} + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} - Ptr m_config; + Ptr m_config; std::ostream& stream; std::vector m_assertions; std::vector > > m_sections; @@ -7774,6 +8482,7 @@ namespace Catch { Ptr m_rootSection; Ptr m_deepestSection; std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; }; @@ -7787,6 +8496,17 @@ namespace Catch { return line; } + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + } // end namespace Catch // #included from: ../internal/catch_reporter_registrars.hpp @@ -7817,7 +8537,7 @@ namespace Catch { template class ReporterRegistrar { - class ReporterFactory : public IReporterFactory { + class ReporterFactory : public SharedImpl { // *** Please Note ***: // - If you end up here looking at a compiler error because it's trying to register @@ -7845,22 +8565,102 @@ namespace Catch { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; } #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + // #included from: ../internal/catch_xmlwriter.hpp #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include #include #include +#include namespace Catch { + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + class XmlWriter { public: @@ -7872,7 +8672,7 @@ namespace Catch { ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ - other.m_writer = NULL; + other.m_writer = CATCH_NULL; } ~ScopedElement() { @@ -7943,11 +8743,8 @@ namespace Catch { } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) { - stream() << " " << name << "=\""; - writeEncodedText( attribute ); - stream() << "\""; - } + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; return *this; } @@ -7958,9 +8755,9 @@ namespace Catch { template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - if( !name.empty() ) - stream() << " " << name << "=\"" << attribute << "\""; - return *this; + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ) { @@ -7969,7 +8766,7 @@ namespace Catch { ensureTagClosed(); if( tagWasOpen && indent ) stream() << m_indent; - writeEncodedText( text ); + stream() << XmlEncode( text ); m_needsNewline = true; } return *this; @@ -8014,30 +8811,6 @@ namespace Catch { } } - void writeEncodedText( std::string const& text ) { - static const char* charsToEncode = "<&\""; - std::string mtext = text; - std::string::size_type pos = mtext.find_first_of( charsToEncode ); - while( pos != std::string::npos ) { - stream() << mtext.substr( 0, pos ); - - switch( mtext[pos] ) { - case '<': - stream() << "<"; - break; - case '&': - stream() << "&"; - break; - case '\"': - stream() << """; - break; - } - mtext = mtext.substr( pos+1 ); - pos = mtext.find_first_of( charsToEncode ); - } - stream() << mtext; - } - bool m_tagIsOpen; bool m_needsNewline; std::vector m_tags; @@ -8046,32 +8819,44 @@ namespace Catch { }; } +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_sectionDepth( 0 ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - virtual ~XmlReporter(); + virtual ~XmlReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as an XML document"; } public: // StreamingReporterBase - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - virtual void noMatchingTestCases( std::string const& s ) { + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { StreamingReporterBase::noMatchingTestCases( s ); } - virtual void testRunStarting( TestRunInfo const& testInfo ) { + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testRunStarting( testInfo ); m_xml.setStream( stream ); m_xml.startElement( "Catch" ); @@ -8079,13 +8864,13 @@ namespace Catch { m_xml.writeAttribute( "name", m_config->name() ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } - virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); @@ -8093,7 +8878,7 @@ namespace Catch { m_testCaseTimer.start(); } - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) @@ -8102,9 +8887,9 @@ namespace Catch { } } - virtual void assertionStarting( AssertionInfo const& ) { } + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { const AssertionResult& assertionResult = assertionStats.assertionResult; // Print any info messages in tags. @@ -8175,7 +8960,7 @@ namespace Catch { return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); @@ -8190,7 +8975,7 @@ namespace Catch { } } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); @@ -8201,7 +8986,7 @@ namespace Catch { m_xml.endElement(); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) @@ -8211,7 +8996,7 @@ namespace Catch { m_xml.endElement(); } - virtual void testRunEnded( TestRunStats const& testRunStats ) { + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) @@ -8242,28 +9027,24 @@ namespace Catch { JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - ~JunitReporter(); + virtual ~JunitReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } - virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - - virtual void testRunStarting( TestRunInfo const& runInfo ) { + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { suiteTimer.start(); stdOutForSuite.str(""); stdErrForSuite.str(""); @@ -8271,25 +9052,25 @@ namespace Catch { CumulativeReporterBase::testGroupStarting( groupInfo ); } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { stdOutForSuite << testCaseStats.stdOut; stdErrForSuite << testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } - virtual void testRunEndedCumulative() { + virtual void testRunEndedCumulative() CATCH_OVERRIDE { xml.endElement(); } @@ -8454,24 +9235,19 @@ namespace Catch { m_headerPrinted( false ) {} - virtual ~ConsoleReporter(); + virtual ~ConsoleReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as plain lines of text"; } - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - virtual void noMatchingTestCases( std::string const& spec ) { + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { stream << "No test cases matched '" << spec << "'" << std::endl; } - virtual void assertionStarting( AssertionInfo const& ) { + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; @@ -8491,11 +9267,11 @@ namespace Catch { return true; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& _sectionStats ) { + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); @@ -8517,11 +9293,11 @@ namespace Catch { StreamingReporterBase::sectionEnded( _sectionStats ); } - virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } - virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; @@ -8530,7 +9306,7 @@ namespace Catch { } StreamingReporterBase::testGroupEnded( _testGroupStats ); } - virtual void testRunEnded( TestRunStats const& _testRunStats ) { + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; @@ -9169,8 +9945,14 @@ namespace Catch { } // end namespace Catch namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods NonCopyable::~NonCopyable() {} IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} IContext::~IContext() {} IResultCapture::~IResultCapture() {} @@ -9204,6 +9986,7 @@ namespace Catch { FreeFunctionTestCase::~FreeFunctionTestCase() {} IGeneratorInfo::~IGeneratorInfo() {} IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} TestSpec::Pattern::~Pattern() {} TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} @@ -9215,6 +9998,13 @@ namespace Catch { Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } } #ifdef __clang__ @@ -9268,8 +10058,9 @@ int main (int argc, char * const argv[]) { #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) @@ -9280,6 +10071,7 @@ int main (int argc, char * const argv[]) { #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) @@ -9295,6 +10087,7 @@ int main (int argc, char * const argv[]) { #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) @@ -9302,6 +10095,7 @@ int main (int argc, char * const argv[]) { #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) @@ -9321,11 +10115,11 @@ int main (int argc, char * const argv[]) { #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) -#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) -#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -9333,8 +10127,9 @@ int main (int argc, char * const argv[]) { #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) @@ -9343,8 +10138,9 @@ int main (int argc, char * const argv[]) { #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) @@ -9360,6 +10156,7 @@ int main (int argc, char * const argv[]) { #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) @@ -9367,6 +10164,7 @@ int main (int argc, char * const argv[]) { #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) @@ -9390,27 +10188,13 @@ int main (int argc, char * const argv[]) { #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define GIVEN( desc ) SECTION( " Given: " desc, "" ) -#define WHEN( desc ) SECTION( " When: " desc, "" ) -#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) -#define THEN( desc ) SECTION( " Then: " desc, "" ) -#define AND_THEN( desc ) SECTION( " And: " desc, "" ) +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) using Catch::Detail::Approx; -// #included from: internal/catch_reenable_warnings.h - -#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(pop) -# else -# pragma clang diagnostic pop -# endif -#elif defined __GNUC__ -# pragma GCC diagnostic pop -#endif - #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED