Merged from develop

This commit is contained in:
Phil Nash 2015-03-27 17:54:45 +00:00
commit d9fbc62093
83 changed files with 4428 additions and 1430 deletions

View File

@ -1,11 +1,13 @@
![catch logo](catch-logo-small.png) ![catch logo](catch-logo-small.png)
*v1.0 build 53 (master branch)* *v1.1 build 14 (develop branch)*
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)
[Please see this page if you are updating from a version before 1.0](docs/whats-changed.md) [Please see this page if you are updating from a version before 1.0](docs/whats-changed.md)
<a href="https://raw.githubusercontent.com/philsquared/Catch/develop/single_include/catch.hpp">[The latest, single header, version can be downloaded directly using this link]</a>
## What's the Catch? ## What's the Catch?
Catch stands for C++ Automated Test Cases in Headers and is a multi-paradigm automated test framework for C++ and Objective-C (and, maybe, C). It is implemented entirely in a set of header files, but is packaged up as a single header for extra convenience. Catch stands for C++ Automated Test Cases in Headers and is a multi-paradigm automated test framework for C++ and Objective-C (and, maybe, C). It is implemented entirely in a set of header files, but is packaged up as a single header for extra convenience.

View File

@ -9,6 +9,8 @@ Before looking at this material be sure to read the [tutorial](tutorial.md)
* [Command line](command-line.md) * [Command line](command-line.md)
* [Build systems](build-systems.md) * [Build systems](build-systems.md)
* [Supplying your own main()](own-main.md) * [Supplying your own main()](own-main.md)
* [Configuration](configuration.md)
* [String Conversions](tostring.md)
* [Why are my tests slow to compile?](slow-compiles.md) * [Why are my tests slow to compile?](slow-compiles.md)
Other Other
@ -16,8 +18,3 @@ Other
* [Why Catch?](why-catch.md) * [Why Catch?](why-catch.md)
* [What's changed](whats-changed.md) * [What's changed](whats-changed.md)
* [Contributing](contributing.md) * [Contributing](contributing.md)
---
[Home](../README.md)

View File

@ -17,12 +17,12 @@ The ```CHECK``` family are equivalent but execution continues in the same test c
Evaluates the expression and records the result. If an exception is thrown it is caught, reported, and counted as a failure. These are the macros you will use most of the time Evaluates the expression and records the result. If an exception is thrown it is caught, reported, and counted as a failure. These are the macros you will use most of the time
Examples: Examples:
```
```c++
CHECK( str == "string value" ); CHECK( str == "string value" );
CHECK( thisReturnsTrue() ); CHECK( thisReturnsTrue() );
REQUIRE( i == 42 ); REQUIRE( i == 42 );
``` ```
* **REQUIRE_FALSE(** _expression_ **)** and * **REQUIRE_FALSE(** _expression_ **)** and
* **CHECK_FALSE(** _expression_ **)** * **CHECK_FALSE(** _expression_ **)**
@ -30,10 +30,28 @@ Evaluates the expression and records the _logical NOT_ of the result. If an exce
(these forms exist as a workaround for the fact that ! prefixed expressions cannot be decomposed). (these forms exist as a workaround for the fact that ! prefixed expressions cannot be decomposed).
Example: Example:
```c++ ```
REQUIRE_FALSE( thisReturnsFalse() ); REQUIRE_FALSE( thisReturnsFalse() );
``` ```
### Floating point comparisons
When comparing floating point numbers - especially if at least one of them has been computed - great care must be taken to allow for rounding errors and inexact representations.
Catch provides a way to perform tolerant comparisons of floating point values through use of a wrapper class called ```Approx```. ```Approx``` can be used on either side of a comparison expression. It overloads the comparisons operators to take a tolerance into account. Here's a simple example:
```
REQUIRE( performComputation() == Approx( 2.1 ) );
```
By default a small epsilon value is used that covers many simple cases of rounding errors. When this is insufficent the epsilon value (the amount within which a difference either way is ignored) can be specified by calling the ```epsilon()``` method on the ```Approx``` instance. e.g.:
```
REQUIRE( 22/7 == Approx( 3.141 ).epsilon( 0.01 ) );
```
When dealing with very large or very small numbers it can be useful to specify a scale, which can be achieved by calling the ```scale()``` method on the ```Approx``` instance.
## Exceptions ## Exceptions
* **REQUIRE_THROWS(** _expression_ **)** and * **REQUIRE_THROWS(** _expression_ **)** and
@ -61,4 +79,4 @@ To support Matchers a slightly different form is used. Matchers will be more ful
--- ---
[Home](../README.md) [Home](Readme.md)

View File

@ -1,5 +1,50 @@
# Integration with build systems # Integration with build systems
Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.
# Continuous Integration systems
Probably the most important aspect to using Catch with a build server is the use of different reporters. Catch comes bundled with three reporters that should cover the majority of build servers out there - although adding more for better integration with some is always a possibility (as has been done with TeamCity).
Two of these reporters are built in (XML and JUnit) and the third (TeamCity) is included as a separate header. It's possible that the other two may be split out in the future too - as that would make the core of Catch smaller for those that don't need them.
## XML Reporter
```-r xml```
The XML Reporter writes in an XML format that is specific to Catch.
The advantage of this format is that it corresponds well to the way Catch works (especially the more unusual features, such as nested sections) and is a fully streaming format - that is it writes output as it goes, without having to store up all its results before it can start writing.
The disadvantage is that, being specific to Catch, no existing build servers understand the format natively. It can be used as input to an XSLT transformation that could covert it to, say, HTML - although this loses the streaming advantage, of course.
## JUnit Reporter
```-r junit```
The JUnit Reporter writes in an XML format that mimics the JUnit ANT schema.
The advantage of this format is that the JUnit Ant schema is widely understood by most build servers and so can usually be consumed with no additional work.
The disadvantage is that this schema was designed to correspond to how JUnit works - and there is a significant mismatch with how Catch works. Additionally the format is not streamable (because opening elements hold counts of failed and passing tests as attributes) - so the whole test run must complete before it can be written.
## TeamCity Reporter
```-r teamcity```
The TeamCity Reporter writes TeamCity service messages to stdout. In order to be able to use this reporter an additional header must also be included.
```catch_reporter_teamcity.hpp``` can be found in the ```include\reporters``` directory. It should be included in the same file that ```#define```s ```CATCH_CONFIG_MAIN``` or ```CATCH_CONFIG_RUNNER```. The ```#include``` should be placed after ```#include```ing Catch itself.
e.g.:
```
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "catch_reporter_teamcity.hpp"
```
Being specific to TeamCity this is the best reporter to use with it - but it is completely unsuitable for any other purpose. It is a streaming format (it writes as it goes) - although test results don't appear in the TeamCity interface until the completion of a suite (usually the whole test run).
# Low-level tools
## CMake ## CMake
You can use the following CMake script to automatically fetch Catch from github and configure it as an external project: You can use the following CMake script to automatically fetch Catch from github and configure it as an external project:
@ -35,3 +80,7 @@ add_subdirectory(${EXT_PROJECTS_DIR}/catch)
include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES}) include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES})
enable_testing(true) # Enables unit-testing. enable_testing(true) # Enables unit-testing.
``` ```
---
[Home](Readme.md)

View File

@ -1,18 +1,33 @@
Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available. Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
Note that options are described according to the following pattern: Click one of the followings links to take you straight to that option - or scroll on to browse the available options.
<a href="#specifying-which-tests-to-run"> ` <test-spec> ...`</a><br /> <a href="#specifying-which-tests-to-run"> ` <test-spec> ...`</a><br />
<a href="#choosing-a-reporter-to-use"> ` -r, --reporter`</a><br /> <a href="#usage"> ` -h, -?, --help`</a><br />
<a href="#breaking-into-the-debugger"> ` -b, --break`</a><br /> <a href="#listing-available-tests-tags-or-reporters"> ` -l, --list-tests`</a><br />
<a href="#listing-available-tests-tags-or-reporters"> ` -t, --list-tags`</a><br />
<a href="#showing-results-for-successful-tests"> ` -s, --success`</a><br /> <a href="#showing-results-for-successful-tests"> ` -s, --success`</a><br />
<a href="#aborting-after-a-certain-number-of-failures"> ` -a, --abort`</a><br /> <a href="#breaking-into-the-debugger"> ` -b, --break`</a><br />
<a href="#listing-available-tests-tags-or-reporters"> ` -l, --list`</a><br />
<a href="#sending-output-to-a-file"> ` -o, --out`</a><br />
<a href="#naming-a-test-run"> ` -n, --name`</a><br />
<a href="#eliding-assertions-expected-to-throw"> ` -e, --nothrow`</a><br /> <a href="#eliding-assertions-expected-to-throw"> ` -e, --nothrow`</a><br />
<a href="#invisibles"> ` -i, --invisibles`</a><br />
<a href="#sending-output-to-a-file"> ` -o, --out`</a><br />
<a href="#choosing-a-reporter-to-use"> ` -r, --reporter`</a><br />
<a href="#naming-a-test-run"> ` -n, --name`</a><br />
<a href="#aborting-after-a-certain-number-of-failures"> ` -a, --abort`</a><br />
<a href="#aborting-after-a-certain-number-of-failures"> ` -x, --abortx`</a><br />
<a href="#warnings"> ` -w, --warn`</a><br /> <a href="#warnings"> ` -w, --warn`</a><br />
<a href="#reporting-timings"> ` -d, --durations`</a><br /> <a href="#reporting-timings"> ` -d, --durations`</a><br />
<a href="#usage"> ` -h, -?, --help`</a><br /> <a href="#input-file"> ` -f, --input-file`</a><br />
</br>
<a href="#list-test-names-only"> ` --list-test-names-only`</a><br />
<a href="#listing-available-tests-tags-or-reporters"> ` --list-reporters`</a><br />
<a href="#order"> ` --order`</a><br />
<a href="#rng-seed"> ` --rng-seed`</a><br />
</br>
<a id="specifying-which-tests-to-run"></a> <a id="specifying-which-tests-to-run"></a>
## Specifying which tests to run ## Specifying which tests to run
@ -21,7 +36,8 @@ Note that options are described according to the following pattern:
Test cases, wildcarded test cases, tags and tag expressions are all passed directly as arguments. Tags are distinguished by being enclosed in square brackets. Test cases, wildcarded test cases, tags and tag expressions are all passed directly as arguments. Tags are distinguished by being enclosed in square brackets.
If no test specs are supplied then all test cases, except "hidden" tests (tagged ```[hide]```, ```[.]``` or, in the legacy case, prefixed by `'./'`) are run. If no test specs are supplied then all test cases, except "hidden" tests, are run.
A test is hidden by giving it any tag starting with (or just) a period (```.```) - or, in the deprecated case, tagged ```[hide]``` or given name starting with `'./'`. To specify hidden tests from the command line ```[.]``` or ```[hide]``` can be used *regardless of how they were declared*.
Specs must be enclosed in quotes if they contain spaces. If they do not contain spaces the quotes are optional. Specs must be enclosed in quotes if they contain spaces. If they do not contain spaces the quotes are optional.
@ -79,7 +95,7 @@ In addition to the command line option, ensure you have built your code with the
<pre>-s, --success</pre> <pre>-s, --success</pre>
Usually you only want to see reporting for failed tests. Sometimes it's useful to see *all* the output (especially when you don't trust that that test you just added worked first time!). Usually you only want to see reporting for failed tests. Sometimes it's useful to see *all* the output (especially when you don't trust that that test you just added worked first time!).
To see successul, as well as failing, test results just pass this option. Note that each reporter may treat this option differently. The Junit reporter, for example, logs all results regardless. To see successful, as well as failing, test results just pass this option. Note that each reporter may treat this option differently. The Junit reporter, for example, logs all results regardless.
<a id="aborting-after-a-certain-number-of-failures"></a> <a id="aborting-after-a-certain-number-of-failures"></a>
## Aborting after a certain number of failures ## Aborting after a certain number of failures
@ -131,6 +147,13 @@ Sometimes exceptions are expected outside of one of the assertions that tests fo
When running with this option any throw checking assertions are skipped so as not to contribute additional noise. Be careful if this affects the behaviour of subsequent tests. When running with this option any throw checking assertions are skipped so as not to contribute additional noise. Be careful if this affects the behaviour of subsequent tests.
<a id="invisibles"></a>
## Make whitespace visible
<pre>-i, --invisibles</pre>
If a string comparison fails due to differences in whitespace - especially leading or trailing whitespace - it can be hard to see what's going on.
This option transforms tabs and newline characters into ```\t``` and ```\n``` respectively when printing.
<a id="warnings"></a> <a id="warnings"></a>
## Warnings ## Warnings
<pre>-w, --warn &lt;warning name></pre> <pre>-w, --warn &lt;warning name></pre>
@ -145,6 +168,47 @@ The ony available warning, presently, is ```NoAssertions```. This warning fails
When set to ```yes``` Catch will report the duration of each test case, in milliseconds. Note that it does this regardless of whether a test case passes or fails. Note, also, the certain reporters (e.g. Junit) always report test case durations regardless of this option being set or not. When set to ```yes``` Catch will report the duration of each test case, in milliseconds. Note that it does this regardless of whether a test case passes or fails. Note, also, the certain reporters (e.g. Junit) always report test case durations regardless of this option being set or not.
<a id="input-file"></a>
## Load test names to run from a file
<pre>-f, --input-file &lt;filename></pre>
Provide the name of a file that contains a list of test case names - one per line. Blank lines are skipped and anything after the comment character, ```#```, is ignored.
A useful way to generate an initial instance of this file is to use the <a href="#list-test-names-only">list-test-names-only</a> option. This can then be manually curated to specify a specific subset of tests - or in a specific order.
<a id="list-test-names-only"></a>
## Just test names
<pre>--list-test-names-only</pre>
This option lists all available tests in a non-indented form, one on each line. This makes it ideal for saving to a file and feeding back into the <a href="#input-file">```-f``` or ```--input-file```</a> option.
<a id="order"></a>
## Specify the order test cases are run
<pre>--order &lt;decl|lex|rand&gt;</pre>
Test cases are ordered one of three ways:
### decl
Declaration order. The order the tests were originally declared in. Note that ordering between files is not guaranteed and is implementation dependent.
### lex
Lexicographically sorted. Tests are sorted, alpha-numerically, by name.
### rand
Randomly sorted. Test names are sorted using ```std::random_shuffle()```. By default the random number generator is seeded with 0 - and so the order is repeatable. To control the random seed see <a href="#rng-seed">rng-seed</a>.
<a id="rng-seed"></a>
## Specify a seed for the Random Number Generator
<pre>--rng-seed &lt;'time'|number&gt;</pre>
Sets a seed for the random number generator using ```std::srand()```.
If a number is provided this is used directly as the seed so the random pattern is repeatable.
Alternatively if the keyword ```time``` is provided then the result of calling ```std::time(0)``` is used and so the pattern becomes unpredictable.
In either case the actual value for the seed is printed as part of Catch's output so if an issue is discovered that is sensitive to test ordering the ordering can be reproduced - even if it was originally seeded from ```std::time(0)```.
<a id="usage"></a> <a id="usage"></a>
## Usage ## Usage
<pre>-h, -?, --help</pre> <pre>-h, -?, --help</pre>
@ -153,4 +217,4 @@ Prints the command line arguments to stdout
--- ---
[Home](../README.md) [Home](Readme.md)

66
docs/configuration.md Normal file
View File

@ -0,0 +1,66 @@
Catch is designed to "just work" as much as possible. For most people the only configuration needed is telling Catch which source file should host all the implementation code (```CATCH_CONFIG_MAIN```).
Nonetheless there are still some occasions where finer control is needed. For these occasions Catch exposes a small set of macros for configuring how it is built.
# main()/ implementation
CATCH_CONFIG_MAIN // Designates this as implementation file and defines main()
CATCH_CONFIG_RUNNER // Designates this as implementation file
Although Catch is header only it still, internally, maintains a distinction between interface headers and headers that contain implementation. Only one source file in your test project should compile the implementation headers and this is controlled through the use of one of these macros - one of these identifiers should be defined before including Catch in *exactly one implementation file in your project*.
# Prefixing Catch macros
CATCH_CONFIG_PREFIX_ALL
To keep test code clean and uncluttered Catch uses short macro names (e.g. ```TEST_CASE``` and ```REQUIRE```). Occasionally these may conflict with identifiers from platform headers or the system under test. In this case the above identifier can be defined. This will cause all the Catch user macros to be prefixed with ```CATCH_``` (e.g. ```CATCH_TEST_CASE``` and ```CATCH_REQUIRE```).
# Terminal colour
CATCH_CONFIG_COLOUR_NONE // completely disables all text colouring
CATCH_CONFIG_COLOUR_WINDOWS // forces the Win32 console API to be used
CATCH_CONFIG_COLOUR_ANSI // forces ANSI colour codes to be used
Yes, I am English, so I will continue to spell "colour" with a 'u'.
When sending output to the terminal, if it detects that it can, Catch will use colourised text. On Windows the Win32 API, ```SetConsoleTextAttribute```, is used. On POSIX systems ANSI colour escape codes are inserted into the stream.
For finer control you can define one of the above identifiers (these are mutually exclusive - but that is not checked so may behave unexpectedly if you mix them):
Note that when ANSI colour codes are used "unistd.h" must be includable - along with a definition of ```isatty()```
Typically you should place the ```#define``` before #including "catch.hpp" in your main source file - but if you prefer you can define it for your whole project by whatever your IDE or build system provides for you to do so.
# Console width
CATCH_CONFIG_CONSOLE_WIDTH = x // where x is a number
Catch formats output intended for the console to fit within a fixed number of characters. This is especially important as indentation is used extensively and uncontrolled line wraps break this.
By default a console width of 80 is assumed but this can be controlled by defining the above identifier to be a different value.
# stdout
CATCH_CONFIG_NOSTDOUT
Catch does not use ```std::cout``` and ```std::cerr``` directly but gets them from ```Catch::cout()``` and ```Catch::cerr()``` respectively. If the above identifier is defined these functions are left unimplemented and you must implement them yourself. Their signatures are:
std::ostream& cout();
std::ostream& cerr();
This can be useful on certain platforms that do not provide ```std::cout``` and ```std::cerr```, such as certain embedded systems.
# C++ conformance toggles
CATCH_CONFIG_CPP11_NULLPTR
CATCH_CONFIG_CPP11_NOEXCEPT
CATCH_CONFIG_SFINAE // Basic, C++03, support for SFINAE
CATCH_CONFIG_VARIADIC_MACROS // Usually pre-C++11 compiler extensions are sufficient
CATCH_CONFIG_NO_VARIADIC_MACROS // Suppress if Catch is too eager to enable it
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.
---
[Home](Readme.md)

View File

@ -16,8 +16,8 @@ In addition to the include files and IDE projects there are a number of tests in
The other directories are ```scripts``` which contains a set of python scripts to help in testing Catch as well as generating the single include, and docs, which contains the documentation as a set of markdown files. The other directories are ```scripts``` which contains a set of python scripts to help in testing Catch as well as generating the single include, and docs, which contains the documentation as a set of markdown files.
*This document is a work in progress and will be updated soon with new information.* *this document is in-progress...*
--- ---
[Home](../README.md) [Home](Readme.md)

View File

