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)
*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)
[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?
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)
* [Build systems](build-systems.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)
Other
@ -16,8 +18,3 @@ Other
* [Why Catch?](why-catch.md)
* [What's changed](whats-changed.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
Examples:
```c++
```
CHECK( str == "string value" );
CHECK( thisReturnsTrue() );
REQUIRE( i == 42 );
```
* **REQUIRE_FALSE(** _expression_ **)** and
* **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).
Example:
```c++
```
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
* **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
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
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})
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.
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="#choosing-a-reporter-to-use"> ` -r, --reporter`</a><br />
<a href="#breaking-into-the-debugger"> ` -b, --break`</a><br />
<a href="#usage"> ` -h, -?, --help`</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="#aborting-after-a-certain-number-of-failures"> ` -a, --abort`</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="#breaking-into-the-debugger"> ` -b, --break`</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="#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>
## 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.
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.
@ -79,7 +95,7 @@ In addition to the command line option, ensure you have built your code with the
<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!).
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>
## 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.
<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>
## Warnings
<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.
<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>
## Usage
<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.
*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
return returnCode;
// Writing to session.configData() or session.Config() here
// overrides command line args.
// Only do this if you know you need to.
// writing to session.configData() or session.Config() here
// overrides command line args
// only do this if you know you need to
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_ \] **)**
* **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)
@ -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++
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.
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.
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.
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>
## 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
@ -220,9 +220,11 @@ Scenario: vectors can be sized and resized
```
## 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"
#ifdef CATCH_CONFIG_MAIN
# define CATCH_CONFIG_RUNNER
#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
# define CATCH_IMPL
#endif
#ifdef CATCH_CONFIG_RUNNER
#ifdef CATCH_IMPL
# ifndef CLARA_CONFIG_MAIN
# define CLARA_CONFIG_MAIN_NOT_DEFINED
# define CLARA_CONFIG_MAIN
@ -43,7 +43,7 @@
#include "internal/catch_objc.hpp"
#endif
#ifdef CATCH_CONFIG_RUNNER
#ifdef CATCH_IMPL
#include "internal/catch_impl.hpp"
#endif

View File

@ -60,6 +60,14 @@ namespace Catch {
m_testsAlreadyRun.insert( *it );
}
}
std::vector<TestCase> skippedTestCases;
getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true );
for( std::vector<TestCase>::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end();
it != itEnd;
++it )
m_reporter->skipTest( *it );
context.testGroupEnded( "all tests", totals, 1, 1 );
return totals;
}
@ -97,7 +105,7 @@ namespace Catch {
std::set<TestCase> m_testsAlreadyRun;
};
class Session {
class Session : NonCopyable {
static bool alreadyInstantiated;
public:
@ -108,7 +116,7 @@ namespace Catch {
: m_cli( makeCommandLineParser() ) {
if( alreadyInstantiated ) {
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 );
}
alreadyInstantiated = true;
@ -118,15 +126,15 @@ namespace Catch {
}
void showHelp( std::string const& processName ) {
std::cout << "\nCatch v" << libraryVersion.majorVersion << "."
Catch::cout() << "\nCatch v" << libraryVersion.majorVersion << "."
<< libraryVersion.minorVersion << " build "
<< libraryVersion.buildNumber;
if( libraryVersion.branchName != std::string( "master" ) )
std::cout << " (" << libraryVersion.branchName << " branch)";
std::cout << "\n";
Catch::cout() << " (" << libraryVersion.branchName << " branch)";
Catch::cout() << "\n";
m_cli.usage( std::cout, processName );
std::cout << "For more detail usage please see the project docs\n" << std::endl;
m_cli.usage( Catch::cout(), processName );
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 ) {
@ -140,11 +148,11 @@ namespace Catch {
catch( std::exception& ex ) {
{
Colour colourGuard( Colour::Red );
std::cerr << "\nError(s) in input:\n"
Catch::cerr() << "\nError(s) in input:\n"
<< Text( ex.what(), TextAttributes().setIndent(2) )
<< "\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 0;
@ -170,6 +178,9 @@ namespace Catch {
try
{
config(); // Force config to be constructed
std::srand( m_configData.rngSeed );
Runner runner( m_config );
// Handle list request
@ -179,7 +190,7 @@ namespace Catch {
return static_cast<int>( runner.runTests().assertions.failed );
}
catch( std::exception& ex ) {
std::cerr << ex.what() << std::endl;
Catch::cerr() << ex.what() << std::endl;
return (std::numeric_limits<int>::max)();
}
}

View File

@ -620,7 +620,7 @@ namespace Clara {
m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
{
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 ) {
@ -649,7 +649,7 @@ namespace Clara {
ArgBuilder operator[]( UnpositionalTag ) {
if( m_floatingArg.get() )
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() );
return builder;
}
@ -791,7 +791,7 @@ namespace Clara {
if( it == itEnd ) {
if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
unusedTokens.push_back( token );
else if( m_throwOnUnrecognisedTokens )
else if( errors.empty() && m_throwOnUnrecognisedTokens )
errors.push_back( "unrecognised option: " + token.data );
}
}

View File

@ -15,7 +15,7 @@
#include "catch_common.h"
#include "catch_tostring.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(); \
__catchResult \
.setLhs( Catch::toString( arg ) ) \
.setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \
.setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
.setOp( "matches" ) \
.setResultType( ::Catch::Matchers::matcher.match( arg ) ); \
__catchResult.captureExpression(); \

View File

@ -29,7 +29,28 @@ namespace Catch {
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
else
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 ) {
// !TBD: accept strings?
@ -137,10 +158,22 @@ namespace Catch {
.describe( "list all/matching test cases names only" )
.bind( &ConfigData::listTestNamesOnly );
cli["--list-reporters"]
cli["--list-reporters"]
.describe( "list all reporters" )
.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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -35,7 +35,7 @@ namespace Catch {
throw;
}
@catch (NSException *exception) {
return toString( [exception description] );
return Catch::toString( [exception description] );
}
#else
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"
#endif
#include "catch_runner.hpp"
#include "../catch_runner.hpp"
#include "catch_registry_hub.hpp"
#include "catch_notimplemented_exception.hpp"
#include "catch_context_impl.hpp"
@ -88,8 +88,6 @@ namespace Catch {
Matchers::Impl::StdString::EndsWith::~EndsWith() {}
void Config::dummy() {}
INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
}
#ifdef __clang__

View File

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

View File

@ -32,6 +32,11 @@ namespace Catch {
Always,
Never
}; };
struct RunTests { enum InWhatOrder {
InDeclarationOrder,
InLexicographicalOrder,
InRandomOrder
}; };
class TestSpec;
@ -49,6 +54,9 @@ namespace Catch {
virtual bool showInvisibles() const = 0;
virtual ShowDurations::OrNot showDurations() 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;
// The return value indicates if the messages buffer should be cleared:
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
};

View File

@ -28,7 +28,7 @@ namespace Catch {
struct ITestCaseRegistry {
virtual ~ITestCaseRegistry();
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 testGroupEnded( TestGroupStats const& testGroupStats );
virtual void testRunEnded( TestRunStats const& testRunStats );
virtual void skipTest( TestCaseInfo const& );
private:
Ptr<IReporter> m_legacyReporter;

View File

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

View File

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

View File

@ -17,7 +17,7 @@
// NB. Any general catch headers included here must be included
// in catch.hpp first to make sure they are included by the single
// 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

View File

@ -9,9 +9,13 @@
#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
#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__
#pragma GCC diagnostic pop
# pragma GCC diagnostic pop
#endif
#endif // TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED

View File

@ -25,7 +25,9 @@ namespace Catch {
Exception = 0x100 | FailureBit,
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_timer.h"
#include "catch_result_builder.h"
#include "catch_fatal_condition.hpp"
#include <set>
#include <string>
@ -209,6 +210,37 @@ namespace Catch {
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:
// !TBD We need to do this another way!
bool aborting() const {
@ -230,12 +262,12 @@ namespace Catch {
Timer timer;
timer.start();
if( m_reporter->getPreferences().shouldRedirectStdOut ) {
StreamRedirect coutRedir( std::cout, redirectedCout );
StreamRedirect cerrRedir( std::cerr, redirectedCerr );
m_activeTestCase->invoke();
StreamRedirect coutRedir( Catch::cout(), redirectedCout );
StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
invokeActiveTestCase();
}
else {
m_activeTestCase->invoke();
invokeActiveTestCase();
}
duration = timer.getElapsedSeconds();
}
@ -243,20 +275,9 @@ namespace Catch {
// This just means the test was aborted due to failure
}
catch(...) {
ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(),
m_lastAssertionInfo.lineInfo,
m_lastAssertionInfo.capturedExpression.c_str(),
m_lastAssertionInfo.resultDisposition );
exResult.useActiveException();
makeUnexpectedResultBuilder().useActiveException();
}
// 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();
handleUnfinishedSections();
m_messages.clear();
Counts assertions = m_totals.assertions - prevAssertions;
@ -272,7 +293,32 @@ namespace Catch {
m_reporter->sectionEnded( testCaseSectionStats );
}
void invokeActiveTestCase() {
FatalConditionHandler fatalConditionHandler; // Handle signals
m_activeTestCase->invoke();
fatalConditionHandler.reset();
}
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 {
UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
: info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )

View File

@ -16,7 +16,7 @@
namespace Catch {
class Section {
class Section : NonCopyable {
public:
Section( SectionInfo const& info );
~Section();
@ -25,15 +25,6 @@ namespace Catch {
operator bool() const;
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;
std::string m_name;

View File

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

View File

@ -15,6 +15,7 @@
#include <stdexcept>
#include <cstdio>
#include <iostream>
namespace Catch {
@ -78,6 +79,15 @@ namespace Catch {
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

View File

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

View File

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

View File

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

View File

@ -17,10 +17,18 @@
#include <set>
#include <sstream>
#include <iostream>
#include <algorithm>
namespace Catch {
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:
TestRegistry() : m_unnamedCount( 0 ) {}
virtual ~TestRegistry();
@ -43,7 +51,7 @@ namespace Catch {
TestCase const& prev = *m_functions.find( testCase );
{
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"
<< "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
}
@ -59,18 +67,38 @@ namespace Catch {
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(),
itEnd = m_functionsInOrder.end();
it != itEnd;
++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 );
}
sortTests( config, matchingTestCases );
}
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::vector<TestCase> m_functionsInOrder;
std::vector<TestCase> m_nonHiddenFunctions;

View File

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

View File

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

View File

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

View File

@ -21,9 +21,50 @@
#include "catch_objc_arc.hpp"
#endif
#ifdef CATCH_CPP11_OR_GREATER
#include <tuple>
#include <type_traits>
#endif
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 {
extern std::string unprintableString;
// SFINAE is currently disabled by default for all compilers.
// If the non SFINAE version of IsStreamInsertable is ambiguous for you
// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
@ -64,10 +105,38 @@ namespace Detail {
#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>
struct StringMakerBase {
#if defined(CATCH_CPP11_OR_GREATER)
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<>
@ -89,9 +158,6 @@ namespace Detail {
} // end namespace Detail
template<typename T>
std::string toString( T const& value );
template<typename T>
struct StringMaker :
Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
@ -122,12 +188,60 @@ namespace Detail {
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>
struct StringMaker<std::vector<T, Allocator> > {
static std::string convert( std::vector<T,Allocator> const& v ) {
return Detail::rangeToString( v.begin(), v.end() );
std::string toString( std::vector<T,Allocator> const& v ) {
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 {
template<typename T>
@ -148,33 +262,6 @@ std::string toString( T const& 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 {
template<typename InputIterator>
@ -182,10 +269,9 @@ std::string toString( std::nullptr_t );
std::ostringstream oss;
oss << "{ ";
if( first != last ) {
oss << toString( *first );
for( ++first ; first != last ; ++first ) {
oss << ", " << toString( *first );
}
oss << Catch::toString( *first );
for( ++first ; first != last ; ++first )
oss << ", " << Catch::toString( *first );
}
oss << " }";
return oss.str();

View File

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

View File

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

View File

@ -13,7 +13,7 @@
namespace Catch {
// 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

View File

@ -8,8 +8,9 @@
#ifndef TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
#include "../internal/catch_stream.h"
#include <sstream>
#include <iostream>
#include <string>
#include <vector>
@ -52,7 +53,7 @@ namespace Catch {
XmlWriter()
: m_tagIsOpen( false ),
m_needsNewline( false ),
m_os( &std::cout )
m_os( &Catch::cout() )
{}
XmlWriter( std::ostream& os )

View File

@ -10,6 +10,8 @@
#include "../internal/catch_interfaces_reporter.h"
#include <cstring>
namespace Catch {
struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
@ -42,7 +44,6 @@ namespace Catch {
}
virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
currentTestCaseInfo.reset();
assert( m_sectionStack.empty() );
}
virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
currentGroupInfo.reset();
@ -53,6 +54,11 @@ namespace Catch {
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;
std::ostream& stream;
@ -183,6 +189,8 @@ namespace Catch {
}
virtual void testRunEndedCumulative() = 0;
virtual void skipTest( TestCaseInfo const& ) {}
Ptr<IConfig> m_config;
std::ostream& stream;
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
#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED

View File

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

View File

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

View File

@ -135,7 +135,7 @@ namespace Catch {
xml.writeAttribute( "classname", className );
xml.writeAttribute( "name", name );
}
xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) );
xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) );
writeAssertions( sectionNode );
@ -168,6 +168,7 @@ namespace Catch {
std::string elementName;
switch( result.getResultType() ) {
case ResultWas::ThrewException:
case ResultWas::FatalErrorCondition:
elementName = "error";
break;
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_reporter_registrars.hpp"
#include "../internal/catch_xmlwriter.hpp"
#include "../internal/catch_timer.h"
namespace Catch {
class XmlReporter : public SharedImpl<IReporter> {
class XmlReporter : public StreamingReporterBase {
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() {
return "Reports test results as an XML document";
}
virtual ~XmlReporter();
private: // IReporter
virtual bool shouldRedirectStdout() const {
return true;
public: // StreamingReporterBase
virtual ReporterPreferences getPreferences() const {
ReporterPreferences prefs;
prefs.shouldRedirectStdOut = true;
return prefs;
}
virtual void StartTesting() {
m_xml.setStream( m_config.stream() );
virtual void noMatchingTestCases( std::string const& s ) {
StreamingReporterBase::noMatchingTestCases( s );
}
virtual void testRunStarting( TestRunInfo const& testInfo ) {
StreamingReporterBase::testRunStarting( testInfo );
m_xml.setStream( stream );
m_xml.startElement( "Catch" );
if( !m_config.fullConfig()->name().empty() )
m_xml.writeAttribute( "name", m_config.fullConfig()->name() );
if( !m_config->name().empty() )
m_xml.writeAttribute( "name", m_config->name() );
}
virtual void EndTesting( const Totals& totals ) {
m_xml.scopedElement( "OverallResults" )
.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 ) {
virtual void testGroupStarting( GroupInfo const& groupInfo ) {
StreamingReporterBase::testGroupStarting( groupInfo );
m_xml.startElement( "Group" )
.writeAttribute( "name", groupName );
.writeAttribute( "name", groupInfo.name );
}
virtual void EndGroup( const std::string&, const Totals& totals ) {
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", totals.assertions.passed )
.writeAttribute( "failures", totals.assertions.failed )
.writeAttribute( "expectedFailures", totals.assertions.failedButOk );
m_xml.endElement();
virtual void testCaseStarting( TestCaseInfo const& testInfo ) {
StreamingReporterBase::testCaseStarting(testInfo);
m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
if ( m_config->showDurations() == ShowDurations::Always )
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 ) {
m_xml.startElement( "Section" )
.writeAttribute( "name", trim( sectionName ) )
.writeAttribute( "description", 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();
.writeAttribute( "name", trim( sectionInfo.name ) )
.writeAttribute( "description", sectionInfo.description );
}
}
virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
m_currentTestSuccess = true;
}
virtual void assertionStarting( AssertionInfo const& ) { }
virtual void Result( const Catch::AssertionResult& assertionResult ) {
if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok )
return;
virtual bool assertionEnded( AssertionStats const& assertionStats ) {
const AssertionResult& assertionResult = assertionStats.assertionResult;
// 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() ) {
m_xml.startElement( "Expression" )
.writeAttribute( "success", assertionResult.succeeded() )
.writeAttribute( "type", assertionResult.getTestMacroName() )
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line );
@ -97,58 +107,96 @@ namespace Catch {
.writeText( assertionResult.getExpression() );
m_xml.scopedElement( "Expanded" )
.writeText( assertionResult.getExpandedExpression() );
m_currentTestSuccess &= assertionResult.succeeded();
}
// And... Print a result applicable to each result type.
switch( assertionResult.getResultType() ) {
case ResultWas::ThrewException:
m_xml.scopedElement( "Exception" )
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line )
.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;
case ResultWas::Info:
m_xml.scopedElement( "Info" )
.writeText( assertionResult.getMessage() );
break;
case ResultWas::Warning:
m_xml.scopedElement( "Warning" )
.writeText( assertionResult.getMessage() );
// Warning will already have been written
break;
case ResultWas::ExplicitFailure:
m_xml.scopedElement( "Failure" )
.writeText( assertionResult.getMessage() );
m_currentTestSuccess = false;
break;
case ResultWas::Unknown:
case ResultWas::Ok:
case ResultWas::FailureBit:
case ResultWas::ExpressionFailed:
case ResultWas::Exception:
case ResultWas::DidntThrowException:
default:
break;
}
if( assertionResult.hasExpression() )
m_xml.endElement();
return true;
}
virtual void Aborted() {
// !TBD
virtual void sectionEnded( SectionStats const& sectionStats ) {
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& ) {
m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
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();
}
private:
ReporterConfig m_config;
bool m_currentTestSuccess;
Timer m_testCaseTimer;
XmlWriter m_xml;
int m_sectionDepth;
};
INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
} // end namespace Catch
#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 "${CATCH_DIR}" PATH)
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
set(SOURCES
@ -21,6 +26,11 @@ set(SOURCES
${SELF_TEST_DIR}/TestMain.cpp
${SELF_TEST_DIR}/TrickyTests.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

View File

@ -1,6 +1,6 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CatchSelfTest is a <version> host application.
CatchSelfTest is a <version> (develop) host application.
Run with -? for options
-------------------------------------------------------------------------------
@ -737,7 +737,7 @@ with expansion:
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>
...............................................................................
@ -748,7 +748,7 @@ warning:
error
-------------------------------------------------------------------------------
Where the LHS is not a simple value[failing]
Where the LHS is not a simple value
-------------------------------------------------------------------------------
TrickyTests.cpp:<line number>
...............................................................................
@ -759,7 +759,7 @@ warning:
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>
...............................................................................
@ -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>
...............................................................................
@ -786,6 +786,6 @@ with expansion:
"first" == "second"
===============================================================================
test cases: 130 | 91 passed | 38 failed | 1 failed as expected
assertions: 709 | 617 passed | 79 failed | 13 failed as expected
test cases: 155 | 116 passed | 38 failed | 1 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
-------------------------------------------------------------------------------
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
-------------------------------------------------------------------------------
@ -3318,7 +3398,7 @@ MiscTests.cpp:<line number>:
PASSED:
REQUIRE( Factorial(10) == 3628800 )
with expansion:
0x<hex digits> == 3628800
0x<hex digits> == 0x<hex digits>
-------------------------------------------------------------------------------
An empty test with no assertions
@ -3985,6 +4065,42 @@ PASSED:
with expansion:
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
plain string
@ -4438,6 +4554,139 @@ with expansion:
five
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
-------------------------------------------------------------------------------
@ -5496,7 +5745,7 @@ with expansion:
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>
...............................................................................
@ -5507,10 +5756,10 @@ warning:
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>
...............................................................................
@ -5521,10 +5770,10 @@ warning:
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>
...............................................................................
@ -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>
...............................................................................
@ -5905,6 +6154,234 @@ TrickyTests.cpp:<line number>
TrickyTests.cpp:<line number>:
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
Empty test spec should have no filters
@ -6932,6 +7409,96 @@ PASSED:
with expansion:
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
The same tag alias can only be registered once
@ -7375,6 +7942,6 @@ with expansion:
true
===============================================================================
test cases: 130 | 75 passed | 54 failed | 1 failed as expected
assertions: 729 | 617 passed | 99 failed | 13 failed as expected
test cases: 155 | 100 passed | 54 failed | 1 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
-------------------------------------------------------------------------------
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
-------------------------------------------------------------------------------
@ -406,6 +486,6 @@ with expansion:
9.1f != Approx( 9.1000003815 )
===============================================================================
test cases: 15 | 11 passed | 3 failed | 1 failed as expected
assertions: 53 | 47 passed | 4 failed | 2 failed as expected
test cases: 19 | 15 passed | 3 failed | 1 failed as expected
assertions: 62 | 56 passed | 4 failed | 2 failed as expected

View File

@ -1,5 +1,9 @@
<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="Approximate comparisons with different epsilons" 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/--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="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/Wrapped once" 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 twice" 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}">
<system-out>
hello
@ -490,9 +503,9 @@ hello
<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="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 the LHS is not a simple value[failing]" time="{duration}"/>
<testcase classname="global" name="A failing expression with a non streamable type is still captured[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" 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">
TrickyTests.cpp:<line number>
</failure>
@ -500,7 +513,7 @@ TrickyTests.cpp:<line number>
TrickyTests.cpp:<line number>
</failure>
</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">
TrickyTests.cpp:<line number>
</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/1/a" 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="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}"/>
@ -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 quoted name" 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="Tag aliases must be of the form [@name]" 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 );
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
#include "catch.hpp"
#include "reporters/catch_reporter_teamcity.hpp"
// Some example tag aliases
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.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;
};
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
TEST_CASE( "Strings can be rendered with colour", "[colour][.]" ) {
TEST_CASE( "Strings can be rendered with colour", "[.colour]" ) {
{
ColourString cs( "hello" );
cs .addColour( Colour::Red, 0 )
.addColour( Colour::Green, -1 );
std::cout << cs << std::endl;
Catch::cout() << cs << std::endl;
}
{
ColourString cs( "hello" );
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
(
"Where the is more to the expression after the RHS[failing]",
"Where there is more to the expression after the RHS",
"[Tricky][failing][.]"
)
{
@ -55,7 +55,7 @@ TEST_CASE
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"Where the LHS is not a simple value[failing]",
"Where the LHS is not a simple value",
"[Tricky][failing][.]"
)
{
@ -81,7 +81,7 @@ struct Opaque
///////////////////////////////////////////////////////////////////////////////
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][.]"
)
{
@ -97,7 +97,7 @@ TEST_CASE
///////////////////////////////////////////////////////////////////////////////
TEST_CASE
(
"string literals of different sizes can be compared[failing]",
"string literals of different sizes can be compared",
"[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++
CXXFLAGS = -I../../include -I../../include/internal
CXXFLAGS = -I../../include -std=c++11
$(EXEC): $(OBJECTS)
CatchSelfTest: $(OBJECTS)
$(CXX) -o $@ $^
test: CatchSelfTest
./CatchSelfTest
clean:
$(RM) $(OBJECTS)
$(RM) $(EXEC)
rm -f $(OBJECTS) CatchSelfTest

View File

@ -7,11 +7,16 @@
objects = {
/* 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 */; };
266B06B816F3A60A004ED264 /* VariadicMacrosTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B06B616F3A60A004ED264 /* VariadicMacrosTests.cpp */; };
266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266ECD73170F3C620030D735 /* BDDTests.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 */; };
2691574C1A532A280054F1ED /* ToStringTuple.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2691574B1A532A280054F1ED /* ToStringTuple.cpp */; };
26948286179A9AB900ED166E /* SectionTrackerTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */; };
2694A1FD16A0000E004816E3 /* catch_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2694A1FB16A0000E004816E3 /* catch_text.cpp */; };
26E1B7D319213BC900812682 /* CmdLineTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E1B7D119213BC900812682 /* CmdLineTests.cpp */; };
@ -66,6 +71,11 @@
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>"; };
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>"; };
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>"; };
@ -87,6 +97,8 @@
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>"; };
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>"; };
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>"; };
@ -246,6 +258,11 @@
4A6D0C40149B3DAB00DB3EAA /* Tests */ = {
isa = PBXGroup;
children = (
2691574B1A532A280054F1ED /* ToStringTuple.cpp */,
263F7A4819B6FE1E009474C2 /* ToStringPair.cpp */,
263F7A4919B6FE1E009474C2 /* ToStringVector.cpp */,
263F7A4A19B6FE1E009474C2 /* ToStringWhich.cpp */,
263F7A4619B6FCBF009474C2 /* EnumToString.cpp */,
266ECD73170F3C620030D735 /* BDDTests.cpp */,
4A6D0C36149B3D9E00DB3EAA /* TrickyTests.cpp */,
4A6D0C2D149B3D9E00DB3EAA /* ApproxTests.cpp */,
@ -300,6 +317,7 @@
4A6D0C67149B3E3D00DB3EAA /* catch_reporter_junit.hpp */,
4A6D0C68149B3E3D00DB3EAA /* catch_reporter_xml.hpp */,
4AB42F84166F3E1A0099F2C8 /* catch_reporter_console.hpp */,
2691574A1A4480C50054F1ED /* catch_reporter_teamcity.hpp */,
);
name = reporters;
path = ../../../../include/reporters;
@ -453,6 +471,7 @@
268F47B018A93F7800D8C14F /* catch_clara.h */,
2656C226192A77EF0040DB02 /* catch_suppress_warnings.h */,
2656C227192A78410040DB02 /* catch_reenable_warnings.h */,
263F7A4519A66608009474C2 /* catch_fatal_condition.hpp */,
);
name = Infrastructure;
sourceTree = "<group>";
@ -492,7 +511,7 @@
4A6D0C17149B3D3B00DB3EAA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0500;
LastUpgradeCheck = 0600;
};
buildConfigurationList = 4A6D0C1A149B3D3B00DB3EAA /* Build configuration list for PBXProject "CatchSelfTest" */;
compatibilityVersion = "Xcode 3.2";
@ -516,6 +535,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
263F7A4719B6FCBF009474C2 /* EnumToString.cpp in Sources */,
4A6D0C37149B3D9E00DB3EAA /* ApproxTests.cpp in Sources */,
4A6D0C38149B3D9E00DB3EAA /* ClassTests.cpp in Sources */,
4A6D0C39149B3D9E00DB3EAA /* ConditionTests.cpp in Sources */,
@ -525,7 +545,10 @@
4A6D0C3D149B3D9E00DB3EAA /* MiscTests.cpp in Sources */,
4A6D0C3E149B3D9E00DB3EAA /* TestMain.cpp in Sources */,
4A6D0C3F149B3D9E00DB3EAA /* TrickyTests.cpp in Sources */,
263F7A4D19B6FE1E009474C2 /* ToStringWhich.cpp in Sources */,
263F7A4B19B6FE1E009474C2 /* ToStringPair.cpp in Sources */,
4AEE032016142F910071E950 /* catch_common.cpp in Sources */,
263F7A4C19B6FE1E009474C2 /* ToStringVector.cpp in Sources */,
4AEE032316142FC70071E950 /* catch_debugger.cpp in Sources */,
4AEE032516142FF10071E950 /* catch_stream.cpp in Sources */,
4AEE0328161434FD0071E950 /* catch_xmlwriter.cpp in Sources */,
@ -538,6 +561,7 @@
4A45DA2D16161FA2004F8D6B /* catch_interfaces_capture.cpp in Sources */,
4A45DA3116161FFC004F8D6B /* catch_interfaces_reporter.cpp in Sources */,
4A45DA3316162047004F8D6B /* catch_interfaces_exception.cpp in Sources */,
2691574C1A532A280054F1ED /* ToStringTuple.cpp in Sources */,
26711C8F195D465C0033EDA2 /* TagAliasTests.cpp in Sources */,
4A45DA3516162071004F8D6B /* catch_interfaces_runner.cpp in Sources */,
4AB3D99D1616216500C9A0F8 /* catch_interfaces_testcase.cpp in Sources */,
@ -564,9 +588,11 @@
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@ -613,10 +639,12 @@
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = 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' )
filenameParser = re.compile( r'.*/(.*\..pp:)(.*)' )
filenameParser = re.compile( r'(.*)/(.*\..pp:)(.*)' )
filelineParser = re.compile( r'(.*\..pp:)([0-9]*)(.*)' )
pathParser = re.compile( r'(.*?)/(.*\..pp)(.*)' )
lineNumberParser = re.compile( r'(.*)line="[0-9]*"(.*)' )
hexParser = re.compile( r'(.*)\b(0[xX][0-9a-fA-F]+)\b(.*)' )
durationsParser = re.compile( r'(.*)time="[0-9]*\.[0-9]*"(.*)' )
@ -26,14 +27,20 @@ overallResult = 0
def filterLine( line ):
m = filenameParser.match( line )
if m:
line = m.group(1) + m.group(2)
m = filelineParser.match( line )
if m:
line = m.group(1) + "<line number>" + m.group(3)
line = m.group(2) + m.group(3)
m2 = filelineParser.match( line )
if m2:
line = m2.group(1) + "<line number>" + m2.group(3)
else:
m = lineNumberParser.match( line )
if m:
line = m.group(1) + m.group(2)
m2 = lineNumberParser.match( line )
if m2:
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 )
if m:
line = m.group(1) + "<version>" + m.group(2)
@ -52,6 +59,8 @@ def filterLine( line ):
def approve( baseName, args ):
global overallResult
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 ) )
rawResultsPath = os.path.join( rootPath, '_{0}.tmp'.format( baseName ) )
filteredResultsPath = os.path.join( rootPath, '{0}.unapproved.txt'.format( baseName ) )

File diff suppressed because it is too large Load Diff