Merged from develop branch

- now v1.3.0
This commit is contained in:
Phil Nash 2015-12-04 10:19:08 +00:00
commit fdc42d0af4
95 changed files with 7680 additions and 2956 deletions

View File

@ -1,19 +1,163 @@
language: cpp language: cpp
sudo: false
compiler: cache:
- clang ccache: true
- gcc directories:
- $HOME/.ccache
env: env:
- BUILD_TYPE=Debug global:
- BUILD_TYPE=Release - 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: 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 - cd Build
- make
- cd ..
script: script:
- cd Build - make -j 2
- ctest -V - ctest -V -j 2

View File

@ -1,6 +1,6 @@
![catch logo](catch-logo-small.png) ![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) Build status (on Travis CI) [![Build Status](https://travis-ci.org/philsquared/Catch.png)](https://travis-ci.org/philsquared/Catch)

View File

@ -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_IS_ENUM // std::is_enum is supported?
CATCH_CONFIG_CPP11_TUPLE // std::tuple is supported CATCH_CONFIG_CPP11_TUPLE // std::tuple is supported
CATCH_CONFIG_VARIADIC_MACROS // Usually pre-C++11 compiler extensions are sufficient 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. 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. 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.

View File

@ -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) 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. 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.
* `[#<filename>]` - 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]`.
* `[@<alias>]` - 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( <alias string>, <tag expression> )
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 ## 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. 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.

View File

@ -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) [Home](Readme.md)

View File

@ -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). 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 <a href="http://jamesnewkirk.typepad.com/posts/2007/09/why-you-should-.html">problems like these</a> that led James Newkirk, who led the team that built NUnit, to start again from scratch and <a href="http://jamesnewkirk.typepad.com/posts/2007/09/announcing-xuni.html">build xUnit</a>). 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 <a href="http://jamesnewkirk.typepad.com/posts/2007/09/why-you-should-.html">problems like these</a> that led James Newkirk, who led the team that built NUnit, to start again from scratch and <a href="http://jamesnewkirk.typepad.com/posts/2007/09/announcing-xuni.html">build xUnit</a>).
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: 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:

View File

@ -70,8 +70,9 @@
#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) #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_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_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_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" ) #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( 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_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 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" ) #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( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __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_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_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __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__ ) #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( 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_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_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_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_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 ) #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( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
#endif #endif
#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) #define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" )
#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) #define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" )
#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) #define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" )
#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) #define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" )
#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " 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 // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
#else #else
@ -135,8 +139,9 @@
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) #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_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_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 REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) #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 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_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_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_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" ) #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( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __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 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 SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
#define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __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__ ) #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( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
#define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, 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 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 SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
#define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) #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 ) #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( name, tags ) TEST_CASE( "Scenario: " name, tags )
#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
#endif #endif
#define GIVEN( desc ) SECTION( " Given: " desc, "" ) #define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" )
#define WHEN( desc ) SECTION( " When: " desc, "" ) #define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" )
#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) #define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" )
#define THEN( desc ) SECTION( " Then: " desc, "" ) #define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" )
#define AND_THEN( desc ) SECTION( " And: " desc, "" ) #define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" )
using Catch::Detail::Approx; using Catch::Detail::Approx;

View File

@ -10,7 +10,7 @@
#include "internal/catch_commandline.hpp" #include "internal/catch_commandline.hpp"
#include "internal/catch_list.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_test_spec.hpp"
#include "internal/catch_version.h" #include "internal/catch_version.h"
#include "internal/catch_text.h" #include "internal/catch_text.h"
@ -21,89 +21,88 @@
namespace Catch { namespace Catch {
class Runner { Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
Ptr<IStreamingReporter> 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: Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
Runner( Ptr<Config> const& config ) std::vector<std::string> reporters = config->getReporterNames();
: m_config( config ) if( reporters.empty() )
{ reporters.push_back( "console" );
openStream();
makeReporter(); Ptr<IStreamingReporter> reporter;
for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
it != itEnd;
++it )
reporter = addReporter( reporter, createReporter( *it, config ) );
return reporter;
}
Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> 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<Config> const& config ) {
Ptr<IConfig const> iconfig = config.get();
Ptr<IStreamingReporter> 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<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
for( std::vector<TestCase>::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<TestCase> const& tests = getAllTestCasesSorted( config );
for(std::size_t i = 0; i < tests.size(); ++i ) {
TestCase& test = const_cast<TestCase&>( tests[i] );
std::set<std::string> 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(); tags.insert( "#" + filename );
if( !testSpec.hasFilters() ) setTags( test, tags );
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
std::vector<TestCase> testCases;
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
int testsRunForGroup = 0;
for( std::vector<TestCase>::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<TestCase> skippedTestCases;
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true );
for( std::vector<TestCase>::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end();
it != itEnd;
++it )
m_reporter->skipTest( *it );
context.testGroupEnded( "all tests", totals, 1, 1 );
return totals;
} }
}
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<Config> m_config;
std::ofstream m_ofs;
Ptr<IStreamingReporter> m_reporter;
std::set<TestCase> m_testsAlreadyRun;
};
class Session : NonCopyable { class Session : NonCopyable {
static bool alreadyInstantiated; static bool alreadyInstantiated;
@ -132,7 +131,7 @@ namespace Catch {
Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; 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 { try {
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
@ -159,7 +158,7 @@ namespace Catch {
m_config.reset(); m_config.reset();
} }
int run( int argc, char* const argv[] ) { int run( int argc, char const* const argv[] ) {
int returnCode = applyCommandLine( argc, argv ); int returnCode = applyCommandLine( argc, argv );
if( returnCode == 0 ) if( returnCode == 0 )
@ -175,15 +174,16 @@ namespace Catch {
{ {
config(); // Force config to be constructed 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 // Handle list request
if( Option<std::size_t> listed = list( config() ) ) if( Option<std::size_t> listed = list( config() ) )
return static_cast<int>( *listed ); return static_cast<int>( *listed );
return static_cast<int>( runner.runTests().assertions.failed ); return static_cast<int>( runTests( m_config ).assertions.failed );
} }
catch( std::exception& ex ) { catch( std::exception& ex ) {
Catch::cerr() << ex.what() << std::endl; Catch::cerr() << ex.what() << std::endl;
@ -205,7 +205,6 @@ namespace Catch {
m_config = new Config( m_configData ); m_config = new Config( m_configData );
return *m_config; return *m_config;
} }
private: private:
Clara::CommandLine<ConfigData> m_cli; Clara::CommandLine<ConfigData> m_cli;
std::vector<Clara::Parser::Token> m_unusedTokens; std::vector<Clara::Parser::Token> m_unusedTokens;

View File

@ -264,11 +264,11 @@ namespace Clara {
template<typename ConfigT> template<typename ConfigT>
class BoundArgFunction { class BoundArgFunction {
public: public:
BoundArgFunction() : functionObj( NULL ) {} BoundArgFunction() : functionObj( CATCH_NULL ) {}
BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {} BoundArgFunction( IArgFunction<ConfigT>* _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 ) { BoundArgFunction& operator = ( BoundArgFunction const& other ) {
IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL;
delete functionObj; delete functionObj;
functionObj = newFunctionObj; functionObj = newFunctionObj;
return *this; return *this;
@ -284,7 +284,7 @@ namespace Clara {
bool takesArg() const { return functionObj->takesArg(); } bool takesArg() const { return functionObj->takesArg(); }
bool isSet() const { bool isSet() const {
return functionObj != NULL; return functionObj != CATCH_NULL;
} }
private: private:
IArgFunction<ConfigT>* functionObj; IArgFunction<ConfigT>* functionObj;
@ -503,12 +503,7 @@ namespace Clara {
} }
}; };
// NOTE: std::auto_ptr is deprecated in c++11/c++0x typedef CATCH_AUTO_PTR( Arg ) ArgAutoPtr;
#if defined(__cplusplus) && __cplusplus > 199711L
typedef std::unique_ptr<Arg> ArgAutoPtr;
#else
typedef std::auto_ptr<Arg> ArgAutoPtr;
#endif
friend void addOptName( Arg& arg, std::string const& optName ) friend void addOptName( Arg& arg, std::string const& optName )
{ {
@ -585,8 +580,8 @@ namespace Clara {
m_arg->description = description; m_arg->description = description;
return *this; return *this;
} }
ArgBuilder& detail( std::string const& detail ) { ArgBuilder& detail( std::string const& _detail ) {
m_arg->detail = detail; m_arg->detail = _detail;
return *this; return *this;
} }
@ -670,14 +665,14 @@ namespace Clara {
maxWidth = (std::max)( maxWidth, it->commands().size() ); maxWidth = (std::max)( maxWidth, it->commands().size() );
for( it = itBegin; it != itEnd; ++it ) { for( it = itBegin; it != itEnd; ++it ) {
Detail::Text usage( it->commands(), Detail::TextAttributes() Detail::Text usageText( it->commands(), Detail::TextAttributes()
.setWidth( maxWidth+indent ) .setWidth( maxWidth+indent )
.setIndent( indent ) ); .setIndent( indent ) );
Detail::Text desc( it->description, Detail::TextAttributes() Detail::Text desc( it->description, Detail::TextAttributes()
.setWidth( width - maxWidth - 3 ) ); .setWidth( width - maxWidth - 3 ) );
for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) {
std::string usageCol = i < usage.size() ? usage[i] : ""; std::string usageCol = i < usageText.size() ? usageText[i] : "";
os << usageCol; os << usageCol;
if( i < desc.size() && !desc[i].empty() ) if( i < desc.size() && !desc[i].empty() )

View File

@ -66,16 +66,16 @@
} while( Catch::alwaysFalse() ) } while( Catch::alwaysFalse() )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ #define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \
do { \ do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
if( __catchResult.allowThrows() ) \ if( __catchResult.allowThrows() ) \
try { \ try { \
expr; \ expr; \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
} \ } \
catch( ... ) { \ catch( ... ) { \
__catchResult.captureResult( Catch::ResultWas::Ok ); \ __catchResult.captureExpectedException( matcher ); \
} \ } \
else \ else \
__catchResult.captureResult( Catch::ResultWas::Ok ); \ __catchResult.captureResult( Catch::ResultWas::Ok ); \
@ -131,12 +131,12 @@
do { \ do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
try { \ try { \
std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ std::string matcherAsString = (matcher).toString(); \
__catchResult \ __catchResult \
.setLhs( Catch::toString( arg ) ) \ .setLhs( Catch::toString( arg ) ) \
.setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
.setOp( "matches" ) \ .setOp( "matches" ) \
.setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ .setResultType( (matcher).match( arg ) ); \
__catchResult.captureExpression(); \ __catchResult.captureExpression(); \
} catch( ... ) { \ } catch( ... ) { \
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \

View File

@ -23,6 +23,7 @@ namespace Catch {
config.abortAfter = x; config.abortAfter = x;
} }
inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } 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 ) { inline void addWarning( ConfigData& config, std::string const& _warning ) {
if( _warning == "NoAssertions" ) if( _warning == "NoAssertions" )
@ -116,7 +117,7 @@ namespace Catch {
cli["-r"]["--reporter"] cli["-r"]["--reporter"]
// .placeholder( "name[:filename]" ) // .placeholder( "name[:filename]" )
.describe( "reporter to use (defaults to console)" ) .describe( "reporter to use (defaults to console)" )
.bind( &ConfigData::reporterName, "name" ); .bind( &addReporterName, "name" );
cli["-n"]["--name"] cli["-n"]["--name"]
.describe( "suite name" ) .describe( "suite name" )
@ -153,12 +154,16 @@ namespace Catch {
.describe( "load test names to run from a file" ) .describe( "load test names to run from a file" )
.bind( &loadTestNamesFromFile, "filename" ); .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 // Less common commands which don't have a short form
cli["--list-test-names-only"] cli["--list-test-names-only"]
.describe( "list all/matching test cases names only" ) .describe( "list all/matching test cases names only" )
.bind( &ConfigData::listTestNamesOnly ); .bind( &ConfigData::listTestNamesOnly );
cli["--list-reporters"] cli["--list-reporters"]
.describe( "list all reporters" ) .describe( "list all reporters" )
.bind( &ConfigData::listReporters ); .bind( &ConfigData::listReporters );

View File

@ -23,6 +23,13 @@
namespace Catch { namespace Catch {
struct IConfig;
struct CaseSensitive { enum Choice {
Yes,
No
}; };
class NonCopyable { class NonCopyable {
#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable const& ) = delete;
@ -109,6 +116,9 @@ namespace Catch {
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); 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 // Use this in variadic streaming macros to allow
// >> +StreamEndStop // >> +StreamEndStop
// as well as // as well as

View File

@ -36,7 +36,7 @@ namespace Catch {
return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; 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 replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
bool replaced = false; bool replaced = false;
std::size_t i = str.find( replaceThis ); std::size_t i = str.find( replaceThis );
@ -50,7 +50,7 @@ namespace Catch {
} }
return replaced; return replaced;
} }
pluralise::pluralise( std::size_t count, std::string const& label ) pluralise::pluralise( std::size_t count, std::string const& label )
: m_count( count ), : m_count( count ),
m_label( label ) m_label( label )
@ -82,6 +82,14 @@ namespace Catch {
return line < other.line || ( line == other.line && file < other.file ); 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 ) { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
#ifndef __GNUG__ #ifndef __GNUG__
os << info.file << "(" << info.line << ")"; os << info.file << "(" << info.line << ")";

View File

@ -16,11 +16,18 @@
// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // 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_IS_ENUM : std::is_enum is supported?
// CATCH_CONFIG_CPP11_TUPLE : std::tuple 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_CPP11_OR_GREATER : Is C++11 supported?
// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros 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_<feature name> form // In general each macro has a _NO_<feature name> form
// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
@ -66,10 +73,13 @@
// GCC // GCC
#ifdef __GNUC__ #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 # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
#endif #endif
// - otherwise more recent versions define __cplusplus >= 201103L
// and will get picked up below
#endif // __GNUC__ #endif // __GNUC__
@ -79,6 +89,7 @@
#if (_MSC_VER >= 1600) #if (_MSC_VER >= 1600)
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
#endif #endif
#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
@ -88,6 +99,8 @@
#endif // _MSC_VER #endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
// Use variadic macros if the compiler supports them // Use variadic macros if the compiler supports them
#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
@ -102,7 +115,7 @@
// C++ language feature support // C++ language feature support
// catch all support for C++11 // catch all support for C++11
#if (__cplusplus >= 201103L) #if defined(__cplusplus) && __cplusplus >= 201103L
# define CATCH_CPP11_OR_GREATER # define CATCH_CPP11_OR_GREATER
@ -130,6 +143,18 @@
# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
# endif # 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 #endif // __cplusplus >= 201103L
// Now set the actual defines based on the above + anything the user has configured // Now set the actual defines based on the above + anything the user has configured
@ -149,7 +174,16 @@
# define CATCH_CONFIG_CPP11_TUPLE # define CATCH_CONFIG_CPP11_TUPLE
#endif #endif
#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) #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 #endif
@ -162,6 +196,26 @@
# define CATCH_NOEXCEPT_IS(x) # define CATCH_NOEXCEPT_IS(x)
#endif #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<T>
#else
# define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
#endif
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED

View File

@ -38,6 +38,7 @@ namespace Catch {
showHelp( false ), showHelp( false ),
showInvisibles( false ), showInvisibles( false ),
forceColour( false ), forceColour( false ),
filenamesAsTags( false ),
abortAfter( -1 ), abortAfter( -1 ),
rngSeed( 0 ), rngSeed( 0 ),
verbosity( Verbosity::Normal ), verbosity( Verbosity::Normal ),
@ -57,6 +58,7 @@ namespace Catch {
bool showHelp; bool showHelp;
bool showInvisibles; bool showInvisibles;
bool forceColour; bool forceColour;
bool filenamesAsTags;
int abortAfter; int abortAfter;
unsigned int rngSeed; unsigned int rngSeed;
@ -66,11 +68,11 @@ namespace Catch {
ShowDurations::OrNot showDurations; ShowDurations::OrNot showDurations;
RunTests::InWhatOrder runOrder; RunTests::InWhatOrder runOrder;
std::string reporterName;
std::string outputFilename; std::string outputFilename;
std::string name; std::string name;
std::string processName; std::string processName;
std::vector<std::string> reporterNames;
std::vector<std::string> testsOrTags; std::vector<std::string> testsOrTags;
}; };
@ -83,12 +85,11 @@ namespace Catch {
public: public:
Config() Config()
: m_os( Catch::cout().rdbuf() )
{} {}
Config( ConfigData const& data ) Config( ConfigData const& data )
: m_data( data ), : m_data( data ),
m_os( Catch::cout().rdbuf() ) m_stream( openStream() )
{ {
if( !data.testsOrTags.empty() ) { if( !data.testsOrTags.empty() ) {
TestSpecParser parser( ITagAliasRegistry::get() ); TestSpecParser parser( ITagAliasRegistry::get() );
@ -99,12 +100,6 @@ namespace Catch {
} }
virtual ~Config() { 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 { std::string const& getFilename() const {
@ -120,18 +115,7 @@ namespace Catch {
bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
void setStreamBuf( std::streambuf* buf ) { std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
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; }
int abortAfter() const { return m_data.abortAfter; } int abortAfter() const { return m_data.abortAfter; }
@ -142,7 +126,7 @@ namespace Catch {
// IConfig interface // IConfig interface
virtual bool allowThrows() const { return !m_data.noThrow; } 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 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 includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
@ -152,14 +136,25 @@ namespace Catch {
virtual bool forceColour() const { return m_data.forceColour; } virtual bool forceColour() const { return m_data.forceColour; }
private: 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; ConfigData m_data;
Stream m_stream; std::auto_ptr<IStream const> m_stream;
mutable std::ostream m_os;
TestSpec m_testSpec; TestSpec m_testSpec;
}; };
} // end namespace Catch } // end namespace Catch
#endif // TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED

View File

@ -60,12 +60,13 @@ namespace {
{ {
CONSOLE_SCREEN_BUFFER_INFO csbiInfo; CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
GetConsoleScreenBufferInfo( stdoutHandle, &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 ) { virtual void use( Colour::Code _colourCode ) {
switch( _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::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Red: return setTextAttribute( FOREGROUND_RED );
case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
@ -85,10 +86,11 @@ namespace {
private: private:
void setTextAttribute( WORD _textAttribute ) { void setTextAttribute( WORD _textAttribute ) {
SetConsoleTextAttribute( stdoutHandle, _textAttribute ); SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
} }
HANDLE stdoutHandle; HANDLE stdoutHandle;
WORD originalAttributes; WORD originalForegroundAttributes;
WORD originalBackgroundAttributes;
}; };
IColourImpl* platformColourInstance() { IColourImpl* platformColourInstance() {

View File

@ -8,7 +8,7 @@
#ifndef TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
#define 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_context.h"
#include "catch_stream.hpp" #include "catch_stream.hpp"
@ -17,7 +17,7 @@ namespace Catch {
class Context : public IMutableContext { 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& ); Context( Context const& );
void operator=( Context const& ); void operator=( Context const& );
@ -63,7 +63,7 @@ namespace Catch {
m_generatorsByTestName.find( testName ); m_generatorsByTestName.find( testName );
return it != m_generatorsByTestName.end() return it != m_generatorsByTestName.end()
? it->second ? it->second
: NULL; : CATCH_NULL;
} }
IGeneratorsForTest& getGeneratorsForCurrentTest() { IGeneratorsForTest& getGeneratorsForCurrentTest() {
@ -84,7 +84,7 @@ namespace Catch {
}; };
namespace { namespace {
Context* currentContext = NULL; Context* currentContext = CATCH_NULL;
} }
IMutableContext& getCurrentMutableContext() { IMutableContext& getCurrentMutableContext() {
if( !currentContext ) if( !currentContext )
@ -95,17 +95,9 @@ namespace Catch {
return getCurrentMutableContext(); 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<OutputDebugWriter>, true );
throw std::domain_error( "Unknown stream: " + streamName );
}
void cleanUpContext() { void cleanUpContext() {
delete currentContext; delete currentContext;
currentContext = NULL; currentContext = CATCH_NULL;
} }
} }

View File

@ -50,7 +50,7 @@
// Call sysctl. // Call sysctl.
size = sizeof(info); 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; Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
return false; return false;
} }

View File

@ -160,13 +160,51 @@ namespace Internal {
return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
} }
#ifdef CATCH_CONFIG_CPP11_LONG_LONG
// long long to unsigned X
template<Operator Op> bool compare( long long lhs, unsigned int rhs ) {
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
}
template<Operator Op> bool compare( long long lhs, unsigned long rhs ) {
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
}
template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) {
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
}
template<Operator Op> bool compare( long long lhs, unsigned char rhs ) {
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
}
// unsigned long long to X
template<Operator Op> bool compare( unsigned long long lhs, int rhs ) {
return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
}
template<Operator Op> bool compare( unsigned long long lhs, long rhs ) {
return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
}
template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) {
return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
}
template<Operator Op> bool compare( unsigned long long lhs, char rhs ) {
return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
}
// pointer to long long (when comparing against NULL)
template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) {
return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
}
template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) {
return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
}
#endif // CATCH_CONFIG_CPP11_LONG_LONG
#ifdef CATCH_CONFIG_CPP11_NULLPTR #ifdef CATCH_CONFIG_CPP11_NULLPTR
// pointer to nullptr_t (when comparing against nullptr) // pointer to nullptr_t (when comparing against nullptr)
template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) { template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
return Evaluator<T*, T*, Op>::evaluate( NULL, rhs ); return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs );
} }
template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) { template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
return Evaluator<T*, T*, Op>::evaluate( lhs, NULL ); return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr );
} }
#endif // CATCH_CONFIG_CPP11_NULLPTR #endif // CATCH_CONFIG_CPP11_NULLPTR

View File

@ -32,13 +32,13 @@ namespace Catch {
#ifdef __OBJC__ #ifdef __OBJC__
// In Objective-C try objective-c exceptions first // In Objective-C try objective-c exceptions first
@try { @try {
throw; return tryTranslators();
} }
@catch (NSException *exception) { @catch (NSException *exception) {
return Catch::toString( [exception description] ); return Catch::toString( [exception description] );
} }
#else #else
throw; return tryTranslators();
#endif #endif
} }
catch( TestFailureException& ) { catch( TestFailureException& ) {
@ -54,20 +54,15 @@ namespace Catch {
return msg; return msg;
} }
catch(...) { catch(...) {
return tryTranslators( m_translators.begin() ); return "Unknown exception";
} }
} }
std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const { std::string tryTranslators() const {
if( it == m_translators.end() ) if( m_translators.empty() )
return "Unknown exception"; throw;
else
try { return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
return (*it)->translate();
}
catch(...) {
return tryTranslators( it+1 );
}
} }
private: private:

View File

@ -16,7 +16,7 @@
#pragma clang diagnostic ignored "-Wweak-vtables" #pragma clang diagnostic ignored "-Wweak-vtables"
#endif #endif
#include "../catch_runner.hpp" #include "../catch_session.hpp"
#include "catch_registry_hub.hpp" #include "catch_registry_hub.hpp"
#include "catch_notimplemented_exception.hpp" #include "catch_notimplemented_exception.hpp"
#include "catch_context_impl.hpp" #include "catch_context_impl.hpp"
@ -35,15 +35,23 @@
#include "catch_tostring.hpp" #include "catch_tostring.hpp"
#include "catch_result_builder.hpp" #include "catch_result_builder.hpp"
#include "catch_tag_alias_registry.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_xml.hpp"
#include "../reporters/catch_reporter_junit.hpp" #include "../reporters/catch_reporter_junit.hpp"
#include "../reporters/catch_reporter_console.hpp" #include "../reporters/catch_reporter_console.hpp"
#include "../reporters/catch_reporter_compact.hpp" #include "../reporters/catch_reporter_compact.hpp"
namespace Catch { namespace Catch {
// These are all here to avoid warnings about not having any out of line
// virtual methods
NonCopyable::~NonCopyable() {} NonCopyable::~NonCopyable() {}
IShared::~IShared() {} IShared::~IShared() {}
IStream::~IStream() CATCH_NOEXCEPT {}
FileStream::~FileStream() CATCH_NOEXCEPT {}
CoutStream::~CoutStream() CATCH_NOEXCEPT {}
DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
IContext::~IContext() {} IContext::~IContext() {}
IResultCapture::~IResultCapture() {} IResultCapture::~IResultCapture() {}
@ -77,6 +85,7 @@ namespace Catch {
FreeFunctionTestCase::~FreeFunctionTestCase() {} FreeFunctionTestCase::~FreeFunctionTestCase() {}
IGeneratorInfo::~IGeneratorInfo() {} IGeneratorInfo::~IGeneratorInfo() {}
IGeneratorsForTest::~IGeneratorsForTest() {} IGeneratorsForTest::~IGeneratorsForTest() {}
WildcardPattern::~WildcardPattern() {}
TestSpec::Pattern::~Pattern() {} TestSpec::Pattern::~Pattern() {}
TestSpec::NamePattern::~NamePattern() {} TestSpec::NamePattern::~NamePattern() {}
TestSpec::TagPattern::~TagPattern() {} TestSpec::TagPattern::~TagPattern() {}
@ -88,6 +97,13 @@ namespace Catch {
Matchers::Impl::StdString::EndsWith::~EndsWith() {} Matchers::Impl::StdString::EndsWith::~EndsWith() {}
void Config::dummy() {} void Config::dummy() {}
namespace TestCaseTracking {
ITracker::~ITracker() {}
TrackerBase::~TrackerBase() {}
SectionTracker::~SectionTracker() {}
IndexTracker::~IndexTracker() {}
}
} }
#ifdef __clang__ #ifdef __clang__

View File

@ -18,6 +18,7 @@ namespace Catch {
class AssertionResult; class AssertionResult;
struct AssertionInfo; struct AssertionInfo;
struct SectionInfo; struct SectionInfo;
struct SectionEndInfo;
struct MessageInfo; struct MessageInfo;
class ScopedMessageBuilder; class ScopedMessageBuilder;
struct Counts; struct Counts;
@ -29,7 +30,8 @@ namespace Catch {
virtual void assertionEnded( AssertionResult const& result ) = 0; virtual void assertionEnded( AssertionResult const& result ) = 0;
virtual bool sectionStarted( SectionInfo const& sectionInfo, virtual bool sectionStarted( SectionInfo const& sectionInfo,
Counts& assertions ) = 0; 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 pushScopedMessage( MessageInfo const& message ) = 0;
virtual void popScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0;

View File

@ -9,15 +9,20 @@
#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
#include <string> #include <string>
#include <vector>
#include "catch_interfaces_registry_hub.h" #include "catch_interfaces_registry_hub.h"
namespace Catch { namespace Catch {
typedef std::string(*exceptionTranslateFunction)(); typedef std::string(*exceptionTranslateFunction)();
struct IExceptionTranslator;
typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
struct IExceptionTranslator { struct IExceptionTranslator {
virtual ~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 { struct IExceptionTranslatorRegistry {
@ -35,9 +40,12 @@ namespace Catch {
: m_translateFunction( translateFunction ) : m_translateFunction( translateFunction )
{} {}
virtual std::string translate() const { virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
try { try {
throw; if( it == itEnd )
throw;
else
return (*it)->translate( it+1, itEnd );
} }
catch( T& ex ) { catch( T& ex ) {
return m_translateFunction( ex ); return m_translateFunction( ex );

View File

@ -8,6 +8,8 @@
#ifndef TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED #ifndef TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
#include "catch_ptr.hpp"
#include <string> #include <string>
namespace Catch { namespace Catch {
@ -29,7 +31,8 @@ namespace Catch {
struct IMutableRegistryHub { struct IMutableRegistryHub {
virtual ~IMutableRegistryHub(); virtual ~IMutableRegistryHub();
virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0;
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
}; };

View File

@ -26,18 +26,18 @@
namespace Catch namespace Catch
{ {
struct ReporterConfig { struct ReporterConfig {
explicit ReporterConfig( Ptr<IConfig> const& _fullConfig ) explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream ) ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
: m_stream( &_stream ), m_fullConfig( _fullConfig ) {} : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
std::ostream& stream() const { return *m_stream; } std::ostream& stream() const { return *m_stream; }
Ptr<IConfig> fullConfig() const { return m_fullConfig; } Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
private: private:
std::ostream* m_stream; std::ostream* m_stream;
Ptr<IConfig> m_fullConfig; Ptr<IConfig const> m_fullConfig;
}; };
struct ReporterPreferences { struct ReporterPreferences {
@ -240,29 +240,34 @@ namespace Catch
// The return value indicates if the messages buffer should be cleared: // The return value indicates if the messages buffer should be cleared:
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
virtual void skipTest( TestCaseInfo const& testInfo ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
}; };
struct IReporterFactory { struct IReporterFactory : IShared {
virtual ~IReporterFactory(); virtual ~IReporterFactory();
virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
virtual std::string getDescription() const = 0; virtual std::string getDescription() const = 0;
}; };
struct IReporterRegistry { struct IReporterRegistry {
typedef std::map<std::string, IReporterFactory*> FactoryMap; typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
typedef std::vector<Ptr<IReporterFactory> > Listeners;
virtual ~IReporterRegistry(); virtual ~IReporterRegistry();
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0; virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
virtual FactoryMap const& getFactories() const = 0; virtual FactoryMap const& getFactories() const = 0;
virtual Listeners const& getListeners() const = 0;
}; };
Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
} }
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED #endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED

View File

@ -28,9 +28,13 @@ namespace Catch {
struct ITestCaseRegistry { struct ITestCaseRegistry {
virtual ~ITestCaseRegistry(); virtual ~ITestCaseRegistry();
virtual std::vector<TestCase> const& getAllTests() const = 0; virtual std::vector<TestCase> const& getAllTests() const = 0;
virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const = 0; virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
}; };
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
} }
#endif // TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED #endif // TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED

View File

@ -34,8 +34,7 @@ namespace Catch {
nameAttr.setInitialIndent( 2 ).setIndent( 4 ); nameAttr.setInitialIndent( 2 ).setIndent( 4 );
tagsAttr.setIndent( 6 ); tagsAttr.setIndent( 6 );
std::vector<TestCase> matchedTestCases; std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
it != itEnd; it != itEnd;
++it ) { ++it ) {
@ -63,8 +62,7 @@ namespace Catch {
if( !config.testSpec().hasFilters() ) if( !config.testSpec().hasFilters() )
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
std::size_t matchedTests = 0; std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases; std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
it != itEnd; it != itEnd;
++it ) { ++it ) {
@ -104,8 +102,7 @@ namespace Catch {
std::map<std::string, TagInfo> tagCounts; std::map<std::string, TagInfo> tagCounts;
std::vector<TestCase> matchedTestCases; std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
it != itEnd; it != itEnd;
++it ) { ++it ) {

View File

@ -12,6 +12,12 @@ namespace Catch {
namespace Matchers { namespace Matchers {
namespace Impl { namespace Impl {
namespace Generic {
template<typename ExpressionT> class AllOf;
template<typename ExpressionT> class AnyOf;
template<typename ExpressionT> class Not;
}
template<typename ExpressionT> template<typename ExpressionT>
struct Matcher : SharedImpl<IShared> struct Matcher : SharedImpl<IShared>
{ {
@ -21,6 +27,10 @@ namespace Matchers {
virtual Ptr<Matcher> clone() const = 0; virtual Ptr<Matcher> clone() const = 0;
virtual bool match( ExpressionT const& expr ) const = 0; virtual bool match( ExpressionT const& expr ) const = 0;
virtual std::string toString() const = 0; virtual std::string toString() const = 0;
Generic::AllOf<ExpressionT> operator && ( Matcher<ExpressionT> const& other ) const;
Generic::AnyOf<ExpressionT> operator || ( Matcher<ExpressionT> const& other ) const;
Generic::Not<ExpressionT> operator ! () const;
}; };
template<typename DerivedT, typename ExpressionT> template<typename DerivedT, typename ExpressionT>
@ -32,6 +42,22 @@ namespace Matchers {
}; };
namespace Generic { namespace Generic {
template<typename ExpressionT>
class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT> {
public:
explicit Not( Matcher<ExpressionT> 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<ExpressionT> > m_matcher;
};
template<typename ExpressionT> template<typename ExpressionT>
class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> { class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
@ -63,6 +89,12 @@ namespace Matchers {
return oss.str(); return oss.str();
} }
AllOf operator && ( Matcher<ExpressionT> const& other ) const {
AllOf allOfExpr( *this );
allOfExpr.add( other );
return allOfExpr;
}
private: private:
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
}; };
@ -97,85 +129,146 @@ namespace Matchers {
return oss.str(); return oss.str();
} }
AnyOf operator || ( Matcher<ExpressionT> const& other ) const {
AnyOf anyOfExpr( *this );
anyOfExpr.add( other );
return anyOfExpr;
}
private: private:
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
}; };
} // namespace Generic
template<typename ExpressionT>
Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator && ( Matcher<ExpressionT> const& other ) const {
Generic::AllOf<ExpressionT> allOfExpr;
allOfExpr.add( *this );
allOfExpr.add( other );
return allOfExpr;
} }
template<typename ExpressionT>
Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator || ( Matcher<ExpressionT> const& other ) const {
Generic::AnyOf<ExpressionT> anyOfExpr;
anyOfExpr.add( *this );
anyOfExpr.add( other );
return anyOfExpr;
}
template<typename ExpressionT>
Generic::Not<ExpressionT> Matcher<ExpressionT>::operator ! () const {
return Generic::Not<ExpressionT>( *this );
}
namespace StdString { namespace StdString {
inline std::string makeString( std::string const& str ) { return str; } inline std::string makeString( std::string const& str ) { return str; }
inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } 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> { struct Equals : MatcherImpl<Equals, std::string> {
Equals( std::string const& str ) : m_str( str ){} Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
Equals( Equals const& other ) : m_str( other.m_str ){} : m_data( str, caseSensitivity )
{}
Equals( Equals const& other ) : m_data( other.m_data ){}
virtual ~Equals(); virtual ~Equals();
virtual bool match( std::string const& expr ) const { 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 { 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> { struct Contains : MatcherImpl<Contains, std::string> {
Contains( std::string const& substr ) : m_substr( substr ){} Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
Contains( Contains const& other ) : m_substr( other.m_substr ){} : m_data( substr, caseSensitivity ){}
Contains( Contains const& other ) : m_data( other.m_data ){}
virtual ~Contains(); virtual ~Contains();
virtual bool match( std::string const& expr ) const { 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 { 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> { struct StartsWith : MatcherImpl<StartsWith, std::string> {
StartsWith( std::string const& substr ) : m_substr( substr ){} StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} : m_data( substr, caseSensitivity ){}
StartsWith( StartsWith const& other ) : m_data( other.m_data ){}
virtual ~StartsWith(); virtual ~StartsWith();
virtual bool match( std::string const& expr ) const { 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 { 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> { struct EndsWith : MatcherImpl<EndsWith, std::string> {
EndsWith( std::string const& substr ) : m_substr( substr ){} EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} : m_data( substr, caseSensitivity ){}
EndsWith( EndsWith const& other ) : m_data( other.m_data ){}
virtual ~EndsWith(); virtual ~EndsWith();
virtual bool match( std::string const& expr ) const { 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 { 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 StdString
} // namespace Impl } // namespace Impl
// The following functions create the actual matcher objects. // The following functions create the actual matcher objects.
// This allows the types to be inferred // This allows the types to be inferred
template<typename ExpressionT>
inline Impl::Generic::Not<ExpressionT> Not( Impl::Matcher<ExpressionT> const& m ) {
return Impl::Generic::Not<ExpressionT>( m );
}
template<typename ExpressionT> template<typename ExpressionT>
inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1, inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
Impl::Matcher<ExpressionT> const& m2 ) { Impl::Matcher<ExpressionT> const& m2 ) {
@ -199,17 +292,17 @@ namespace Matchers {
return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 ); return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
} }
inline Impl::StdString::Equals Equals( std::string const& str ) { inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
return Impl::StdString::Equals( str ); return Impl::StdString::Equals( str, caseSensitivity );
} }
inline Impl::StdString::Equals Equals( const char* str ) { inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity );
} }
inline Impl::StdString::Contains Contains( std::string const& substr ) { inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
return Impl::StdString::Contains( substr ); return Impl::StdString::Contains( substr, caseSensitivity );
} }
inline Impl::StdString::Contains Contains( const char* substr ) { inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity );
} }
inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
return Impl::StdString::StartsWith( substr ); return Impl::StdString::StartsWith( substr );

View File

@ -72,7 +72,7 @@ namespace Catch {
inline size_t registerTestMethods() { inline size_t registerTestMethods() {
size_t noTestMethods = 0; 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); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
objc_getClassList( classes, noClasses ); objc_getClassList( classes, noClasses );

View File

@ -16,12 +16,12 @@ namespace Catch {
template<typename T> template<typename T>
class Option { class Option {
public: public:
Option() : nullableValue( NULL ) {} Option() : nullableValue( CATCH_NULL ) {}
Option( T const& _value ) Option( T const& _value )
: nullableValue( new( storage ) T( _value ) ) : nullableValue( new( storage ) T( _value ) )
{} {}
Option( Option const& _other ) Option( Option const& _other )
: nullableValue( _other ? new( storage ) T( *_other ) : NULL ) : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL )
{} {}
~Option() { ~Option() {
@ -45,7 +45,7 @@ namespace Catch {
void reset() { void reset() {
if( nullableValue ) if( nullableValue )
nullableValue->~T(); nullableValue->~T();
nullableValue = NULL; nullableValue = CATCH_NULL;
} }
T& operator*() { return *nullableValue; } T& operator*() { return *nullableValue; }
@ -57,10 +57,10 @@ namespace Catch {
return nullableValue ? *nullableValue : defaultValue; return nullableValue ? *nullableValue : defaultValue;
} }
bool some() const { return nullableValue != NULL; } bool some() const { return nullableValue != CATCH_NULL; }
bool none() const { return nullableValue == 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 { operator SafeBool::type() const {
return SafeBool::makeSafe( some() ); return SafeBool::makeSafe( some() );
} }

View File

@ -23,7 +23,7 @@ namespace Catch {
template<typename T> template<typename T>
class Ptr { class Ptr {
public: public:
Ptr() : m_p( NULL ){} Ptr() : m_p( CATCH_NULL ){}
Ptr( T* p ) : m_p( p ){ Ptr( T* p ) : m_p( p ){
if( m_p ) if( m_p )
m_p->addRef(); m_p->addRef();
@ -39,7 +39,7 @@ namespace Catch {
void reset() { void reset() {
if( m_p ) if( m_p )
m_p->release(); m_p->release();
m_p = NULL; m_p = CATCH_NULL;
} }
Ptr& operator = ( T* p ){ Ptr& operator = ( T* p ){
Ptr temp( p ); Ptr temp( p );
@ -52,12 +52,11 @@ namespace Catch {
return *this; return *this;
} }
void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
T* get() { return m_p; } T* get() const{ return m_p; }
const T* get() const{ return m_p; }
T& operator*() const { return *m_p; } T& operator*() const { return *m_p; }
T* operator->() const { return m_p; } T* operator->() const { return m_p; }
bool operator !() const { return m_p == NULL; } bool operator !() const { return m_p == CATCH_NULL; }
operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); }
private: private:
T* m_p; T* m_p;

View File

@ -26,24 +26,27 @@ namespace Catch {
public: // IRegistryHub public: // IRegistryHub
RegistryHub() { RegistryHub() {
} }
virtual IReporterRegistry const& getReporterRegistry() const { virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE {
return m_reporterRegistry; return m_reporterRegistry;
} }
virtual ITestCaseRegistry const& getTestCaseRegistry() const { virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE {
return m_testCaseRegistry; return m_testCaseRegistry;
} }
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
return m_exceptionTranslatorRegistry; return m_exceptionTranslatorRegistry;
} }
public: // IMutableRegistryHub public: // IMutableRegistryHub
virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
m_reporterRegistry.registerReporter( name, factory ); m_reporterRegistry.registerReporter( name, factory );
} }
virtual void registerTest( TestCase const& testInfo ) { virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
m_reporterRegistry.registerListener( factory );
}
virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE {
m_testCaseRegistry.registerTest( testInfo ); m_testCaseRegistry.registerTest( testInfo );
} }
virtual void registerTranslator( const IExceptionTranslator* translator ) { virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
m_exceptionTranslatorRegistry.registerTranslator( translator ); m_exceptionTranslatorRegistry.registerTranslator( translator );
} }
@ -55,7 +58,7 @@ namespace Catch {
// Single, global, instance // Single, global, instance
inline RegistryHub*& getTheRegistryHub() { inline RegistryHub*& getTheRegistryHub() {
static RegistryHub* theRegistryHub = NULL; static RegistryHub* theRegistryHub = CATCH_NULL;
if( !theRegistryHub ) if( !theRegistryHub )
theRegistryHub = new RegistryHub(); theRegistryHub = new RegistryHub();
return theRegistryHub; return theRegistryHub;
@ -70,7 +73,7 @@ namespace Catch {
} }
void cleanUp() { void cleanUp() {
delete getTheRegistryHub(); delete getTheRegistryHub();
getTheRegistryHub() = NULL; getTheRegistryHub() = CATCH_NULL;
cleanUpContext(); cleanUpContext();
} }
std::string translateActiveException() { std::string translateActiveException() {

View File

@ -36,7 +36,7 @@ namespace Catch {
template<typename T> template<typename T>
class ReporterRegistrar { class ReporterRegistrar {
class ReporterFactory : public IReporterFactory { class ReporterFactory : public SharedImpl<IReporterFactory> {
// *** Please Note ***: // *** Please Note ***:
// - If you end up here looking at a compiler error because it's trying to register // - 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() ); getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
} }
}; };
template<typename T>
class ListenerRegistrar {
class ListenerFactory : public SharedImpl<IReporterFactory> {
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 ) \ #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
#endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED

View File

@ -18,27 +18,32 @@ namespace Catch {
public: public:
virtual ~ReporterRegistry() { virtual ~ReporterRegistry() CATCH_OVERRIDE {}
deleteAllValues( m_factories );
}
virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const { virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
FactoryMap::const_iterator it = m_factories.find( name ); FactoryMap::const_iterator it = m_factories.find( name );
if( it == m_factories.end() ) if( it == m_factories.end() )
return NULL; return CATCH_NULL;
return it->second->create( ReporterConfig( config ) ); return it->second->create( ReporterConfig( config ) );
} }
void registerReporter( std::string const& name, IReporterFactory* factory ) { void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) {
m_factories.insert( std::make_pair( name, factory ) ); m_factories.insert( std::make_pair( name, factory ) );
} }
void registerListener( Ptr<IReporterFactory> const& factory ) {
m_listeners.push_back( factory );
}
FactoryMap const& getFactories() const { virtual FactoryMap const& getFactories() const CATCH_OVERRIDE {
return m_factories; return m_factories;
} }
virtual Listeners const& getListeners() const CATCH_OVERRIDE {
return m_listeners;
}
private: private:
FactoryMap m_factories; FactoryMap m_factories;
Listeners m_listeners;
}; };
} }

View File

@ -11,6 +11,7 @@
#include "catch_result_type.h" #include "catch_result_type.h"
#include "catch_assertionresult.h" #include "catch_assertionresult.h"
#include "catch_common.h" #include "catch_common.h"
#include "catch_matchers.hpp"
namespace Catch { namespace Catch {
@ -38,7 +39,8 @@ namespace Catch {
ResultBuilder( char const* macroName, ResultBuilder( char const* macroName,
SourceLineInfo const& lineInfo, SourceLineInfo const& lineInfo,
char const* capturedExpression, char const* capturedExpression,
ResultDisposition::Flags resultDisposition ); ResultDisposition::Flags resultDisposition,
char const* secondArg = "" );
template<typename T> template<typename T>
ExpressionLhs<T const&> operator <= ( T const& operand ); ExpressionLhs<T const&> operator <= ( T const& operand );
@ -67,6 +69,9 @@ namespace Catch {
void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
void captureResult( ResultWas::OfType resultType ); void captureResult( ResultWas::OfType resultType );
void captureExpression(); void captureExpression();
void captureExpectedException( std::string const& expectedMessage );
void captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher );
void handleResult( AssertionResult const& result );
void react(); void react();
bool shouldDebugBreak() const; bool shouldDebugBreak() const;
bool allowThrows() const; bool allowThrows() const;
@ -80,7 +85,7 @@ namespace Catch {
std::string lhs, rhs, op; std::string lhs, rhs, op;
} m_exprComponents; } m_exprComponents;
CopyableStream m_stream; CopyableStream m_stream;
bool m_shouldDebugBreak; bool m_shouldDebugBreak;
bool m_shouldThrow; bool m_shouldThrow;
}; };

View File

@ -14,15 +14,21 @@
#include "catch_interfaces_runner.h" #include "catch_interfaces_runner.h"
#include "catch_interfaces_capture.h" #include "catch_interfaces_capture.h"
#include "catch_interfaces_registry_hub.h" #include "catch_interfaces_registry_hub.h"
#include "catch_wildcard_pattern.hpp"
namespace Catch { 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, ResultBuilder::ResultBuilder( char const* macroName,
SourceLineInfo const& lineInfo, SourceLineInfo const& lineInfo,
char const* capturedExpression, char const* capturedExpression,
ResultDisposition::Flags resultDisposition ) ResultDisposition::Flags resultDisposition,
: m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), char const* secondArg )
: m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ),
m_shouldDebugBreak( false ), m_shouldDebugBreak( false ),
m_shouldThrow( false ) m_shouldThrow( false )
{} {}
@ -63,9 +69,35 @@ namespace Catch {
setResultType( resultType ); setResultType( resultType );
captureExpression(); captureExpression();
} }
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
if( expectedMessage.empty() )
captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() );
else
captureExpectedException( Matchers::Equals( expectedMessage ) );
}
void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> 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() { void ResultBuilder::captureExpression() {
AssertionResult result = build(); AssertionResult result = build();
handleResult( result );
}
void ResultBuilder::handleResult( AssertionResult const& result )
{
getResultCapture().assertionEnded( result ); getResultCapture().assertionEnded( result );
if( !result.isOk() ) { if( !result.isOk() ) {

View File

@ -55,7 +55,7 @@ namespace Catch {
inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
} // end namespace Catch } // end namespace Catch
#endif // TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED #endif // TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED

View File

@ -59,15 +59,12 @@ namespace Catch {
public: public:
explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter ) explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter )
: m_runInfo( config->name() ), : m_runInfo( _config->name() ),
m_context( getCurrentMutableContext() ), m_context( getCurrentMutableContext() ),
m_activeTestCase( NULL ), m_activeTestCase( CATCH_NULL ),
m_config( config ), m_config( _config ),
m_reporter( reporter ), m_reporter( reporter )
m_prevRunner( m_context.getRunner() ),
m_prevResultCapture( m_context.getResultCapture() ),
m_prevConfig( m_context.getConfig() )
{ {
m_context.setRunner( this ); m_context.setRunner( this );
m_context.setConfig( m_config ); m_context.setConfig( m_config );
@ -77,10 +74,6 @@ namespace Catch {
virtual ~RunContext() { virtual ~RunContext() {
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); 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 ) { 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_reporter->testCaseStarting( testInfo );
m_activeTestCase = &testCase; m_activeTestCase = &testCase;
m_testCaseTracker = TestCaseTracker( testInfo.name );
do { do {
m_trackerContext.startRun();
do { do {
m_trackerContext.startCycle();
m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name );
runCurrentTest( redirectedCout, redirectedCerr ); 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() ); while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
Totals deltaTotals = m_totals.delta( prevTotals ); Totals deltaTotals = m_totals.delta( prevTotals );
@ -119,8 +116,8 @@ namespace Catch {
redirectedCerr, redirectedCerr,
aborting() ) ); aborting() ) );
m_activeTestCase = NULL; m_activeTestCase = CATCH_NULL;
m_testCaseTracker.reset(); m_testCaseTracker = CATCH_NULL;
return deltaTotals; return deltaTotals;
} }
@ -156,8 +153,10 @@ namespace Catch {
std::ostringstream oss; std::ostringstream oss;
oss << sectionInfo.name << "@" << sectionInfo.lineInfo; oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
if( !m_testCaseTracker->enterSection( oss.str() ) ) ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() );
if( !sectionTracker.isOpen() )
return false; return false;
m_activeSections.push_back( &sectionTracker );
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
@ -168,30 +167,40 @@ namespace Catch {
return true; return true;
} }
bool testForMissingAssertions( Counts& assertions ) { bool testForMissingAssertions( Counts& assertions ) {
if( assertions.total() != 0 || if( assertions.total() != 0 )
!m_config->warnAboutMissingAssertions() || return false;
m_testCaseTracker->currentSectionHasChildren() ) if( !m_config->warnAboutMissingAssertions() )
return false;
if( m_trackerContext.currentTracker().hasChildren() )
return false; return false;
m_totals.assertions.failed++; m_totals.assertions.failed++;
assertions.failed++; assertions.failed++;
return true; return true;
} }
virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { virtual void sectionEnded( SectionEndInfo const& endInfo ) {
if( std::uncaught_exception() ) { Counts assertions = m_totals.assertions - endInfo.prevAssertions;
m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
return;
}
Counts assertions = m_totals.assertions - prevAssertions;
bool missingAssertions = testForMissingAssertions( assertions ); 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(); 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 ) { virtual void pushScopedMessage( MessageInfo const& message ) {
m_messages.push_back( message ); m_messages.push_back( message );
} }
@ -257,7 +266,8 @@ namespace Catch {
double duration = 0; double duration = 0;
try { try {
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
TestCaseTracker::Guard guard( *m_testCaseTracker );
seedRng( *m_config );
Timer timer; Timer timer;
timer.start(); timer.start();
@ -277,6 +287,7 @@ namespace Catch {
catch(...) { catch(...) {
makeUnexpectedResultBuilder().useActiveException(); makeUnexpectedResultBuilder().useActiveException();
} }
m_testCaseTracker->close();
handleUnfinishedSections(); handleUnfinishedSections();
m_messages.clear(); m_messages.clear();
@ -311,39 +322,29 @@ namespace Catch {
void handleUnfinishedSections() { void handleUnfinishedSections() {
// If sections ended prematurely due to an exception we stored their // If sections ended prematurely due to an exception we stored their
// infos here so we can tear them down outside the unwind process. // infos here so we can tear them down outside the unwind process.
for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(), for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
itEnd = m_unfinishedSections.rend(); itEnd = m_unfinishedSections.rend();
it != itEnd; it != itEnd;
++it ) ++it )
sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); sectionEnded( *it );
m_unfinishedSections.clear(); 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; TestRunInfo m_runInfo;
IMutableContext& m_context; IMutableContext& m_context;
TestCase const* m_activeTestCase; TestCase const* m_activeTestCase;
Option<TestCaseTracker> m_testCaseTracker; ITracker* m_testCaseTracker;
ITracker* m_currentSectionTracker;
AssertionResult m_lastResult; AssertionResult m_lastResult;
Ptr<IConfig const> m_config; Ptr<IConfig const> m_config;
Totals m_totals; Totals m_totals;
Ptr<IStreamingReporter> m_reporter; Ptr<IStreamingReporter> m_reporter;
std::vector<MessageInfo> m_messages; std::vector<MessageInfo> m_messages;
IRunner* m_prevRunner;
IResultCapture* m_prevResultCapture;
Ptr<IConfig const> m_prevConfig;
AssertionInfo m_lastAssertionInfo; AssertionInfo m_lastAssertionInfo;
std::vector<UnfinishedSections> m_unfinishedSections; std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
}; };
IResultCapture& getResultCapture() { IResultCapture& getResultCapture() {

View File

@ -32,8 +32,13 @@ namespace Catch {
} }
Section::~Section() { Section::~Section() {
if( m_sectionIncluded ) if( m_sectionIncluded ) {
getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); 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 // This indicates whether the section should be executed or not

View File

@ -9,6 +9,7 @@
#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
#include "catch_common.h" #include "catch_common.h"
#include "catch_totals.hpp"
namespace Catch { namespace Catch {
@ -23,6 +24,16 @@ namespace Catch {
SourceLineInfo lineInfo; 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 } // end namespace Catch
#endif // TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED #endif // TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED

View File

@ -36,7 +36,7 @@ namespace Catch {
RunningSection( std::string const& name ) RunningSection( std::string const& name )
: m_state( Root ), : m_state( Root ),
m_parent( NULL ), m_parent( CATCH_NULL ),
m_name( name ) m_name( name )
{} {}

View File

@ -9,28 +9,55 @@
#ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED #ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#include <streambuf> #include "catch_compiler_capabilities.h"
#include "catch_streambuf.h"
#ifdef __clang__ #include <streambuf>
#pragma clang diagnostic ignored "-Wpadded" #include <ostream>
#endif #include <fstream>
namespace Catch { 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& cout();
std::ostream& cerr(); 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<StreamBufBase> 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 #endif // TWOBLUECUBES_CATCH_STREAM_H_INCLUDED

View File

@ -10,7 +10,6 @@
#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
#include "catch_stream.h" #include "catch_stream.h"
#include "catch_streambuf.h"
#include "catch_debugger.h" #include "catch_debugger.h"
#include <stdexcept> #include <stdexcept>
@ -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 { struct OutputDebugWriter {
void operator()( std::string const&str ) { void operator()( std::string const&str ) {
@ -64,20 +77,23 @@ namespace Catch {
} }
}; };
Stream::Stream() DebugOutStream::DebugOutStream()
: streamBuf( NULL ), isOwned( false ) : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
m_os( m_streamBuf.get() )
{} {}
Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) std::ostream& DebugOutStream::stream() const {
: streamBuf( _streamBuf ), isOwned( _isOwned ) 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() { std::ostream& CoutStream::stream() const {
if( isOwned ) { return m_os;
delete streamBuf;
streamBuf = NULL;
isOwned = false;
}
} }
#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions

View File

@ -5,9 +5,6 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) * 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 __clang__
# ifdef __ICC // icpc defines the __clang__ macro # ifdef __ICC // icpc defines the __clang__ macro
# pragma warning(push) # pragma warning(push)
@ -22,6 +19,7 @@
# pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat"
# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
# pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wswitch-enum"
# pragma clang diagnostic ignored "-Wcovered-switch-default"
# endif # endif
#elif defined __GNUC__ #elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wvariadic-macros" # pragma GCC diagnostic ignored "-Wvariadic-macros"
@ -29,5 +27,3 @@
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wpadded" # pragma GCC diagnostic ignored "-Wpadded"
#endif #endif
#endif // TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED

View File

@ -31,7 +31,7 @@ namespace Catch {
MayFail = 1 << 3, MayFail = 1 << 3,
Throws = 1 << 4 Throws = 1 << 4
}; };
TestCaseInfo( std::string const& _name, TestCaseInfo( std::string const& _name,
std::string const& _className, std::string const& _className,
std::string const& _description, std::string const& _description,
@ -40,6 +40,8 @@ namespace Catch {
TestCaseInfo( TestCaseInfo const& other ); TestCaseInfo( TestCaseInfo const& other );
friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags );
bool isHidden() const; bool isHidden() const;
bool throws() const; bool throws() const;
bool okToFail() const; bool okToFail() const;

View File

@ -93,6 +93,21 @@ namespace Catch {
return TestCase( _testCase, info ); return TestCase( _testCase, info );
} }
void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags )
{
testCaseInfo.tags = tags;
testCaseInfo.lcaseTags.clear();
std::ostringstream oss;
for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
oss << "[" << *it << "]";
std::string lcaseTag = toLower( *it );
testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
testCaseInfo.lcaseTags.insert( lcaseTag );
}
testCaseInfo.tagsAsString = oss.str();
}
TestCaseInfo::TestCaseInfo( std::string const& _name, TestCaseInfo::TestCaseInfo( std::string const& _name,
std::string const& _className, std::string const& _className,
std::string const& _description, std::string const& _description,
@ -101,18 +116,10 @@ namespace Catch {
: name( _name ), : name( _name ),
className( _className ), className( _className ),
description( _description ), description( _description ),
tags( _tags ),
lineInfo( _lineInfo ), lineInfo( _lineInfo ),
properties( None ) properties( None )
{ {
std::ostringstream oss; setTags( *this, _tags );
for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) {
oss << "[" << *it << "]";
std::string lcaseTag = toLower( *it );
properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) );
lcaseTags.insert( lcaseTag );
}
tagsAsString = oss.str();
} }
TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )

View File

@ -21,14 +21,71 @@
namespace Catch { namespace Catch {
class TestRegistry : public ITestCaseRegistry { struct LexSort {
struct LexSort { bool operator() (TestCase i,TestCase j) const { return (i<j);}
bool operator() (TestCase i,TestCase j) const { return (i<j);} };
}; struct RandomNumberGenerator {
struct RandomNumberGenerator { int operator()( int n ) const { return std::rand() % n; }
int operator()( int n ) const { return std::rand() % n; } };
};
inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
std::vector<TestCase> 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<TestCase> const& functions ) {
std::set<TestCase> seenFunctions;
for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
it != itEnd;
++it ) {
std::pair<std::set<TestCase>::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<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
std::vector<TestCase> filtered;
filtered.reserve( testCases.size() );
for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
it != itEnd;
++it )
if( matchTest( *it, testSpec, config ) )
filtered.push_back( *it );
return filtered;
}
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
}
class TestRegistry : public ITestCaseRegistry {
public: public:
TestRegistry() : m_unnamedCount( 0 ) {} TestRegistry() : m_unnamedCount( 0 ) {}
virtual ~TestRegistry(); virtual ~TestRegistry();
@ -40,68 +97,27 @@ namespace Catch {
oss << "Anonymous test case " << ++m_unnamedCount; oss << "Anonymous test case " << ++m_unnamedCount;
return registerTest( testCase.withName( oss.str() ) ); return registerTest( testCase.withName( oss.str() ) );
} }
m_functions.push_back( testCase );
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);
}
} }
virtual std::vector<TestCase> const& getAllTests() const { virtual std::vector<TestCase> const& getAllTests() const {
return m_functionsInOrder; return m_functions;
} }
virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const {
if( m_sortedFunctions.empty() )
enforceNoDuplicateTestCases( m_functions );
virtual std::vector<TestCase> const& getAllNonHiddenTests() const { if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
return m_nonHiddenFunctions; m_sortedFunctions = sortTests( config, m_functions );
} m_currentSortOrder = config.runOrder();
virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const {
for( std::vector<TestCase>::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 );
} }
sortTests( config, matchingTestCases ); return m_sortedFunctions;
} }
private: private:
std::vector<TestCase> m_functions;
static void sortTests( IConfig const& config, std::vector<TestCase>& matchingTestCases ) { mutable RunTests::InWhatOrder m_currentSortOrder;
mutable std::vector<TestCase> m_sortedFunctions;
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<TestCase> m_functions;
std::vector<TestCase> m_functionsInOrder;
std::vector<TestCase> m_nonHiddenFunctions;
size_t m_unnamedCount; size_t m_unnamedCount;
std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
}; };
@ -136,29 +152,38 @@ namespace Catch {
return className; 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, AutoReg::AutoReg
SourceLineInfo const& lineInfo, ( TestFunction function,
NameAndDesc const& nameAndDesc ) { SourceLineInfo const& lineInfo,
registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); NameAndDesc const& nameAndDesc ) {
registerTestCaseFunction( function, lineInfo, nameAndDesc );
} }
AutoReg::~AutoReg() {} 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 } // end namespace Catch

View File

@ -8,140 +8,308 @@
#ifndef TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
#define 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 <map> #include <map>
#include <string> #include <string>
#include <assert.h> #include <assert.h>
#include <vector>
namespace Catch { 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<ITracker> const& child ) = 0;
virtual ITracker* findChild( std::string const& name ) = 0;
virtual void openChild() = 0;
};
class TrackerContext {
class TrackedSection {
typedef std::map<std::string, TrackedSection> TrackedSections;
public:
enum RunState { enum RunState {
NotStarted, NotStarted,
Executing, Executing,
ExecutingChildren, CompletedCycle
Completed
}; };
TrackedSection( std::string const& name, TrackedSection* parent ) Ptr<ITracker> m_rootTracker;
: m_name( name ), m_runState( NotStarted ), m_parent( parent ) 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() { ITracker& startRun();
return m_parent;
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<ITracker> const& tracker ) {
return tracker->name() == m_name;
}
};
typedef std::vector<Ptr<ITracker> > 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(); return !m_children.empty();
} }
private:
std::string m_name; virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE {
RunState m_runState; m_children.push_back( child );
TrackedSections m_children; }
TrackedSection* m_parent;
}; virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE {
Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) );
inline TrackedSection* TrackedSection::findChild( std::string const& childName ) { return( it != m_children.end() )
TrackedSections::iterator it = m_children.find( childName ); ? it->get()
return it != m_children.end() : CATCH_NULL;
? &it->second }
: NULL; virtual ITracker& parent() CATCH_OVERRIDE {
} assert( m_parent ); // Should always be non-null except for root
inline TrackedSection* TrackedSection::acquireChild( std::string const& childName ) { return *m_parent;
if( TrackedSection* child = findChild( childName ) ) }
return child;
m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); virtual void openChild() CATCH_OVERRIDE {
return findChild( childName ); if( m_runState != ExecutingChildren ) {
}
inline void TrackedSection::leave() {
for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end();
it != itEnd;
++it )
if( it->second.runState() != Completed ) {
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() { void open() {
m_currentSection->leave(); m_runState = Executing;
m_currentSection = m_currentSection->getParent(); moveToThis();
assert( m_currentSection != NULL ); if( m_parent )
m_completedASectionThisRun = true; m_parent->openChild();
} }
bool currentSectionHasChildren() const { virtual void close() CATCH_OVERRIDE {
return m_currentSection->hasChildren();
}
bool isCompleted() const {
return m_testCase.runState() == TrackedSection::Completed;
}
class Guard { // Close any still open children (e.g. generators)
public: while( &m_ctx.currentTracker() != this )
Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { m_ctx.currentTracker().close();
m_tracker.enterTestCase();
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() { moveToParent();
m_tracker.leaveTestCase(); m_ctx.completeCycle();
} }
private: virtual void fail() CATCH_OVERRIDE {
Guard( Guard const& ); m_runState = Failed;
void operator = ( Guard const& ); if( m_parent )
TestCaseTracker& m_tracker; m_parent->markAsNeedingAnotherRun();
}; moveToParent();
m_ctx.completeCycle();
}
virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE {
m_runState = NeedsAnotherRun;
}
private: private:
void enterTestCase() { void moveToParent() {
m_currentSection = &m_testCase; assert( m_parent );
m_completedASectionThisRun = false; m_ctx.setCurrentTracker( m_parent );
m_testCase.enter();
} }
void leaveTestCase() { void moveToThis() {
m_testCase.leave(); 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<SectionTracker*>( childTracker );
assert( section );
}
else {
section = new SectionTracker( name, ctx, &currentTracker );
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<IndexTracker*>( childTracker );
assert( tracker );
}
else {
tracker = new IndexTracker( name, ctx, &currentTracker, 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 } // namespace Catch

View File

@ -42,27 +42,32 @@ struct NameAndDesc {
const char* description; const char* description;
}; };
void registerTestCase
( ITestCase* testCase,
char const* className,
NameAndDesc const& nameAndDesc,
SourceLineInfo const& lineInfo );
struct AutoReg { struct AutoReg {
AutoReg( TestFunction function, AutoReg
SourceLineInfo const& lineInfo, ( TestFunction function,
NameAndDesc const& nameAndDesc ); SourceLineInfo const& lineInfo,
NameAndDesc const& nameAndDesc );
template<typename C> template<typename C>
AutoReg( void (C::*method)(), AutoReg
char const* className, ( void (C::*method)(),
NameAndDesc const& nameAndDesc, char const* className,
SourceLineInfo const& lineInfo ) { NameAndDesc const& nameAndDesc,
registerTestCase( new MethodTestCase<C>( method ), SourceLineInfo const& lineInfo ) {
className,
nameAndDesc,
lineInfo );
}
void registerTestCase( ITestCase* testCase, registerTestCase
char const* className, ( new MethodTestCase<C>( method ),
NameAndDesc const& nameAndDesc, className,
SourceLineInfo const& lineInfo ); nameAndDesc,
lineInfo );
}
~AutoReg(); ~AutoReg();
@ -71,6 +76,11 @@ private:
void operator= ( AutoReg const& ); void operator= ( AutoReg const& );
}; };
void registerTestCaseFunction
( TestFunction function,
SourceLineInfo const& lineInfo,
NameAndDesc const& nameAndDesc );
} // end namespace Catch } // end namespace Catch
#ifdef CATCH_CONFIG_VARIADIC_MACROS #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() 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 #else
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ #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() 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
#endif // TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED

View File

@ -13,6 +13,7 @@
#pragma clang diagnostic ignored "-Wpadded" #pragma clang diagnostic ignored "-Wpadded"
#endif #endif
#include "catch_wildcard_pattern.hpp"
#include "catch_test_case_info.h" #include "catch_test_case_info.h"
#include <string> #include <string>
@ -26,50 +27,18 @@ namespace Catch {
virtual bool matches( TestCaseInfo const& testCase ) const = 0; virtual bool matches( TestCaseInfo const& testCase ) const = 0;
}; };
class NamePattern : public Pattern { class NamePattern : public Pattern {
enum WildcardPosition {
NoWildcard = 0,
WildcardAtStart = 1,
WildcardAtEnd = 2,
WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
};
public: public:
NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { NamePattern( std::string const& name )
if( startsWith( m_name, "*" ) ) { : m_wildcardPattern( toLower( name ), CaseSensitive::No )
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<WildcardPosition>( m_wildcard | WildcardAtEnd );
}
}
virtual ~NamePattern(); virtual ~NamePattern();
virtual bool matches( TestCaseInfo const& testCase ) const { virtual bool matches( TestCaseInfo const& testCase ) const {
switch( m_wildcard ) { return m_wildcardPattern.matches( toLower( testCase.name ) );
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
} }
private: private:
std::string m_name; WildcardPattern m_wildcardPattern;
WildcardPosition m_wildcard;
}; };
class TagPattern : public Pattern { class TagPattern : public Pattern {
public: public:
TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
@ -80,6 +49,7 @@ namespace Catch {
private: private:
std::string m_tag; std::string m_tag;
}; };
class ExcludedPattern : public Pattern { class ExcludedPattern : public Pattern {
public: public:
ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}

View File

@ -37,7 +37,7 @@ namespace Catch {
#else #else
uint64_t getCurrentTicks() { uint64_t getCurrentTicks() {
timeval t; timeval t;
gettimeofday(&t,NULL); gettimeofday(&t,CATCH_NULL);
return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec ); return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
} }
#endif #endif

View File

@ -52,6 +52,11 @@ std::string toString( char value );
std::string toString( signed char value ); std::string toString( signed char value );
std::string toString( unsigned 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 #ifdef CATCH_CONFIG_CPP11_NULLPTR
std::string toString( std::nullptr_t ); std::string toString( std::nullptr_t );
#endif #endif
@ -62,10 +67,10 @@ std::string toString( std::nullptr_t );
std::string toString( NSObject* const& nsObject ); std::string toString( NSObject* const& nsObject );
#endif #endif
namespace Detail { namespace Detail {
extern std::string unprintableString; extern const std::string unprintableString;
struct BorgType { struct BorgType {
template<typename T> BorgType( T const& ); template<typename T> BorgType( T const& );
@ -73,7 +78,7 @@ namespace Detail {
struct TrueType { char sizer[1]; }; struct TrueType { char sizer[1]; };
struct FalseType { char sizer[2]; }; struct FalseType { char sizer[2]; };
TrueType& testStreamable( std::ostream& ); TrueType& testStreamable( std::ostream& );
FalseType testStreamable( FalseType ); FalseType testStreamable( FalseType );
@ -148,7 +153,7 @@ struct StringMaker<T*> {
template<typename U> template<typename U>
static std::string convert( U* p ) { static std::string convert( U* p ) {
if( !p ) if( !p )
return INTERNAL_CATCH_STRINGIFY( NULL ); return "NULL";
else else
return Detail::rawMemoryToString( p ); return Detail::rawMemoryToString( p );
} }
@ -158,7 +163,7 @@ template<typename R, typename C>
struct StringMaker<R C::*> { struct StringMaker<R C::*> {
static std::string convert( R C::* p ) { static std::string convert( R C::* p ) {
if( !p ) if( !p )
return INTERNAL_CATCH_STRINGIFY( NULL ); return "NULL";
else else
return Detail::rawMemoryToString( p ); return Detail::rawMemoryToString( p );
} }

View File

@ -15,9 +15,11 @@ namespace Catch {
namespace Detail { namespace Detail {
std::string unprintableString = "{?}"; const std::string unprintableString = "{?}";
namespace { namespace {
const int hexThreshold = 255;
struct Endianness { struct Endianness {
enum Arch { Big, Little }; enum Arch { Big, Little };
@ -99,7 +101,7 @@ std::string toString( wchar_t* const value )
std::string toString( int value ) { std::string toString( int value ) {
std::ostringstream oss; std::ostringstream oss;
oss << value; oss << value;
if( value >= 255 ) if( value > Detail::hexThreshold )
oss << " (0x" << std::hex << value << ")"; oss << " (0x" << std::hex << value << ")";
return oss.str(); return oss.str();
} }
@ -107,7 +109,7 @@ std::string toString( int value ) {
std::string toString( unsigned long value ) { std::string toString( unsigned long value ) {
std::ostringstream oss; std::ostringstream oss;
oss << value; oss << value;
if( value >= 255 ) if( value > Detail::hexThreshold )
oss << " (0x" << std::hex << value << ")"; oss << " (0x" << std::hex << value << ")";
return oss.str(); return oss.str();
} }
@ -157,6 +159,23 @@ std::string toString( unsigned char value ) {
return toString( static_cast<char>( value ) ); return toString( static_cast<char>( 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 #ifdef CATCH_CONFIG_CPP11_NULLPTR
std::string toString( std::nullptr_t ) { std::string toString( std::nullptr_t ) {
return "nullptr"; return "nullptr";

View File

@ -27,7 +27,7 @@ namespace Catch {
unsigned int const buildNumber; unsigned int const buildNumber;
friend std::ostream& operator << ( std::ostream& os, Version const& version ); friend std::ostream& operator << ( std::ostream& os, Version const& version );
private: private:
void operator=( Version const& ); void operator=( Version const& );
}; };

View File

@ -37,7 +37,7 @@ namespace Catch {
return os; return os;
} }
Version libraryVersion( 1, 2, 1, "", 0 ); Version libraryVersion( 1, 3, 0, "", 0 );
} }

View File

@ -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<WildcardPosition>( 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

View File

@ -8,14 +8,72 @@
#ifndef TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
#define 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 <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <iomanip>
namespace Catch { 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 << "&lt;"; break;
case '&': os << "&amp;"; break;
case '>':
// See: http://www.w3.org/TR/xml/#syntax
if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
os << "&gt;";
else
os << c;
break;
case '\"':
if( m_forWhat == ForAttributes )
os << "&quot;";
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<int>( 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 { class XmlWriter {
public: public:
@ -27,7 +85,7 @@ namespace Catch {
ScopedElement( ScopedElement const& other ) ScopedElement( ScopedElement const& other )
: m_writer( other.m_writer ){ : m_writer( other.m_writer ){
other.m_writer = NULL; other.m_writer = CATCH_NULL;
} }
~ScopedElement() { ~ScopedElement() {
@ -98,11 +156,8 @@ namespace Catch {
} }
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
if( !name.empty() && !attribute.empty() ) { if( !name.empty() && !attribute.empty() )
stream() << " " << name << "=\""; stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\"";
writeEncodedText( attribute );
stream() << "\"";
}
return *this; return *this;
} }
@ -113,9 +168,9 @@ namespace Catch {
template<typename T> template<typename T>
XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
if( !name.empty() ) std::ostringstream oss;
stream() << " " << name << "=\"" << attribute << "\""; oss << attribute;
return *this; return writeAttribute( name, oss.str() );
} }
XmlWriter& writeText( std::string const& text, bool indent = true ) { XmlWriter& writeText( std::string const& text, bool indent = true ) {
@ -124,7 +179,7 @@ namespace Catch {
ensureTagClosed(); ensureTagClosed();
if( tagWasOpen && indent ) if( tagWasOpen && indent )
stream() << m_indent; stream() << m_indent;
writeEncodedText( text ); stream() << XmlEncode( text );
m_needsNewline = true; m_needsNewline = true;
} }
return *this; 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() << "&lt;";
break;
case '&':
stream() << "&amp;";
break;
case '\"':
stream() << "&quot;";
break;
}
mtext = mtext.substr( pos+1 );
pos = mtext.find_first_of( charsToEncode );
}
stream() << mtext;
}
bool m_tagIsOpen; bool m_tagIsOpen;
bool m_needsNewline; bool m_needsNewline;
std::vector<std::string> m_tags; std::vector<std::string> m_tags;
@ -201,4 +232,6 @@ namespace Catch {
}; };
} }
#include "catch_reenable_warnings.h"
#endif // TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED

View File

@ -19,47 +19,53 @@ namespace Catch {
StreamingReporterBase( ReporterConfig const& _config ) StreamingReporterBase( ReporterConfig const& _config )
: m_config( _config.fullConfig() ), : m_config( _config.fullConfig() ),
stream( _config.stream() ) 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; currentTestRunInfo = _testRunInfo;
} }
virtual void testGroupStarting( GroupInfo const& _groupInfo ) { virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE {
currentGroupInfo = _groupInfo; currentGroupInfo = _groupInfo;
} }
virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE {
currentTestCaseInfo = _testInfo; currentTestCaseInfo = _testInfo;
} }
virtual void sectionStarting( SectionInfo const& _sectionInfo ) { virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
m_sectionStack.push_back( _sectionInfo ); m_sectionStack.push_back( _sectionInfo );
} }
virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE {
m_sectionStack.pop_back(); m_sectionStack.pop_back();
} }
virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE {
currentTestCaseInfo.reset(); currentTestCaseInfo.reset();
} }
virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE {
currentGroupInfo.reset(); currentGroupInfo.reset();
} }
virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE {
currentTestCaseInfo.reset(); currentTestCaseInfo.reset();
currentGroupInfo.reset(); currentGroupInfo.reset();
currentTestRunInfo.reset(); currentTestRunInfo.reset();
} }
virtual void skipTest( TestCaseInfo const& ) { virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {
// Don't do anything with this by default. // Don't do anything with this by default.
// It can optionally be overridden in the derived class. // It can optionally be overridden in the derived class.
} }
Ptr<IConfig> m_config; Ptr<IConfig const> m_config;
std::ostream& stream; std::ostream& stream;
LazyStat<TestRunInfo> currentTestRunInfo; LazyStat<TestRunInfo> currentTestRunInfo;
@ -67,6 +73,7 @@ namespace Catch {
LazyStat<TestCaseInfo> currentTestCaseInfo; LazyStat<TestCaseInfo> currentTestCaseInfo;
std::vector<SectionInfo> m_sectionStack; std::vector<SectionInfo> m_sectionStack;
ReporterPreferences m_reporterPrefs;
}; };
struct CumulativeReporterBase : SharedImpl<IStreamingReporter> { struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
@ -118,15 +125,21 @@ namespace Catch {
CumulativeReporterBase( ReporterConfig const& _config ) CumulativeReporterBase( ReporterConfig const& _config )
: m_config( _config.fullConfig() ), : m_config( _config.fullConfig() ),
stream( _config.stream() ) stream( _config.stream() )
{} {
m_reporterPrefs.shouldRedirectStdOut = false;
}
~CumulativeReporterBase(); ~CumulativeReporterBase();
virtual void testRunStarting( TestRunInfo const& ) {} virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
virtual void testGroupStarting( GroupInfo const& ) {} 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 ); SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
Ptr<SectionNode> node; Ptr<SectionNode> node;
if( m_sectionStack.empty() ) { if( m_sectionStack.empty() ) {
@ -151,7 +164,7 @@ namespace Catch {
m_deepestSection = node; m_deepestSection = node;
} }
virtual void assertionStarting( AssertionInfo const& ) {} virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
virtual bool assertionEnded( AssertionStats const& assertionStats ) { virtual bool assertionEnded( AssertionStats const& assertionStats ) {
assert( !m_sectionStack.empty() ); assert( !m_sectionStack.empty() );
@ -159,13 +172,13 @@ namespace Catch {
sectionNode.assertions.push_back( assertionStats ); sectionNode.assertions.push_back( assertionStats );
return true; return true;
} }
virtual void sectionEnded( SectionStats const& sectionStats ) { virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
assert( !m_sectionStack.empty() ); assert( !m_sectionStack.empty() );
SectionNode& node = *m_sectionStack.back(); SectionNode& node = *m_sectionStack.back();
node.stats = sectionStats; node.stats = sectionStats;
m_sectionStack.pop_back(); m_sectionStack.pop_back();
} }
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats ); Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
assert( m_sectionStack.size() == 0 ); assert( m_sectionStack.size() == 0 );
node->children.push_back( m_rootSection ); node->children.push_back( m_rootSection );
@ -176,12 +189,12 @@ namespace Catch {
m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdOut = testCaseStats.stdOut;
m_deepestSection->stdErr = testCaseStats.stdErr; m_deepestSection->stdErr = testCaseStats.stdErr;
} }
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats ); Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
node->children.swap( m_testCases ); node->children.swap( m_testCases );
m_testGroups.push_back( node ); m_testGroups.push_back( node );
} }
virtual void testRunEnded( TestRunStats const& testRunStats ) { virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
Ptr<TestRunNode> node = new TestRunNode( testRunStats ); Ptr<TestRunNode> node = new TestRunNode( testRunStats );
node->children.swap( m_testGroups ); node->children.swap( m_testGroups );
m_testRuns.push_back( node ); m_testRuns.push_back( node );
@ -189,9 +202,9 @@ namespace Catch {
} }
virtual void testRunEndedCumulative() = 0; virtual void testRunEndedCumulative() = 0;
virtual void skipTest( TestCaseInfo const& ) {} virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
Ptr<IConfig> m_config; Ptr<IConfig const> m_config;
std::ostream& stream; std::ostream& stream;
std::vector<AssertionStats> m_assertions; std::vector<AssertionStats> m_assertions;
std::vector<std::vector<Ptr<SectionNode> > > m_sections; std::vector<std::vector<Ptr<SectionNode> > > m_sections;
@ -203,6 +216,7 @@ namespace Catch {
Ptr<SectionNode> m_rootSection; Ptr<SectionNode> m_rootSection;
Ptr<SectionNode> m_deepestSection; Ptr<SectionNode> m_deepestSection;
std::vector<Ptr<SectionNode> > m_sectionStack; std::vector<Ptr<SectionNode> > m_sectionStack;
ReporterPreferences m_reporterPrefs;
}; };
@ -216,6 +230,18 @@ namespace Catch {
return line; 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 } // end namespace Catch
#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED

View File

@ -21,24 +21,19 @@ namespace Catch {
m_headerPrinted( false ) m_headerPrinted( false )
{} {}
virtual ~ConsoleReporter(); virtual ~ConsoleReporter() CATCH_OVERRIDE;
static std::string getDescription() { static std::string getDescription() {
return "Reports test results as plain lines of text"; 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; 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; AssertionResult const& result = _assertionStats.assertionResult;
bool printInfoMessages = true; bool printInfoMessages = true;
@ -58,11 +53,11 @@ namespace Catch {
return true; return true;
} }
virtual void sectionStarting( SectionInfo const& _sectionInfo ) { virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
m_headerPrinted = false; m_headerPrinted = false;
StreamingReporterBase::sectionStarting( _sectionInfo ); StreamingReporterBase::sectionStarting( _sectionInfo );
} }
virtual void sectionEnded( SectionStats const& _sectionStats ) { virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE {
if( _sectionStats.missingAssertions ) { if( _sectionStats.missingAssertions ) {
lazyPrint(); lazyPrint();
Colour colour( Colour::ResultError ); Colour colour( Colour::ResultError );
@ -84,11 +79,11 @@ namespace Catch {
StreamingReporterBase::sectionEnded( _sectionStats ); StreamingReporterBase::sectionEnded( _sectionStats );
} }
virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseEnded( _testCaseStats ); StreamingReporterBase::testCaseEnded( _testCaseStats );
m_headerPrinted = false; m_headerPrinted = false;
} }
virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE {
if( currentGroupInfo.used ) { if( currentGroupInfo.used ) {
printSummaryDivider(); printSummaryDivider();
stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
@ -97,7 +92,7 @@ namespace Catch {
} }
StreamingReporterBase::testGroupEnded( _testGroupStats ); StreamingReporterBase::testGroupEnded( _testGroupStats );
} }
virtual void testRunEnded( TestRunStats const& _testRunStats ) { virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE {
printTotalsDivider( _testRunStats.totals ); printTotalsDivider( _testRunStats.totals );
printTotals( _testRunStats.totals ); printTotals( _testRunStats.totals );
stream << std::endl; stream << std::endl;

View File

@ -23,28 +23,24 @@ namespace Catch {
JunitReporter( ReporterConfig const& _config ) JunitReporter( ReporterConfig const& _config )
: CumulativeReporterBase( _config ), : CumulativeReporterBase( _config ),
xml( _config.stream() ) xml( _config.stream() )
{} {
m_reporterPrefs.shouldRedirectStdOut = true;
}
~JunitReporter(); virtual ~JunitReporter() CATCH_OVERRIDE;
static std::string getDescription() { static std::string getDescription() {
return "Reports test results in an XML format that looks like Ant's junitreport target"; 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 { virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE {
ReporterPreferences prefs;
prefs.shouldRedirectStdOut = true;
return prefs;
}
virtual void testRunStarting( TestRunInfo const& runInfo ) {
CumulativeReporterBase::testRunStarting( runInfo ); CumulativeReporterBase::testRunStarting( runInfo );
xml.startElement( "testsuites" ); xml.startElement( "testsuites" );
} }
virtual void testGroupStarting( GroupInfo const& groupInfo ) { virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
suiteTimer.start(); suiteTimer.start();
stdOutForSuite.str(""); stdOutForSuite.str("");
stdErrForSuite.str(""); stdErrForSuite.str("");
@ -52,25 +48,25 @@ namespace Catch {
CumulativeReporterBase::testGroupStarting( groupInfo ); CumulativeReporterBase::testGroupStarting( groupInfo );
} }
virtual bool assertionEnded( AssertionStats const& assertionStats ) { virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
unexpectedExceptions++; unexpectedExceptions++;
return CumulativeReporterBase::assertionEnded( assertionStats ); return CumulativeReporterBase::assertionEnded( assertionStats );
} }
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
stdOutForSuite << testCaseStats.stdOut; stdOutForSuite << testCaseStats.stdOut;
stdErrForSuite << testCaseStats.stdErr; stdErrForSuite << testCaseStats.stdErr;
CumulativeReporterBase::testCaseEnded( testCaseStats ); CumulativeReporterBase::testCaseEnded( testCaseStats );
} }
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
double suiteTime = suiteTimer.getElapsedSeconds(); double suiteTime = suiteTimer.getElapsedSeconds();
CumulativeReporterBase::testGroupEnded( testGroupStats ); CumulativeReporterBase::testGroupEnded( testGroupStats );
writeGroup( *m_testGroups.back(), suiteTime ); writeGroup( *m_testGroups.back(), suiteTime );
} }
virtual void testRunEndedCumulative() { virtual void testRunEndedCumulative() CATCH_OVERRIDE {
xml.endElement(); xml.endElement();
} }
@ -108,7 +104,7 @@ namespace Catch {
SectionNode const& rootSection = *testCaseNode.children.front(); SectionNode const& rootSection = *testCaseNode.children.front();
std::string className = stats.testInfo.className; std::string className = stats.testInfo.className;
if( className.empty() ) { if( className.empty() ) {
if( rootSection.childSections.empty() ) if( rootSection.childSections.empty() )
className = "global"; className = "global";
@ -122,7 +118,7 @@ namespace Catch {
std::string name = trim( sectionNode.stats.sectionInfo.name ); std::string name = trim( sectionNode.stats.sectionInfo.name );
if( !rootName.empty() ) if( !rootName.empty() )
name = rootName + "/" + name; name = rootName + "/" + name;
if( !sectionNode.assertions.empty() || if( !sectionNode.assertions.empty() ||
!sectionNode.stdOut.empty() || !sectionNode.stdOut.empty() ||
!sectionNode.stdErr.empty() ) { !sectionNode.stdErr.empty() ) {
@ -191,7 +187,7 @@ namespace Catch {
elementName = "internalError"; elementName = "internalError";
break; break;
} }
XmlWriter::ScopedElement e = xml.scopedElement( elementName ); XmlWriter::ScopedElement e = xml.scopedElement( elementName );
xml.writeAttribute( "message", result.getExpandedExpression() ); xml.writeAttribute( "message", result.getExpandedExpression() );
@ -220,7 +216,7 @@ namespace Catch {
unsigned int unexpectedExceptions; unsigned int unexpectedExceptions;
}; };
INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
} // end namespace Catch } // end namespace Catch

View File

@ -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<IStreamingReporter> {
typedef std::vector<Ptr<IStreamingReporter> > Reporters;
Reporters m_reporters;
public:
void add( Ptr<IStreamingReporter> 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<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
Ptr<IStreamingReporter> resultingReporter;
if( existingReporter ) {
MultipleReporters* multi = dynamic_cast<MultipleReporters*>( existingReporter.get() );
if( !multi ) {
multi = new MultipleReporters;
resultingReporter = Ptr<IStreamingReporter>( 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

View File

@ -17,18 +17,22 @@
#include <cstring> #include <cstring>
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic push # pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wpadded"
# pragma clang diagnostic ignored "-Wc++98-compat"
# pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
#endif #endif
namespace Catch { namespace Catch {
struct TeamCityReporter : StreamingReporterBase { struct TeamCityReporter : StreamingReporterBase {
TeamCityReporter( ReporterConfig const& _config ) TeamCityReporter( ReporterConfig const& _config )
: StreamingReporterBase( _config ), : StreamingReporterBase( _config ),
m_headerPrintedForThisSection( false ) m_headerPrintedForThisSection( false )
{} {
m_reporterPrefs.shouldRedirectStdOut = true;
}
static std::string escape( std::string const& str ) { static std::string escape( std::string const& str ) {
std::string escaped = str; std::string escaped = str;
replaceInPlace( escaped, "|", "||" ); replaceInPlace( escaped, "|", "||" );
@ -39,18 +43,13 @@ namespace Catch {
replaceInPlace( escaped, "]", "|]" ); replaceInPlace( escaped, "]", "|]" );
return escaped; return escaped;
} }
virtual ~TeamCityReporter(); virtual ~TeamCityReporter() CATCH_OVERRIDE;
static std::string getDescription() { static std::string getDescription() {
return "Reports test results as TeamCity service messages"; 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='" stream << "##teamcity[testIgnored name='"
<< escape( testInfo.name ) << "'"; << escape( testInfo.name ) << "'";
if( testInfo.isHidden() ) if( testInfo.isHidden() )
@ -59,35 +58,35 @@ namespace Catch {
stream << " message='test skipped because it didn|'t match the test spec'"; stream << " message='test skipped because it didn|'t match the test spec'";
stream << "]\n"; stream << "]\n";
} }
virtual void noMatchingTestCases( std::string const& /* spec */ ) {} virtual void noMatchingTestCases( std::string const& /* spec */ ) CATCH_OVERRIDE {}
virtual void testGroupStarting( GroupInfo const& groupInfo ) { virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testGroupStarting( groupInfo ); StreamingReporterBase::testGroupStarting( groupInfo );
stream << "##teamcity[testSuiteStarted name='" stream << "##teamcity[testSuiteStarted name='"
<< escape( groupInfo.name ) << "']\n"; << escape( groupInfo.name ) << "']\n";
} }
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
StreamingReporterBase::testGroupEnded( testGroupStats ); StreamingReporterBase::testGroupEnded( testGroupStats );
stream << "##teamcity[testSuiteFinished name='" stream << "##teamcity[testSuiteFinished name='"
<< escape( testGroupStats.groupInfo.name ) << "']\n"; << 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; AssertionResult const& result = assertionStats.assertionResult;
if( !result.isOk() ) { if( !result.isOk() ) {
std::ostringstream msg; std::ostringstream msg;
if( !m_headerPrintedForThisSection ) if( !m_headerPrintedForThisSection )
printSectionHeader( msg ); printSectionHeader( msg );
m_headerPrintedForThisSection = true; m_headerPrintedForThisSection = true;
msg << result.getSourceInfo() << "\n"; msg << result.getSourceInfo() << "\n";
switch( result.getResultType() ) { switch( result.getResultType() ) {
case ResultWas::ExpressionFailed: case ResultWas::ExpressionFailed:
msg << "expression failed"; msg << "expression failed";
@ -126,15 +125,15 @@ namespace Catch {
it != itEnd; it != itEnd;
++it ) ++it )
msg << "\n \"" << it->message << "\""; msg << "\n \"" << it->message << "\"";
if( result.hasExpression() ) { if( result.hasExpression() ) {
msg << msg <<
"\n " << result.getExpressionInMacro() << "\n" "\n " << result.getExpressionInMacro() << "\n"
"with expansion:\n" << "with expansion:\n" <<
" " << result.getExpandedExpression() << "\n"; " " << result.getExpandedExpression() << "\n";
} }
stream << "##teamcity[testFailed" stream << "##teamcity[testFailed"
<< " name='" << escape( currentTestCaseInfo->name )<< "'" << " name='" << escape( currentTestCaseInfo->name )<< "'"
<< " message='" << escape( msg.str() ) << "'" << " message='" << escape( msg.str() ) << "'"
@ -142,19 +141,19 @@ namespace Catch {
} }
return true; return true;
} }
virtual void sectionStarting( SectionInfo const& sectionInfo ) { virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
m_headerPrintedForThisSection = false; m_headerPrintedForThisSection = false;
StreamingReporterBase::sectionStarting( sectionInfo ); StreamingReporterBase::sectionStarting( sectionInfo );
} }
virtual void testCaseStarting( TestCaseInfo const& testInfo ) { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseStarting( testInfo ); StreamingReporterBase::testCaseStarting( testInfo );
stream << "##teamcity[testStarted name='" stream << "##teamcity[testStarted name='"
<< escape( testInfo.name ) << "']\n"; << escape( testInfo.name ) << "']\n";
} }
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseEnded( testCaseStats ); StreamingReporterBase::testCaseEnded( testCaseStats );
if( !testCaseStats.stdOut.empty() ) if( !testCaseStats.stdOut.empty() )
stream << "##teamcity[testStdOut name='" stream << "##teamcity[testStdOut name='"
@ -182,9 +181,9 @@ namespace Catch {
printHeaderString( os, it->name ); printHeaderString( os, it->name );
os << getLineOfChars<'-'>() << "\n"; os << getLineOfChars<'-'>() << "\n";
} }
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
if( !lineInfo.empty() ) if( !lineInfo.empty() )
os << lineInfo << "\n"; os << lineInfo << "\n";
os << getLineOfChars<'.'>() << "\n\n"; os << getLineOfChars<'.'>() << "\n\n";
@ -204,19 +203,19 @@ namespace Catch {
} }
private: private:
bool m_headerPrintedForThisSection; bool m_headerPrintedForThisSection;
}; };
#ifdef CATCH_IMPL #ifdef CATCH_IMPL
TeamCityReporter::~TeamCityReporter() {} TeamCityReporter::~TeamCityReporter() {}
#endif #endif
INTERNAL_CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter ) INTERNAL_CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter )
} // end namespace Catch } // end namespace Catch
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop # pragma clang diagnostic pop
#endif #endif
#endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED

View File

@ -21,26 +21,23 @@ namespace Catch {
XmlReporter( ReporterConfig const& _config ) XmlReporter( ReporterConfig const& _config )
: StreamingReporterBase( _config ), : StreamingReporterBase( _config ),
m_sectionDepth( 0 ) m_sectionDepth( 0 )
{} {
m_reporterPrefs.shouldRedirectStdOut = true;
}
virtual ~XmlReporter() CATCH_OVERRIDE;
virtual ~XmlReporter();
static std::string getDescription() { static std::string getDescription() {
return "Reports test results as an XML document"; return "Reports test results as an XML document";
} }
public: // StreamingReporterBase 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 ); StreamingReporterBase::noMatchingTestCases( s );
} }
virtual void testRunStarting( TestRunInfo const& testInfo ) { virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testRunStarting( testInfo ); StreamingReporterBase::testRunStarting( testInfo );
m_xml.setStream( stream ); m_xml.setStream( stream );
m_xml.startElement( "Catch" ); m_xml.startElement( "Catch" );
@ -48,13 +45,13 @@ namespace Catch {
m_xml.writeAttribute( "name", m_config->name() ); m_xml.writeAttribute( "name", m_config->name() );
} }
virtual void testGroupStarting( GroupInfo const& groupInfo ) { virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testGroupStarting( groupInfo ); StreamingReporterBase::testGroupStarting( groupInfo );
m_xml.startElement( "Group" ) m_xml.startElement( "Group" )
.writeAttribute( "name", groupInfo.name ); .writeAttribute( "name", groupInfo.name );
} }
virtual void testCaseStarting( TestCaseInfo const& testInfo ) { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseStarting(testInfo); StreamingReporterBase::testCaseStarting(testInfo);
m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
@ -62,7 +59,7 @@ namespace Catch {
m_testCaseTimer.start(); m_testCaseTimer.start();
} }
virtual void sectionStarting( SectionInfo const& sectionInfo ) { virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
StreamingReporterBase::sectionStarting( sectionInfo ); StreamingReporterBase::sectionStarting( sectionInfo );
if( m_sectionDepth++ > 0 ) { if( m_sectionDepth++ > 0 ) {
m_xml.startElement( "Section" ) 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; const AssertionResult& assertionResult = assertionStats.assertionResult;
// Print any info messages in <Info> tags. // Print any info messages in <Info> tags.
if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
@ -137,14 +134,14 @@ namespace Catch {
default: default:
break; break;
} }
if( assertionResult.hasExpression() ) if( assertionResult.hasExpression() )
m_xml.endElement(); m_xml.endElement();
return true; return true;
} }
virtual void sectionEnded( SectionStats const& sectionStats ) { virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
StreamingReporterBase::sectionEnded( sectionStats ); StreamingReporterBase::sectionEnded( sectionStats );
if( --m_sectionDepth > 0 ) { if( --m_sectionDepth > 0 ) {
XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); 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 ); StreamingReporterBase::testCaseEnded( testCaseStats );
XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
@ -170,7 +167,7 @@ namespace Catch {
m_xml.endElement(); m_xml.endElement();
} }
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
StreamingReporterBase::testGroupEnded( testGroupStats ); StreamingReporterBase::testGroupEnded( testGroupStats );
// TODO: Check testGroupStats.aborting and act accordingly. // TODO: Check testGroupStats.aborting and act accordingly.
m_xml.scopedElement( "OverallResults" ) m_xml.scopedElement( "OverallResults" )
@ -179,8 +176,8 @@ namespace Catch {
.writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
m_xml.endElement(); m_xml.endElement();
} }
virtual void testRunEnded( TestRunStats const& testRunStats ) { virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
StreamingReporterBase::testRunEnded( testRunStats ); StreamingReporterBase::testRunEnded( testRunStats );
m_xml.scopedElement( "OverallResults" ) m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", testRunStats.totals.assertions.passed ) .writeAttribute( "successes", testRunStats.totals.assertions.passed )

View File

@ -22,7 +22,7 @@ set(SOURCES
${SELF_TEST_DIR}/GeneratorTests.cpp ${SELF_TEST_DIR}/GeneratorTests.cpp
${SELF_TEST_DIR}/MessageTests.cpp ${SELF_TEST_DIR}/MessageTests.cpp
${SELF_TEST_DIR}/MiscTests.cpp ${SELF_TEST_DIR}/MiscTests.cpp
${SELF_TEST_DIR}/SectionTrackerTests.cpp ${SELF_TEST_DIR}/PartTrackerTests.cpp
${SELF_TEST_DIR}/TestMain.cpp ${SELF_TEST_DIR}/TestMain.cpp
${SELF_TEST_DIR}/TrickyTests.cpp ${SELF_TEST_DIR}/TrickyTests.cpp
${SELF_TEST_DIR}/VariadicMacrosTests.cpp ${SELF_TEST_DIR}/VariadicMacrosTests.cpp

View File

@ -16,7 +16,7 @@ TEST_CASE
) )
{ {
double d = 1.23; double d = 1.23;
REQUIRE( d == Approx( 1.23 ) ); REQUIRE( d == Approx( 1.23 ) );
REQUIRE( d != Approx( 1.22 ) ); REQUIRE( d != Approx( 1.22 ) );
REQUIRE( d != Approx( 1.24 ) ); REQUIRE( d != Approx( 1.24 ) );
@ -34,7 +34,7 @@ TEST_CASE
) )
{ {
double d = 1.23; double d = 1.23;
REQUIRE( d != Approx( 1.231 ) ); REQUIRE( d != Approx( 1.231 ) );
REQUIRE( d == Approx( 1.231 ).epsilon( 0.1 ) ); REQUIRE( d == Approx( 1.231 ).epsilon( 0.1 ) );
} }
@ -71,7 +71,7 @@ TEST_CASE
const double dZero = 0; const double dZero = 0;
const double dSmall = 0.00001; const double dSmall = 0.00001;
const double dMedium = 1.234; const double dMedium = 1.234;
REQUIRE( 1.0f == Approx( 1 ) ); REQUIRE( 1.0f == Approx( 1 ) );
REQUIRE( 0 == Approx( dZero) ); REQUIRE( 0 == Approx( dZero) );
REQUIRE( 0 == Approx( dSmall ).epsilon( 0.001 ) ); REQUIRE( 0 == Approx( dSmall ).epsilon( 0.001 ) );
@ -87,14 +87,14 @@ TEST_CASE
) )
{ {
double d = 1.23; double d = 1.23;
Approx approx = Approx::custom().epsilon( 0.005 ); Approx approx = Approx::custom().epsilon( 0.005 );
REQUIRE( d == approx( 1.23 ) ); REQUIRE( d == approx( 1.23 ) );
REQUIRE( d == approx( 1.22 ) ); REQUIRE( d == approx( 1.22 ) );
REQUIRE( d == approx( 1.24 ) ); REQUIRE( d == approx( 1.24 ) );
REQUIRE( d != approx( 1.25 ) ); REQUIRE( d != approx( 1.25 ) );
REQUIRE( approx( d ) == 1.23 ); REQUIRE( approx( d ) == 1.23 );
REQUIRE( approx( d ) == 1.22 ); REQUIRE( approx( d ) == 1.22 );
REQUIRE( approx( d ) == 1.24 ); REQUIRE( approx( d ) == 1.24 );

View File

@ -30,13 +30,13 @@ SCENARIO( "Vector resizing affects size and capacity", "[vector][bdd][size][capa
GIVEN( "an empty vector" ) { GIVEN( "an empty vector" ) {
std::vector<int> v; std::vector<int> v;
REQUIRE( v.size() == 0 ); REQUIRE( v.size() == 0 );
WHEN( "it is made larger" ) { WHEN( "it is made larger" ) {
v.resize( 10 ); v.resize( 10 );
THEN( "the size and capacity go up" ) { THEN( "the size and capacity go up" ) {
REQUIRE( v.size() == 10 ); REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 ); REQUIRE( v.capacity() >= 10 );
AND_WHEN( "it is made smaller again" ) { AND_WHEN( "it is made smaller again" ) {
v.resize( 5 ); v.resize( 5 );
THEN( "the size goes down but the capacity stays the same" ) { 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" ) { WHEN( "we reserve more space" ) {
v.reserve( 10 ); v.reserve( 10 );
THEN( "The capacity is increased but the size remains the same" ) { THEN( "The capacity is increased but the size remains the same" ) {
@ -76,19 +76,19 @@ struct Fixture
: d_counter(0) : d_counter(0)
{ {
} }
int counter() int counter()
{ {
return d_counter++; return d_counter++;
} }
int d_counter; int d_counter;
}; };
} }
SCENARIO_METHOD(Fixture, 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]") { "[bdd][fixtures]") {
const int before(counter()); const int before(counter());
GIVEN("No operations precede me") { GIVEN("No operations precede me") {

View File

@ -356,7 +356,7 @@ due to unexpected exception with message:
expected exception expected exception
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Unexpected custom exceptions can be translated Non-std exceptions can be translated
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
ExceptionTests.cpp:<line number> ExceptionTests.cpp:<line number>
............................................................................... ...............................................................................
@ -365,6 +365,16 @@ ExceptionTests.cpp:<line number>: FAILED:
due to unexpected exception with message: due to unexpected exception with message:
custom exception custom exception
-------------------------------------------------------------------------------
Custom std-exceptions can be custom translated
-------------------------------------------------------------------------------
ExceptionTests.cpp:<line number>
...............................................................................
ExceptionTests.cpp:<line number>: FAILED:
due to unexpected exception with message:
custom std exception
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Custom exceptions can be translated when testing for nothrow Custom exceptions can be translated when testing for nothrow
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -397,6 +407,17 @@ ExceptionTests.cpp:<line number>: FAILED:
due to unexpected exception with message: due to unexpected exception with message:
3.14 3.14
-------------------------------------------------------------------------------
Mismatching exception messages failing the test
-------------------------------------------------------------------------------
ExceptionTests.cpp:<line number>
...............................................................................
ExceptionTests.cpp:<line number>: FAILED:
REQUIRE_THROWS_WITH( thisThrows(), "should fail" )
with expansion:
expected exception
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
INFO and WARN do not abort tests INFO and WARN do not abort tests
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -696,6 +717,29 @@ MiscTests.cpp:<line number>: FAILED:
with expansion: with expansion:
"this string contains 'abc' as a substring" equals: "something else" "this string contains 'abc' as a substring" equals: "something else"
-------------------------------------------------------------------------------
Matchers can be composed with both && and || - failing
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>: 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:<line number>
...............................................................................
MiscTests.cpp:<line number>: FAILED:
CHECK_THAT( testStringForMatching() !Contains( "substring" ) )
with expansion:
"this string contains 'abc' as a substring" not contains: "substring"
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Nice descriptive name Nice descriptive name
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -786,6 +830,6 @@ with expansion:
"first" == "second" "first" == "second"
=============================================================================== ===============================================================================
test cases: 155 | 116 passed | 38 failed | 1 failed as expected test cases: 167 | 124 passed | 42 failed | 1 failed as expected
assertions: 765 | 673 passed | 79 failed | 13 failed as expected assertions: 914 | 818 passed | 83 failed | 13 failed as expected

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
<testsuites> <testsuites>
<testsuite name="all tests" errors="12" failures="87" tests="785" hostname="tbd" time="{duration}" timestamp="tbd"> <testsuite name="CatchSelfTest" errors="13" failures="72" tests="916" hostname="tbd" time="{duration}" timestamp="tbd">
<testcase classname="global" name="toString(enum)" time="{duration}"/> <testcase classname="global" name="toString(enum)" time="{duration}"/>
<testcase classname="global" name="toString(enum w/operator&lt;&lt;)" time="{duration}"/> <testcase classname="global" name="toString(enum w/operator&lt;&lt;)" time="{duration}"/>
<testcase classname="global" name="toString(enum class)" time="{duration}"/> <testcase classname="global" name="toString(enum class)" time="{duration}"/>
@ -226,9 +226,15 @@ expected exception
ExceptionTests.cpp:<line number> ExceptionTests.cpp:<line number>
</error> </error>
</testcase> </testcase>
<testcase classname="global" name="Unexpected custom exceptions can be translated" time="{duration}"> <testcase classname="global" name="Non-std exceptions can be translated" time="{duration}">
<error type="TEST_CASE"> <error type="TEST_CASE">
custom exception custom exception
ExceptionTests.cpp:<line number>
</error>
</testcase>
<testcase classname="global" name="Custom std-exceptions can be custom translated" time="{duration}">
<error type="TEST_CASE">
custom std exception
ExceptionTests.cpp:<line number> ExceptionTests.cpp:<line number>
</error> </error>
</testcase> </testcase>
@ -251,6 +257,14 @@ ExceptionTests.cpp:<line number>
</error> </error>
</testcase> </testcase>
<testcase classname="global" name="NotImplemented exception" time="{duration}"/> <testcase classname="global" name="NotImplemented exception" time="{duration}"/>
<testcase classname="Exception messages can be tested for" name="exact match" time="{duration}"/>
<testcase classname="Exception messages can be tested for" name="different case" time="{duration}"/>
<testcase classname="Exception messages can be tested for" name="wildcarded" time="{duration}"/>
<testcase classname="global" name="Mismatching exception messages failing the test" time="{duration}">
<failure message="expected exception" type="REQUIRE_THROWS_WITH">
ExceptionTests.cpp:<line number>
</failure>
</testcase>
<testcase classname="global" name="Generators over two ranges" time="{duration}"/> <testcase classname="global" name="Generators over two ranges" time="{duration}"/>
<testcase classname="global" name="Generator over a range of pairs" time="{duration}"/> <testcase classname="global" name="Generator over a range of pairs" time="{duration}"/>
<testcase classname="global" name="INFO and WARN do not abort tests" time="{duration}"/> <testcase classname="global" name="INFO and WARN do not abort tests" time="{duration}"/>
@ -333,6 +347,11 @@ MessageTests.cpp:<line number>
MiscTests.cpp:<line number> MiscTests.cpp:<line number>
</failure> </failure>
</testcase> </testcase>
<testcase classname="more nested SECTION tests" name="s1/s3" time="{duration}"/>
<testcase classname="more nested SECTION tests" name="s1/s4" time="{duration}"/>
<testcase classname="even more nested SECTION tests" name="c/d (leaf)" time="{duration}"/>
<testcase classname="even more nested SECTION tests" name="c/e (leaf)" time="{duration}"/>
<testcase classname="even more nested SECTION tests" name="f (leaf)" time="{duration}"/>
<testcase classname="looped SECTION tests" name="s1" time="{duration}"> <testcase classname="looped SECTION tests" name="s1" time="{duration}">
<failure message="0 > 1" type="CHECK"> <failure message="0 > 1" type="CHECK">
MiscTests.cpp:<line number> MiscTests.cpp:<line number>
@ -391,6 +410,8 @@ MiscTests.cpp:<line number>
MiscTests.cpp:<line number> MiscTests.cpp:<line number>
</failure> </failure>
</testcase> </testcase>
<testcase classname="xmlentitycheck" name="embedded xml" time="{duration}"/>
<testcase classname="xmlentitycheck" name="encoded chars" time="{duration}"/>
<testcase classname="global" name="send a single char to INFO" time="{duration}"> <testcase classname="global" name="send a single char to INFO" time="{duration}">
<failure message="false" type="REQUIRE"> <failure message="false" type="REQUIRE">
3 3
@ -423,6 +444,20 @@ MiscTests.cpp:<line number>
<testcase classname="global" name="AllOf matcher" time="{duration}"/> <testcase classname="global" name="AllOf matcher" time="{duration}"/>
<testcase classname="global" name="AnyOf matcher" time="{duration}"/> <testcase classname="global" name="AnyOf matcher" time="{duration}"/>
<testcase classname="global" name="Equals" time="{duration}"/> <testcase classname="global" name="Equals" time="{duration}"/>
<testcase classname="global" name="Matchers can be (AllOf) composed with the &amp;&amp; operator" time="{duration}"/>
<testcase classname="global" name="Matchers can be (AnyOf) composed with the || operator" time="{duration}"/>
<testcase classname="global" name="Matchers can be composed with both &amp;&amp; and ||" time="{duration}"/>
<testcase classname="global" name="Matchers can be composed with both &amp;&amp; and || - failing" time="{duration}">
<failure message="&quot;this string contains 'abc' as a substring&quot; ( ( contains: &quot;string&quot; or contains: &quot;different&quot; ) and contains: &quot;random&quot; )" type="CHECK_THAT">
MiscTests.cpp:<line number>
</failure>
</testcase>
<testcase classname="global" name="Matchers can be negated (Not) with the ! operator" time="{duration}"/>
<testcase classname="global" name="Matchers can be negated (Not) with the ! operator - failing" time="{duration}">
<failure message="&quot;this string contains 'abc' as a substring&quot; not contains: &quot;substring&quot;" type="CHECK_THAT">
MiscTests.cpp:<line number>
</failure>
</testcase>
<testcase classname="global" name="Factorials are computed" time="{duration}"/> <testcase classname="global" name="Factorials are computed" time="{duration}"/>
<testcase classname="global" name="Nice descriptive name" time="{duration}"/> <testcase classname="global" name="Nice descriptive name" time="{duration}"/>
<testcase classname="vectors can be sized and resized" name="root" time="{duration}"/> <testcase classname="vectors can be sized and resized" name="root" time="{duration}"/>
@ -455,12 +490,22 @@ MiscTests.cpp:<line number>
<testcase classname="global" name="toString on const wchar_t pointer returns the string contents" time="{duration}"/> <testcase classname="global" name="toString on const wchar_t pointer returns the string contents" time="{duration}"/>
<testcase classname="global" name="toString on wchar_t const pointer returns the string contents" time="{duration}"/> <testcase classname="global" name="toString on wchar_t const pointer returns the string contents" time="{duration}"/>
<testcase classname="global" name="toString on wchar_t returns the string contents" time="{duration}"/> <testcase classname="global" name="toString on wchar_t returns the string contents" time="{duration}"/>
<testcase classname="XmlEncode" name="normal string" time="{duration}"/>
<testcase classname="XmlEncode" name="empty string" time="{duration}"/>
<testcase classname="XmlEncode" name="string with ampersand" time="{duration}"/>
<testcase classname="XmlEncode" name="string with less-than" time="{duration}"/>
<testcase classname="XmlEncode" name="string with greater-than" time="{duration}"/>
<testcase classname="XmlEncode" name="string with quotes" time="{duration}"/>
<testcase classname="XmlEncode" name="string with control char (1)" time="{duration}"/>
<testcase classname="XmlEncode" name="string with control char (x7F)" time="{duration}"/>
<testcase classname="global" name="long long" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="default - no arguments" time="{duration}"/> <testcase classname="Process can be configured on command line" name="default - no arguments" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="test lists/1 test" time="{duration}"/> <testcase classname="Process can be configured on command line" name="test lists/1 test" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="test lists/Specify one test case exclusion using exclude:" time="{duration}"/> <testcase classname="Process can be configured on command line" name="test lists/Specify one test case exclusion using exclude:" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="test lists/Specify one test case exclusion using ~" time="{duration}"/> <testcase classname="Process can be configured on command line" name="test lists/Specify one test case exclusion using ~" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="reporter/-r/console" time="{duration}"/> <testcase classname="Process can be configured on command line" name="reporter/-r/console" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="reporter/-r/xml" time="{duration}"/> <testcase classname="Process can be configured on command line" name="reporter/-r/xml" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="reporter/-r xml and junit" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="reporter/--reporter/junit" time="{duration}"/> <testcase classname="Process can be configured on command line" name="reporter/--reporter/junit" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="debugger/-b" time="{duration}"/> <testcase classname="Process can be configured on command line" name="debugger/-b" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="debugger/--break" time="{duration}"/> <testcase classname="Process can be configured on command line" name="debugger/--break" time="{duration}"/>
@ -502,6 +547,7 @@ hello
</testcase> </testcase>
<testcase classname="global" name="Text can be formatted using the Text class" time="{duration}"/> <testcase classname="global" name="Text can be formatted using the Text class" time="{duration}"/>
<testcase classname="global" name="Long text is truncted" time="{duration}"/> <testcase classname="global" name="Long text is truncted" time="{duration}"/>
<testcase classname="global" name="ManuallyRegistered" time="{duration}"/>
<testcase classname="global" name="Parsing a std::pair" time="{duration}"/> <testcase classname="global" name="Parsing a std::pair" time="{duration}"/>
<testcase classname="global" name="Where there is more to the expression after the RHS" time="{duration}"/> <testcase classname="global" name="Where there is more to the expression after the RHS" time="{duration}"/>
<testcase classname="global" name="Where the LHS is not a simple value" time="{duration}"/> <testcase classname="global" name="Where the LHS is not a simple value" time="{duration}"/>
@ -548,6 +594,23 @@ TrickyTests.cpp:<line number>
<testcase classname="global" name="toString( vectors&lt;has_toString )" time="{duration}"/> <testcase classname="global" name="toString( vectors&lt;has_toString )" time="{duration}"/>
<testcase classname="global" name="toString( vectors&lt;has_maker )" time="{duration}"/> <testcase classname="global" name="toString( vectors&lt;has_maker )" time="{duration}"/>
<testcase classname="global" name="toString( vectors&lt;has_maker_and_toString )" time="{duration}"/> <testcase classname="global" name="toString( vectors&lt;has_maker_and_toString )" time="{duration}"/>
<testcase classname="Tracker" name="root" time="{duration}"/>
<testcase classname="Tracker" name="successfully close one section" time="{duration}"/>
<testcase classname="Tracker" name="fail one section" time="{duration}"/>
<testcase classname="Tracker" name="fail one section/re-enter after failed section" time="{duration}"/>
<testcase classname="Tracker" name="fail one section/re-enter after failed section and find next section" time="{duration}"/>
<testcase classname="Tracker" name="successfully close one section, then find another" time="{duration}"/>
<testcase classname="Tracker" name="successfully close one section, then find another/Re-enter - skips S1 and enters S2" time="{duration}"/>
<testcase classname="Tracker" name="successfully close one section, then find another/Re-enter - skips S1 and enters S2/Successfully close S2" time="{duration}"/>
<testcase classname="Tracker" name="successfully close one section, then find another/Re-enter - skips S1 and enters S2/fail S2" time="{duration}"/>
<testcase classname="Tracker" name="open a nested section" time="{duration}"/>
<testcase classname="Tracker" name="start a generator" time="{duration}"/>
<testcase classname="Tracker" name="start a generator/close outer section" time="{duration}"/>
<testcase classname="Tracker" name="start a generator/close outer section/Re-enter for second generation" time="{duration}"/>
<testcase classname="Tracker" name="start a generator/Start a new inner section" time="{duration}"/>
<testcase classname="Tracker" name="start a generator/Start a new inner section/Re-enter for second generation" time="{duration}"/>
<testcase classname="Tracker" name="start a generator/Fail an inner section" time="{duration}"/>
<testcase classname="Tracker" name="start a generator/Fail an inner section/Re-enter for second generation" time="{duration}"/>
<testcase classname="global" name="std::pair&lt;int,std::string> -> toString" time="{duration}"/> <testcase classname="global" name="std::pair&lt;int,std::string> -> toString" time="{duration}"/>
<testcase classname="global" name="std::pair&lt;int,const std::string> -> toString" time="{duration}"/> <testcase classname="global" name="std::pair&lt;int,const std::string> -> toString" time="{duration}"/>
<testcase classname="global" name="std::vector&lt;std::pair&lt;std::string,int> > -> toString" time="{duration}"/> <testcase classname="global" name="std::vector&lt;std::pair&lt;std::string,int> > -> toString" time="{duration}"/>
@ -607,11 +670,6 @@ TrickyTests.cpp:<line number>
<testcase classname="Scenario: This is a really long scenario name to see how the list command deals with wrapping" name="Given: A section name that is so long that it cannot fit in a single console width/When: The test headers are printed as part of the normal running of the scenario/Then: The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent" time="{duration}"/> <testcase classname="Scenario: This is a really long scenario name to see how the list command deals with wrapping" name="Given: A section name that is so long that it cannot fit in a single console width/When: The test headers are printed as part of the normal running of the scenario/Then: The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent" time="{duration}"/>
<testcase classname="Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me" time="{duration}"/> <testcase classname="Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me" time="{duration}"/>
<testcase classname="Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me/When: We get the count/Then: Subsequently values are higher" time="{duration}"/> <testcase classname="Fixture" name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me/When: We get the count/Then: Subsequently values are higher" time="{duration}"/>
<testcase classname="section tracking" name="root" time="{duration}"/>
<testcase classname="section tracking" name="test case with no sections" time="{duration}"/>
<testcase classname="section tracking" name="test case with one section" time="{duration}"/>
<testcase classname="section tracking" name="test case with two consecutive sections" time="{duration}"/>
<testcase classname="section tracking" name="test case with one section within another" time="{duration}"/>
<system-out> <system-out>
Message from section one Message from section one
Message from section two Message from section two

File diff suppressed because it is too large Load Diff

View File

@ -13,18 +13,18 @@ namespace
class TestClass class TestClass
{ {
std::string s; std::string s;
public: public:
TestClass() TestClass()
: s( "hello" ) : s( "hello" )
{} {}
void succeedingCase() void succeedingCase()
{ {
REQUIRE( s == "hello" ); REQUIRE( s == "hello" );
} }
void failingCase() void failingCase()
{ {
REQUIRE( s == "world" ); REQUIRE( s == "world" );
} }
}; };
@ -38,20 +38,20 @@ METHOD_AS_TEST_CASE( TestClass::failingCase, "A METHOD_AS_TEST_CASE based test r
struct Fixture struct Fixture
{ {
Fixture() : m_a( 1 ) {} Fixture() : m_a( 1 ) {}
int m_a; int m_a;
}; };
TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that succeeds", "[class]" ) 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 // We should be able to write our tests within a different namespace
namespace Inner namespace Inner
{ {
TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that fails", "[.][class][failing]" ) TEST_CASE_METHOD( Fixture, "A TEST_CASE_METHOD based test run that fails", "[.][class][failing]" )
{ {
REQUIRE( m_a == 2 ); REQUIRE( m_a == 2 );
} }
} }

View File

@ -9,8 +9,11 @@
#include "catch.hpp" #include "catch.hpp"
#include "catch_test_spec_parser.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", "" ) { TEST_CASE( "Parse test names and tags", "" ) {

View File

@ -6,7 +6,8 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/ */
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wpadded"
# pragma clang diagnostic ignored "-Wc++98-compat"
#endif #endif
#include "catch.hpp" #include "catch.hpp"
@ -21,7 +22,7 @@ struct TestData {
float_nine_point_one( 9.1f ), float_nine_point_one( 9.1f ),
double_pi( 3.1415926535 ) double_pi( 3.1415926535 )
{} {}
int int_seven; int int_seven;
std::string str_hello; std::string str_hello;
float float_nine_point_one; float float_nine_point_one;
@ -36,7 +37,7 @@ struct TestDef {
TestDef& operator[]( const std::string& ) { TestDef& operator[]( const std::string& ) {
return *this; return *this;
} }
}; };
// The "failing" tests all use the CHECK macro, which continues if the specific test fails. // 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; TestDef td;
td + "hello" + "hello"; td + "hello" + "hello";
TestData data; TestData data;
REQUIRE( data.int_seven == 7 ); REQUIRE( data.int_seven == 7 );
REQUIRE( data.float_nine_point_one == Approx( 9.1f ) ); REQUIRE( data.float_nine_point_one == Approx( 9.1f ) );
REQUIRE( data.double_pi == Approx( 3.1415926535 ) ); REQUIRE( data.double_pi == Approx( 3.1415926535 ) );
REQUIRE( data.str_hello == "hello" ); REQUIRE( data.str_hello == "hello" );
REQUIRE( "hello" == data.str_hello ); REQUIRE( "hello" == data.str_hello );
REQUIRE( data.str_hello.size() == 5 ); REQUIRE( data.str_hello.size() == 5 );
double x = 1.1 + 0.1 + 0.1; 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]" ) TEST_CASE( "Equality checks that should fail", "[.][failing][!mayfail]" )
{ {
TestData data; TestData data;
CHECK( data.int_seven == 6 ); CHECK( data.int_seven == 6 );
CHECK( data.int_seven == 8 ); CHECK( data.int_seven == 8 );
CHECK( data.int_seven == 0 ); 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", "" ) TEST_CASE( "Inequality checks that should succeed", "" )
{ {
TestData data; TestData data;
REQUIRE( data.int_seven != 6 ); REQUIRE( data.int_seven != 6 );
REQUIRE( data.int_seven != 8 ); REQUIRE( data.int_seven != 8 );
REQUIRE( data.float_nine_point_one != Approx( 9.11f ) ); 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]" ) TEST_CASE( "Inequality checks that should fail", "[.][failing]" )
{ {
TestData data; TestData data;
CHECK( data.int_seven != 7 ); CHECK( data.int_seven != 7 );
CHECK( data.float_nine_point_one != Approx( 9.1f ) ); CHECK( data.float_nine_point_one != Approx( 9.1f ) );
CHECK( data.double_pi != Approx( 3.1415926535 ) ); 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", "" ) TEST_CASE( "Ordering comparison checks that should succeed", "" )
{ {
TestData data; TestData data;
REQUIRE( data.int_seven < 8 ); REQUIRE( data.int_seven < 8 );
REQUIRE( data.int_seven > 6 ); REQUIRE( data.int_seven > 6 );
REQUIRE( data.int_seven > 0 ); 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 >= 6 );
REQUIRE( data.int_seven <= 7 ); REQUIRE( data.int_seven <= 7 );
REQUIRE( data.int_seven <= 8 ); REQUIRE( data.int_seven <= 8 );
REQUIRE( data.float_nine_point_one > 9 ); REQUIRE( data.float_nine_point_one > 9 );
REQUIRE( data.float_nine_point_one < 10 ); REQUIRE( data.float_nine_point_one < 10 );
REQUIRE( data.float_nine_point_one < 9.2 ); REQUIRE( data.float_nine_point_one < 9.2 );
REQUIRE( data.str_hello <= "hello" ); REQUIRE( data.str_hello <= "hello" );
REQUIRE( data.str_hello >= "hello" ); REQUIRE( data.str_hello >= "hello" );
REQUIRE( data.str_hello < "hellp" ); REQUIRE( data.str_hello < "hellp" );
REQUIRE( data.str_hello < "zebra" ); REQUIRE( data.str_hello < "zebra" );
REQUIRE( data.str_hello > "hellm" ); 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]" ) TEST_CASE( "Ordering comparison checks that should fail", "[.][failing]" )
{ {
TestData data; TestData data;
CHECK( data.int_seven > 7 ); CHECK( data.int_seven > 7 );
CHECK( data.int_seven < 7 ); CHECK( data.int_seven < 7 );
CHECK( data.int_seven > 8 ); 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 >= 8 );
CHECK( data.int_seven <= 6 ); CHECK( data.int_seven <= 6 );
CHECK( data.float_nine_point_one < 9 ); CHECK( data.float_nine_point_one < 9 );
CHECK( data.float_nine_point_one > 10 ); CHECK( data.float_nine_point_one > 10 );
CHECK( data.float_nine_point_one > 9.2 ); CHECK( data.float_nine_point_one > 9.2 );
CHECK( data.str_hello > "hello" ); CHECK( data.str_hello > "hello" );
CHECK( data.str_hello < "hello" ); CHECK( data.str_hello < "hello" );
CHECK( data.str_hello > "hellp" ); 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; unsigned long ul = 4;
char c = 5; char c = 5;
unsigned char uc = 6; unsigned char uc = 6;
REQUIRE( i == 1 ); REQUIRE( i == 1 );
REQUIRE( ui == 2 ); REQUIRE( ui == 2 );
REQUIRE( l == 3 ); REQUIRE( l == 3 );
@ -214,7 +215,7 @@ TEST_CASE( "comparisons between int variables", "" )
unsigned short unsigned_short_var = 1; unsigned short unsigned_short_var = 1;
unsigned int unsigned_int_var = 1; unsigned int unsigned_int_var = 1;
unsigned long unsigned_long_var = 1L; unsigned long unsigned_long_var = 1L;
REQUIRE( long_var == unsigned_char_var ); REQUIRE( long_var == unsigned_char_var );
REQUIRE( long_var == unsigned_short_var ); REQUIRE( long_var == unsigned_short_var );
REQUIRE( long_var == unsigned_int_var ); REQUIRE( long_var == unsigned_int_var );
@ -251,7 +252,7 @@ template<typename T>
struct Ex struct Ex
{ {
Ex( T ){} Ex( T ){}
bool operator == ( const T& ) const { return true; } bool operator == ( const T& ) const { return true; }
T operator * ( const T& ) const { return T(); } 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 #pragma GCC diagnostic pop
#endif #endif
inline const char* returnsConstNull(){ return NULL; } inline const char* returnsConstNull(){ return CATCH_NULL; }
inline char* returnsNull(){ return NULL; } inline char* returnsNull(){ return CATCH_NULL; }
TEST_CASE( "Pointers can be compared to null", "" ) TEST_CASE( "Pointers can be compared to null", "" )
{ {
TestData* p = NULL; TestData* p = CATCH_NULL;
TestData* pNULL = NULL; TestData* pNULL = CATCH_NULL;
REQUIRE( p == NULL ); REQUIRE( p == CATCH_NULL );
REQUIRE( p == pNULL ); REQUIRE( p == pNULL );
TestData data; TestData data;
p = &data; p = &data;
REQUIRE( p != NULL ); REQUIRE( p != CATCH_NULL );
const TestData* cp = p; const TestData* cp = p;
REQUIRE( cp != NULL ); REQUIRE( cp != CATCH_NULL );
const TestData* const cpc = p; const TestData* const cpc = p;
REQUIRE( cpc != NULL ); REQUIRE( cpc != CATCH_NULL );
REQUIRE( returnsNull() == NULL ); REQUIRE( returnsNull() == CATCH_NULL );
REQUIRE( returnsConstNull() == NULL ); REQUIRE( returnsConstNull() == CATCH_NULL );
REQUIRE( NULL != p ); REQUIRE( CATCH_NULL != p );
} }
// Not (!) tests // Not (!) tests
@ -303,7 +304,7 @@ TEST_CASE( "Pointers can be compared to null", "" )
TEST_CASE( "'Not' checks that should succeed", "" ) TEST_CASE( "'Not' checks that should succeed", "" )
{ {
bool falseValue = false; bool falseValue = false;
REQUIRE( false == false ); REQUIRE( false == false );
REQUIRE( true == true ); REQUIRE( true == true );
REQUIRE( !false ); REQUIRE( !false );
@ -319,15 +320,15 @@ TEST_CASE( "'Not' checks that should succeed", "" )
TEST_CASE( "'Not' checks that should fail", "[.][failing]" ) TEST_CASE( "'Not' checks that should fail", "[.][failing]" )
{ {
bool trueValue = true; bool trueValue = true;
CHECK( false != false ); CHECK( false != false );
CHECK( true != true ); CHECK( true != true );
CHECK( !true ); CHECK( !true );
CHECK_FALSE( true ); CHECK_FALSE( true );
CHECK( !trueValue ); CHECK( !trueValue );
CHECK_FALSE( trueValue ); CHECK_FALSE( trueValue );
CHECK( !(1 == 1) ); CHECK( !(1 == 1) );
CHECK_FALSE( 1 == 1 ); CHECK_FALSE( 1 == 1 );
} }

View File

@ -96,6 +96,23 @@ public:
CustomException( const std::string& msg ) CustomException( const std::string& msg )
: m_msg( 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 std::string getMessage() const
{ {
@ -106,22 +123,34 @@ private:
std::string m_msg; std::string m_msg;
}; };
CATCH_TRANSLATE_EXCEPTION( CustomException& ex ) CATCH_TRANSLATE_EXCEPTION( CustomException& ex )
{ {
return ex.getMessage(); return ex.getMessage();
} }
CATCH_TRANSLATE_EXCEPTION( CustomStdException& ex )
{
return ex.getMessage();
}
CATCH_TRANSLATE_EXCEPTION( double& ex ) CATCH_TRANSLATE_EXCEPTION( double& ex )
{ {
return Catch::toString( 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() ) if( Catch::alwaysTrue() )
throw CustomException( "custom exception" ); 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() { inline void throwCustom() {
if( Catch::alwaysTrue() ) if( Catch::alwaysTrue() )
throw CustomException( "custom exception - not std" ); throw CustomException( "custom exception - not std" );
@ -152,3 +181,23 @@ TEST_CASE( "NotImplemented exception", "" )
{ {
REQUIRE_THROWS( thisFunctionNotImplemented( 7 ) ); 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" );
}

View File

@ -19,10 +19,10 @@ inline int multiply( int a, int b )
CATCH_TEST_CASE( "Generators over two ranges", "[generators]" ) CATCH_TEST_CASE( "Generators over two ranges", "[generators]" )
{ {
using namespace Catch::Generators; using namespace Catch::Generators;
int i = CATCH_GENERATE( between( 1, 5 ).then( values( 15, 20, 21 ).then( 36 ) ) ); int i = CATCH_GENERATE( between( 1, 5 ).then( values( 15, 20, 21 ).then( 36 ) ) );
int j = CATCH_GENERATE( between( 100, 107 ) ); int j = CATCH_GENERATE( between( 100, 107 ) );
CATCH_REQUIRE( multiply( i, 2 ) == i*2 ); CATCH_REQUIRE( multiply( i, 2 ) == i*2 );
CATCH_REQUIRE( multiply( j, 2 ) == j*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]" ) CATCH_TEST_CASE( "Generator over a range of pairs", "[generators]" )
{ {
using namespace Catch::Generators; using namespace Catch::Generators;
IntPair p[] = { { 0, 1 }, { 2, 3 } }; IntPair p[] = { { 0, 1 }, { 2, 3 } };
IntPair* i = CATCH_GENERATE( between( p, &p[1] ) ); IntPair* i = CATCH_GENERATE( between( p, &p[1] ) );
CATCH_REQUIRE( i->first == i->second-1 ); CATCH_REQUIRE( i->first == i->second-1 );
} }

View File

@ -38,7 +38,7 @@ TEST_CASE( "INFO gets logged on failure, even if captured before successful asse
CHECK( a == 2 ); CHECK( a == 2 );
INFO( "this message should be logged" ); INFO( "this message should be logged" );
CHECK( a == 1 ); CHECK( a == 1 );
INFO( "and this, but later" ); 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; std::cout << "Message from section one" << std::endl;
} }
SECTION( "two", "" ) SECTION( "two", "" )
{ {
std::cout << "Message from section two" << std::endl; std::cout << "Message from section two" << std::endl;

View File

@ -8,17 +8,20 @@
#include "catch.hpp" #include "catch.hpp"
#include <iostream>
#ifdef __clang__ #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 #endif
#include "../include/internal/catch_xmlwriter.hpp"
#include <iostream>
TEST_CASE( "random SECTION tests", "[.][sections][failing]" ) TEST_CASE( "random SECTION tests", "[.][sections][failing]" )
{ {
int a = 1; int a = 1;
int b = 2; int b = 2;
SECTION( "s1", "doesn't equal" ) SECTION( "s1", "doesn't equal" )
{ {
REQUIRE( a != b ); REQUIRE( a != b );
@ -35,7 +38,7 @@ TEST_CASE( "nested SECTION tests", "[.][sections][failing]" )
{ {
int a = 1; int a = 1;
int b = 2; int b = 2;
SECTION( "s1", "doesn't equal" ) SECTION( "s1", "doesn't equal" )
{ {
REQUIRE( a != b ); REQUIRE( a != b );
@ -52,7 +55,7 @@ TEST_CASE( "more nested SECTION tests", "[sections][failing][.]" )
{ {
int a = 1; int a = 1;
int b = 2; int b = 2;
SECTION( "s1", "doesn't equal" ) SECTION( "s1", "doesn't equal" )
{ {
SECTION( "s2", "equal" ) SECTION( "s2", "equal" )
@ -77,29 +80,32 @@ TEST_CASE( "even more nested SECTION tests", "[sections]" )
{ {
SECTION( "d (leaf)", "" ) SECTION( "d (leaf)", "" )
{ {
SUCCEED(""); // avoid failing due to no tests
} }
SECTION( "e (leaf)", "" ) SECTION( "e (leaf)", "" )
{ {
SUCCEED(""); // avoid failing due to no tests
} }
} }
SECTION( "f (leaf)", "" ) SECTION( "f (leaf)", "" )
{ {
SUCCEED(""); // avoid failing due to no tests
} }
} }
TEST_CASE( "looped SECTION tests", "[.][failing][sections]" ) TEST_CASE( "looped SECTION tests", "[.][failing][sections]" )
{ {
int a = 1; int a = 1;
for( int b = 0; b < 10; ++b ) for( int b = 0; b < 10; ++b )
{ {
std::ostringstream oss; std::ostringstream oss;
oss << "b is currently: " << b; oss << "b is currently: " << b;
SECTION( "s1", oss.str() ) 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]" ) TEST_CASE( "looped tests", "[.][failing]" )
{ {
static const int fib[] = { 1, 1, 2, 3, 5, 8, 13, 21 }; static const int fib[] = { 1, 1, 2, 3, 5, 8, 13, 21 };
for( size_t i=0; i < sizeof(fib)/sizeof(int); ++i ) for( size_t i=0; i < sizeof(fib)/sizeof(int); ++i )
{ {
INFO( "Testing if fib[" << i << "] (" << fib[i] << ") is even" ); 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", "[.]" ) TEST_CASE( "Sends stuff to stdout and stderr", "[.]" )
{ {
std::cout << "A string sent directly to stdout" << std::endl; std::cout << "A string sent directly to stdout" << std::endl;
std::cerr << "A string sent directly to stderr" << std::endl; std::cerr << "A string sent directly to stderr" << std::endl;
} }
inline const char* makeString( bool makeNull ) inline const char* makeString( bool makeNull )
{ {
return makeNull ? NULL : "valid string"; return makeNull ? CATCH_NULL : "valid string";
} }
TEST_CASE( "null strings", "" ) TEST_CASE( "null strings", "" )
{ {
REQUIRE( makeString( false ) != static_cast<char*>(NULL)); REQUIRE( makeString( false ) != static_cast<char*>(CATCH_NULL));
REQUIRE( makeString( true ) == static_cast<char*>(NULL)); REQUIRE( makeString( true ) == static_cast<char*>(CATCH_NULL));
} }
@ -156,7 +162,7 @@ inline bool testCheckedElse( bool flag )
{ {
CHECKED_ELSE( flag ) CHECKED_ELSE( flag )
return false; return false;
return true; return true;
} }
@ -174,24 +180,24 @@ TEST_CASE( "xmlentitycheck", "" )
{ {
SECTION( "embedded xml", "<test>it should be possible to embed xml characters, such as <, \" or &, or even whole <xml>documents</xml> within an attribute</test>" ) SECTION( "embedded xml", "<test>it should be possible to embed xml characters, such as <, \" or &, or even whole <xml>documents</xml> within an attribute</test>" )
{ {
// No test SUCCEED(""); // We need this here to stop it failing due to no tests
} }
SECTION( "encoded chars", "these should all be encoded: &&&\"\"\"<<<&\"<<&\"" ) 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][.]" ) TEST_CASE( "send a single char to INFO", "[failing][.]" )
{ {
INFO(3); INFO(3);
REQUIRE(false); REQUIRE(false);
} }
TEST_CASE( "atomic if", "[failing][0]") TEST_CASE( "atomic if", "[failing][0]")
{ {
size_t x = 0; size_t x = 0;
if( x ) if( x )
REQUIRE(x > 0); REQUIRE(x > 0);
else else
@ -202,10 +208,16 @@ inline const char* testStringForMatching()
{ {
return "this string contains 'abc' as a substring"; 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]" ) TEST_CASE("String matchers", "[matchers]" )
{ {
REQUIRE_THAT( testStringForMatching(), Contains( "string" ) ); REQUIRE_THAT( testStringForMatching(), Contains( "string" ) );
CHECK_THAT( testStringForMatching(), Contains( "abc" ) ); CHECK_THAT( testStringForMatching(), Contains( "abc" ) );
CHECK_THAT( testStringForMatching(), StartsWith( "this" ) ); CHECK_THAT( testStringForMatching(), StartsWith( "this" ) );
@ -233,7 +245,7 @@ TEST_CASE("Equals string matcher", "[.][failing][matchers]")
} }
TEST_CASE("Equals string matcher, with NULL", "[matchers]") TEST_CASE("Equals string matcher, with NULL", "[matchers]")
{ {
REQUIRE_THAT("", Equals(NULL)); REQUIRE_THAT("", Equals(CATCH_NULL));
} }
TEST_CASE("AllOf matcher", "[matchers]") TEST_CASE("AllOf matcher", "[matchers]")
{ {
@ -250,6 +262,42 @@ TEST_CASE("Equals", "[matchers]")
CHECK_THAT( testStringForMatching(), Equals( "this string contains 'abc' as a substring" ) ); 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 ) inline unsigned int Factorial( unsigned int number )
{ {
// return number <= 1 ? number : Factorial(number-1)*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]" ) { TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
std::vector<int> v( 5 ); std::vector<int> v( 5 );
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 ); REQUIRE( v.capacity() >= 5 );
SECTION( "resizing bigger changes size and capacity", "" ) { SECTION( "resizing bigger changes size and capacity", "" ) {
v.resize( 10 ); v.resize( 10 );
REQUIRE( v.size() == 10 ); REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 ); REQUIRE( v.capacity() >= 10 );
} }
SECTION( "resizing smaller changes size but not capacity", "" ) { SECTION( "resizing smaller changes size but not capacity", "" ) {
v.resize( 0 ); v.resize( 0 );
REQUIRE( v.size() == 0 ); REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 ); REQUIRE( v.capacity() >= 5 );
SECTION( "We can use the 'swap trick' to reset the capacity", "" ) { SECTION( "We can use the 'swap trick' to reset the capacity", "" ) {
std::vector<int> empty; std::vector<int> empty;
empty.swap( v ); empty.swap( v );
REQUIRE( v.capacity() == 0 ); REQUIRE( v.capacity() == 0 );
} }
} }
SECTION( "reserving bigger changes capacity but not size", "" ) { SECTION( "reserving bigger changes capacity but not size", "" ) {
v.reserve( 10 ); v.reserve( 10 );
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 ); REQUIRE( v.capacity() >= 10 );
} }
SECTION( "reserving smaller does not change size or capacity", "" ) { SECTION( "reserving smaller does not change size or capacity", "" ) {
v.reserve( 0 ); v.reserve( 0 );
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 ); REQUIRE( v.capacity() >= 5 );
} }
@ -381,6 +429,50 @@ TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
CHECK( result == "\"wide load\"" ); 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 &amp; jones" );
}
SECTION( "string with less-than" ) {
REQUIRE( encode( "smith < jones" ) == "smith &lt; jones" );
}
SECTION( "string with greater-than" ) {
REQUIRE( encode( "smith > jones" ) == "smith > jones" );
REQUIRE( encode( "smith ]]> jones" ) == "smith ]]&gt; 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 &quot;quote&quot; me on that" );
}
SECTION( "string with control char (1)" ) {
REQUIRE( encode( "[\x01]" ) == "[&#x1]" );
}
SECTION( "string with control char (x7F)" ) {
REQUIRE( encode( "[\x7F]" ) == "[&#x7F]" );
}
}
#ifdef CATCH_CONFIG_CPP11_LONG_LONG
TEST_CASE( "long long" ) {
long long l = std::numeric_limits<long long>::max();
REQUIRE( l == std::numeric_limits<long long>::max() );
}
#endif
//TEST_CASE( "Divide by Zero signal handler", "[.][sig]" ) { //TEST_CASE( "Divide by Zero signal handler", "[.][sig]" ) {
// int i = 0; // int i = 0;
// int x = 10/i; // This should cause the signal to fire // int x = 10/i; // This should cause the signal to fire

View File

@ -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
}
}

View File

@ -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() );
}
}

View File

@ -1 +1,2 @@
#include "catch_suppress_warnings.h"
#include "catch_interfaces_exception.h" #include "catch_interfaces_exception.h"

View File

@ -1,2 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // 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" #include "catch_interfaces_registry_hub.h"

View File

@ -1,2 +1,3 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // 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" #include "catch_stream.h"

View File

@ -1,2 +1,4 @@
// This file is only here to verify (to the extent possible) the self sufficiency of the header // 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_xmlwriter.hpp"
#include "catch_reenable_warnings.h"

View File

@ -11,6 +11,8 @@
TEST_CASE( "Tag alias can be registered against tag patterns", "" ) { TEST_CASE( "Tag alias can be registered against tag patterns", "" ) {
using namespace Catch::Matchers;
Catch::TagAliasRegistry registry; Catch::TagAliasRegistry registry;
registry.add( "[@zzz]", "[one][two]", Catch::SourceLineInfo( "file", 2 ) ); registry.add( "[@zzz]", "[one][two]", Catch::SourceLineInfo( "file", 2 ) );

View File

@ -8,7 +8,7 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include "catch.hpp" #include "catch.hpp"
#include "reporters/catch_reporter_teamcity.hpp" #include "../include/reporters/catch_reporter_teamcity.hpp"
// Some example tag aliases // Some example tag aliases
CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" ) CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
@ -16,8 +16,9 @@ CATCH_REGISTER_TAG_ALIAS( "[@tricky]", "[tricky]~[.]" )
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wpadded"
#pragma clang diagnostic ignored "-Wweak-vtables" # pragma clang diagnostic ignored "-Wweak-vtables"
# pragma clang diagnostic ignored "-Wc++98-compat"
#endif #endif
@ -39,22 +40,24 @@ std::string parseIntoConfigAndReturnError( const char * (&argv)[size], Catch::Co
return ""; 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]" ) { TEST_CASE( "Process can be configured on command line", "[config][command-line]" ) {
using namespace Catch::Matchers;
Catch::ConfigData config; Catch::ConfigData config;
SECTION( "default - no arguments", "" ) { SECTION( "default - no arguments", "" ) {
const char* argv[] = { "test" }; const char* argv[] = { "test" };
CHECK_NOTHROW( parseIntoConfig( argv, config ) ); CHECK_NOTHROW( parseIntoConfig( argv, config ) );
CHECK( config.shouldDebugBreak == false ); CHECK( config.shouldDebugBreak == false );
CHECK( config.abortAfter == -1 ); CHECK( config.abortAfter == -1 );
CHECK( config.noThrow == false ); CHECK( config.noThrow == false );
CHECK( config.reporterName.empty() ); CHECK( config.reporterNames.empty() );
} }
SECTION( "test lists", "" ) { SECTION( "test lists", "" ) {
SECTION( "1 test", "Specify one test case using" ) { SECTION( "1 test", "Specify one test case using" ) {
const char* argv[] = { "test", "test1" }; const char* argv[] = { "test", "test1" };
@ -83,43 +86,51 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
} }
} }
SECTION( "reporter", "" ) { SECTION( "reporter", "" ) {
SECTION( "-r/console", "" ) { SECTION( "-r/console", "" ) {
const char* argv[] = { "test", "-r", "console" }; const char* argv[] = { "test", "-r", "console" };
CHECK_NOTHROW( parseIntoConfig( argv, config ) ); CHECK_NOTHROW( parseIntoConfig( argv, config ) );
REQUIRE( config.reporterName == "console" ); REQUIRE( config.reporterNames[0] == "console" );
} }
SECTION( "-r/xml", "" ) { SECTION( "-r/xml", "" ) {
const char* argv[] = { "test", "-r", "xml" }; const char* argv[] = { "test", "-r", "xml" };
CHECK_NOTHROW( parseIntoConfig( argv, config ) ); 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", "" ) { SECTION( "--reporter/junit", "" ) {
const char* argv[] = { "test", "--reporter", "junit" }; const char* argv[] = { "test", "--reporter", "junit" };
CHECK_NOTHROW( parseIntoConfig( argv, config ) ); CHECK_NOTHROW( parseIntoConfig( argv, config ) );
REQUIRE( config.reporterName == "junit" ); REQUIRE( config.reporterNames[0] == "junit" );
} }
} }
SECTION( "debugger", "" ) { SECTION( "debugger", "" ) {
SECTION( "-b", "" ) { SECTION( "-b", "" ) {
const char* argv[] = { "test", "-b" }; const char* argv[] = { "test", "-b" };
CHECK_NOTHROW( parseIntoConfig( argv, config ) ); CHECK_NOTHROW( parseIntoConfig( argv, config ) );
REQUIRE( config.shouldDebugBreak == true ); REQUIRE( config.shouldDebugBreak == true );
} }
SECTION( "--break", "" ) { SECTION( "--break", "" ) {
const char* argv[] = { "test", "--break" }; const char* argv[] = { "test", "--break" };
CHECK_NOTHROW( parseIntoConfig( argv, config ) ); CHECK_NOTHROW( parseIntoConfig( argv, config ) );
REQUIRE( config.shouldDebugBreak ); REQUIRE( config.shouldDebugBreak );
} }
} }
SECTION( "abort", "" ) { SECTION( "abort", "" ) {
SECTION( "-a aborts after first failure", "" ) { SECTION( "-a aborts after first failure", "" ) {
const char* argv[] = { "test", "-a" }; 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" ) ); REQUIRE_THAT( parseIntoConfigAndReturnError( argv, config ), Contains( "-x" ) );
} }
} }
SECTION( "nothrow", "" ) { SECTION( "nothrow", "" ) {
SECTION( "-e", "" ) { SECTION( "-e", "" ) {
const char* argv[] = { "test", "-e" }; const char* argv[] = { "test", "-e" };
@ -208,7 +219,7 @@ TEST_CASE( "Long strings can be wrapped", "[wrap]" ) {
SECTION( "plain string", "" ) { SECTION( "plain string", "" ) {
// guide: 123456789012345678 // guide: 123456789012345678
std::string testString = "one two three four"; std::string testString = "one two three four";
SECTION( "No wrapping", "" ) { SECTION( "No wrapping", "" ) {
CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString ); CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString );
CHECK( Text( testString, TextAttributes().setWidth( 18 ) ).toString() == testString ); CHECK( Text( testString, TextAttributes().setWidth( 18 ) ).toString() == testString );
@ -252,14 +263,14 @@ TEST_CASE( "Long strings can be wrapped", "[wrap]" ) {
.setInitialIndent( 1 ) ); .setInitialIndent( 1 ) );
CHECK( text.toString() == " one two\n three\n four" ); CHECK( text.toString() == " one two\n three\n four" );
} }
} }
SECTION( "With newlines", "" ) { SECTION( "With newlines", "" ) {
// guide: 1234567890123456789 // guide: 1234567890123456789
std::string testString = "one two\nthree four"; std::string testString = "one two\nthree four";
SECTION( "No wrapping" , "" ) { SECTION( "No wrapping" , "" ) {
CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString ); CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString );
CHECK( Text( testString, TextAttributes().setWidth( 18 ) ).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" ); CHECK( Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one\ntwo\nthree\nfour" );
} }
} }
SECTION( "With tabs", "" ) { SECTION( "With tabs", "" ) {
// guide: 1234567890123456789 // guide: 1234567890123456789
std::string testString = "one two \tthree four five six"; std::string testString = "one two \tthree four five six";
CHECK( Text( testString, TextAttributes().setWidth( 15 ) ).toString() CHECK( Text( testString, TextAttributes().setWidth( 15 ) ).toString()
== "one two three\n four\n five\n six" ); == "one two three\n four\n five\n six" );
} }
} }
using namespace Catch; using namespace Catch;
@ -315,7 +326,7 @@ public:
ColourString( std::string const& _string, std::vector<ColourIndex> const& _colours ) ColourString( std::string const& _string, std::vector<ColourIndex> const& _colours )
: string( _string ), colours( _colours ) : string( _string ), colours( _colours )
{} {}
ColourString& addColour( Colour::Code colour, int _index ) { ColourString& addColour( Colour::Code colour, int _index ) {
colours.push_back( ColourIndex( colour, colours.push_back( ColourIndex( colour,
resolveRelativeIndex( _index ), resolveRelativeIndex( _index ),
@ -328,7 +339,7 @@ public:
resolveLastRelativeIndex( _toIndex ) ) ); resolveLastRelativeIndex( _toIndex ) ) );
return *this; return *this;
} }
void writeToStream( std::ostream& _stream ) const { void writeToStream( std::ostream& _stream ) const {
std::size_t last = 0; std::size_t last = 0;
for( std::size_t i = 0; i < colours.size(); ++i ) { for( std::size_t i = 0; i < colours.size(); ++i ) {
@ -342,7 +353,7 @@ public:
last = index.toIndex; last = index.toIndex;
} }
if( last < string.size() ) if( last < string.size() )
_stream << string.substr( last ); _stream << string.substr( last );
} }
friend std::ostream& operator << ( std::ostream& _stream, ColourString const& _colourString ) { friend std::ostream& operator << ( std::ostream& _stream, ColourString const& _colourString ) {
_colourString.writeToStream( _stream ); _colourString.writeToStream( _stream );
@ -399,7 +410,7 @@ TEST_CASE( "replaceInPlace", "" ) {
// !TBD: This will be folded into Text class // !TBD: This will be folded into Text class
TEST_CASE( "Strings can be rendered with colour", "[.colour]" ) { TEST_CASE( "Strings can be rendered with colour", "[.colour]" ) {
{ {
ColourString cs( "hello" ); ColourString cs( "hello" );
cs .addColour( Colour::Red, 0 ) cs .addColour( Colour::Red, 0 )
@ -411,19 +422,19 @@ TEST_CASE( "Strings can be rendered with colour", "[.colour]" ) {
{ {
ColourString cs( "hello" ); ColourString cs( "hello" );
cs .addColour( Colour::Blue, 1, -2 ); cs .addColour( Colour::Blue, 1, -2 );
Catch::cout() << cs << std::endl; Catch::cout() << cs << std::endl;
} }
} }
TEST_CASE( "Text can be formatted using the Text class", "" ) { TEST_CASE( "Text can be formatted using the Text class", "" ) {
CHECK( Text( "hi there" ).toString() == "hi there" ); CHECK( Text( "hi there" ).toString() == "hi there" );
TextAttributes narrow; TextAttributes narrow;
narrow.setWidth( 6 ); narrow.setWidth( 6 );
CHECK( Text( "hi there", narrow ).toString() == "hi\nthere" ); CHECK( Text( "hi there", narrow ).toString() == "hi\nthere" );
} }
@ -436,5 +447,15 @@ TEST_CASE( "Long text is truncted", "[Text][Truncated]" ) {
oss << longLine << longLine << "\n"; oss << longLine << longLine << "\n";
Text t( oss.str() ); Text t( oss.str() );
CHECK_THAT( t.toString(), EndsWith( "... message truncated due to excessive size" ) ); 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;

View File

@ -42,12 +42,14 @@ TEST_CASE( "tuple<tuple<int>,tuple<>,float>", "[toString][tuple]" )
CHECK( "{ { 42 }, { }, 1.2f }" == Catch::toString(value) ); CHECK( "{ { 42 }, { }, 1.2f }" == Catch::toString(value) );
} }
#ifdef CATCH_CONFIG_CPP11_NULLPTR
TEST_CASE( "tuple<nullptr,int,const char *>", "[toString][tuple]" ) TEST_CASE( "tuple<nullptr,int,const char *>", "[toString][tuple]" )
{ {
typedef std::tuple<std::nullptr_t,int,const char *> type; typedef std::tuple<std::nullptr_t,int,const char *> type;
type value { nullptr, 42, "Catch me" }; type value { nullptr, 42, "Catch me" };
CHECK( "{ nullptr, 42, \"Catch me\" }" == Catch::toString(value) ); CHECK( "{ nullptr, 42, \"Catch me\" }" == Catch::toString(value) );
} }
#endif
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop

View File

@ -25,7 +25,7 @@ namespace Catch
std::ostringstream oss; std::ostringstream oss;
oss << "std::pair( " << value.first << ", " << value.second << " )"; oss << "std::pair( " << value.first << ", " << value.second << " )";
return oss.str(); return oss.str();
} }
} }
@ -38,7 +38,7 @@ TEST_CASE
{ {
std::pair<int, int> aNicePair( 1, 2 ); std::pair<int, int> aNicePair( 1, 2 );
REQUIRE( (std::pair<int, int>( 1, 2 )) == aNicePair ); REQUIRE( (std::pair<int, int>( 1, 2 )) == aNicePair );
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -62,7 +62,7 @@ TEST_CASE
/* /*
int a = 1; int a = 1;
int b = 2; int b = 2;
// This only captures part of the expression, but issues a warning about the rest // This only captures part of the expression, but issues a warning about the rest
REQUIRE( a+1 == b-1 ); REQUIRE( a+1 == b-1 );
*/ */
@ -85,38 +85,38 @@ TEST_CASE
"[Tricky][failing][.]" "[Tricky][failing][.]"
) )
{ {
Opaque o1, o2; Opaque o1, o2;
o1.val = 7; o1.val = 7;
o2.val = 8; o2.val = 8;
CHECK( &o1 == &o2 ); CHECK( &o1 == &o2 );
CHECK( o1 == o2 ); CHECK( o1 == o2 );
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
TEST_CASE TEST_CASE
( (
"string literals of different sizes can be compared", "string literals of different sizes can be compared",
"[Tricky][failing][.]" "[Tricky][failing][.]"
) )
{ {
REQUIRE( std::string( "first" ) == "second" ); REQUIRE( std::string( "first" ) == "second" );
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
TEST_CASE TEST_CASE
( (
"An expression with side-effects should only be evaluated once", "An expression with side-effects should only be evaluated once",
"[Tricky]" "[Tricky]"
) )
{ {
int i = 7; int i = 7;
REQUIRE( i++ == 7 ); REQUIRE( i++ == 7 );
REQUIRE( i++ == 8 ); REQUIRE( i++ == 8 );
} }
namespace A { namespace A {
@ -167,8 +167,8 @@ TEST_CASE
*/ */
namespace ObjectWithConversions namespace ObjectWithConversions
{ {
struct Object struct Object
{ {
operator unsigned int() {return 0xc0000000;} operator unsigned int() {return 0xc0000000;}
}; };
@ -179,31 +179,31 @@ namespace ObjectWithConversions
"Operators at different namespace levels not hijacked by Koenig lookup", "Operators at different namespace levels not hijacked by Koenig lookup",
"[Tricky]" "[Tricky]"
) )
{ {
Object o; Object o;
REQUIRE(0xc0000000 == o ); REQUIRE(0xc0000000 == o );
} }
} }
namespace ObjectWithNonConstEqualityOperator namespace ObjectWithNonConstEqualityOperator
{ {
struct Test struct Test
{ {
Test( unsigned int v ) Test( unsigned int v )
: m_value(v) : m_value(v)
{} {}
bool operator==( const Test&rhs ) bool operator==( const Test&rhs )
{ {
return (m_value == rhs.m_value); return (m_value == rhs.m_value);
} }
bool operator==( const Test&rhs ) const bool operator==( const Test&rhs ) const
{ {
return (m_value != rhs.m_value); return (m_value != rhs.m_value);
} }
unsigned int m_value; unsigned int m_value;
}; };
TEST_CASE("Demonstrate that a non-const == is not used", "[Tricky]" ) TEST_CASE("Demonstrate that a non-const == is not used", "[Tricky]" )
{ {
Test t( 1 ); Test t( 1 );
@ -226,7 +226,7 @@ namespace EnumBitFieldTests
struct Obj struct Obj
{ {
Obj():prop(&p){} Obj():prop(&p){}
int p; int p;
int* prop; int* prop;
}; };
@ -234,7 +234,7 @@ struct Obj
TEST_CASE("boolean member", "[Tricky]") TEST_CASE("boolean member", "[Tricky]")
{ {
Obj obj; Obj obj;
REQUIRE( obj.prop != NULL ); REQUIRE( obj.prop != CATCH_NULL );
} }
// Tests for a problem submitted by Ralph McArdell // 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]" )
{ {
} }
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 // This was causing a failure due to the way the console reporter was handling
// the current section // the current section
REQUIRE( Catch::alwaysTrue() ); REQUIRE( Catch::alwaysTrue() );
SECTION( "A section", "" ) SECTION( "A section", "" )
{ {
REQUIRE( Catch::alwaysTrue() ); REQUIRE( Catch::alwaysTrue() );
SECTION( "Another section", "" ) SECTION( "Another section", "" )
{ {
REQUIRE( Catch::alwaysTrue() ); REQUIRE( Catch::alwaysTrue() );

View File

@ -7,6 +7,7 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* 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 */; }; 263F7A4719B6FCBF009474C2 /* EnumToString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4619B6FCBF009474C2 /* EnumToString.cpp */; };
263F7A4B19B6FE1E009474C2 /* ToStringPair.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4819B6FE1E009474C2 /* ToStringPair.cpp */; }; 263F7A4B19B6FE1E009474C2 /* ToStringPair.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4819B6FE1E009474C2 /* ToStringPair.cpp */; };
263F7A4C19B6FE1E009474C2 /* ToStringVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4919B6FE1E009474C2 /* ToStringVector.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 */; }; 26711C8F195D465C0033EDA2 /* TagAliasTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26711C8D195D465C0033EDA2 /* TagAliasTests.cpp */; };
26847E5F16BBADB40043B9C1 /* catch_message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26847E5D16BBADB40043B9C1 /* catch_message.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 */; }; 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 */; }; 2694A1FD16A0000E004816E3 /* catch_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2694A1FB16A0000E004816E3 /* catch_text.cpp */; };
26E1B7D319213BC900812682 /* CmdLineTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E1B7D119213BC900812682 /* CmdLineTests.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 */; }; 4A45DA2416161EF9004F8D6B /* catch_console_colour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A45DA2316161EF9004F8D6B /* catch_console_colour.cpp */; };
@ -62,6 +62,7 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
26059AF11BD4B94C003D575C /* PartTrackerTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PartTrackerTests.cpp; path = ../../../SelfTest/PartTrackerTests.cpp; sourceTree = "<group>"; };
261488FA184C81130041FBEB /* catch_test_spec.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_spec.hpp; sourceTree = "<group>"; }; 261488FA184C81130041FBEB /* catch_test_spec.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_spec.hpp; sourceTree = "<group>"; };
261488FC184D1DC10041FBEB /* catch_stream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_stream.h; sourceTree = "<group>"; }; 261488FC184D1DC10041FBEB /* catch_stream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_stream.h; sourceTree = "<group>"; };
261488FD184D21290041FBEB /* catch_section_info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_section_info.h; sourceTree = "<group>"; }; 261488FD184D21290041FBEB /* catch_section_info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_section_info.h; sourceTree = "<group>"; };
@ -91,7 +92,6 @@
26711C91195D47820033EDA2 /* catch_tag_alias.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_tag_alias.h; sourceTree = "<group>"; }; 26711C91195D47820033EDA2 /* catch_tag_alias.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_tag_alias.h; sourceTree = "<group>"; };
26711C92195D48F60033EDA2 /* catch_tag_alias_registry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_tag_alias_registry.hpp; sourceTree = "<group>"; }; 26711C92195D48F60033EDA2 /* catch_tag_alias_registry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_tag_alias_registry.hpp; sourceTree = "<group>"; };
26711C94195D4B120033EDA2 /* catch_tag_alias_registry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_tag_alias_registry.h; sourceTree = "<group>"; }; 26711C94195D4B120033EDA2 /* catch_tag_alias_registry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_tag_alias_registry.h; sourceTree = "<group>"; };
26759472171C72A400A84BD1 /* catch_sfinae.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_sfinae.hpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
26759473171C74C200A84BD1 /* catch_compiler_capabilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = catch_compiler_capabilities.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 26759473171C74C200A84BD1 /* catch_compiler_capabilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = catch_compiler_capabilities.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
26847E5B16BBAB790043B9C1 /* catch_message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_message.h; sourceTree = "<group>"; }; 26847E5B16BBAB790043B9C1 /* catch_message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_message.h; sourceTree = "<group>"; };
26847E5C16BBACB60043B9C1 /* catch_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_message.hpp; sourceTree = "<group>"; }; 26847E5C16BBACB60043B9C1 /* catch_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_message.hpp; sourceTree = "<group>"; };
@ -101,7 +101,6 @@
2691574B1A532A280054F1ED /* ToStringTuple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringTuple.cpp; path = ../../../SelfTest/ToStringTuple.cpp; sourceTree = "<group>"; }; 2691574B1A532A280054F1ED /* ToStringTuple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringTuple.cpp; path = ../../../SelfTest/ToStringTuple.cpp; sourceTree = "<group>"; };
26926E8318D7777D004E10F2 /* clara.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = clara.h; path = ../../../../include/external/clara.h; sourceTree = "<group>"; }; 26926E8318D7777D004E10F2 /* clara.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = clara.h; path = ../../../../include/external/clara.h; sourceTree = "<group>"; };
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 = "<group>"; }; 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 = "<group>"; };
26948284179A9AB900ED166E /* SectionTrackerTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SectionTrackerTests.cpp; path = ../../../SelfTest/SectionTrackerTests.cpp; sourceTree = "<group>"; };
26948287179EF7F900ED166E /* catch_test_case_tracker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_tracker.hpp; sourceTree = "<group>"; }; 26948287179EF7F900ED166E /* catch_test_case_tracker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_tracker.hpp; sourceTree = "<group>"; };
2694A1FB16A0000E004816E3 /* catch_text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catch_text.cpp; sourceTree = "<group>"; }; 2694A1FB16A0000E004816E3 /* catch_text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catch_text.cpp; sourceTree = "<group>"; };
269831E519078C1600BB0CE0 /* catch_tostring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_tostring.h; sourceTree = "<group>"; }; 269831E519078C1600BB0CE0 /* catch_tostring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_tostring.h; sourceTree = "<group>"; };
@ -109,7 +108,9 @@
269831E719121CA500BB0CE0 /* catch_reporter_compact.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_compact.hpp; sourceTree = "<group>"; }; 269831E719121CA500BB0CE0 /* catch_reporter_compact.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_compact.hpp; sourceTree = "<group>"; };
26AEAF1617BEA18E009E32C9 /* catch_platform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_platform.h; sourceTree = "<group>"; }; 26AEAF1617BEA18E009E32C9 /* catch_platform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_platform.h; sourceTree = "<group>"; };
26DACF2F17206D3400A21326 /* catch_text.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_text.h; sourceTree = "<group>"; }; 26DACF2F17206D3400A21326 /* catch_text.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_text.h; sourceTree = "<group>"; };
26DFD3B11B53F84700FD6F16 /* catch_wildcard_pattern.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_wildcard_pattern.hpp; sourceTree = "<group>"; };
26E1B7D119213BC900812682 /* CmdLineTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CmdLineTests.cpp; path = ../../../SelfTest/CmdLineTests.cpp; sourceTree = "<group>"; }; 26E1B7D119213BC900812682 /* CmdLineTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CmdLineTests.cpp; path = ../../../SelfTest/CmdLineTests.cpp; sourceTree = "<group>"; };
26EDFBD91B72011F00B1873C /* catch_reporter_multi.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_multi.hpp; sourceTree = "<group>"; };
4A084F1C15DACEEA0027E631 /* catch_test_case_info.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_info.hpp; sourceTree = "<group>"; }; 4A084F1C15DACEEA0027E631 /* catch_test_case_info.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_info.hpp; sourceTree = "<group>"; };
4A3D7DD01503869D005F9203 /* catch_matchers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_matchers.hpp; sourceTree = "<group>"; }; 4A3D7DD01503869D005F9203 /* catch_matchers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_matchers.hpp; sourceTree = "<group>"; };
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 = "<group>"; }; 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 = "<group>"; };
@ -136,7 +137,7 @@
4A6D0C34149B3D9E00DB3EAA /* MiscTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MiscTests.cpp; path = ../../../SelfTest/MiscTests.cpp; sourceTree = "<group>"; }; 4A6D0C34149B3D9E00DB3EAA /* MiscTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MiscTests.cpp; path = ../../../SelfTest/MiscTests.cpp; sourceTree = "<group>"; };
4A6D0C35149B3D9E00DB3EAA /* TestMain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestMain.cpp; path = ../../../SelfTest/TestMain.cpp; sourceTree = "<group>"; }; 4A6D0C35149B3D9E00DB3EAA /* TestMain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestMain.cpp; path = ../../../SelfTest/TestMain.cpp; sourceTree = "<group>"; };
4A6D0C36149B3D9E00DB3EAA /* TrickyTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TrickyTests.cpp; path = ../../../SelfTest/TrickyTests.cpp; sourceTree = "<group>"; }; 4A6D0C36149B3D9E00DB3EAA /* TrickyTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TrickyTests.cpp; path = ../../../SelfTest/TrickyTests.cpp; sourceTree = "<group>"; };
4A6D0C42149B3E1500DB3EAA /* catch_runner.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; name = catch_runner.hpp; path = ../../../../include/catch_runner.hpp; sourceTree = "<group>"; 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 = "<group>"; 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 = "<group>"; }; 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 = "<group>"; };
4A6D0C44149B3E1500DB3EAA /* catch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch.hpp; path = ../../../../include/catch.hpp; sourceTree = "<group>"; }; 4A6D0C44149B3E1500DB3EAA /* catch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch.hpp; path = ../../../../include/catch.hpp; sourceTree = "<group>"; };
4A6D0C46149B3E3D00DB3EAA /* catch_approx.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_approx.hpp; sourceTree = "<group>"; }; 4A6D0C46149B3E3D00DB3EAA /* catch_approx.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_approx.hpp; sourceTree = "<group>"; };
@ -163,7 +164,7 @@
4A6D0C5B149B3E3D00DB3EAA /* catch_reporter_registry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_registry.hpp; sourceTree = "<group>"; }; 4A6D0C5B149B3E3D00DB3EAA /* catch_reporter_registry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_registry.hpp; sourceTree = "<group>"; };
4A6D0C5C149B3E3D00DB3EAA /* catch_result_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_result_type.h; sourceTree = "<group>"; }; 4A6D0C5C149B3E3D00DB3EAA /* catch_result_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_result_type.h; sourceTree = "<group>"; };
4A6D0C5D149B3E3D00DB3EAA /* catch_assertionresult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = catch_assertionresult.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 4A6D0C5D149B3E3D00DB3EAA /* catch_assertionresult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = catch_assertionresult.h; sourceTree = "<group>"; 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 = "<group>"; 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 = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
4A6D0C5F149B3E3D00DB3EAA /* catch_section.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_section.hpp; sourceTree = "<group>"; }; 4A6D0C5F149B3E3D00DB3EAA /* catch_section.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_section.hpp; sourceTree = "<group>"; };
4A6D0C60149B3E3D00DB3EAA /* catch_stream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_stream.hpp; sourceTree = "<group>"; }; 4A6D0C60149B3E3D00DB3EAA /* catch_stream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_stream.hpp; sourceTree = "<group>"; };
4A6D0C61149B3E3D00DB3EAA /* catch_test_case_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_test_case_info.h; sourceTree = "<group>"; }; 4A6D0C61149B3E3D00DB3EAA /* catch_test_case_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_test_case_info.h; sourceTree = "<group>"; };
@ -211,7 +212,7 @@
266E9AD317290E710061DAB2 /* Introspective Tests */ = { 266E9AD317290E710061DAB2 /* Introspective Tests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
26948284179A9AB900ED166E /* SectionTrackerTests.cpp */, 26059AF11BD4B94C003D575C /* PartTrackerTests.cpp */,
26E1B7D119213BC900812682 /* CmdLineTests.cpp */, 26E1B7D119213BC900812682 /* CmdLineTests.cpp */,
26711C8D195D465C0033EDA2 /* TagAliasTests.cpp */, 26711C8D195D465C0033EDA2 /* TagAliasTests.cpp */,
); );
@ -285,7 +286,7 @@
4AA7B8B4165428BA003155F6 /* catch_version.hpp */, 4AA7B8B4165428BA003155F6 /* catch_version.hpp */,
4A8E4DCF160A34E200194CBD /* SurrogateCpps */, 4A8E4DCF160A34E200194CBD /* SurrogateCpps */,
4A6D0C44149B3E1500DB3EAA /* catch.hpp */, 4A6D0C44149B3E1500DB3EAA /* catch.hpp */,
4A6D0C42149B3E1500DB3EAA /* catch_runner.hpp */, 4A6D0C42149B3E1500DB3EAA /* catch_session.hpp */,
4A6D0C43149B3E1500DB3EAA /* catch_with_main.hpp */, 4A6D0C43149B3E1500DB3EAA /* catch_with_main.hpp */,
4A6D0C45149B3E3D00DB3EAA /* internal */, 4A6D0C45149B3E3D00DB3EAA /* internal */,
4A6D0C65149B3E3D00DB3EAA /* reporters */, 4A6D0C65149B3E3D00DB3EAA /* reporters */,
@ -318,6 +319,7 @@
4A6D0C68149B3E3D00DB3EAA /* catch_reporter_xml.hpp */, 4A6D0C68149B3E3D00DB3EAA /* catch_reporter_xml.hpp */,
4AB42F84166F3E1A0099F2C8 /* catch_reporter_console.hpp */, 4AB42F84166F3E1A0099F2C8 /* catch_reporter_console.hpp */,
2691574A1A4480C50054F1ED /* catch_reporter_teamcity.hpp */, 2691574A1A4480C50054F1ED /* catch_reporter_teamcity.hpp */,
26EDFBD91B72011F00B1873C /* catch_reporter_multi.hpp */,
); );
name = reporters; name = reporters;
path = ../../../../include/reporters; path = ../../../../include/reporters;
@ -358,7 +360,7 @@
4A4B0F9715CE6CFB00AE2392 /* catch_registry_hub.hpp */, 4A4B0F9715CE6CFB00AE2392 /* catch_registry_hub.hpp */,
4A6D0C50149B3E3D00DB3EAA /* catch_generators_impl.hpp */, 4A6D0C50149B3E3D00DB3EAA /* catch_generators_impl.hpp */,
4A6D0C52149B3E3D00DB3EAA /* catch_context_impl.hpp */, 4A6D0C52149B3E3D00DB3EAA /* catch_context_impl.hpp */,
4A6D0C5E149B3E3D00DB3EAA /* catch_runner_impl.hpp */, 4A6D0C5E149B3E3D00DB3EAA /* catch_run_context.hpp */,
4A6D0C62149B3E3D00DB3EAA /* catch_test_case_registry_impl.hpp */, 4A6D0C62149B3E3D00DB3EAA /* catch_test_case_registry_impl.hpp */,
4AB1C73514F97BDA00F31DF7 /* catch_console_colour_impl.hpp */, 4AB1C73514F97BDA00F31DF7 /* catch_console_colour_impl.hpp */,
4A4B0F9B15CEF8C400AE2392 /* catch_notimplemented_exception.hpp */, 4A4B0F9B15CEF8C400AE2392 /* catch_notimplemented_exception.hpp */,
@ -453,6 +455,7 @@
266ECD8C1713614B0030D735 /* catch_legacy_reporter_adapter.hpp */, 266ECD8C1713614B0030D735 /* catch_legacy_reporter_adapter.hpp */,
266ECD8D1713614B0030D735 /* catch_legacy_reporter_adapter.h */, 266ECD8D1713614B0030D735 /* catch_legacy_reporter_adapter.h */,
4A6D0C49149B3E3D00DB3EAA /* catch_common.h */, 4A6D0C49149B3E3D00DB3EAA /* catch_common.h */,
262E739A1846759000CAC268 /* catch_common.hpp */,
4A6D0C4B149B3E3D00DB3EAA /* catch_debugger.hpp */, 4A6D0C4B149B3E3D00DB3EAA /* catch_debugger.hpp */,
261488FF184DC4A20041FBEB /* catch_debugger.h */, 261488FF184DC4A20041FBEB /* catch_debugger.h */,
4A6D0C60149B3E3D00DB3EAA /* catch_stream.hpp */, 4A6D0C60149B3E3D00DB3EAA /* catch_stream.hpp */,
@ -461,17 +464,16 @@
4AB77CB51551AEA200857BF0 /* catch_ptr.hpp */, 4AB77CB51551AEA200857BF0 /* catch_ptr.hpp */,
4AEE0326161431070071E950 /* catch_streambuf.h */, 4AEE0326161431070071E950 /* catch_streambuf.h */,
4ACE21C8166CA19700FB5509 /* catch_option.hpp */, 4ACE21C8166CA19700FB5509 /* catch_option.hpp */,
26759472171C72A400A84BD1 /* catch_sfinae.hpp */,
26759473171C74C200A84BD1 /* catch_compiler_capabilities.h */, 26759473171C74C200A84BD1 /* catch_compiler_capabilities.h */,
26DACF2F17206D3400A21326 /* catch_text.h */, 26DACF2F17206D3400A21326 /* catch_text.h */,
263FD06117AF8DF200988A20 /* catch_timer.h */, 263FD06117AF8DF200988A20 /* catch_timer.h */,
26AEAF1617BEA18E009E32C9 /* catch_platform.h */, 26AEAF1617BEA18E009E32C9 /* catch_platform.h */,
262E739A1846759000CAC268 /* catch_common.hpp */,
261488FC184D1DC10041FBEB /* catch_stream.h */, 261488FC184D1DC10041FBEB /* catch_stream.h */,
268F47B018A93F7800D8C14F /* catch_clara.h */, 268F47B018A93F7800D8C14F /* catch_clara.h */,
2656C226192A77EF0040DB02 /* catch_suppress_warnings.h */, 2656C226192A77EF0040DB02 /* catch_suppress_warnings.h */,
2656C227192A78410040DB02 /* catch_reenable_warnings.h */, 2656C227192A78410040DB02 /* catch_reenable_warnings.h */,
263F7A4519A66608009474C2 /* catch_fatal_condition.hpp */, 263F7A4519A66608009474C2 /* catch_fatal_condition.hpp */,
26DFD3B11B53F84700FD6F16 /* catch_wildcard_pattern.hpp */,
); );
name = Infrastructure; name = Infrastructure;
sourceTree = "<group>"; sourceTree = "<group>";
@ -546,6 +548,7 @@
4A6D0C3E149B3D9E00DB3EAA /* TestMain.cpp in Sources */, 4A6D0C3E149B3D9E00DB3EAA /* TestMain.cpp in Sources */,
4A6D0C3F149B3D9E00DB3EAA /* TrickyTests.cpp in Sources */, 4A6D0C3F149B3D9E00DB3EAA /* TrickyTests.cpp in Sources */,
263F7A4D19B6FE1E009474C2 /* ToStringWhich.cpp in Sources */, 263F7A4D19B6FE1E009474C2 /* ToStringWhich.cpp in Sources */,
26059AF21BD4B94C003D575C /* PartTrackerTests.cpp in Sources */,
263F7A4B19B6FE1E009474C2 /* ToStringPair.cpp in Sources */, 263F7A4B19B6FE1E009474C2 /* ToStringPair.cpp in Sources */,
4AEE032016142F910071E950 /* catch_common.cpp in Sources */, 4AEE032016142F910071E950 /* catch_common.cpp in Sources */,
263F7A4C19B6FE1E009474C2 /* ToStringVector.cpp in Sources */, 263F7A4C19B6FE1E009474C2 /* ToStringVector.cpp in Sources */,
@ -572,7 +575,6 @@
26847E5F16BBADB40043B9C1 /* catch_message.cpp in Sources */, 26847E5F16BBADB40043B9C1 /* catch_message.cpp in Sources */,
266B06B816F3A60A004ED264 /* VariadicMacrosTests.cpp in Sources */, 266B06B816F3A60A004ED264 /* VariadicMacrosTests.cpp in Sources */,
266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */, 266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */,
26948286179A9AB900ED166E /* SectionTrackerTests.cpp in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -10,31 +10,31 @@
<string>CatchSelfTestSingle</string> <string>CatchSelfTestSingle</string>
<key>IDESourceControlProjectOriginsDictionary</key> <key>IDESourceControlProjectOriginsDictionary</key>
<dict> <dict>
<key>01DD8CA9-7DC3-46BC-B998-EFF40EA3485F</key> <key>90C00904F36E6ADB57A7313E998815D255B0DEAF</key>
<string>ssh://github.com/philsquared/Catch.git</string> <string>https://github.com/philsquared/Catch.git</string>
</dict> </dict>
<key>IDESourceControlProjectPath</key> <key>IDESourceControlProjectPath</key>
<string>projects/XCode4/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.xcworkspace</string> <string>projects/XCode/CatchSelfTest/CatchSelfTestSingle.xcodeproj</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key> <key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict> <dict>
<key>01DD8CA9-7DC3-46BC-B998-EFF40EA3485F</key> <key>90C00904F36E6ADB57A7313E998815D255B0DEAF</key>
<string>../../../../..</string> <string>../../../../..</string>
</dict> </dict>
<key>IDESourceControlProjectURL</key> <key>IDESourceControlProjectURL</key>
<string>ssh://github.com/philsquared/Catch.git</string> <string>https://github.com/philsquared/Catch.git</string>
<key>IDESourceControlProjectVersion</key> <key>IDESourceControlProjectVersion</key>
<integer>110</integer> <integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key> <key>IDESourceControlProjectWCCIdentifier</key>
<string>01DD8CA9-7DC3-46BC-B998-EFF40EA3485F</string> <string>90C00904F36E6ADB57A7313E998815D255B0DEAF</string>
<key>IDESourceControlProjectWCConfigurations</key> <key>IDESourceControlProjectWCConfigurations</key>
<array> <array>
<dict> <dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key> <key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string> <string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key> <key>IDESourceControlWCCIdentifierKey</key>
<string>01DD8CA9-7DC3-46BC-B998-EFF40EA3485F</string> <string>90C00904F36E6ADB57A7313E998815D255B0DEAF</string>
<key>IDESourceControlWCCName</key> <key>IDESourceControlWCCName</key>
<string>Catch</string> <string>Catch-Develop</string>
</dict> </dict>
</array> </array>
</dict> </dict>

View File

@ -13,7 +13,7 @@
@interface iTchRunnerAppDelegate : NSObject <UIApplicationDelegate> @interface iTchRunnerAppDelegate : NSObject <UIApplicationDelegate>
{ {
UIWindow *window; 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 = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window setUserInteractionEnabled:YES]; [window setUserInteractionEnabled:YES];
[window setMultipleTouchEnabled:YES]; [window setMultipleTouchEnabled:YES];
CGRect screenRect = [[UIScreen mainScreen] applicationFrame]; CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
iTchRunnerMainView* view = [[iTchRunnerMainView alloc] initWithFrame:screenRect]; iTchRunnerMainView* view = [[iTchRunnerMainView alloc] initWithFrame:screenRect];
[window addSubview:view]; [window addSubview:view];
[window makeKeyAndVisible]; [window makeKeyAndVisible];
arcSafeRelease( view ); arcSafeRelease( view );
@ -42,7 +42,7 @@
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
- (void)dealloc - (void)dealloc
{ {
#if !CATCH_ARC_ENABLED #if !CATCH_ARC_ENABLED
[window release]; [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. 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. 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. 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. 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. 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. Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.

View File

@ -33,7 +33,7 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
-(id) initWithFrame:(CGRect)frame -(id) initWithFrame:(CGRect)frame
{ {
if ((self = [super initWithFrame:frame])) if ((self = [super initWithFrame:frame]))
{ {
// Initialization code // Initialization code
self.backgroundColor = [UIColor blackColor]; self.backgroundColor = [UIColor blackColor];
@ -64,7 +64,7 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
-(void) showAlert -(void) showAlert
{ {
UIActionSheet* menu = [[UIActionSheet alloc] initWithTitle:@"Options" UIActionSheet* menu = [[UIActionSheet alloc] initWithTitle:@"Options"
delegate:self delegate:self
cancelButtonTitle:nil cancelButtonTitle:nil
@ -72,7 +72,7 @@
otherButtonTitles:@"Run all tests", nil]; otherButtonTitles:@"Run all tests", nil];
[menu showInView: self]; [menu showInView: self];
arcSafeRelease( menu ); arcSafeRelease( menu );
} }
// This is a copy & paste from Catch::Runner2 to get us bootstrapped (this is due to all be // 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; const Catch::AssertionResult& resultInfo = *pResultInfo;
std::ostringstream oss; std::ostringstream oss;
if( resultInfo.hasExpression() ) if( resultInfo.hasExpression() )
{ {
oss << resultInfo.getExpression(); oss << resultInfo.getExpression();
@ -174,7 +174,7 @@ inline Catch::Totals runTestsForGroup( Catch::RunContext& context, const Catch::
default: default:
break; break;
} }
if( resultInfo.hasExpression() ) if( resultInfo.hasExpression() )
{ {
oss << " for: " << resultInfo.getExpandedExpression(); oss << " for: " << resultInfo.getExpandedExpression();

View File

@ -13,7 +13,7 @@
@protocol iTchRunnerDelegate @protocol iTchRunnerDelegate
-(void) testWasRun: (const Catch::AssertionResult*) result; -(void) testWasRun: (const Catch::AssertionResult*) result;
@end @end
@ -38,14 +38,14 @@ namespace Catch
{ {
return true; return true;
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
static std::string getDescription static std::string getDescription
() ()
{ {
return "Captures results for iOS runner"; return "Captures results for iOS runner";
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
size_t getSucceeded size_t getSucceeded
() ()
@ -53,7 +53,7 @@ namespace Catch
{ {
return m_totals.assertions.passed; return m_totals.assertions.passed;
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
size_t getFailed size_t getFailed
() ()
@ -61,20 +61,20 @@ namespace Catch
{ {
return m_totals.assertions.failed; return m_totals.assertions.failed;
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
void reset() void reset()
{ {
m_totals = Totals(); m_totals = Totals();
} }
private: // IReporter private: // IReporter
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void StartTesting virtual void StartTesting
() ()
{} {}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void EndTesting virtual void EndTesting
( (
@ -83,7 +83,7 @@ namespace Catch
{ {
m_totals = totals; m_totals = totals;
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void Result virtual void Result
( (
@ -92,7 +92,7 @@ namespace Catch
{ {
[m_delegate testWasRun: &result]; [m_delegate testWasRun: &result];
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Deliberately unimplemented: // Deliberately unimplemented:
virtual void StartGroup( const std::string& ){} virtual void StartGroup( const std::string& ){}
@ -107,7 +107,7 @@ namespace Catch
private: private:
Totals m_totals; Totals m_totals;
id<iTchRunnerDelegate> m_delegate; id<iTchRunnerDelegate> m_delegate;
}; };
} }

View File

@ -15,7 +15,8 @@ pathParser = re.compile( r'(.*?)/(.*\..pp)(.*)' )
lineNumberParser = re.compile( r'(.*)line="[0-9]*"(.*)' ) lineNumberParser = re.compile( r'(.*)line="[0-9]*"(.*)' )
hexParser = re.compile( r'(.*)\b(0[xX][0-9a-fA-F]+)\b(.*)' ) hexParser = re.compile( r'(.*)\b(0[xX][0-9a-fA-F]+)\b(.*)' )
durationsParser = re.compile( r'(.*)time="[0-9]*\.[0-9]*"(.*)' ) 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: if len(sys.argv) == 2:
cmdPath = sys.argv[1] cmdPath = sys.argv[1]
@ -41,9 +42,13 @@ def filterLine( line ):
if path.startswith( catchPath ): if path.startswith( catchPath ):
path = path[1+len(catchPath):] path = path[1+len(catchPath):]
line = m.group(1) + path + m.group(3) line = m.group(1) + path + m.group(3)
m = versionParser.match( line ) m = devVersionParser.match( line )
if m: if m:
line = m.group(1) + "<version>" + m.group(2) line = m.group(1) + "<version>" + m.group(2)
else:
m = versionParser.match( line )
if m:
line = m.group(1) + "<version>" + m.group(2)
while True: while True:
m = hexParser.match( line ) m = hexParser.match( line )

View File

@ -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" )

File diff suppressed because it is too large Load Diff