@ -49,4 +49,4 @@ These macros are now deprecated and are just aliases for INFO and CAPTURE (which
--- ---
[Home](../README.md) [Home](Readme.md)

View File

@ -47,9 +47,9 @@ int main( int argc, char* const argv[] )
if( returnCode != 0 ) // Indicates a command line error if( returnCode != 0 ) // Indicates a command line error
return returnCode; return returnCode;
// Writing to session.configData() or session.Config() here // writing to session.configData() or session.Config() here
// overrides command line args. // overrides command line args
// Only do this if you know you need to. // only do this if you know you need to
return session.run(); return session.run();
} }
@ -65,4 +65,4 @@ Catch embeds a powerful command line parser which you can also use to parse your
--- ---
[Home](../README.md) [Home](Readme.md)

View File

@ -19,4 +19,4 @@ As a result the main source file *does* compile the whole of Catch every time! S
--- ---
[Home](../README.md) [Home](Readme.md)

View File

@ -9,7 +9,7 @@ Test cases and sections are very easy to use in practice:
* **TEST_CASE(** _test name_ \[, _tags_ \] **)** * **TEST_CASE(** _test name_ \[, _tags_ \] **)**
* **SECTION(** _section name_ **)** * **SECTION(** _section name_ **)**
_test name_ and _section name_ are free-form quoted strings. The optional _tags_ argument is a quoted string containing one or more tags enclosed in square brackets. Tags are discussed below. Test names must be unique within the Catch executable. _test name_ and _section name_ are free form, quoted, strings. The optional _tags_ argument is a quoted string containing one or more tags enclosed in square brackets. Tags are discussed below. Test names must be unique within the Catch executable.
For examples see the [Tutorial](tutorial.md) For examples see the [Tutorial](tutorial.md)
@ -57,4 +57,4 @@ Other than the additional prefixes and the formatting in the console reporter th
--- ---
[Home](../README.md) [Home](Readme.md)

View File

@ -1,4 +1,4 @@
Although Catch allows you to group tests together as sections within a test case, it can still be convenient, sometimes, to group them using a more traditional test fixture. Catch fully supports this too. You define the test fixture as a simple structure: Although Catch allows you to group tests together as sections within a test case, it can still convenient, sometimes, to group them using a more traditional test fixture. Catch fully supports this too. You define the test fixture as a simple structure:
```c++ ```c++
class UniqueTestsFixture { class UniqueTestsFixture {
@ -29,4 +29,4 @@ The two test cases here will create uniquely-named derived classes of UniqueTest
--- ---
[Home](../README.md) [Home](Readme.md)

46
docs/tostring.md Normal file
View File

@ -0,0 +1,46 @@
# String conversions
Catch needs to be able to convert types you use in assertions and logging expressions into strings (for logging and reporting purposes).
Most built-in or std types are supported out of the box but there are two ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
## operator << overload for std::ostream
This is the standard way of providing string conversions in C++ - and the chances are you may already provide this for your own purposes. If you're not familiar with this idiom it involves writing a free function of the form:
```
std::ostream& operator << ( std::ostream& os, T const& value ) {
os << convertMyTypeToString( value );
return os;
}
```
(where ```T``` is your type and ```convertMyTypeToString``` is where you'll write whatever code is necessary to make your type printable - it doesn't have to be in another function).
You should put this function in the same namespace as your type.
Alternatively you may prefer to write it as a member function:
```
std::ostream& T::operator << ( std::ostream& os ) const {
os << convertMyTypeToString( *this );
return os;
}
```
## Catch::toString overload
If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide an overload for ```Catch::toString()``` for your type.
```
namespace Catch {
std::string toString( T const& value ) {
return convertMyTypeToString( value );
}
}
```
Again ```T``` is your type and ```convertMyTypeToString``` is where you'll write whatever code is necessary to make your type printable. Note that the function must be in the Catch namespace, which itself must be in the global namespace.
---
[Home](Readme.md)

View File

@ -86,10 +86,10 @@ Of course there are still more issues to do deal with. For example we'll hit pro
Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take moment to consider those before we move on. Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take moment to consider those before we move on.
1. All we did was ```#define``` one identifier and ```#include``` one header and we got everything - even an implementation of ```main()``` that will [respond to command line arguments](command-line.md). You can only use that ```#define``` in one implementation file, for (hopefully) obvious reasons. Once you have more than one file with unit tests in you'll just ```#include "catch.hpp"``` and go. Usually it's a good idea to have a dedicated implementation file that just has ```#define CATCH_CONFIG_MAIN``` and ```#include "catch.hpp"```. You can also provide your own implementation of main and drive Catch yourself (see [Supplying-your-own-main()](own-main.md). 1. All we did was ```#define``` one identifier and ```#include``` one header and we got everything - even an implementation of ```main()``` that will [respond to command line arguments](command-line.md). You can only use that ```#define``` in one implementation file, for (hopefully) obvious reasons. Once you have more than one file with unit tests in you'll just ```#include "catch.hpp"``` and go. Usually it's a good idea to have a dedicated implementation file that just has ```#define CATCH_CONFIG_MAIN``` and ```#include "catch.hpp"```. You can also provide your own implementation of main and drive Catch yourself (see [Supplying-your-own-main()](own-main.md)).
2. We introduce test cases with the TEST_CASE macro. This macro takes one or two arguments - a free form test name and, optionally, one or more tags (for more see <a href="#test-cases-and-sections">Test cases and Sections</a>, below. The test name must be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [command line docs](command-line.md) for more information on running tests. 2. We introduce test cases with the ```TEST_CASE``` macro. This macro takes one or two arguments - a free form test name and, optionally, one or more tags (for more see <a href="#test-cases-and-sections">Test cases and Sections</a>, below. The test name must be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [command line docs](command-line.md) for more information on running tests.
3. The name and tags arguments are just strings. We haven't had to declare a function or method - or explicitly register the test case anywhere. Behind the scenes a function with a generated name is defined for you, and automatically registered using static registry classes. By abstracting the function name away we can name our tests without the constraints of identifier names. 3. The name and tags arguments are just strings. We haven't had to declare a function or method - or explicitly register the test case anywhere. Behind the scenes a function with a generated name is defined for you, and automatically registered using static registry classes. By abstracting the function name away we can name our tests without the constraints of identifier names.
4. We write our individual test assertions using the REQUIRE macro. Rather than a separate macro for each type of condition we express the condition naturally using C/C++ syntax. Behind the scenes a simple set of expression templates captures the left-hand-side and right-hand-side of the expression so we can display the values in our test report. As we'll see later there _are_ other assertion macros - but because of this technique the number of them is drastically reduced. 4. We write our individual test assertions using the ```REQUIRE``` macro. Rather than a separate macro for each type of condition we express the condition naturally using C/C++ syntax. Behind the scenes a simple set of expression templates captures the left-hand-side and right-hand-side of the expression so we can display the values in our test report. As we'll see later there _are_ other assertion macros - but because of this technique the number of them is drastically reduced.
<a id="test-cases-and-sections"></a> <a id="test-cases-and-sections"></a>
## Test cases and sections ## Test cases and sections
@ -157,7 +157,7 @@ The power of sections really shows, however, when we need to execute a sequence
} }
``` ```
Sections can be nested to an arbitrary depth (limited only by your stack size). Each leaf section (i.e. a section that contains no nested sections) will be executed exactly once, on a separate path of execution from any other leaf section (so no leaf section can interfere with another). Obviously a failure in a parent section will prevent nested sections from running - but that's the idea. Sections can be nested to an arbitrary depth (limited only by your stack size). Each leaf section (i.e. a section that contains no nested sections) will be executed exactly once, on a separate path of execution from any other leaf section (so no leaf section can interfere with another). A failure in a parent section will prevent nested sections from running - but then that's the idea.
## BDD-Style ## BDD-Style
@ -220,9 +220,11 @@ Scenario: vectors can be sized and resized
``` ```
## Next steps ## Next steps
For more specific information see the [Reference pages](Readme.md)
This has been a brief introduction to get you up and running with Catch, and to point out some of the key differences between Catch and other frameworks you may already be familiar with. This will get you going quite far already and you are now in a position to dive in and write some tests.
Of course there is more to learn - most of which you should be able to page-fault in as you go. Please see the every-growing [Reference section](Readme.md) for what's available.
--- ---
[Home](../README.md) [Home](Readme.md)

View File

@ -21,4 +21,4 @@ If you find any issues please raise issue tickets on the [issue tracker on GitHu
--- ---
[Home](../README.md) [Home](Readme.md)

View File

@ -39,4 +39,4 @@ See the [tutorial](tutorial.md) to get more of a taste of using CATCH in practic
--- ---
[Home](../README.md) [Home](Readme.md)

View File

@ -11,11 +11,11 @@
#include "internal/catch_suppress_warnings.h" #include "internal/catch_suppress_warnings.h"
#ifdef CATCH_CONFIG_MAIN #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
# define CATCH_CONFIG_RUNNER # define CATCH_IMPL
#endif #endif
#ifdef CATCH_CONFIG_RUNNER #ifdef CATCH_IMPL
# ifndef CLARA_CONFIG_MAIN # ifndef CLARA_CONFIG_MAIN
# define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN_NOT_DEFINED
# define CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN
@ -43,7 +43,7 @@
#include "internal/catch_objc.hpp" #include "internal/catch_objc.hpp"
#endif #endif
#ifdef CATCH_CONFIG_RUNNER #ifdef CATCH_IMPL
#include "internal/catch_impl.hpp" #include "internal/catch_impl.hpp"
#endif #endif

View File

@ -60,6 +60,14 @@ namespace Catch {
m_testsAlreadyRun.insert( *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 ); context.testGroupEnded( "all tests", totals, 1, 1 );
return totals; return totals;
} }
@ -97,7 +105,7 @@ namespace Catch {
std::set<TestCase> m_testsAlreadyRun; std::set<TestCase> m_testsAlreadyRun;
}; };
class Session { class Session : NonCopyable {
static bool alreadyInstantiated; static bool alreadyInstantiated;
public: public:
@ -108,7 +116,7 @@ namespace Catch {
: m_cli( makeCommandLineParser() ) { : m_cli( makeCommandLineParser() ) {
if( alreadyInstantiated ) { if( alreadyInstantiated ) {
std::string msg = "Only one instance of Catch::Session can ever be used"; std::string msg = "Only one instance of Catch::Session can ever be used";
std::cerr << msg << std::endl; Catch::cerr() << msg << std::endl;
throw std::logic_error( msg ); throw std::logic_error( msg );
} }
alreadyInstantiated = true; alreadyInstantiated = true;
@ -118,15 +126,15 @@ namespace Catch {
} }
void showHelp( std::string const& processName ) { void showHelp( std::string const& processName ) {
std::cout << "\nCatch v" << libraryVersion.majorVersion << "." Catch::cout() << "\nCatch v" << libraryVersion.majorVersion << "."
<< libraryVersion.minorVersion << " build " << libraryVersion.minorVersion << " build "
<< libraryVersion.buildNumber; << libraryVersion.buildNumber;
if( libraryVersion.branchName != std::string( "master" ) ) if( libraryVersion.branchName != std::string( "master" ) )
std::cout << " (" << libraryVersion.branchName << " branch)"; Catch::cout() << " (" << libraryVersion.branchName << " branch)";
std::cout << "\n"; Catch::cout() << "\n";
m_cli.usage( std::cout, processName ); m_cli.usage( Catch::cout(), processName );
std::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 argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
@ -140,11 +148,11 @@ namespace Catch {
catch( std::exception& ex ) { catch( std::exception& ex ) {
{ {
Colour colourGuard( Colour::Red ); Colour colourGuard( Colour::Red );
std::cerr << "\nError(s) in input:\n" Catch::cerr() << "\nError(s) in input:\n"
<< Text( ex.what(), TextAttributes().setIndent(2) ) << Text( ex.what(), TextAttributes().setIndent(2) )
<< "\n\n"; << "\n\n";
} }
m_cli.usage( std::cout, m_configData.processName ); m_cli.usage( Catch::cout(), m_configData.processName );
return (std::numeric_limits<int>::max)(); return (std::numeric_limits<int>::max)();
} }
return 0; return 0;
@ -170,6 +178,9 @@ namespace Catch {
try try
{ {
config(); // Force config to be constructed config(); // Force config to be constructed
std::srand( m_configData.rngSeed );
Runner runner( m_config ); Runner runner( m_config );
// Handle list request // Handle list request
@ -179,7 +190,7 @@ namespace Catch {
return static_cast<int>( runner.runTests().assertions.failed ); return static_cast<int>( runner.runTests().assertions.failed );
} }
catch( std::exception& ex ) { catch( std::exception& ex ) {
std::cerr << ex.what() << std::endl; Catch::cerr() << ex.what() << std::endl;
return (std::numeric_limits<int>::max)(); return (std::numeric_limits<int>::max)();
} }
} }

View File

@ -620,7 +620,7 @@ namespace Clara {
m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
{ {
if( other.m_floatingArg.get() ) if( other.m_floatingArg.get() )
m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) ); m_floatingArg.reset( new Arg( *other.m_floatingArg ) );
} }
CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
@ -649,7 +649,7 @@ namespace Clara {
ArgBuilder operator[]( UnpositionalTag ) { ArgBuilder operator[]( UnpositionalTag ) {
if( m_floatingArg.get() ) if( m_floatingArg.get() )
throw std::logic_error( "Only one unpositional argument can be added" ); throw std::logic_error( "Only one unpositional argument can be added" );
m_floatingArg = ArgAutoPtr( new Arg() ); m_floatingArg.reset( new Arg() );
ArgBuilder builder( m_floatingArg.get() ); ArgBuilder builder( m_floatingArg.get() );
return builder; return builder;
} }
@ -791,7 +791,7 @@ namespace Clara {
if( it == itEnd ) { if( it == itEnd ) {
if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
unusedTokens.push_back( token ); unusedTokens.push_back( token );
else if( m_throwOnUnrecognisedTokens ) else if( errors.empty() && m_throwOnUnrecognisedTokens )
errors.push_back( "unrecognised option: " + token.data ); errors.push_back( "unrecognised option: " + token.data );
} }
} }

View File

@ -15,7 +15,7 @@
#include "catch_common.h" #include "catch_common.h"
#include "catch_tostring.h" #include "catch_tostring.h"
#include "catch_interfaces_runner.h" #include "catch_interfaces_runner.h"
#include "internal/catch_compiler_capabilities.h" #include "catch_compiler_capabilities.h"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -134,7 +134,7 @@
std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \
__catchResult \ __catchResult \
.setLhs( Catch::toString( arg ) ) \ .setLhs( Catch::toString( arg ) ) \
.setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
.setOp( "matches" ) \ .setOp( "matches" ) \
.setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \
__catchResult.captureExpression(); \ __catchResult.captureExpression(); \

View File

@ -29,7 +29,28 @@ namespace Catch {
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions ); config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
else else
throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
}
inline void setOrder( ConfigData& config, std::string const& order ) {
if( startsWith( "declared", order ) )
config.runOrder = RunTests::InDeclarationOrder;
else if( startsWith( "lexical", order ) )
config.runOrder = RunTests::InLexicographicalOrder;
else if( startsWith( "random", order ) )
config.runOrder = RunTests::InRandomOrder;
else
throw std::runtime_error( "Unrecognised ordering: '" + order + "'" );
}
inline void setRngSeed( ConfigData& config, std::string const& seed ) {
if( seed == "time" ) {
config.rngSeed = static_cast<unsigned int>( std::time(0) );
}
else {
std::stringstream ss;
ss << seed;
ss >> config.rngSeed;
if( ss.fail() )
throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" );
}
} }
inline void setVerbosity( ConfigData& config, int level ) { inline void setVerbosity( ConfigData& config, int level ) {
// !TBD: accept strings? // !TBD: accept strings?
@ -137,10 +158,22 @@ namespace Catch {
.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 );
cli["--order"]
.describe( "test case order (defaults to decl)" )
.bind( &setOrder, "decl|lex|rand" );
cli["--rng-seed"]
.describe( "set a specific seed for random numbers" )
.bind( &setRngSeed, "'time'|number" );
cli["--force-colour"]
.describe( "force colourised output" )
.bind( &ConfigData::forceColour );
return cli; return cli;
} }

View File

@ -24,8 +24,16 @@
namespace Catch { namespace Catch {
class NonCopyable { class NonCopyable {
NonCopyable( NonCopyable const& ); #ifdef CATCH_CPP11_OR_GREATER
void operator = ( NonCopyable const& ); NonCopyable( NonCopyable const& ) = delete;
NonCopyable( NonCopyable && ) = delete;
NonCopyable& operator = ( NonCopyable const& ) = delete;
NonCopyable& operator = ( NonCopyable && ) = delete;
#else
NonCopyable( NonCopyable const& info );
NonCopyable& operator = ( NonCopyable const& );
#endif
protected: protected:
NonCopyable() {} NonCopyable() {}
virtual ~NonCopyable(); virtual ~NonCopyable();
@ -63,6 +71,7 @@ namespace Catch {
void toLowerInPlace( std::string& s ); void toLowerInPlace( std::string& s );
std::string toLower( std::string const& s ); std::string toLower( std::string const& s );
std::string trim( std::string const& str ); std::string trim( std::string const& str );
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
struct pluralise { struct pluralise {
pluralise( std::size_t count, std::string const& label ); pluralise( std::size_t count, std::string const& label );
@ -85,6 +94,7 @@ namespace Catch {
# endif # endif
bool empty() const; bool empty() const;
bool operator == ( SourceLineInfo const& other ) const; bool operator == ( SourceLineInfo const& other ) const;
bool operator < ( SourceLineInfo const& other ) const;
std::string file; std::string file;
std::size_t line; std::size_t line;

View File

@ -36,7 +36,21 @@ 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 replaced = false;
std::size_t i = str.find( replaceThis );
while( i != std::string::npos ) {
replaced = true;
str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
if( i < str.size()-withThis.size() )
i = str.find( replaceThis, i+withThis.size() );
else
i = std::string::npos;
}
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 )
@ -64,6 +78,9 @@ namespace Catch {
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
return line == other.line && file == other.file; return line == other.line && file == other.file;
} }
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
return line < other.line || ( line == other.line && file < other.file );
}
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
#ifndef __GNUG__ #ifndef __GNUG__

View File

@ -80,6 +80,10 @@
// Visual C++ // Visual C++
#ifdef _MSC_VER #ifdef _MSC_VER
#if (_MSC_VER >= 1600)
#define CATCH_CONFIG_CPP11_NULLPTR
#endif
#if (_MSC_VER >= 1310 ) // (VC++ 7.0+) #if (_MSC_VER >= 1310 ) // (VC++ 7.0+)
//#define CATCH_CONFIG_SFINAE // Not confirmed //#define CATCH_CONFIG_SFINAE // Not confirmed
#endif #endif

View File

@ -17,6 +17,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <ctime>
#ifndef CATCH_CONFIG_CONSOLE_WIDTH #ifndef CATCH_CONFIG_CONSOLE_WIDTH
#define CATCH_CONFIG_CONSOLE_WIDTH 80 #define CATCH_CONFIG_CONSOLE_WIDTH 80
@ -36,10 +37,13 @@ namespace Catch {
noThrow( false ), noThrow( false ),
showHelp( false ), showHelp( false ),
showInvisibles( false ), showInvisibles( false ),
forceColour( false ),
abortAfter( -1 ), abortAfter( -1 ),
rngSeed( 0 ),
verbosity( Verbosity::Normal ), verbosity( Verbosity::Normal ),
warnings( WarnAbout::Nothing ), warnings( WarnAbout::Nothing ),
showDurations( ShowDurations::DefaultForReporter ) showDurations( ShowDurations::DefaultForReporter ),
runOrder( RunTests::InDeclarationOrder )
{} {}
bool listTests; bool listTests;
@ -52,12 +56,15 @@ namespace Catch {
bool noThrow; bool noThrow;
bool showHelp; bool showHelp;
bool showInvisibles; bool showInvisibles;
bool forceColour;
int abortAfter; int abortAfter;
unsigned int rngSeed;
Verbosity::Level verbosity; Verbosity::Level verbosity;
WarnAbout::What warnings; WarnAbout::What warnings;
ShowDurations::OrNot showDurations; ShowDurations::OrNot showDurations;
RunTests::InWhatOrder runOrder;
std::string reporterName; std::string reporterName;
std::string outputFilename; std::string outputFilename;
@ -76,12 +83,12 @@ namespace Catch {
public: public:
Config() Config()
: m_os( std::cout.rdbuf() ) : m_os( Catch::cout().rdbuf() )
{} {}
Config( ConfigData const& data ) Config( ConfigData const& data )
: m_data( data ), : m_data( data ),
m_os( std::cout.rdbuf() ) m_os( Catch::cout().rdbuf() )
{ {
if( !data.testsOrTags.empty() ) { if( !data.testsOrTags.empty() ) {
TestSpecParser parser( ITagAliasRegistry::get() ); TestSpecParser parser( ITagAliasRegistry::get() );
@ -92,7 +99,7 @@ namespace Catch {
} }
virtual ~Config() { virtual ~Config() {
m_os.rdbuf( std::cout.rdbuf() ); m_os.rdbuf( Catch::cout().rdbuf() );
m_stream.release(); m_stream.release();
} }
@ -114,7 +121,7 @@ namespace Catch {
bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
void setStreamBuf( std::streambuf* buf ) { void setStreamBuf( std::streambuf* buf ) {
m_os.rdbuf( buf ? buf : std::cout.rdbuf() ); m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() );
} }
void useStream( std::string const& streamName ) { void useStream( std::string const& streamName ) {
@ -126,7 +133,6 @@ namespace Catch {
std::string getReporterName() const { return m_data.reporterName; } std::string getReporterName() const { return m_data.reporterName; }
int abortAfter() const { return m_data.abortAfter; } int abortAfter() const { return m_data.abortAfter; }
TestSpec const& testSpec() const { return m_testSpec; } TestSpec const& testSpec() const { return m_testSpec; }
@ -141,7 +147,9 @@ namespace Catch {
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; }
virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; }
virtual unsigned int rngSeed() const { return m_data.rngSeed; }
virtual bool forceColour() const { return m_data.forceColour; }
private: private:
ConfigData m_data; ConfigData m_data;

View File

@ -12,10 +12,6 @@
namespace Catch { namespace Catch {
namespace Detail {
struct IColourImpl;
}
struct Colour { struct Colour {
enum Code { enum Code {
None = 0, None = 0,
@ -61,7 +57,6 @@ namespace Catch {
static void use( Code _colourCode ); static void use( Code _colourCode );
private: private:
static Detail::IColourImpl* impl();
bool m_moved; bool m_moved;
}; };

View File

@ -10,14 +10,36 @@
#include "catch_console_colour.hpp" #include "catch_console_colour.hpp"
namespace Catch { namespace Detail { namespace Catch {
struct IColourImpl { namespace {
virtual ~IColourImpl() {}
virtual void use( Colour::Code _colourCode ) = 0;
};
}}
#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// struct IColourImpl {
virtual ~IColourImpl() {}
virtual void use( Colour::Code _colourCode ) = 0;
};
struct NoColourImpl : IColourImpl {
void use( Colour::Code ) {}
static IColourImpl* instance() {
static NoColourImpl s_instance;
return &s_instance;
}
};
} // anon namespace
} // namespace Catch
#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
# ifdef CATCH_PLATFORM_WINDOWS
# define CATCH_CONFIG_COLOUR_WINDOWS
# else
# define CATCH_CONFIG_COLOUR_ANSI
# endif
#endif
#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
#ifndef NOMINMAX #ifndef NOMINMAX
#define NOMINMAX #define NOMINMAX
@ -32,7 +54,7 @@ namespace Catch { namespace Detail {
namespace Catch { namespace Catch {
namespace { namespace {
class Win32ColourImpl : public Detail::IColourImpl { class Win32ColourImpl : public IColourImpl {
public: public:
Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
{ {
@ -69,11 +91,7 @@ namespace {
WORD originalAttributes; WORD originalAttributes;
}; };
inline bool shouldUseColourForPlatform() { IColourImpl* platformColourInstance() {
return true;
}
static Detail::IColourImpl* platformColourInstance() {
static Win32ColourImpl s_instance; static Win32ColourImpl s_instance;
return &s_instance; return &s_instance;
} }
@ -81,7 +99,7 @@ namespace {
} // end anon namespace } // end anon namespace
} // end namespace Catch } // end namespace Catch
#else // Not Windows - assumed to be POSIX compatible ////////////////////////// #elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
#include <unistd.h> #include <unistd.h>
@ -92,7 +110,7 @@ namespace {
// Thanks to Adam Strzelecki for original contribution // Thanks to Adam Strzelecki for original contribution
// (http://github.com/nanoant) // (http://github.com/nanoant)
// https://github.com/philsquared/Catch/pull/131 // https://github.com/philsquared/Catch/pull/131
class PosixColourImpl : public Detail::IColourImpl { class PosixColourImpl : public IColourImpl {
public: public:
virtual void use( Colour::Code _colourCode ) { virtual void use( Colour::Code _colourCode ) {
switch( _colourCode ) { switch( _colourCode ) {
@ -113,53 +131,48 @@ namespace {
case Colour::Bright: throw std::logic_error( "not a colour" ); case Colour::Bright: throw std::logic_error( "not a colour" );
} }
} }
static IColourImpl* instance() {
static PosixColourImpl s_instance;
return &s_instance;
}
private: private:
void setColour( const char* _escapeCode ) { void setColour( const char* _escapeCode ) {
std::cout << '\033' << _escapeCode; Catch::cout() << '\033' << _escapeCode;
} }
}; };
inline bool shouldUseColourForPlatform() { IColourImpl* platformColourInstance() {
return isatty(STDOUT_FILENO); Ptr<IConfig const> config = getCurrentContext().getConfig();
} return (config && config->forceColour()) || isatty(STDOUT_FILENO)
? PosixColourImpl::instance()
static Detail::IColourImpl* platformColourInstance() { : NoColourImpl::instance();
static PosixColourImpl s_instance;
return &s_instance;
} }
} // end anon namespace } // end anon namespace
} // end namespace Catch } // end namespace Catch
#endif // not Windows #else // not Windows or ANSI ///////////////////////////////////////////////
namespace Catch { namespace Catch {
namespace { static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
struct NoColourImpl : Detail::IColourImpl {
void use( Colour::Code ) {}
static IColourImpl* instance() { } // end namespace Catch
static NoColourImpl s_instance;
return &s_instance; #endif // Windows/ ANSI/ None
}
}; namespace Catch {
static bool shouldUseColour() {
return shouldUseColourForPlatform() && !isDebuggerActive();
}
}
Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; } Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
Colour::~Colour(){ if( !m_moved ) use( None ); } Colour::~Colour(){ if( !m_moved ) use( None ); }
void Colour::use( Code _colourCode ) {
impl()->use( _colourCode );
}
Detail::IColourImpl* Colour::impl() { void Colour::use( Code _colourCode ) {
return shouldUseColour() static IColourImpl* impl = isDebuggerActive()
? platformColourInstance() ? NoColourImpl::instance()
: NoColourImpl::instance(); : platformColourInstance();
impl->use( _colourCode );
} }
} // end namespace Catch } // end namespace Catch

View File

@ -60,7 +60,7 @@ namespace Catch {
std::string testName = getResultCapture()->getCurrentTestName(); std::string testName = getResultCapture()->getCurrentTestName();
std::map<std::string, IGeneratorsForTest*>::const_iterator it = std::map<std::string, IGeneratorsForTest*>::const_iterator it =
m_generatorsByTestName.find( testName ); m_generatorsByTestName.find( testName );
return it != m_generatorsByTestName.end() return it != m_generatorsByTestName.end()
? it->second ? it->second
: NULL; : NULL;
@ -96,8 +96,8 @@ namespace Catch {
} }
Stream createStream( std::string const& streamName ) { Stream createStream( std::string const& streamName ) {
if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false ); if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false );
if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false ); if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false );
if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true ); if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
throw std::domain_error( "Unknown stream: " + streamName ); throw std::domain_error( "Unknown stream: " + streamName );

View File

@ -51,7 +51,7 @@
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, NULL, 0) != 0 ) {
std::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;
} }
@ -92,7 +92,7 @@
namespace Catch { namespace Catch {
void writeToDebugConsole( std::string const& text ) { void writeToDebugConsole( std::string const& text ) {
// !TBD: Need a version for Mac/ XCode and other IDEs // !TBD: Need a version for Mac/ XCode and other IDEs
std::cout << text; Catch::cout() << text;
} }
} }
#endif // Platform #endif // Platform

View File

@ -35,7 +35,7 @@ namespace Catch {
throw; throw;
} }
@catch (NSException *exception) { @catch (NSException *exception) {
return toString( [exception description] ); return Catch::toString( [exception description] );
} }
#else #else
throw; throw;

View File

@ -0,0 +1,85 @@
/*
* Created by Phil on 21/08/2014
* Copyright 2014 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_FATAL_CONDITION_H_INCLUDED
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
namespace Catch {
// Report the error condition then exit the process
inline void fatal( std::string const& message, int exitCode ) {
IContext& context = Catch::getCurrentContext();
IResultCapture* resultCapture = context.getResultCapture();
resultCapture->handleFatalErrorCondition( message );
if( Catch::alwaysTrue() ) // avoids "no return" warnings
exit( exitCode );
}
} // namespace Catch
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
namespace Catch {
struct FatalConditionHandler {
void reset() {}
};
} // namespace Catch
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
#include <signal.h>
namespace Catch {
struct SignalDefs { int id; const char* name; };
extern SignalDefs signalDefs[];
SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
{ SIGILL, "SIGILL - Illegal instruction signal" },
{ SIGFPE, "SIGFPE - Floating point error signal" },
{ SIGSEGV, "SIGSEGV - Segmentation violation signal" },
{ SIGTERM, "SIGTERM - Termination request signal" },
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
};
struct FatalConditionHandler {
static void handleSignal( int sig ) {
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
if( sig == signalDefs[i].id )
fatal( signalDefs[i].name, -sig );
fatal( "<unknown signal>", -sig );
}
FatalConditionHandler() : m_isSet( true ) {
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
signal( signalDefs[i].id, handleSignal );
}
~FatalConditionHandler() {
reset();
}
void reset() {
if( m_isSet ) {
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
signal( signalDefs[i].id, SIG_DFL );
m_isSet = false;
}
}
bool m_isSet;
};
} // namespace Catch
#endif // not Windows
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED

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_runner.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"
@ -88,8 +88,6 @@ namespace Catch {
Matchers::Impl::StdString::EndsWith::~EndsWith() {} Matchers::Impl::StdString::EndsWith::~EndsWith() {}
void Config::dummy() {} void Config::dummy() {}
INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
} }
#ifdef __clang__ #ifdef __clang__

View File

@ -35,6 +35,8 @@ namespace Catch {
virtual std::string getCurrentTestName() const = 0; virtual std::string getCurrentTestName() const = 0;
virtual const AssertionResult* getLastResult() const = 0; virtual const AssertionResult* getLastResult() const = 0;
virtual void handleFatalErrorCondition( std::string const& message ) = 0;
}; };
IResultCapture& getResultCapture(); IResultCapture& getResultCapture();

View File

@ -32,6 +32,11 @@ namespace Catch {
Always, Always,
Never Never
}; }; }; };
struct RunTests { enum InWhatOrder {
InDeclarationOrder,
InLexicographicalOrder,
InRandomOrder
}; };
class TestSpec; class TestSpec;
@ -49,6 +54,9 @@ namespace Catch {
virtual bool showInvisibles() const = 0; virtual bool showInvisibles() const = 0;
virtual ShowDurations::OrNot showDurations() const = 0; virtual ShowDurations::OrNot showDurations() const = 0;
virtual TestSpec const& testSpec() const = 0; virtual TestSpec const& testSpec() const = 0;
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
virtual bool forceColour() const = 0;
}; };
} }

View File

@ -238,11 +238,14 @@ namespace Catch
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
// 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;
}; };

View File

@ -28,7 +28,7 @@ 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 ) const = 0; virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const = 0;
}; };
} }

View File

@ -50,6 +50,7 @@ namespace Catch
virtual void testCaseEnded( TestCaseStats const& testCaseStats ); virtual void testCaseEnded( TestCaseStats const& testCaseStats );
virtual void testGroupEnded( TestGroupStats const& testGroupStats ); virtual void testGroupEnded( TestGroupStats const& testGroupStats );
virtual void testRunEnded( TestRunStats const& testRunStats ); virtual void testRunEnded( TestRunStats const& testRunStats );
virtual void skipTest( TestCaseInfo const& );
private: private:
Ptr<IReporter> m_legacyReporter; Ptr<IReporter> m_legacyReporter;

View File

@ -77,6 +77,8 @@ namespace Catch
void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
m_legacyReporter->EndTesting( testRunStats.totals ); m_legacyReporter->EndTesting( testRunStats.totals );
} }
void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
}
} }
#endif // TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED #endif // TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED

View File

@ -23,9 +23,9 @@ namespace Catch {
TestSpec testSpec = config.testSpec(); TestSpec testSpec = config.testSpec();
if( config.testSpec().hasFilters() ) if( config.testSpec().hasFilters() )
std::cout << "Matching test cases:\n"; Catch::cout() << "Matching test cases:\n";
else { else {
std::cout << "All available test cases:\n"; Catch::cout() << "All available test cases:\n";
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
} }
@ -46,15 +46,15 @@ namespace Catch {
: Colour::None; : Colour::None;
Colour colourGuard( colour ); Colour colourGuard( colour );
std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl; Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
if( !testCaseInfo.tags.empty() ) if( !testCaseInfo.tags.empty() )
std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
} }
if( !config.testSpec().hasFilters() ) if( !config.testSpec().hasFilters() )
std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl; Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
else else
std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
return matchedTests; return matchedTests;
} }
@ -70,7 +70,7 @@ namespace Catch {
++it ) { ++it ) {
matchedTests++; matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
std::cout << testCaseInfo.name << std::endl; Catch::cout() << testCaseInfo.name << std::endl;
} }
return matchedTests; return matchedTests;
} }
@ -96,9 +96,9 @@ namespace Catch {
inline std::size_t listTags( Config const& config ) { inline std::size_t listTags( Config const& config ) {
TestSpec testSpec = config.testSpec(); TestSpec testSpec = config.testSpec();
if( config.testSpec().hasFilters() ) if( config.testSpec().hasFilters() )
std::cout << "Tags for matching test cases:\n"; Catch::cout() << "Tags for matching test cases:\n";
else { else {
std::cout << "All available tags:\n"; Catch::cout() << "All available tags:\n";
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
} }
@ -132,14 +132,14 @@ namespace Catch {
.setInitialIndent( 0 ) .setInitialIndent( 0 )
.setIndent( oss.str().size() ) .setIndent( oss.str().size() )
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
std::cout << oss.str() << wrapper << "\n"; Catch::cout() << oss.str() << wrapper << "\n";
} }
std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
return tagCounts.size(); return tagCounts.size();
} }
inline std::size_t listReporters( Config const& /*config*/ ) { inline std::size_t listReporters( Config const& /*config*/ ) {
std::cout << "Available reports:\n"; Catch::cout() << "Available reporters:\n";
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
std::size_t maxNameLen = 0; std::size_t maxNameLen = 0;
@ -151,13 +151,13 @@ namespace Catch {
.setInitialIndent( 0 ) .setInitialIndent( 0 )
.setIndent( 7+maxNameLen ) .setIndent( 7+maxNameLen )
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
std::cout << " " Catch::cout() << " "
<< it->first << it->first
<< ":" << ":"
<< std::string( maxNameLen - it->first.size() + 2, ' ' ) << std::string( maxNameLen - it->first.size() + 2, ' ' )
<< wrapper << "\n"; << wrapper << "\n";
} }
std::cout << std::endl; Catch::cout() << std::endl;
return factories.size(); return factories.size();
} }

View File

@ -17,7 +17,7 @@
// NB. Any general catch headers included here must be included // NB. Any general catch headers included here must be included
// in catch.hpp first to make sure they are included by the single // in catch.hpp first to make sure they are included by the single
// header for non obj-usage // header for non obj-usage
#include "internal/catch_test_case_info.h" #include "catch_test_case_info.h"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// This protocol is really only here for (self) documenting purposes, since // This protocol is really only here for (self) documenting purposes, since

View File

@ -9,9 +9,13 @@
#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED #define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop # ifdef __ICC // icpc defines the __clang__ macro
# pragma warning(pop)
# else
# pragma clang diagnostic pop
# endif
#elif defined __GNUC__ #elif defined __GNUC__
#pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
#endif // TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED #endif // TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED

View File

@ -25,7 +25,9 @@ namespace Catch {
Exception = 0x100 | FailureBit, Exception = 0x100 | FailureBit,
ThrewException = Exception | 1, ThrewException = Exception | 1,
DidntThrowException = Exception | 2 DidntThrowException = Exception | 2,
FatalErrorCondition = 0x200 | FailureBit
}; }; }; };

View File

@ -20,6 +20,7 @@
#include "catch_test_case_tracker.hpp" #include "catch_test_case_tracker.hpp"
#include "catch_timer.h" #include "catch_timer.h"
#include "catch_result_builder.h" #include "catch_result_builder.h"
#include "catch_fatal_condition.hpp"
#include <set> #include <set>
#include <string> #include <string>
@ -209,6 +210,37 @@ namespace Catch {
return &m_lastResult; return &m_lastResult;
} }
virtual void handleFatalErrorCondition( std::string const& message ) {
ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
resultBuilder.setResultType( ResultWas::FatalErrorCondition );
resultBuilder << message;
resultBuilder.captureExpression();
handleUnfinishedSections();
// Recreate section for test case (as we will lose the one that was in scope)
TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
Counts assertions;
assertions.failed = 1;
SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
m_reporter->sectionEnded( testCaseSectionStats );
TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
Totals deltaTotals;
deltaTotals.testCases.failed = 1;
m_reporter->testCaseEnded( TestCaseStats( testInfo,
deltaTotals,
"",
"",
false ) );
m_totals.testCases.failed++;
testGroupEnded( "", m_totals, 1, 1 );
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
}
public: public:
// !TBD We need to do this another way! // !TBD We need to do this another way!
bool aborting() const { bool aborting() const {
@ -230,12 +262,12 @@ namespace Catch {
Timer timer; Timer timer;
timer.start(); timer.start();
if( m_reporter->getPreferences().shouldRedirectStdOut ) { if( m_reporter->getPreferences().shouldRedirectStdOut ) {
StreamRedirect coutRedir( std::cout, redirectedCout ); StreamRedirect coutRedir( Catch::cout(), redirectedCout );
StreamRedirect cerrRedir( std::cerr, redirectedCerr ); StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
m_activeTestCase->invoke(); invokeActiveTestCase();
} }
else { else {
m_activeTestCase->invoke(); invokeActiveTestCase();
} }
duration = timer.getElapsedSeconds(); duration = timer.getElapsedSeconds();
} }
@ -243,20 +275,9 @@ namespace Catch {
// This just means the test was aborted due to failure // This just means the test was aborted due to failure
} }
catch(...) { catch(...) {
ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(), makeUnexpectedResultBuilder().useActiveException();
m_lastAssertionInfo.lineInfo,
m_lastAssertionInfo.capturedExpression.c_str(),
m_lastAssertionInfo.resultDisposition );
exResult.useActiveException();
} }
// If sections ended prematurely due to an exception we stored their handleUnfinishedSections();
// infos here so we can tear them down outside the unwind process.
for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
itEnd = m_unfinishedSections.rend();
it != itEnd;
++it )
sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
m_unfinishedSections.clear();
m_messages.clear(); m_messages.clear();
Counts assertions = m_totals.assertions - prevAssertions; Counts assertions = m_totals.assertions - prevAssertions;
@ -272,7 +293,32 @@ namespace Catch {
m_reporter->sectionEnded( testCaseSectionStats ); m_reporter->sectionEnded( testCaseSectionStats );
} }
void invokeActiveTestCase() {
FatalConditionHandler fatalConditionHandler; // Handle signals
m_activeTestCase->invoke();
fatalConditionHandler.reset();
}
private: private:
ResultBuilder makeUnexpectedResultBuilder() const {
return ResultBuilder( m_lastAssertionInfo.macroName.c_str(),
m_lastAssertionInfo.lineInfo,
m_lastAssertionInfo.capturedExpression.c_str(),
m_lastAssertionInfo.resultDisposition );
}
void handleUnfinishedSections() {
// If sections ended prematurely due to an exception we stored their
// infos here so we can tear them down outside the unwind process.
for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
itEnd = m_unfinishedSections.rend();
it != itEnd;
++it )
sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
m_unfinishedSections.clear();
}
struct UnfinishedSections { struct UnfinishedSections {
UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
: info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )

View File

@ -16,7 +16,7 @@
namespace Catch { namespace Catch {
class Section { class Section : NonCopyable {
public: public:
Section( SectionInfo const& info ); Section( SectionInfo const& info );
~Section(); ~Section();
@ -25,15 +25,6 @@ namespace Catch {
operator bool() const; operator bool() const;
private: private:
#ifdef CATCH_CPP11_OR_GREATER
Section( Section const& ) = delete;
Section( Section && ) = delete;
Section& operator = ( Section const& ) = delete;
Section& operator = ( Section && ) = delete;
#else
Section( Section const& info );
Section& operator = ( Section const& );
#endif
SectionInfo m_info; SectionInfo m_info;
std::string m_name; std::string m_name;

View File

@ -28,6 +28,9 @@ namespace Catch {
private: private:
bool isOwned; bool isOwned;
}; };
std::ostream& cout();
std::ostream& cerr();
} }
#endif // TWOBLUECUBES_CATCH_STREAM_H_INCLUDED #endif // TWOBLUECUBES_CATCH_STREAM_H_INCLUDED

View File

@ -15,6 +15,7 @@
#include <stdexcept> #include <stdexcept>
#include <cstdio> #include <cstdio>
#include <iostream>
namespace Catch { namespace Catch {
@ -78,6 +79,15 @@ namespace Catch {
isOwned = false; isOwned = false;
} }
} }
#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions
std::ostream& cout() {
return std::cout;
}
std::ostream& cerr() {
return std::cerr;
}
#endif
} }
#endif // TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED

View File

@ -9,19 +9,24 @@
#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED #define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic ignored "-Wglobal-constructors" # ifdef __ICC // icpc defines the __clang__ macro
#pragma clang diagnostic ignored "-Wvariadic-macros" # pragma warning(push)
#pragma clang diagnostic ignored "-Wc99-extensions" # pragma warning(disable: 161 1682)
#pragma clang diagnostic ignored "-Wunused-variable" # else // __ICC
#pragma clang diagnostic push # pragma clang diagnostic ignored "-Wglobal-constructors"
#pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wvariadic-macros"
#pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc99-extensions"
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wunused-variable"
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wpadded"
# pragma clang diagnostic ignored "-Wc++98-compat"
# pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
# endif
#elif defined __GNUC__ #elif defined __GNUC__
#pragma GCC diagnostic ignored "-Wvariadic-macros" # pragma GCC diagnostic ignored "-Wvariadic-macros"
#pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wunused-variable"
#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 #endif // TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED

View File

@ -73,7 +73,7 @@ namespace Catch {
} }
catch( std::exception& ex ) { catch( std::exception& ex ) {
Colour colourGuard( Colour::Red ); Colour colourGuard( Colour::Red );
std::cerr << ex.what() << std::endl; Catch::cerr() << ex.what() << std::endl;
exit(1); exit(1);
} }
} }

View File

@ -16,7 +16,7 @@
namespace Catch { namespace Catch {
inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
if( tag == "." || if( startsWith( tag, "." ) ||
tag == "hide" || tag == "hide" ||
tag == "!hide" ) tag == "!hide" )
return TestCaseInfo::IsHidden; return TestCaseInfo::IsHidden;
@ -36,13 +36,13 @@ namespace Catch {
if( isReservedTag( tag ) ) { if( isReservedTag( tag ) ) {
{ {
Colour colourGuard( Colour::Red ); Colour colourGuard( Colour::Red );
std::cerr Catch::cerr()
<< "Tag name [" << tag << "] not allowed.\n" << "Tag name [" << tag << "] not allowed.\n"
<< "Tag names starting with non alpha-numeric characters are reserved\n"; << "Tag names starting with non alpha-numeric characters are reserved\n";
} }
{ {
Colour colourGuard( Colour::FileName ); Colour colourGuard( Colour::FileName );
std::cerr << _lineInfo << std::endl; Catch::cerr() << _lineInfo << std::endl;
} }
exit(1); exit(1);
} }
@ -70,14 +70,15 @@ namespace Catch {
} }
else { else {
if( c == ']' ) { if( c == ']' ) {
enforceNotReservedTag( tag, _lineInfo ); TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
if( prop == TestCaseInfo::IsHidden )
inTag = false;
if( tag == "hide" || tag == "." )
isHidden = true; isHidden = true;
else else if( prop == TestCaseInfo::None )
tags.insert( tag ); enforceNotReservedTag( tag, _lineInfo );
tags.insert( tag );
tag.clear(); tag.clear();
inTag = false;
} }
else else
tag += c; tag += c;

View File

@ -17,10 +17,18 @@
#include <set> #include <set>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
#include <algorithm>
namespace Catch { namespace Catch {
class TestRegistry : public ITestCaseRegistry { class TestRegistry : public ITestCaseRegistry {
struct LexSort {
bool operator() (TestCase i,TestCase j) const { return (i<j);}
};
struct RandomNumberGenerator {
int operator()( int n ) const { return std::rand() % n; }
};
public: public:
TestRegistry() : m_unnamedCount( 0 ) {} TestRegistry() : m_unnamedCount( 0 ) {}
virtual ~TestRegistry(); virtual ~TestRegistry();
@ -43,7 +51,7 @@ namespace Catch {
TestCase const& prev = *m_functions.find( testCase ); TestCase const& prev = *m_functions.find( testCase );
{ {
Colour colourGuard( Colour::Red ); Colour colourGuard( Colour::Red );
std::cerr << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" Catch::cerr() << "error: TEST_CASE( \"" << name << "\" ) already defined.\n"
<< "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n"
<< "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
} }
@ -59,18 +67,38 @@ namespace Catch {
return m_nonHiddenFunctions; return m_nonHiddenFunctions;
} }
virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const { 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(), for( std::vector<TestCase>::const_iterator it = m_functionsInOrder.begin(),
itEnd = m_functionsInOrder.end(); itEnd = m_functionsInOrder.end();
it != itEnd; it != itEnd;
++it ) { ++it ) {
if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) ) bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() );
if( includeTest != negated )
matchingTestCases.push_back( *it ); matchingTestCases.push_back( *it );
} }
sortTests( config, matchingTestCases );
} }
private: private:
static void sortTests( IConfig const& config, std::vector<TestCase>& matchingTestCases ) {
switch( config.runOrder() ) {
case RunTests::InLexicographicalOrder:
std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() );
break;
case RunTests::InRandomOrder:
{
RandomNumberGenerator rng;
std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng );
}
break;
case RunTests::InDeclarationOrder:
// already in declaration order
break;
}
}
std::set<TestCase> m_functions; std::set<TestCase> m_functions;
std::vector<TestCase> m_functionsInOrder; std::vector<TestCase> m_functionsInOrder;
std::vector<TestCase> m_nonHiddenFunctions; std::vector<TestCase> m_nonHiddenFunctions;

View File

@ -10,7 +10,7 @@
#include "catch_common.h" #include "catch_common.h"
#include "catch_interfaces_testcase.h" #include "catch_interfaces_testcase.h"
#include "internal/catch_compiler_capabilities.h" #include "catch_compiler_capabilities.h"
namespace Catch { namespace Catch {

View File

@ -22,7 +22,7 @@ namespace Catch {
public: public:
Timer() : m_ticks( 0 ) {} Timer() : m_ticks( 0 ) {}
void start(); void start();
unsigned int getElapsedNanoseconds() const; unsigned int getElapsedMicroseconds() const;
unsigned int getElapsedMilliseconds() const; unsigned int getElapsedMilliseconds() const;
double getElapsedSeconds() const; double getElapsedSeconds() const;

View File

@ -27,11 +27,11 @@ namespace Catch {
uint64_t getCurrentTicks() { uint64_t getCurrentTicks() {
static uint64_t hz=0, hzo=0; static uint64_t hz=0, hzo=0;
if (!hz) { if (!hz) {
QueryPerformanceFrequency((LARGE_INTEGER*)&hz); QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) );
QueryPerformanceCounter((LARGE_INTEGER*)&hzo); QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
} }
uint64_t t; uint64_t t;
QueryPerformanceCounter((LARGE_INTEGER*)&t); QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
return ((t-hzo)*1000000)/hz; return ((t-hzo)*1000000)/hz;
} }
#else #else
@ -46,14 +46,14 @@ namespace Catch {
void Timer::start() { void Timer::start() {
m_ticks = getCurrentTicks(); m_ticks = getCurrentTicks();
} }
unsigned int Timer::getElapsedNanoseconds() const { unsigned int Timer::getElapsedMicroseconds() const {
return static_cast<unsigned int>(getCurrentTicks() - m_ticks); return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
} }
unsigned int Timer::getElapsedMilliseconds() const { unsigned int Timer::getElapsedMilliseconds() const {
return static_cast<unsigned int>((getCurrentTicks() - m_ticks)/1000); return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
} }
double Timer::getElapsedSeconds() const { double Timer::getElapsedSeconds() const {
return (getCurrentTicks() - m_ticks)/1000000.0; return getElapsedMicroseconds()/1000000.0;
} }
} // namespace Catch } // namespace Catch

View File

@ -21,9 +21,50 @@
#include "catch_objc_arc.hpp" #include "catch_objc_arc.hpp"
#endif #endif
#ifdef CATCH_CPP11_OR_GREATER
#include <tuple>
#include <type_traits>
#endif
namespace Catch { namespace Catch {
// Why we're here.
template<typename T>
std::string toString( T const& value );
// Built in overloads
std::string toString( std::string const& value );
std::string toString( std::wstring const& value );
std::string toString( const char* const value );
std::string toString( char* const value );
std::string toString( const wchar_t* const value );
std::string toString( wchar_t* const value );
std::string toString( int value );
std::string toString( unsigned long value );
std::string toString( unsigned int value );
std::string toString( const double value );
std::string toString( const float value );
std::string toString( bool value );
std::string toString( char value );
std::string toString( signed char value );
std::string toString( unsigned char value );
#ifdef CATCH_CONFIG_CPP11_NULLPTR
std::string toString( std::nullptr_t );
#endif
#ifdef __OBJC__
std::string toString( NSString const * const& nsstring );
std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
std::string toString( NSObject* const& nsObject );
#endif
namespace Detail { namespace Detail {
extern std::string unprintableString;
// SFINAE is currently disabled by default for all compilers. // SFINAE is currently disabled by default for all compilers.
// If the non SFINAE version of IsStreamInsertable is ambiguous for you // If the non SFINAE version of IsStreamInsertable is ambiguous for you
// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE // and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
@ -64,10 +105,38 @@ namespace Detail {
#endif #endif
#if defined(CATCH_CPP11_OR_GREATER)
template<typename T,
bool IsEnum = std::is_enum<T>::value
>
struct EnumStringMaker
{
static std::string convert( T const& ) { return unprintableString; }
};
template<typename T>
struct EnumStringMaker<T,true>
{
static std::string convert( T const& v )
{
return ::Catch::toString(
static_cast<typename std::underlying_type<T>::type>(v)
);
}
};
#endif
template<bool C> template<bool C>
struct StringMakerBase { struct StringMakerBase {
#if defined(CATCH_CPP11_OR_GREATER)
template<typename T> template<typename T>
static std::string convert( T const& ) { return "{?}"; } static std::string convert( T const& v )
{
return EnumStringMaker<T>::convert( v );
}
#else
template<typename T>
static std::string convert( T const& ) { return unprintableString; }
#endif
}; };
template<> template<>
@ -89,9 +158,6 @@ namespace Detail {
} // end namespace Detail } // end namespace Detail
template<typename T>
std::string toString( T const& value );
template<typename T> template<typename T>
struct StringMaker : struct StringMaker :
Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {}; Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
@ -122,12 +188,60 @@ namespace Detail {
std::string rangeToString( InputIterator first, InputIterator last ); std::string rangeToString( InputIterator first, InputIterator last );
} }
//template<typename T, typename Allocator>
//struct StringMaker<std::vector<T, Allocator> > {
// static std::string convert( std::vector<T,Allocator> const& v ) {
// return Detail::rangeToString( v.begin(), v.end() );
// }
//};
template<typename T, typename Allocator> template<typename T, typename Allocator>
struct StringMaker<std::vector<T, Allocator> > { std::string toString( std::vector<T,Allocator> const& v ) {
static std::string convert( std::vector<T,Allocator> const& v ) { return Detail::rangeToString( v.begin(), v.end() );
return Detail::rangeToString( v.begin(), v.end() ); }
#ifdef CATCH_CPP11_OR_GREATER
// toString for tuples
namespace TupleDetail {
template<
typename Tuple,
std::size_t N = 0,
bool = (N < std::tuple_size<Tuple>::value)
>
struct ElementPrinter {
static void print( const Tuple& tuple, std::ostream& os )
{
os << ( N ? ", " : " " )
<< Catch::toString(std::get<N>(tuple));
ElementPrinter<Tuple,N+1>::print(tuple,os);
}
};
template<
typename Tuple,
std::size_t N
>
struct ElementPrinter<Tuple,N,false> {
static void print( const Tuple&, std::ostream& ) {}
};
}
template<typename ...Types>
struct StringMaker<std::tuple<Types...>> {
static std::string convert( const std::tuple<Types...>& tuple )
{
std::ostringstream os;
os << '{';
TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os );
os << " }";
return os.str();
} }
}; };
#endif
namespace Detail { namespace Detail {
template<typename T> template<typename T>
@ -148,33 +262,6 @@ std::string toString( T const& value ) {
return StringMaker<T>::convert( value ); return StringMaker<T>::convert( value );
} }
// Built in overloads
std::string toString( std::string const& value );
std::string toString( std::wstring const& value );
std::string toString( const char* const value );
std::string toString( char* const value );
std::string toString( const wchar_t* const value );
std::string toString( wchar_t* const value );
std::string toString( int value );
std::string toString( unsigned long value );
std::string toString( unsigned int value );
std::string toString( const double value );
std::string toString( const float value );
std::string toString( bool value );
std::string toString( char value );
std::string toString( signed char value );
std::string toString( unsigned char value );
#ifdef CATCH_CONFIG_CPP11_NULLPTR
std::string toString( std::nullptr_t );
#endif
#ifdef __OBJC__
std::string toString( NSString const * const& nsstring );
std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
std::string toString( NSObject* const& nsObject );
#endif
namespace Detail { namespace Detail {
template<typename InputIterator> template<typename InputIterator>
@ -182,10 +269,9 @@ std::string toString( std::nullptr_t );
std::ostringstream oss; std::ostringstream oss;
oss << "{ "; oss << "{ ";
if( first != last ) { if( first != last ) {
oss << toString( *first ); oss << Catch::toString( *first );
for( ++first ; first != last ; ++first ) { for( ++first ; first != last ; ++first )
oss << ", " << toString( *first ); oss << ", " << Catch::toString( *first );
}
} }
oss << " }"; oss << " }";
return oss.str(); return oss.str();

View File

@ -15,6 +15,8 @@ namespace Catch {
namespace Detail { namespace Detail {
std::string unprintableString = "{?}";
namespace { namespace {
struct Endianness { struct Endianness {
enum Arch { Big, Little }; enum Arch { Big, Little };
@ -73,7 +75,7 @@ std::string toString( std::wstring const& value ) {
s.reserve( value.size() ); s.reserve( value.size() );
for(size_t i = 0; i < value.size(); ++i ) for(size_t i = 0; i < value.size(); ++i )
s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?'; s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
return toString( s ); return Catch::toString( s );
} }
std::string toString( const char* const value ) { std::string toString( const char* const value ) {
@ -96,7 +98,10 @@ 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; if( value > 8192 )
oss << "0x" << std::hex << value;
else
oss << value;
return oss.str(); return oss.str();
} }
@ -110,7 +115,7 @@ std::string toString( unsigned long value ) {
} }
std::string toString( unsigned int value ) { std::string toString( unsigned int value ) {
return toString( static_cast<unsigned long>( value ) ); return Catch::toString( static_cast<unsigned long>( value ) );
} }
template<typename T> template<typename T>

View File

@ -35,6 +35,9 @@ namespace Catch {
bool allPassed() const { bool allPassed() const {
return failed == 0 && failedButOk == 0; return failed == 0 && failedButOk == 0;
} }
bool allOk() const {
return failed == 0;
}
std::size_t passed; std::size_t passed;
std::size_t failed; std::size_t failed;

View File

@ -13,7 +13,7 @@
namespace Catch { namespace Catch {
// These numbers are maintained by a script // These numbers are maintained by a script
Version libraryVersion( 1, 0, 53, "master" ); Version libraryVersion( 1, 1, 14, "develop" );
} }
#endif // TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED

View File

@ -8,8 +8,9 @@
#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 <sstream> #include <sstream>
#include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>
@ -52,7 +53,7 @@ namespace Catch {
XmlWriter() XmlWriter()
: m_tagIsOpen( false ), : m_tagIsOpen( false ),
m_needsNewline( false ), m_needsNewline( false ),
m_os( &std::cout ) m_os( &Catch::cout() )
{} {}
XmlWriter( std::ostream& os ) XmlWriter( std::ostream& os )

View File

@ -10,6 +10,8 @@
#include "../internal/catch_interfaces_reporter.h" #include "../internal/catch_interfaces_reporter.h"
#include <cstring>
namespace Catch { namespace Catch {
struct StreamingReporterBase : SharedImpl<IStreamingReporter> { struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
@ -42,7 +44,6 @@ namespace Catch {
} }
virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
currentTestCaseInfo.reset(); currentTestCaseInfo.reset();
assert( m_sectionStack.empty() );
} }
virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
currentGroupInfo.reset(); currentGroupInfo.reset();
@ -53,6 +54,11 @@ namespace Catch {
currentTestRunInfo.reset(); currentTestRunInfo.reset();
} }
virtual void skipTest( TestCaseInfo const& ) {
// Don't do anything with this by default.
// It can optionally be overridden in the derived class.
}
Ptr<IConfig> m_config; Ptr<IConfig> m_config;
std::ostream& stream; std::ostream& stream;
@ -183,6 +189,8 @@ namespace Catch {
} }
virtual void testRunEndedCumulative() = 0; virtual void testRunEndedCumulative() = 0;
virtual void skipTest( TestCaseInfo const& ) {}
Ptr<IConfig> m_config; Ptr<IConfig> m_config;
std::ostream& stream; std::ostream& stream;
std::vector<AssertionStats> m_assertions; std::vector<AssertionStats> m_assertions;
@ -198,6 +206,16 @@ namespace Catch {
}; };
template<char C>
char const* getLineOfChars() {
static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
if( !*line ) {
memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
}
return line;
}
} // end namespace Catch } // end namespace Catch
#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED

View File

@ -109,6 +109,13 @@ namespace Catch {
printExpressionWas(); printExpressionWas();
printRemainingMessages(); printRemainingMessages();
break; break;
case ResultWas::FatalErrorCondition:
printResultType( Colour::Error, failedString() );
printIssue( "fatal error condition with message:" );
printMessage();
printExpressionWas();
printRemainingMessages();
break;
case ResultWas::DidntThrowException: case ResultWas::DidntThrowException:
printResultType( Colour::Error, failedString() ); printResultType( Colour::Error, failedString() );
printIssue( "expected exception, got none" ); printIssue( "expected exception, got none" );

View File

@ -13,8 +13,6 @@
#include "../internal/catch_reporter_registrars.hpp" #include "../internal/catch_reporter_registrars.hpp"
#include "../internal/catch_console_colour.hpp" #include "../internal/catch_console_colour.hpp"
#include <cstring>
namespace Catch { namespace Catch {
struct ConsoleReporter : StreamingReporterBase { struct ConsoleReporter : StreamingReporterBase {
@ -149,6 +147,11 @@ namespace Catch {
passOrFail = "FAILED"; passOrFail = "FAILED";
messageLabel = "due to unexpected exception with message"; messageLabel = "due to unexpected exception with message";
break; break;
case ResultWas::FatalErrorCondition:
colour = Colour::Error;
passOrFail = "FAILED";
messageLabel = "due to a fatal error condition";
break;
case ResultWas::DidntThrowException: case ResultWas::DidntThrowException:
colour = Colour::Error; colour = Colour::Error;
passOrFail = "FAILED"; passOrFail = "FAILED";
@ -266,6 +269,9 @@ namespace Catch {
stream << " host application.\n" stream << " host application.\n"
<< "Run with -? for options\n\n"; << "Run with -? for options\n\n";
if( m_config->rngSeed() != 0 )
stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
currentTestRunInfo.used = true; currentTestRunInfo.used = true;
} }
void lazyPrintGroupInfo() { void lazyPrintGroupInfo() {
@ -437,15 +443,6 @@ namespace Catch {
void printSummaryDivider() { void printSummaryDivider() {
stream << getLineOfChars<'-'>() << "\n"; stream << getLineOfChars<'-'>() << "\n";
} }
template<char C>
static char const* getLineOfChars() {
static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
if( !*line ) {
memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
}
return line;
}
private: private:
bool m_headerPrinted; bool m_headerPrinted;

View File

@ -135,7 +135,7 @@ namespace Catch {
xml.writeAttribute( "classname", className ); xml.writeAttribute( "classname", className );
xml.writeAttribute( "name", name ); xml.writeAttribute( "name", name );
} }
xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) ); xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) );
writeAssertions( sectionNode ); writeAssertions( sectionNode );
@ -168,6 +168,7 @@ namespace Catch {
std::string elementName; std::string elementName;
switch( result.getResultType() ) { switch( result.getResultType() ) {
case ResultWas::ThrewException: case ResultWas::ThrewException:
case ResultWas::FatalErrorCondition:
elementName = "error"; elementName = "error";
break; break;
case ResultWas::ExplicitFailure: case ResultWas::ExplicitFailure:

View File

@ -0,0 +1,222 @@
/*
* Created by Phil Nash on 19th December 2014
* Copyright 2014 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_TEAMCITY_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
// Don't #include any Catch headers here - we can assume they are already
// included before this header.
// This is not good practice in general but is necessary in this case so this
// file can be distributed as a single header that works with the main
// Catch single header.
#include <cstring>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpadded"
#endif
namespace Catch {
struct TeamCityReporter : StreamingReporterBase {
TeamCityReporter( ReporterConfig const& _config )
: StreamingReporterBase( _config ),
m_headerPrintedForThisSection( false )
{}
static std::string escape( std::string const& str ) {
std::string escaped = str;
replaceInPlace( escaped, "|", "||" );
replaceInPlace( escaped, "'", "|'" );
replaceInPlace( escaped, "\n", "|n" );
replaceInPlace( escaped, "\r", "|r" );
replaceInPlace( escaped, "[", "|[" );
replaceInPlace( escaped, "]", "|]" );
return escaped;
}
virtual ~TeamCityReporter();
static std::string getDescription() {
return "Reports test results as TeamCity service messages";
}
virtual ReporterPreferences getPreferences() const {
ReporterPreferences prefs;
prefs.shouldRedirectStdOut = true;
return prefs;
}
virtual void skipTest( TestCaseInfo const& testInfo ) {
stream << "##teamcity[testIgnored name='"
<< escape( testInfo.name ) << "'";
if( testInfo.isHidden() )
stream << " message='hidden test'";
else
stream << " message='test skipped because it didn|'t match the test spec'";
stream << "]\n";
}
virtual void noMatchingTestCases( std::string const& /* spec */ ) {}
virtual void testGroupStarting( GroupInfo const& groupInfo ) {
StreamingReporterBase::testGroupStarting( groupInfo );
stream << "##teamcity[testSuiteStarted name='"
<< escape( groupInfo.name ) << "']\n";
}
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
StreamingReporterBase::testGroupEnded( testGroupStats );
stream << "##teamcity[testSuiteFinished name='"
<< escape( testGroupStats.groupInfo.name ) << "']\n";
}
virtual void assertionStarting( AssertionInfo const& ) {
}
virtual bool assertionEnded( AssertionStats const& assertionStats ) {
AssertionResult const& result = assertionStats.assertionResult;
if( !result.isOk() ) {
std::ostringstream msg;
if( !m_headerPrintedForThisSection )
printSectionHeader( msg );
m_headerPrintedForThisSection = true;
msg << result.getSourceInfo() << "\n";
switch( result.getResultType() ) {
case ResultWas::ExpressionFailed:
msg << "expression failed";
break;
case ResultWas::ThrewException:
msg << "unexpected exception";
break;
case ResultWas::FatalErrorCondition:
msg << "fatal error condition";
break;
case ResultWas::DidntThrowException:
msg << "no exception was thrown where one was expected";
break;
case ResultWas::ExplicitFailure:
msg << "explicit failure";
break;
// We shouldn't get here because of the isOk() test
case ResultWas::Ok:
case ResultWas::Info:
case ResultWas::Warning:
// These cases are here to prevent compiler warnings
case ResultWas::Unknown:
case ResultWas::FailureBit:
case ResultWas::Exception:
CATCH_NOT_IMPLEMENTED;
}
if( assertionStats.infoMessages.size() == 1 )
msg << " with message:";
if( assertionStats.infoMessages.size() > 1 )
msg << " with messages:";
for( std::vector<MessageInfo>::const_iterator
it = assertionStats.infoMessages.begin(),
itEnd = assertionStats.infoMessages.end();
it != itEnd;
++it )
msg << "\n \"" << it->message << "\"";
if( result.hasExpression() ) {
msg <<
"\n " << result.getExpressionInMacro() << "\n"
"with expansion:\n" <<
" " << result.getExpandedExpression() << "\n";
}
stream << "##teamcity[testFailed"
<< " name='" << escape( currentTestCaseInfo->name )<< "'"
<< " message='" << escape( msg.str() ) << "'"
<< "]\n";
}
return true;
}
virtual void sectionStarting( SectionInfo const& sectionInfo ) {
m_headerPrintedForThisSection = false;
StreamingReporterBase::sectionStarting( sectionInfo );
}
virtual void testCaseStarting( TestCaseInfo const& testInfo ) {
StreamingReporterBase::testCaseStarting( testInfo );
stream << "##teamcity[testStarted name='"
<< escape( testInfo.name ) << "']\n";
}
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
StreamingReporterBase::testCaseEnded( testCaseStats );
if( !testCaseStats.stdOut.empty() )
stream << "##teamcity[testStdOut name='"
<< escape( testCaseStats.testInfo.name )
<< "' out='" << escape( testCaseStats.stdOut ) << "']\n";
if( !testCaseStats.stdErr.empty() )
stream << "##teamcity[testStdErr name='"
<< escape( testCaseStats.testInfo.name )
<< "' out='" << escape( testCaseStats.stdErr ) << "']\n";
stream << "##teamcity[testFinished name='"
<< escape( testCaseStats.testInfo.name ) << "']\n";
}
private:
void printSectionHeader( std::ostream& os ) {
assert( !m_sectionStack.empty() );
if( m_sectionStack.size() > 1 ) {
os << getLineOfChars<'-'>() << "\n";
std::vector<SectionInfo>::const_iterator
it = m_sectionStack.begin()+1, // Skip first section (test case)
itEnd = m_sectionStack.end();
for( ; it != itEnd; ++it )
printHeaderString( os, it->name );
os << getLineOfChars<'-'>() << "\n";
}
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
if( !lineInfo.empty() )
os << lineInfo << "\n";
os << getLineOfChars<'.'>() << "\n\n";
}
// if string has a : in first line will set indent to follow it on
// subsequent lines
void printHeaderString( std::ostream& os, std::string const& _string, std::size_t indent = 0 ) {
std::size_t i = _string.find( ": " );
if( i != std::string::npos )
i+=2;
else
i = 0;
os << Text( _string, TextAttributes()
.setIndent( indent+i)
.setInitialIndent( indent ) ) << "\n";
}
private:
bool m_headerPrintedForThisSection;
};
#ifdef CATCH_IMPL
TeamCityReporter::~TeamCityReporter() {}
#endif
INTERNAL_CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter )
} // end namespace Catch
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED

View File

@ -13,83 +13,93 @@
#include "../internal/catch_capture.hpp" #include "../internal/catch_capture.hpp"
#include "../internal/catch_reporter_registrars.hpp" #include "../internal/catch_reporter_registrars.hpp"
#include "../internal/catch_xmlwriter.hpp" #include "../internal/catch_xmlwriter.hpp"
#include "../internal/catch_timer.h"
namespace Catch { namespace Catch {
class XmlReporter : public SharedImpl<IReporter> { class XmlReporter : public StreamingReporterBase {
public: public:
XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {} XmlReporter( ReporterConfig const& _config )
: StreamingReporterBase( _config ),
m_sectionDepth( 0 )
{}
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";
} }
virtual ~XmlReporter();
private: // IReporter public: // StreamingReporterBase
virtual ReporterPreferences getPreferences() const {
virtual bool shouldRedirectStdout() const { ReporterPreferences prefs;
return true; prefs.shouldRedirectStdOut = true;
return prefs;
} }
virtual void StartTesting() { virtual void noMatchingTestCases( std::string const& s ) {
m_xml.setStream( m_config.stream() ); StreamingReporterBase::noMatchingTestCases( s );
}
virtual void testRunStarting( TestRunInfo const& testInfo ) {
StreamingReporterBase::testRunStarting( testInfo );
m_xml.setStream( stream );
m_xml.startElement( "Catch" ); m_xml.startElement( "Catch" );
if( !m_config.fullConfig()->name().empty() ) if( !m_config->name().empty() )
m_xml.writeAttribute( "name", m_config.fullConfig()->name() ); m_xml.writeAttribute( "name", m_config->name() );
} }
virtual void EndTesting( const Totals& totals ) { virtual void testGroupStarting( GroupInfo const& groupInfo ) {
m_xml.scopedElement( "OverallResults" ) StreamingReporterBase::testGroupStarting( groupInfo );
.writeAttribute( "successes", totals.assertions.passed )
.writeAttribute( "failures", totals.assertions.failed )
.writeAttribute( "expectedFailures", totals.assertions.failedButOk );
m_xml.endElement();
}
virtual void StartGroup( const std::string& groupName ) {
m_xml.startElement( "Group" ) m_xml.startElement( "Group" )
.writeAttribute( "name", groupName ); .writeAttribute( "name", groupInfo.name );
} }
virtual void EndGroup( const std::string&, const Totals& totals ) { virtual void testCaseStarting( TestCaseInfo const& testInfo ) {
m_xml.scopedElement( "OverallResults" ) StreamingReporterBase::testCaseStarting(testInfo);
.writeAttribute( "successes", totals.assertions.passed ) m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
.writeAttribute( "failures", totals.assertions.failed )
.writeAttribute( "expectedFailures", totals.assertions.failedButOk ); if ( m_config->showDurations() == ShowDurations::Always )
m_xml.endElement(); m_testCaseTimer.start();
} }
virtual void StartSection( const std::string& sectionName, const std::string& description ) { virtual void sectionStarting( SectionInfo const& sectionInfo ) {
StreamingReporterBase::sectionStarting( sectionInfo );
if( m_sectionDepth++ > 0 ) { if( m_sectionDepth++ > 0 ) {
m_xml.startElement( "Section" ) m_xml.startElement( "Section" )
.writeAttribute( "name", trim( sectionName ) ) .writeAttribute( "name", trim( sectionInfo.name ) )
.writeAttribute( "description", description ); .writeAttribute( "description", sectionInfo.description );
}
}
virtual void NoAssertionsInSection( const std::string& ) {}
virtual void NoAssertionsInTestCase( const std::string& ) {}
virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) {
if( --m_sectionDepth > 0 ) {
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", assertions.passed )
.writeAttribute( "failures", assertions.failed )
.writeAttribute( "expectedFailures", assertions.failedButOk );
m_xml.endElement();
} }
} }
virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) { virtual void assertionStarting( AssertionInfo const& ) { }
m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
m_currentTestSuccess = true;
}
virtual void Result( const Catch::AssertionResult& assertionResult ) { virtual bool assertionEnded( AssertionStats const& assertionStats ) {
if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok ) const AssertionResult& assertionResult = assertionStats.assertionResult;
return;
// Print any info messages in <Info> tags.
if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
it != itEnd;
++it ) {
if( it->type == ResultWas::Info ) {
m_xml.scopedElement( "Info" )
.writeText( it->message );
} else if ( it->type == ResultWas::Warning ) {
m_xml.scopedElement( "Warning" )
.writeText( it->message );
}
}
}
// Drop out if result was successful but we're not printing them.
if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) )
return true;
// Print the expression if there is one.
if( assertionResult.hasExpression() ) { if( assertionResult.hasExpression() ) {
m_xml.startElement( "Expression" ) m_xml.startElement( "Expression" )
.writeAttribute( "success", assertionResult.succeeded() ) .writeAttribute( "success", assertionResult.succeeded() )
.writeAttribute( "type", assertionResult.getTestMacroName() )
.writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line ); .writeAttribute( "line", assertionResult.getSourceInfo().line );
@ -97,58 +107,96 @@ namespace Catch {
.writeText( assertionResult.getExpression() ); .writeText( assertionResult.getExpression() );
m_xml.scopedElement( "Expanded" ) m_xml.scopedElement( "Expanded" )
.writeText( assertionResult.getExpandedExpression() ); .writeText( assertionResult.getExpandedExpression() );
m_currentTestSuccess &= assertionResult.succeeded();
} }
// And... Print a result applicable to each result type.
switch( assertionResult.getResultType() ) { switch( assertionResult.getResultType() ) {
case ResultWas::ThrewException: case ResultWas::ThrewException:
m_xml.scopedElement( "Exception" ) m_xml.scopedElement( "Exception" )
.writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeAttribute( "line", assertionResult.getSourceInfo().line )
.writeText( assertionResult.getMessage() ); .writeText( assertionResult.getMessage() );
m_currentTestSuccess = false; break;
case ResultWas::FatalErrorCondition:
m_xml.scopedElement( "Fatal Error Condition" )
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line )
.writeText( assertionResult.getMessage() );
break; break;
case ResultWas::Info: case ResultWas::Info:
m_xml.scopedElement( "Info" ) m_xml.scopedElement( "Info" )
.writeText( assertionResult.getMessage() ); .writeText( assertionResult.getMessage() );
break; break;
case ResultWas::Warning: case ResultWas::Warning:
m_xml.scopedElement( "Warning" ) // Warning will already have been written
.writeText( assertionResult.getMessage() );
break; break;
case ResultWas::ExplicitFailure: case ResultWas::ExplicitFailure:
m_xml.scopedElement( "Failure" ) m_xml.scopedElement( "Failure" )
.writeText( assertionResult.getMessage() ); .writeText( assertionResult.getMessage() );
m_currentTestSuccess = false;
break; break;
case ResultWas::Unknown: default:
case ResultWas::Ok:
case ResultWas::FailureBit:
case ResultWas::ExpressionFailed:
case ResultWas::Exception:
case ResultWas::DidntThrowException:
break; break;
} }
if( assertionResult.hasExpression() ) if( assertionResult.hasExpression() )
m_xml.endElement(); m_xml.endElement();
return true;
} }
virtual void Aborted() { virtual void sectionEnded( SectionStats const& sectionStats ) {
// !TBD StreamingReporterBase::sectionEnded( sectionStats );
if( --m_sectionDepth > 0 ) {
XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
e.writeAttribute( "successes", sectionStats.assertions.passed );
e.writeAttribute( "failures", sectionStats.assertions.failed );
e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
if ( m_config->showDurations() == ShowDurations::Always )
e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
m_xml.endElement();
}
} }
virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) { virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess ); StreamingReporterBase::testCaseEnded( testCaseStats );
XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
if ( m_config->showDurations() == ShowDurations::Always )
e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
m_xml.endElement();
}
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
StreamingReporterBase::testGroupEnded( testGroupStats );
// TODO: Check testGroupStats.aborting and act accordingly.
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", testGroupStats.totals.assertions.passed )
.writeAttribute( "failures", testGroupStats.totals.assertions.failed )
.writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
m_xml.endElement();
}
virtual void testRunEnded( TestRunStats const& testRunStats ) {
StreamingReporterBase::testRunEnded( testRunStats );
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", testRunStats.totals.assertions.passed )
.writeAttribute( "failures", testRunStats.totals.assertions.failed )
.writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
m_xml.endElement(); m_xml.endElement();
} }
private: private:
ReporterConfig m_config; Timer m_testCaseTimer;
bool m_currentTestSuccess;
XmlWriter m_xml; XmlWriter m_xml;
int m_sectionDepth; int m_sectionDepth;
}; };
INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
} // end namespace Catch } // end namespace Catch
#endif // TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED

View File

@ -6,6 +6,11 @@ project(Catch)
get_filename_component(CATCH_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CATCH_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
get_filename_component(CATCH_DIR "${CATCH_DIR}" PATH) get_filename_component(CATCH_DIR "${CATCH_DIR}" PATH)
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest) set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
if(USE_CPP11)
## We can't turn this on by default, since it breaks on travis
message(STATUS "Enabling C++11")
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
endif()
# define the sources of the self test # define the sources of the self test
set(SOURCES set(SOURCES
@ -21,6 +26,11 @@ set(SOURCES
${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
${SELF_TEST_DIR}/EnumToString.cpp
${SELF_TEST_DIR}/ToStringPair.cpp
${SELF_TEST_DIR}/ToStringVector.cpp
${SELF_TEST_DIR}/ToStringWhich.cpp
${SELF_TEST_DIR}/ToStringTuple.cpp
) )
# configure the executable # configure the executable

View File

@ -1,6 +1,6 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CatchSelfTest is a <version> host application. CatchSelfTest is a <version> (develop) host application.
Run with -? for options Run with -? for options
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -737,7 +737,7 @@ with expansion:
hello hello
hello hello
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Where the is more to the expression after the RHS[failing] Where there is more to the expression after the RHS
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
............................................................................... ...............................................................................
@ -748,7 +748,7 @@ warning:
error error
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Where the LHS is not a simple value[failing] Where the LHS is not a simple value
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
............................................................................... ...............................................................................
@ -759,7 +759,7 @@ warning:
error error
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
A failing expression with a non streamable type is still captured[failing] A failing expression with a non streamable type is still captured
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
............................................................................... ...............................................................................
@ -775,7 +775,7 @@ with expansion:
{?} == {?} {?} == {?}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
string literals of different sizes can be compared[failing] string literals of different sizes can be compared
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
............................................................................... ...............................................................................
@ -786,6 +786,6 @@ with expansion:
"first" == "second" "first" == "second"
=============================================================================== ===============================================================================
test cases: 130 | 91 passed | 38 failed | 1 failed as expected test cases: 155 | 116 passed | 38 failed | 1 failed as expected
assertions: 709 | 617 passed | 79 failed | 13 failed as expected assertions: 765 | 673 passed | 79 failed | 13 failed as expected

View File

@ -1,8 +1,88 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CatchSelfTest is a <version> host application. CatchSelfTest is a <version> (develop) host application.
Run with -? for options Run with -? for options
-------------------------------------------------------------------------------
toString(enum)
-------------------------------------------------------------------------------
EnumToString.cpp:<line number>
...............................................................................
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e0) == "0" )
with expansion:
"0" == "0"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e1) == "1" )
with expansion:
"1" == "1"
-------------------------------------------------------------------------------
toString(enum w/operator<<)
-------------------------------------------------------------------------------
EnumToString.cpp:<line number>
...............................................................................
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e0) == "E2{0}" )
with expansion:
"E2{0}" == "E2{0}"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e1) == "E2{1}" )
with expansion:
"E2{1}" == "E2{1}"
-------------------------------------------------------------------------------
toString(enum class)
-------------------------------------------------------------------------------
EnumToString.cpp:<line number>
...............................................................................
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e0) == "0" )
with expansion:
"0" == "0"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e1) == "1" )
with expansion:
"1" == "1"
-------------------------------------------------------------------------------
toString(enum class w/operator<<)
-------------------------------------------------------------------------------
EnumToString.cpp:<line number>
...............................................................................
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e0) == "E2/V0" )
with expansion:
"E2/V0" == "E2/V0"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e1) == "E2/V1" )
with expansion:
"E2/V1" == "E2/V1"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e3) == "Unknown enum value 10" )
with expansion:
"Unknown enum value 10"
==
"Unknown enum value 10"
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Some simple comparisons between doubles Some simple comparisons between doubles
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -3318,7 +3398,7 @@ MiscTests.cpp:<line number>:
PASSED: PASSED:
REQUIRE( Factorial(10) == 3628800 ) REQUIRE( Factorial(10) == 3628800 )
with expansion: with expansion:
0x<hex digits> == 3628800 0x<hex digits> == 0x<hex digits>
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
An empty test with no assertions An empty test with no assertions
@ -3985,6 +4065,42 @@ PASSED:
with expansion: with expansion:
true == true true == true
-------------------------------------------------------------------------------
Process can be configured on command line
force-colour
--force-colour
-------------------------------------------------------------------------------
TestMain.cpp:<line number>
...............................................................................
TestMain.cpp:<line number>:
PASSED:
CHECK_NOTHROW( parseIntoConfig( argv, config ) )
TestMain.cpp:<line number>:
PASSED:
REQUIRE( config.forceColour )
with expansion:
true
-------------------------------------------------------------------------------
Process can be configured on command line
force-colour
without --force-colour
-------------------------------------------------------------------------------
TestMain.cpp:<line number>
...............................................................................
TestMain.cpp:<line number>:
PASSED:
CHECK_NOTHROW( parseIntoConfig( argv, config ) )
TestMain.cpp:<line number>:
PASSED:
REQUIRE( !config.forceColour )
with expansion:
true
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Long strings can be wrapped Long strings can be wrapped
plain string plain string
@ -4438,6 +4554,139 @@ with expansion:
five five
six" six"
-------------------------------------------------------------------------------
replaceInPlace
replace single char
-------------------------------------------------------------------------------
TestMain.cpp:<line number>
...............................................................................
TestMain.cpp:<line number>:
PASSED:
CHECK( replaceInPlace( letters, "b", "z" ) )
with expansion:
true
TestMain.cpp:<line number>:
PASSED:
CHECK( letters == "azcdefcg" )
with expansion:
"azcdefcg" == "azcdefcg"
-------------------------------------------------------------------------------
replaceInPlace
replace two chars
-------------------------------------------------------------------------------
TestMain.cpp:<line number>
...............................................................................
TestMain.cpp:<line number>:
PASSED:
CHECK( replaceInPlace( letters, "c", "z" ) )
with expansion:
true
TestMain.cpp:<line number>:
PASSED:
CHECK( letters == "abzdefzg" )
with expansion:
"abzdefzg" == "abzdefzg"
-------------------------------------------------------------------------------
replaceInPlace
replace first char
-------------------------------------------------------------------------------
TestMain.cpp:<line number>
...............................................................................
TestMain.cpp:<line number>:
PASSED:
CHECK( replaceInPlace( letters, "a", "z" ) )
with expansion:
true
TestMain.cpp:<line number>:
PASSED:
CHECK( letters == "zbcdefcg" )
with expansion:
"zbcdefcg" == "zbcdefcg"
-------------------------------------------------------------------------------
replaceInPlace
replace last char
-------------------------------------------------------------------------------
TestMain.cpp:<line number>
...............................................................................
TestMain.cpp:<line number>:
PASSED:
CHECK( replaceInPlace( letters, "g", "z" ) )
with expansion:
true
TestMain.cpp:<line number>:
PASSED:
CHECK( letters == "abcdefcz" )
with expansion:
"abcdefcz" == "abcdefcz"
-------------------------------------------------------------------------------
replaceInPlace
replace all chars
-------------------------------------------------------------------------------
TestMain.cpp:<line number>
...............................................................................
TestMain.cpp:<line number>:
PASSED:
CHECK( replaceInPlace( letters, letters, "replaced" ) )
with expansion:
true
TestMain.cpp:<line number>:
PASSED:
CHECK( letters == "replaced" )
with expansion:
"replaced" == "replaced"
-------------------------------------------------------------------------------
replaceInPlace
replace no chars
-------------------------------------------------------------------------------
TestMain.cpp:<line number>
...............................................................................
TestMain.cpp:<line number>:
PASSED:
CHECK_FALSE( replaceInPlace( letters, "x", "z" ) )
with expansion:
!false
TestMain.cpp:<line number>:
PASSED:
CHECK( letters == letters )
with expansion:
"abcdefcg" == "abcdefcg"
-------------------------------------------------------------------------------
replaceInPlace
escape '
-------------------------------------------------------------------------------
TestMain.cpp:<line number>
...............................................................................
TestMain.cpp:<line number>:
PASSED:
CHECK( replaceInPlace( s, "'", "|'" ) )
with expansion:
true
TestMain.cpp:<line number>:
PASSED:
CHECK( s == "didn|'t" )
with expansion:
"didn|'t" == "didn|'t"
hello hello
hello hello
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -5496,7 +5745,7 @@ with expansion:
std::pair( 1, 2 ) == std::pair( 1, 2 ) std::pair( 1, 2 ) == std::pair( 1, 2 )
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Where the is more to the expression after the RHS[failing] Where there is more to the expression after the RHS
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
............................................................................... ...............................................................................
@ -5507,10 +5756,10 @@ warning:
error error
No assertions in test case 'Where the is more to the expression after the RHS[failing]' No assertions in test case 'Where there is more to the expression after the RHS'
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Where the LHS is not a simple value[failing] Where the LHS is not a simple value
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
............................................................................... ...............................................................................
@ -5521,10 +5770,10 @@ warning:
error error
No assertions in test case 'Where the LHS is not a simple value[failing]' No assertions in test case 'Where the LHS is not a simple value'
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
A failing expression with a non streamable type is still captured[failing] A failing expression with a non streamable type is still captured
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
............................................................................... ...............................................................................
@ -5540,7 +5789,7 @@ with expansion:
{?} == {?} {?} == {?}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
string literals of different sizes can be compared[failing] string literals of different sizes can be compared
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
............................................................................... ...............................................................................
@ -5905,6 +6154,234 @@ TrickyTests.cpp:<line number>
TrickyTests.cpp:<line number>: TrickyTests.cpp:<line number>:
PASSED: PASSED:
-------------------------------------------------------------------------------
toString( has_toString )
-------------------------------------------------------------------------------
ToStringWhich.cpp:<line number>
...............................................................................
ToStringWhich.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString( item ) == "toString( has_toString )" )
with expansion:
"toString( has_toString )"
==
"toString( has_toString )"
-------------------------------------------------------------------------------
toString( has_maker )
-------------------------------------------------------------------------------
ToStringWhich.cpp:<line number>
...............................................................................
ToStringWhich.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString( item ) == "StringMaker<has_maker>" )
with expansion:
"StringMaker<has_maker>"
==
"StringMaker<has_maker>"
-------------------------------------------------------------------------------
toString( has_maker_and_toString )
-------------------------------------------------------------------------------
ToStringWhich.cpp:<line number>
...............................................................................
ToStringWhich.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString( item ) == "toString( has_maker_and_toString )" )
with expansion:
"toString( has_maker_and_toString )"
==
"toString( has_maker_and_toString )"
-------------------------------------------------------------------------------
toString( vectors<has_toString )
-------------------------------------------------------------------------------
ToStringWhich.cpp:<line number>
...............................................................................
ToStringWhich.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString( v ) == "{ {?} }" )
with expansion:
"{ {?} }" == "{ {?} }"
-------------------------------------------------------------------------------
toString( vectors<has_maker )
-------------------------------------------------------------------------------
ToStringWhich.cpp:<line number>
...............................................................................
ToStringWhich.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString( v ) == "{ StringMaker<has_maker> }" )
with expansion:
"{ StringMaker<has_maker> }"
==
"{ StringMaker<has_maker> }"
-------------------------------------------------------------------------------
toString( vectors<has_maker_and_toString )
-------------------------------------------------------------------------------
ToStringWhich.cpp:<line number>
...............................................................................
ToStringWhich.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString( v ) == "{ StringMaker<has_maker_and_toString> }" )
with expansion:
"{ StringMaker<has_maker_and_toString> }"
==
"{ StringMaker<has_maker_and_toString> }"
-------------------------------------------------------------------------------
std::pair<int,std::string> -> toString
-------------------------------------------------------------------------------
ToStringPair.cpp:<line number>
...............................................................................
ToStringPair.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString( value ) == "{ 34, \"xyzzy\" }" )
with expansion:
"{ 34, "xyzzy" }" == "{ 34, "xyzzy" }"
-------------------------------------------------------------------------------
std::pair<int,const std::string> -> toString
-------------------------------------------------------------------------------
ToStringPair.cpp:<line number>
...............................................................................
ToStringPair.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(value) == "{ 34, \"xyzzy\" }" )
with expansion:
"{ 34, "xyzzy" }" == "{ 34, "xyzzy" }"
-------------------------------------------------------------------------------
std::vector<std::pair<std::string,int> > -> toString
-------------------------------------------------------------------------------
ToStringPair.cpp:<line number>
...............................................................................
ToStringPair.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString( pr ) == "{ { \"green\", 55 } }" )
with expansion:
"{ { "green", 55 } }"
==
"{ { "green", 55 } }"
-------------------------------------------------------------------------------
pair<pair<int,const char *,pair<std::string,int> > -> toString
-------------------------------------------------------------------------------
ToStringPair.cpp:<line number>
...............................................................................
ToStringPair.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" )
with expansion:
"{ { 42, "Arthur" }, { "Ford", 24 } }"
==
"{ { 42, "Arthur" }, { "Ford", 24 } }"
-------------------------------------------------------------------------------
vector<int> -> toString
-------------------------------------------------------------------------------
ToStringVector.cpp:<line number>
...............................................................................
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(vv) == "{ }" )
with expansion:
"{ }" == "{ }"
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(vv) == "{ 42 }" )
with expansion:
"{ 42 }" == "{ 42 }"
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(vv) == "{ 42, 512 }" )
with expansion:
"{ 42, 512 }" == "{ 42, 512 }"
-------------------------------------------------------------------------------
vector<string> -> toString
-------------------------------------------------------------------------------
ToStringVector.cpp:<line number>
...............................................................................
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(vv) == "{ }" )
with expansion:
"{ }" == "{ }"
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(vv) == "{ \"hello\" }" )
with expansion:
"{ "hello" }" == "{ "hello" }"
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(vv) == "{ \"hello\", \"world\" }" )
with expansion:
"{ "hello", "world" }"
==
"{ "hello", "world" }"
-------------------------------------------------------------------------------
vector<int,allocator> -> toString
-------------------------------------------------------------------------------
ToStringVector.cpp:<line number>
...............................................................................
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(vv) == "{ }" )
with expansion:
"{ }" == "{ }"
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(vv) == "{ 42 }" )
with expansion:
"{ 42 }" == "{ 42 }"
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(vv) == "{ 42, 512 }" )
with expansion:
"{ 42, 512 }" == "{ 42, 512 }"
-------------------------------------------------------------------------------
vec<vec<string,alloc>> -> toString
-------------------------------------------------------------------------------
ToStringVector.cpp:<line number>
...............................................................................
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(v) == "{ }" )
with expansion:
"{ }" == "{ }"
ToStringVector.cpp:<line number>:
PASSED:
REQUIRE( Catch::toString(v) == "{ { \"hello\" }, { \"world\" } }" )
with expansion:
"{ { "hello" }, { "world" } }"
==
"{ { "hello" }, { "world" } }"
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Parse test names and tags Parse test names and tags
Empty test spec should have no filters Empty test spec should have no filters
@ -6932,6 +7409,96 @@ PASSED:
with expansion: with expansion:
true == true true == true
-------------------------------------------------------------------------------
tuple<>
-------------------------------------------------------------------------------
ToStringTuple.cpp:<line number>
...............................................................................
ToStringTuple.cpp:<line number>:
PASSED:
CHECK( "{ }" == Catch::toString(type{}) )
with expansion:
"{ }" == "{ }"
ToStringTuple.cpp:<line number>:
PASSED:
CHECK( "{ }" == Catch::toString(value) )
with expansion:
"{ }" == "{ }"
-------------------------------------------------------------------------------
tuple<int>
-------------------------------------------------------------------------------
ToStringTuple.cpp:<line number>
...............................................................................
ToStringTuple.cpp:<line number>:
PASSED:
CHECK( "{ 0 }" == Catch::toString(type{0}) )
with expansion:
"{ 0 }" == "{ 0 }"
-------------------------------------------------------------------------------
tuple<float,int>
-------------------------------------------------------------------------------
ToStringTuple.cpp:<line number>
...............................................................................
ToStringTuple.cpp:<line number>:
PASSED:
CHECK( "1.2f" == Catch::toString(float(1.2)) )
with expansion:
"1.2f" == "1.2f"
ToStringTuple.cpp:<line number>:
PASSED:
CHECK( "{ 1.2f, 0 }" == Catch::toString(type{1.2,0}) )
with expansion:
"{ 1.2f, 0 }" == "{ 1.2f, 0 }"
-------------------------------------------------------------------------------
tuple<string,string>
-------------------------------------------------------------------------------
ToStringTuple.cpp:<line number>
...............................................................................
ToStringTuple.cpp:<line number>:
PASSED:
CHECK( "{ \"hello\", \"world\" }" == Catch::toString(type{"hello","world"}) )
with expansion:
"{ "hello", "world" }"
==
"{ "hello", "world" }"
-------------------------------------------------------------------------------
tuple<tuple<int>,tuple<>,float>
-------------------------------------------------------------------------------
ToStringTuple.cpp:<line number>
...............................................................................
ToStringTuple.cpp:<line number>:
PASSED:
CHECK( "{ { 42 }, { }, 1.2f }" == Catch::toString(value) )
with expansion:
"{ { 42 }, { }, 1.2f }"
==
"{ { 42 }, { }, 1.2f }"
-------------------------------------------------------------------------------
tuple<nullptr,int,const char *>
-------------------------------------------------------------------------------
ToStringTuple.cpp:<line number>
...............................................................................
ToStringTuple.cpp:<line number>:
PASSED:
CHECK( "{ nullptr, 42, \"Catch me\" }" == Catch::toString(value) )
with expansion:
"{ nullptr, 42, "Catch me" }"
==
"{ nullptr, 42, "Catch me" }"
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Tag alias can be registered against tag patterns Tag alias can be registered against tag patterns
The same tag alias can only be registered once The same tag alias can only be registered once
@ -7375,6 +7942,6 @@ with expansion:
true true
=============================================================================== ===============================================================================
test cases: 130 | 75 passed | 54 failed | 1 failed as expected test cases: 155 | 100 passed | 54 failed | 1 failed as expected
assertions: 729 | 617 passed | 99 failed | 13 failed as expected assertions: 785 | 673 passed | 99 failed | 13 failed as expected

View File

@ -1,8 +1,88 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CatchSelfTest is a <version> host application. CatchSelfTest is a <version> (develop) host application.
Run with -? for options Run with -? for options
-------------------------------------------------------------------------------
toString(enum)
-------------------------------------------------------------------------------
EnumToString.cpp:<line number>
...............................................................................
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e0) == "0" )
with expansion:
"0" == "0"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e1) == "1" )
with expansion:
"1" == "1"
-------------------------------------------------------------------------------
toString(enum w/operator<<)
-------------------------------------------------------------------------------
EnumToString.cpp:<line number>
...............................................................................
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e0) == "E2{0}" )
with expansion:
"E2{0}" == "E2{0}"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e1) == "E2{1}" )
with expansion:
"E2{1}" == "E2{1}"
-------------------------------------------------------------------------------
toString(enum class)
-------------------------------------------------------------------------------
EnumToString.cpp:<line number>
...............................................................................
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e0) == "0" )
with expansion:
"0" == "0"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e1) == "1" )
with expansion:
"1" == "1"
-------------------------------------------------------------------------------
toString(enum class w/operator<<)
-------------------------------------------------------------------------------
EnumToString.cpp:<line number>
...............................................................................
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e0) == "E2/V0" )
with expansion:
"E2/V0" == "E2/V0"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e1) == "E2/V1" )
with expansion:
"E2/V1" == "E2/V1"
EnumToString.cpp:<line number>:
PASSED:
CHECK( Catch::toString(e3) == "Unknown enum value 10" )
with expansion:
"Unknown enum value 10"
==
"Unknown enum value 10"
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Some simple comparisons between doubles Some simple comparisons between doubles
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -406,6 +486,6 @@ with expansion:
9.1f != Approx( 9.1000003815 ) 9.1f != Approx( 9.1000003815 )
=============================================================================== ===============================================================================
test cases: 15 | 11 passed | 3 failed | 1 failed as expected test cases: 19 | 15 passed | 3 failed | 1 failed as expected
assertions: 53 | 47 passed | 4 failed | 2 failed as expected assertions: 62 | 56 passed | 4 failed | 2 failed as expected

View File

@ -1,5 +1,9 @@
<testsuites> <testsuites>
<testsuite name="all tests" errors="12" failures="87" tests="729" hostname="tbd" time="{duration}" timestamp="tbd"> <testsuite name="all tests" errors="12" failures="87" tests="785" hostname="tbd" time="{duration}" timestamp="tbd">
<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 class)" time="{duration}"/>
<testcase classname="global" name="toString(enum class w/operator&lt;&lt;)" time="{duration}"/>
<testcase classname="global" name="Some simple comparisons between doubles" time="{duration}"/> <testcase classname="global" name="Some simple comparisons between doubles" time="{duration}"/>
<testcase classname="global" name="Approximate comparisons with different epsilons" time="{duration}"/> <testcase classname="global" name="Approximate comparisons with different epsilons" time="{duration}"/>
<testcase classname="global" name="Approximate comparisons with floats" time="{duration}"/> <testcase classname="global" name="Approximate comparisons with floats" time="{duration}"/>
@ -469,6 +473,8 @@ MiscTests.cpp:<line number>
<testcase classname="Process can be configured on command line" name="output filename/-o filename" time="{duration}"/> <testcase classname="Process can be configured on command line" name="output filename/-o filename" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="output filename/--out" time="{duration}"/> <testcase classname="Process can be configured on command line" name="output filename/--out" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="combinations/Single character flags can be combined" time="{duration}"/> <testcase classname="Process can be configured on command line" name="combinations/Single character flags can be combined" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="force-colour/--force-colour" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="force-colour/without --force-colour" time="{duration}"/>
<testcase classname="Long strings can be wrapped" name="plain string/No wrapping" time="{duration}"/> <testcase classname="Long strings can be wrapped" name="plain string/No wrapping" time="{duration}"/>
<testcase classname="Long strings can be wrapped" name="plain string/Wrapped once" time="{duration}"/> <testcase classname="Long strings can be wrapped" name="plain string/Wrapped once" time="{duration}"/>
<testcase classname="Long strings can be wrapped" name="plain string/Wrapped twice" time="{duration}"/> <testcase classname="Long strings can be wrapped" name="plain string/Wrapped twice" time="{duration}"/>
@ -481,6 +487,13 @@ MiscTests.cpp:<line number>
<testcase classname="Long strings can be wrapped" name="With newlines/Wrapped once" time="{duration}"/> <testcase classname="Long strings can be wrapped" name="With newlines/Wrapped once" time="{duration}"/>
<testcase classname="Long strings can be wrapped" name="With newlines/Wrapped twice" time="{duration}"/> <testcase classname="Long strings can be wrapped" name="With newlines/Wrapped twice" time="{duration}"/>
<testcase classname="Long strings can be wrapped" name="With tabs" time="{duration}"/> <testcase classname="Long strings can be wrapped" name="With tabs" time="{duration}"/>
<testcase classname="replaceInPlace" name="replace single char" time="{duration}"/>
<testcase classname="replaceInPlace" name="replace two chars" time="{duration}"/>
<testcase classname="replaceInPlace" name="replace first char" time="{duration}"/>
<testcase classname="replaceInPlace" name="replace last char" time="{duration}"/>
<testcase classname="replaceInPlace" name="replace all chars" time="{duration}"/>
<testcase classname="replaceInPlace" name="replace no chars" time="{duration}"/>
<testcase classname="replaceInPlace" name="escape '" time="{duration}"/>
<testcase classname="global" name="Strings can be rendered with colour" time="{duration}"> <testcase classname="global" name="Strings can be rendered with colour" time="{duration}">
<system-out> <system-out>
hello hello
@ -490,9 +503,9 @@ hello
<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="Parsing a std::pair" time="{duration}"/> <testcase classname="global" name="Parsing a std::pair" time="{duration}"/>
<testcase classname="global" name="Where the is more to the expression after the RHS[failing]" 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[failing]" time="{duration}"/> <testcase classname="global" name="Where the LHS is not a simple value" time="{duration}"/>
<testcase classname="global" name="A failing expression with a non streamable type is still captured[failing]" time="{duration}"> <testcase classname="global" name="A failing expression with a non streamable type is still captured" time="{duration}">
<failure message="0x<hex digits> == 0x<hex digits>" type="CHECK"> <failure message="0x<hex digits> == 0x<hex digits>" type="CHECK">
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
</failure> </failure>
@ -500,7 +513,7 @@ TrickyTests.cpp:<line number>
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
</failure> </failure>
</testcase> </testcase>
<testcase classname="global" name="string literals of different sizes can be compared[failing]" time="{duration}"> <testcase classname="global" name="string literals of different sizes can be compared" time="{duration}">
<failure message="&quot;first&quot; == &quot;second&quot;" type="REQUIRE"> <failure message="&quot;first&quot; == &quot;second&quot;" type="REQUIRE">
TrickyTests.cpp:<line number> TrickyTests.cpp:<line number>
</failure> </failure>
@ -529,6 +542,20 @@ TrickyTests.cpp:<line number>
<testcase classname="global" name="X/level/0/b" time="{duration}"/> <testcase classname="global" name="X/level/0/b" time="{duration}"/>
<testcase classname="global" name="X/level/1/a" time="{duration}"/> <testcase classname="global" name="X/level/1/a" time="{duration}"/>
<testcase classname="global" name="X/level/1/b" time="{duration}"/> <testcase classname="global" name="X/level/1/b" time="{duration}"/>
<testcase classname="global" name="toString( has_toString )" time="{duration}"/>
<testcase classname="global" name="toString( has_maker )" time="{duration}"/>
<testcase classname="global" name="toString( has_maker_and_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_and_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::vector&lt;std::pair&lt;std::string,int> > -> toString" time="{duration}"/>
<testcase classname="global" name="pair&lt;pair&lt;int,const char *,pair&lt;std::string,int> > -> toString" time="{duration}"/>
<testcase classname="global" name="vector&lt;int> -> toString" time="{duration}"/>
<testcase classname="global" name="vector&lt;string> -> toString" time="{duration}"/>
<testcase classname="global" name="vector&lt;int,allocator> -> toString" time="{duration}"/>
<testcase classname="global" name="vec&lt;vec&lt;string,alloc>> -> toString" time="{duration}"/>
<testcase classname="Parse test names and tags" name="Empty test spec should have no filters" time="{duration}"/> <testcase classname="Parse test names and tags" name="Empty test spec should have no filters" time="{duration}"/>
<testcase classname="Parse test names and tags" name="Test spec from empty string should have no filters" time="{duration}"/> <testcase classname="Parse test names and tags" name="Test spec from empty string should have no filters" time="{duration}"/>
<testcase classname="Parse test names and tags" name="Test spec from just a comma should have no filters" time="{duration}"/> <testcase classname="Parse test names and tags" name="Test spec from just a comma should have no filters" time="{duration}"/>
@ -560,6 +587,12 @@ TrickyTests.cpp:<line number>
<testcase classname="Parse test names and tags" name="empty tag" time="{duration}"/> <testcase classname="Parse test names and tags" name="empty tag" time="{duration}"/>
<testcase classname="Parse test names and tags" name="empty quoted name" time="{duration}"/> <testcase classname="Parse test names and tags" name="empty quoted name" time="{duration}"/>
<testcase classname="Parse test names and tags" name="quoted string followed by tag exclusion" time="{duration}"/> <testcase classname="Parse test names and tags" name="quoted string followed by tag exclusion" time="{duration}"/>
<testcase classname="global" name="tuple&lt;>" time="{duration}"/>
<testcase classname="global" name="tuple&lt;int>" time="{duration}"/>
<testcase classname="global" name="tuple&lt;float,int>" time="{duration}"/>
<testcase classname="global" name="tuple&lt;string,string>" time="{duration}"/>
<testcase classname="global" name="tuple&lt;tuple&lt;int>,tuple&lt;>,float>" time="{duration}"/>
<testcase classname="global" name="tuple&lt;nullptr,int,const char *>" time="{duration}"/>
<testcase classname="Tag alias can be registered against tag patterns" name="The same tag alias can only be registered once" time="{duration}"/> <testcase classname="Tag alias can be registered against tag patterns" name="The same tag alias can only be registered once" time="{duration}"/>
<testcase classname="Tag alias can be registered against tag patterns" name="Tag aliases must be of the form [@name]" time="{duration}"/> <testcase classname="Tag alias can be registered against tag patterns" name="Tag aliases must be of the form [@name]" time="{duration}"/>
<testcase classname="global" name="Anonymous test case 1" time="{duration}"/> <testcase classname="global" name="Anonymous test case 1" time="{duration}"/>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
#include "catch.hpp"
/*
TODO: maybe ought to check that user-provided specialisations of
Catch::toString also do the right thing
*/
// Enum without user-provided stream operator
enum Enum1 { Enum1Value0, Enum1Value1 };
TEST_CASE( "toString(enum)", "[toString][enum]" ) {
Enum1 e0 = Enum1Value0;
CHECK( Catch::toString(e0) == "0" );
Enum1 e1 = Enum1Value1;
CHECK( Catch::toString(e1) == "1" );
}
// Enum with user-provided stream operator
enum Enum2 { Enum2Value0, Enum2Value1 };
inline std::ostream& operator<<( std::ostream& os, Enum2 v ) {
return os << "E2{" << static_cast<int>(v) << "}";
}
TEST_CASE( "toString(enum w/operator<<)", "[toString][enum]" ) {
Enum2 e0 = Enum2Value0;
CHECK( Catch::toString(e0) == "E2{0}" );
Enum2 e1 = Enum2Value1;
CHECK( Catch::toString(e1) == "E2{1}" );
}
#if defined(CATCH_CPP11_OR_GREATER)
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc++98-compat"
#endif
// Enum class without user-provided stream operator
enum class EnumClass1 { EnumClass1Value0, EnumClass1Value1 };
TEST_CASE( "toString(enum class)", "[toString][enum][enumClass]" ) {
EnumClass1 e0 = EnumClass1::EnumClass1Value0;
CHECK( Catch::toString(e0) == "0" );
EnumClass1 e1 = EnumClass1::EnumClass1Value1;
CHECK( Catch::toString(e1) == "1" );
}
// Enum class with user-provided stream operator
enum class EnumClass2 : short { EnumClass2Value0, EnumClass2Value1 };
inline std::ostream& operator<<( std::ostream& os, EnumClass2 e2 ) {
switch( static_cast<int>( e2 ) ) {
case static_cast<int>( EnumClass2::EnumClass2Value0 ):
return os << "E2/V0";
case static_cast<int>( EnumClass2::EnumClass2Value1 ):
return os << "E2/V1";
default:
return os << "Unknown enum value " << static_cast<int>( e2 );
}
}
TEST_CASE( "toString(enum class w/operator<<)", "[toString][enum][enumClass]" ) {
EnumClass2 e0 = EnumClass2::EnumClass2Value0;
CHECK( Catch::toString(e0) == "E2/V0" );
EnumClass2 e1 = EnumClass2::EnumClass2Value1;
CHECK( Catch::toString(e1) == "E2/V1" );
EnumClass2 e3 = static_cast<EnumClass2>(10);
CHECK( Catch::toString(e3) == "Unknown enum value 10" );
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif // CATCH_CPP11_OR_GREATER

View File

@ -380,3 +380,9 @@ TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
std::string result = Catch::toString( s ); std::string result = Catch::toString( s );
CHECK( result == "\"wide load\"" ); CHECK( result == "\"wide load\"" );
} }
//TEST_CASE( "Divide by Zero signal handler", "[.][sig]" ) {
// int i = 0;
// int x = 10/i; // This should cause the signal to fire
// CHECK( x == 0 );
//}

View File

@ -8,6 +8,7 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include "catch.hpp" #include "catch.hpp"
#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]~[.]" )
@ -181,7 +182,23 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK( config.shouldDebugBreak ); CHECK( config.shouldDebugBreak );
CHECK( config.noThrow == true ); CHECK( config.noThrow == true );
} }
} }
SECTION( "force-colour", "") {
SECTION( "--force-colour", "" ) {
const char* argv[] = { "test", "--force-colour" };
CHECK_NOTHROW( parseIntoConfig( argv, config ) );
REQUIRE( config.forceColour );
}
SECTION( "without --force-colour", "" ) {
const char* argv[] = { "test" };
CHECK_NOTHROW( parseIntoConfig( argv, config ) );
REQUIRE( !config.forceColour );
}
}
} }
@ -347,22 +364,55 @@ private:
std::vector<ColourIndex> colours; std::vector<ColourIndex> colours;
}; };
TEST_CASE( "replaceInPlace", "" ) {
std::string letters = "abcdefcg";
SECTION( "replace single char" ) {
CHECK( replaceInPlace( letters, "b", "z" ) );
CHECK( letters == "azcdefcg" );
}
SECTION( "replace two chars" ) {
CHECK( replaceInPlace( letters, "c", "z" ) );
CHECK( letters == "abzdefzg" );
}
SECTION( "replace first char" ) {
CHECK( replaceInPlace( letters, "a", "z" ) );
CHECK( letters == "zbcdefcg" );
}
SECTION( "replace last char" ) {
CHECK( replaceInPlace( letters, "g", "z" ) );
CHECK( letters == "abcdefcz" );
}
SECTION( "replace all chars" ) {
CHECK( replaceInPlace( letters, letters, "replaced" ) );
CHECK( letters == "replaced" );
}
SECTION( "replace no chars" ) {
CHECK_FALSE( replaceInPlace( letters, "x", "z" ) );
CHECK( letters == letters );
}
SECTION( "escape '" ) {
std::string s = "didn't";
CHECK( replaceInPlace( s, "'", "|'" ) );
CHECK( s == "didn|'t" );
}
}
// !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 )
.addColour( Colour::Green, -1 ); .addColour( Colour::Green, -1 );
std::cout << cs << std::endl; Catch::cout() << cs << std::endl;
} }
{ {
ColourString cs( "hello" ); ColourString cs( "hello" );
cs .addColour( Colour::Blue, 1, -2 ); cs .addColour( Colour::Blue, 1, -2 );
std::cout << cs << std::endl; Catch::cout() << cs << std::endl;
} }
} }

View File

@ -0,0 +1,47 @@
#include "catch.hpp"
// === Pair ===
namespace Catch {
// Note: If we put this in the right place in catch_tostring, then
// we can make it an overload of Catch::toString
template<typename T1, typename T2>
struct StringMaker<std::pair<T1,T2> > {
static std::string convert( const std::pair<T1,T2>& pair ) {
std::ostringstream oss;
oss << "{ "
<< toString( pair.first )
<< ", "
<< toString( pair.second )
<< " }";
return oss.str();
}
};
}
TEST_CASE( "std::pair<int,std::string> -> toString", "[toString][pair]" ) {
std::pair<int,std::string> value( 34, "xyzzy" );
REQUIRE( Catch::toString( value ) == "{ 34, \"xyzzy\" }" );
}
TEST_CASE( "std::pair<int,const std::string> -> toString", "[toString][pair]" ) {
std::pair<int,const std::string> value( 34, "xyzzy" );
REQUIRE( Catch::toString(value) == "{ 34, \"xyzzy\" }" );
}
TEST_CASE( "std::vector<std::pair<std::string,int> > -> toString", "[toString][pair]" ) {
std::vector<std::pair<std::string,int> > pr;
pr.push_back( std::make_pair("green", 55 ) );
REQUIRE( Catch::toString( pr ) == "{ { \"green\", 55 } }" );
}
// This is pretty contrived - I figure if this works, anything will...
TEST_CASE( "pair<pair<int,const char *,pair<std::string,int> > -> toString", "[toString][pair]" ) {
typedef std::pair<int,const char *> left_t;
typedef std::pair<std::string,int> right_t;
left_t left( 42, "Arthur" );
right_t right( "Ford", 24 );
std::pair<left_t,right_t> pair( left, right );
REQUIRE( Catch::toString( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" );
}

View File

@ -0,0 +1,48 @@
#include "catch.hpp"
#ifdef CATCH_CPP11_OR_GREATER
TEST_CASE( "tuple<>", "[toString][tuple]" )
{
typedef std::tuple<> type;
CHECK( "{ }" == Catch::toString(type{}) );
type value {};
CHECK( "{ }" == Catch::toString(value) );
}
TEST_CASE( "tuple<int>", "[toString][tuple]" )
{
typedef std::tuple<int> type;
CHECK( "{ 0 }" == Catch::toString(type{0}) );
}
TEST_CASE( "tuple<float,int>", "[toString][tuple]" )
{
typedef std::tuple<float,int> type;
CHECK( "1.2f" == Catch::toString(float(1.2)) );
CHECK( "{ 1.2f, 0 }" == Catch::toString(type{1.2,0}) );
}
TEST_CASE( "tuple<string,string>", "[toString][tuple]" )
{
typedef std::tuple<std::string,std::string> type;
CHECK( "{ \"hello\", \"world\" }" == Catch::toString(type{"hello","world"}) );
}
TEST_CASE( "tuple<tuple<int>,tuple<>,float>", "[toString][tuple]" )
{
typedef std::tuple<std::tuple<int>,std::tuple<>,float> type;
type value { std::tuple<int>{42}, {}, 1.2f };
CHECK( "{ { 42 }, { }, 1.2f }" == Catch::toString(value) );
}
TEST_CASE( "tuple<nullptr,int,const char *>", "[toString][tuple]" )
{
typedef std::tuple<std::nullptr_t,int,const char *> type;
type value { nullptr, 42, "Catch me" };
CHECK( "{ nullptr, 42, \"Catch me\" }" == Catch::toString(value) );
}
#endif /* #ifdef CATCH_CPP11_OR_GREATER */

View File

@ -0,0 +1,77 @@
#include "catch.hpp"
#include <vector>
// vedctor
TEST_CASE( "vector<int> -> toString", "[toString][vector]" )
{
std::vector<int> vv;
REQUIRE( Catch::toString(vv) == "{ }" );
vv.push_back( 42 );
REQUIRE( Catch::toString(vv) == "{ 42 }" );
vv.push_back( 512 );
REQUIRE( Catch::toString(vv) == "{ 42, 512 }" );
}
TEST_CASE( "vector<string> -> toString", "[toString][vector]" )
{
std::vector<std::string> vv;
REQUIRE( Catch::toString(vv) == "{ }" );
vv.push_back( "hello" );
REQUIRE( Catch::toString(vv) == "{ \"hello\" }" );
vv.push_back( "world" );
REQUIRE( Catch::toString(vv) == "{ \"hello\", \"world\" }" );
}
#if defined(CATCH_CPP11_OR_GREATER)
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc++98-compat"
#endif
/*
Note: These tests *can* be made to work with C++ < 11, but the
allocator is a lot more work...
*/
namespace {
/* Minimal Allocator */
template<typename T>
struct minimal_allocator {
typedef T value_type;
typedef std::size_t size_type;
T *allocate( size_type n ) {
return static_cast<T *>( ::operator new( n * sizeof(T) ) );
}
void deallocate( T *p, size_type /*n*/ ) {
::operator delete( static_cast<void *>(p) );
}
template<typename U>
bool operator==( const minimal_allocator<U>& ) const { return true; }
template<typename U>
bool operator!=( const minimal_allocator<U>& ) const { return false; }
};
}
TEST_CASE( "vector<int,allocator> -> toString", "[toString][vector,allocator]" ) {
std::vector<int,minimal_allocator<int> > vv;
REQUIRE( Catch::toString(vv) == "{ }" );
vv.push_back( 42 );
REQUIRE( Catch::toString(vv) == "{ 42 }" );
vv.push_back( 512 );
REQUIRE( Catch::toString(vv) == "{ 42, 512 }" );
}
TEST_CASE( "vec<vec<string,alloc>> -> toString", "[toString][vector,allocator]" ) {
typedef std::vector<std::string,minimal_allocator<std::string> > inner;
typedef std::vector<inner> vector;
vector v;
REQUIRE( Catch::toString(v) == "{ }" );
v.push_back( inner { "hello" } );
v.push_back( inner { "world" } );
REQUIRE( Catch::toString(v) == "{ { \"hello\" }, { \"world\" } }" );
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif // CATCH_CPP11_OR_GREATER

View File

@ -0,0 +1,68 @@
#include "catch.hpp"
/*
Demonstrate which version of toString/StringMaker is being used
for various types
*/
struct has_toString { };
struct has_maker {};
struct has_maker_and_toString {};
namespace Catch {
inline std::string toString( const has_toString& ) {
return "toString( has_toString )";
}
inline std::string toString( const has_maker_and_toString& ) {
return "toString( has_maker_and_toString )";
}
template<>
struct StringMaker<has_maker> {
static std::string convert( const has_maker& ) {
return "StringMaker<has_maker>";
}
};
template<>
struct StringMaker<has_maker_and_toString> {
static std::string convert( const has_maker_and_toString& ) {
return "StringMaker<has_maker_and_toString>";
}
};
}
// Call the overload
TEST_CASE( "toString( has_toString )", "[toString]" ) {
has_toString item;
REQUIRE( Catch::toString( item ) == "toString( has_toString )" );
}
// Call the overload
TEST_CASE( "toString( has_maker )", "[toString]" ) {
has_maker item;
REQUIRE( Catch::toString( item ) == "StringMaker<has_maker>" );
}
// Call the overload
TEST_CASE( "toString( has_maker_and_toString )", "[toString]" ) {
has_maker_and_toString item;
REQUIRE( Catch::toString( item ) == "toString( has_maker_and_toString )" );
}
// Vectors...
TEST_CASE( "toString( vectors<has_toString )", "[toString]" ) {
std::vector<has_toString> v(1);
// This invokes template<T> toString which actually gives us '{ ? }'
REQUIRE( Catch::toString( v ) == "{ {?} }" );
}
TEST_CASE( "toString( vectors<has_maker )", "[toString]" ) {
std::vector<has_maker> v(1);
REQUIRE( Catch::toString( v ) == "{ StringMaker<has_maker> }" );
}
TEST_CASE( "toString( vectors<has_maker_and_toString )", "[toString]" ) {
std::vector<has_maker_and_toString> v(1);
// Note: This invokes the template<T> toString -> StringMaker
REQUIRE( Catch::toString( v ) == "{ StringMaker<has_maker_and_toString> }" );
}

View File

@ -44,7 +44,7 @@ TEST_CASE
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
TEST_CASE TEST_CASE
( (
"Where the is more to the expression after the RHS[failing]", "Where there is more to the expression after the RHS",
"[Tricky][failing][.]" "[Tricky][failing][.]"
) )
{ {
@ -55,7 +55,7 @@ TEST_CASE
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
TEST_CASE TEST_CASE
( (
"Where the LHS is not a simple value[failing]", "Where the LHS is not a simple value",
"[Tricky][failing][.]" "[Tricky][failing][.]"
) )
{ {
@ -81,7 +81,7 @@ struct Opaque
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
TEST_CASE TEST_CASE
( (
"A failing expression with a non streamable type is still captured[failing]", "A failing expression with a non streamable type is still captured",
"[Tricky][failing][.]" "[Tricky][failing][.]"
) )
{ {
@ -97,7 +97,7 @@ TEST_CASE
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
TEST_CASE TEST_CASE
( (
"string literals of different sizes can be compared[failing]", "string literals of different sizes can be compared",
"[Tricky][failing][.]" "[Tricky][failing][.]"
) )
{ {

View File

@ -1,14 +1,30 @@
SOURCES = ApproxTests.cpp \
ClassTests.cpp \
ConditionTests.cpp \
ExceptionTests.cpp \
GeneratorTests.cpp \
MessageTests.cpp \
MiscTests.cpp \
TestMain.cpp \
TrickyTests.cpp \
BDDTests.cpp \
VariadicMacrosTests.cpp \
EnumToString.cpp \
ToStringPair.cpp \
ToStringVector.cpp \
ToStringWhich.cpp
EXEC=CatchSelfTest
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
OBJECTS = $(patsubst %.cpp, %.o, $(SOURCES))
CXX = g++ CXX = g++
CXXFLAGS = -I../../include -I../../include/internal CXXFLAGS = -I../../include -std=c++11
$(EXEC): $(OBJECTS) CatchSelfTest: $(OBJECTS)
$(CXX) -o $@ $^ $(CXX) -o $@ $^
test: CatchSelfTest
./CatchSelfTest
clean: clean:
$(RM) $(OBJECTS) rm -f $(OBJECTS) CatchSelfTest
$(RM) $(EXEC)

View File

@ -7,11 +7,16 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
263F7A4719B6FCBF009474C2 /* EnumToString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4619B6FCBF009474C2 /* EnumToString.cpp */; };
263F7A4B19B6FE1E009474C2 /* ToStringPair.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4819B6FE1E009474C2 /* ToStringPair.cpp */; };
263F7A4C19B6FE1E009474C2 /* ToStringVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4919B6FE1E009474C2 /* ToStringVector.cpp */; };
263F7A4D19B6FE1E009474C2 /* ToStringWhich.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 263F7A4A19B6FE1E009474C2 /* ToStringWhich.cpp */; };
2656C2211925E7330040DB02 /* catch_test_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2656C2201925E7330040DB02 /* catch_test_spec.cpp */; }; 2656C2211925E7330040DB02 /* catch_test_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2656C2201925E7330040DB02 /* catch_test_spec.cpp */; };
266B06B816F3A60A004ED264 /* VariadicMacrosTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B06B616F3A60A004ED264 /* VariadicMacrosTests.cpp */; }; 266B06B816F3A60A004ED264 /* VariadicMacrosTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B06B616F3A60A004ED264 /* VariadicMacrosTests.cpp */; };
266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266ECD73170F3C620030D735 /* BDDTests.cpp */; }; 266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266ECD73170F3C620030D735 /* BDDTests.cpp */; };
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 */; };
26948286179A9AB900ED166E /* SectionTrackerTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26948284179A9AB900ED166E /* SectionTrackerTests.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 */; };
@ -66,6 +71,11 @@
2627F7061935B55F009BCE2D /* catch_result_builder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_result_builder.hpp; sourceTree = "<group>"; }; 2627F7061935B55F009BCE2D /* catch_result_builder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_result_builder.hpp; sourceTree = "<group>"; };
262E7399184673A800CAC268 /* catch_reporter_bases.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_bases.hpp; sourceTree = "<group>"; }; 262E7399184673A800CAC268 /* catch_reporter_bases.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_bases.hpp; sourceTree = "<group>"; };
262E739A1846759000CAC268 /* catch_common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_common.hpp; sourceTree = "<group>"; }; 262E739A1846759000CAC268 /* catch_common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_common.hpp; sourceTree = "<group>"; };
263F7A4519A66608009474C2 /* catch_fatal_condition.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_fatal_condition.hpp; sourceTree = "<group>"; };
263F7A4619B6FCBF009474C2 /* EnumToString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = EnumToString.cpp; path = ../../../SelfTest/EnumToString.cpp; sourceTree = "<group>"; };
263F7A4819B6FE1E009474C2 /* ToStringPair.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringPair.cpp; path = ../../../SelfTest/ToStringPair.cpp; sourceTree = "<group>"; };
263F7A4919B6FE1E009474C2 /* ToStringVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringVector.cpp; path = ../../../SelfTest/ToStringVector.cpp; sourceTree = "<group>"; };
263F7A4A19B6FE1E009474C2 /* ToStringWhich.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringWhich.cpp; path = ../../../SelfTest/ToStringWhich.cpp; sourceTree = "<group>"; };
263FD06017AF8DF200988A20 /* catch_timer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_timer.hpp; sourceTree = "<group>"; }; 263FD06017AF8DF200988A20 /* catch_timer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_timer.hpp; sourceTree = "<group>"; };
263FD06117AF8DF200988A20 /* catch_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_timer.h; sourceTree = "<group>"; }; 263FD06117AF8DF200988A20 /* catch_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_timer.h; sourceTree = "<group>"; };
2656C21F1925E5100040DB02 /* catch_test_spec_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_test_spec_parser.hpp; sourceTree = "<group>"; }; 2656C21F1925E5100040DB02 /* catch_test_spec_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_test_spec_parser.hpp; sourceTree = "<group>"; };
@ -87,6 +97,8 @@
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>"; };
26847E5D16BBADB40043B9C1 /* catch_message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_message.cpp; path = ../../../SelfTest/SurrogateCpps/catch_message.cpp; sourceTree = "<group>"; }; 26847E5D16BBADB40043B9C1 /* catch_message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_message.cpp; path = ../../../SelfTest/SurrogateCpps/catch_message.cpp; sourceTree = "<group>"; };
268F47B018A93F7800D8C14F /* catch_clara.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_clara.h; sourceTree = "<group>"; }; 268F47B018A93F7800D8C14F /* catch_clara.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_clara.h; sourceTree = "<group>"; };
2691574A1A4480C50054F1ED /* catch_reporter_teamcity.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_teamcity.hpp; 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>"; }; 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SectionTrackerTests.cpp; path = ../../../SelfTest/SectionTrackerTests.cpp; sourceTree = "<group>"; };
@ -246,6 +258,11 @@
4A6D0C40149B3DAB00DB3EAA /* Tests */ = { 4A6D0C40149B3DAB00DB3EAA /* Tests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
2691574B1A532A280054F1ED /* ToStringTuple.cpp */,
263F7A4819B6FE1E009474C2 /* ToStringPair.cpp */,
263F7A4919B6FE1E009474C2 /* ToStringVector.cpp */,
263F7A4A19B6FE1E009474C2 /* ToStringWhich.cpp */,
263F7A4619B6FCBF009474C2 /* EnumToString.cpp */,
266ECD73170F3C620030D735 /* BDDTests.cpp */, 266ECD73170F3C620030D735 /* BDDTests.cpp */,
4A6D0C36149B3D9E00DB3EAA /* TrickyTests.cpp */, 4A6D0C36149B3D9E00DB3EAA /* TrickyTests.cpp */,
4A6D0C2D149B3D9E00DB3EAA /* ApproxTests.cpp */, 4A6D0C2D149B3D9E00DB3EAA /* ApproxTests.cpp */,
@ -300,6 +317,7 @@
4A6D0C67149B3E3D00DB3EAA /* catch_reporter_junit.hpp */, 4A6D0C67149B3E3D00DB3EAA /* catch_reporter_junit.hpp */,
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 */,
); );
name = reporters; name = reporters;
path = ../../../../include/reporters; path = ../../../../include/reporters;
@ -453,6 +471,7 @@
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 */,
); );
name = Infrastructure; name = Infrastructure;
sourceTree = "<group>"; sourceTree = "<group>";
@ -492,7 +511,7 @@
4A6D0C17149B3D3B00DB3EAA /* Project object */ = { 4A6D0C17149B3D3B00DB3EAA /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 0500; LastUpgradeCheck = 0600;
}; };
buildConfigurationList = 4A6D0C1A149B3D3B00DB3EAA /* Build configuration list for PBXProject "CatchSelfTest" */; buildConfigurationList = 4A6D0C1A149B3D3B00DB3EAA /* Build configuration list for PBXProject "CatchSelfTest" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
@ -516,6 +535,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
263F7A4719B6FCBF009474C2 /* EnumToString.cpp in Sources */,
4A6D0C37149B3D9E00DB3EAA /* ApproxTests.cpp in Sources */, 4A6D0C37149B3D9E00DB3EAA /* ApproxTests.cpp in Sources */,
4A6D0C38149B3D9E00DB3EAA /* ClassTests.cpp in Sources */, 4A6D0C38149B3D9E00DB3EAA /* ClassTests.cpp in Sources */,
4A6D0C39149B3D9E00DB3EAA /* ConditionTests.cpp in Sources */, 4A6D0C39149B3D9E00DB3EAA /* ConditionTests.cpp in Sources */,
@ -525,7 +545,10 @@
4A6D0C3D149B3D9E00DB3EAA /* MiscTests.cpp in Sources */, 4A6D0C3D149B3D9E00DB3EAA /* MiscTests.cpp in Sources */,
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 */,
263F7A4B19B6FE1E009474C2 /* ToStringPair.cpp in Sources */,
4AEE032016142F910071E950 /* catch_common.cpp in Sources */, 4AEE032016142F910071E950 /* catch_common.cpp in Sources */,
263F7A4C19B6FE1E009474C2 /* ToStringVector.cpp in Sources */,
4AEE032316142FC70071E950 /* catch_debugger.cpp in Sources */, 4AEE032316142FC70071E950 /* catch_debugger.cpp in Sources */,
4AEE032516142FF10071E950 /* catch_stream.cpp in Sources */, 4AEE032516142FF10071E950 /* catch_stream.cpp in Sources */,
4AEE0328161434FD0071E950 /* catch_xmlwriter.cpp in Sources */, 4AEE0328161434FD0071E950 /* catch_xmlwriter.cpp in Sources */,
@ -538,6 +561,7 @@
4A45DA2D16161FA2004F8D6B /* catch_interfaces_capture.cpp in Sources */, 4A45DA2D16161FA2004F8D6B /* catch_interfaces_capture.cpp in Sources */,
4A45DA3116161FFC004F8D6B /* catch_interfaces_reporter.cpp in Sources */, 4A45DA3116161FFC004F8D6B /* catch_interfaces_reporter.cpp in Sources */,
4A45DA3316162047004F8D6B /* catch_interfaces_exception.cpp in Sources */, 4A45DA3316162047004F8D6B /* catch_interfaces_exception.cpp in Sources */,
2691574C1A532A280054F1ED /* ToStringTuple.cpp in Sources */,
26711C8F195D465C0033EDA2 /* TagAliasTests.cpp in Sources */, 26711C8F195D465C0033EDA2 /* TagAliasTests.cpp in Sources */,
4A45DA3516162071004F8D6B /* catch_interfaces_runner.cpp in Sources */, 4A45DA3516162071004F8D6B /* catch_interfaces_runner.cpp in Sources */,
4AB3D99D1616216500C9A0F8 /* catch_interfaces_testcase.cpp in Sources */, 4AB3D99D1616216500C9A0F8 /* catch_interfaces_testcase.cpp in Sources */,
@ -564,9 +588,11 @@
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO; CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@ -613,10 +639,12 @@
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO; CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO;
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>034502BF-F920-4DB6-82F5-71E61E50118C</string>
<key>IDESourceControlProjectName</key>
<string>CatchSelfTest</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>01DD8CA9-7DC3-46BC-B998-EFF40EA3485F</key>
<string>ssh://github.com/philsquared/Catch.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>01DD8CA9-7DC3-46BC-B998-EFF40EA3485F</key>
<string>../../../../..</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>ssh://github.com/philsquared/Catch.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>110</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>01DD8CA9-7DC3-46BC-B998-EFF40EA3485F</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>01DD8CA9-7DC3-46BC-B998-EFF40EA3485F</string>
<key>IDESourceControlWCCName</key>
<string>Catch</string>
</dict>
</array>
</dict>
</plist>

View File

@ -9,8 +9,9 @@ from scriptCommon import catchPath
rootPath = os.path.join( catchPath, 'projects/SelfTest/Baselines' ) rootPath = os.path.join( catchPath, 'projects/SelfTest/Baselines' )
filenameParser = re.compile( r'.*/(.*\..pp:)(.*)' ) filenameParser = re.compile( r'(.*)/(.*\..pp:)(.*)' )
filelineParser = re.compile( r'(.*\..pp:)([0-9]*)(.*)' ) filelineParser = re.compile( r'(.*\..pp:)([0-9]*)(.*)' )
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]*"(.*)' )
@ -26,14 +27,20 @@ overallResult = 0
def filterLine( line ): def filterLine( line ):
m = filenameParser.match( line ) m = filenameParser.match( line )
if m: if m:
line = m.group(1) + m.group(2) line = m.group(2) + m.group(3)
m = filelineParser.match( line ) m2 = filelineParser.match( line )
if m: if m2:
line = m.group(1) + "<line number>" + m.group(3) line = m2.group(1) + "<line number>" + m2.group(3)
else: else:
m = lineNumberParser.match( line ) m2 = lineNumberParser.match( line )
if m: if m2:
line = m.group(1) + m.group(2) line = m2.group(1) + m2.group(2)
m = pathParser.match( line )
if m:
path = "/" + m.group(2)
if path.startswith( catchPath ):
path = path[1+len(catchPath):]
line = m.group(1) + path + m.group(3)
m = versionParser.match( line ) m = versionParser.match( line )
if m: if m:
line = m.group(1) + "<version>" + m.group(2) line = m.group(1) + "<version>" + m.group(2)
@ -52,6 +59,8 @@ def filterLine( line ):
def approve( baseName, args ): def approve( baseName, args ):
global overallResult global overallResult
args[0:0] = [cmdPath] args[0:0] = [cmdPath]
if not os.path.exists( cmdPath ):
raise Exception( "Executable doesn't exist at " + cmdPath )
baselinesPath = os.path.join( rootPath, '{0}.approved.txt'.format( baseName ) ) baselinesPath = os.path.join( rootPath, '{0}.approved.txt'.format( baseName ) )
rawResultsPath = os.path.join( rootPath, '_{0}.tmp'.format( baseName ) ) rawResultsPath = os.path.join( rootPath, '_{0}.tmp'.format( baseName ) )
filteredResultsPath = os.path.join( rootPath, '{0}.unapproved.txt'.format( baseName ) ) filteredResultsPath = os.path.join( rootPath, '{0}.unapproved.txt'.format( baseName ) )

File diff suppressed because it is too large Load Diff