diff --git a/README.md b/README.md index 47d85c18..c81a4fe4 100644 --- a/README.md +++ b/README.md @@ -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) +[The latest, single header, version can be downloaded directly using this link] + ## 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. diff --git a/docs/Readme.md b/docs/Readme.md index 45350f9a..74b876de 100644 --- a/docs/Readme.md +++ b/docs/Readme.md @@ -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) - diff --git a/docs/assertions.md b/docs/assertions.md index 47826b04..82bb96a3 100644 --- a/docs/assertions.md +++ b/docs/assertions.md @@ -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) \ No newline at end of file diff --git a/docs/build-systems.md b/docs/build-systems.md index 1cb93c87..b001dc19 100644 --- a/docs/build-systems.md +++ b/docs/build-systems.md @@ -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) \ No newline at end of file diff --git a/docs/command-line.md b/docs/command-line.md index f534d858..d1d4bd4a 100644 --- a/docs/command-line.md +++ b/docs/command-line.md @@ -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. ` ...`
- ` -r, --reporter`
- ` -b, --break`
+ ` -h, -?, --help`
+ ` -l, --list-tests`
+ ` -t, --list-tags`
` -s, --success`
- ` -a, --abort`
- ` -l, --list`
- ` -o, --out`
- ` -n, --name`
+ ` -b, --break`
` -e, --nothrow`
+ ` -i, --invisibles`
+ ` -o, --out`
+ ` -r, --reporter`
+ ` -n, --name`
+ ` -a, --abort`
+ ` -x, --abortx`
` -w, --warn`
` -d, --durations`
- ` -h, -?, --help`
+ ` -f, --input-file`
+ +
+ + ` --list-test-names-only`
+ ` --list-reporters`
+ ` --order`
+ ` --rng-seed`
+ +
+ + ## 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
-s, --success
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. ## 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. + +## Make whitespace visible +
-i, --invisibles
+ +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. + ## Warnings
-w, --warn <warning name>
@@ -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. + +## Load test names to run from a file +
-f, --input-file <filename>
+ +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 list-test-names-only option. This can then be manually curated to specify a specific subset of tests - or in a specific order. + + +## Just test names +
--list-test-names-only
+ +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 ```-f``` or ```--input-file``` option. + + + +## Specify the order test cases are run +
--order <decl|lex|rand>
+ +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 rng-seed. + + +## Specify a seed for the Random Number Generator +
--rng-seed <'time'|number>
+ +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)```. + ## Usage
-h, -?, --help
@@ -153,4 +217,4 @@ Prints the command line arguments to stdout --- -[Home](../README.md) +[Home](Readme.md) \ No newline at end of file diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..f12ec68e --- /dev/null +++ b/docs/configuration.md @@ -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) \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md index 57bf59c4..5e228362 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -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) \ No newline at end of file diff --git a/docs/logging.md b/docs/logging.md index 4be20c59..a659b3e8 100644 --- a/docs/logging.md +++ b/docs/logging.md @@ -49,4 +49,4 @@ These macros are now deprecated and are just aliases for INFO and CAPTURE (which --- -[Home](../README.md) \ No newline at end of file +[Home](Readme.md) \ No newline at end of file diff --git a/docs/own-main.md b/docs/own-main.md index 36e9ab58..f8c836e6 100644 --- a/docs/own-main.md +++ b/docs/own-main.md @@ -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) \ No newline at end of file diff --git a/docs/slow-compiles.md b/docs/slow-compiles.md index 0673612c..5291aecc 100644 --- a/docs/slow-compiles.md +++ b/docs/slow-compiles.md @@ -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) \ No newline at end of file diff --git a/docs/test-cases-and-sections.md b/docs/test-cases-and-sections.md index 7e9379fa..28426d78 100644 --- a/docs/test-cases-and-sections.md +++ b/docs/test-cases-and-sections.md @@ -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) \ No newline at end of file diff --git a/docs/test-fixtures.md b/docs/test-fixtures.md index adac75d4..6bef762b 100644 --- a/docs/test-fixtures.md +++ b/docs/test-fixtures.md @@ -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) \ No newline at end of file diff --git a/docs/tostring.md b/docs/tostring.md new file mode 100644 index 00000000..f354d239 --- /dev/null +++ b/docs/tostring.md @@ -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) diff --git a/docs/tutorial.md b/docs/tutorial.md index ef48ec60..c0a163df 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -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 Test cases and Sections, 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 Test cases and Sections, 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. ## 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) diff --git a/docs/whats-changed.md b/docs/whats-changed.md index 40b95a6d..10a1bbc5 100644 --- a/docs/whats-changed.md +++ b/docs/whats-changed.md @@ -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) \ No newline at end of file diff --git a/docs/why-catch.md b/docs/why-catch.md index d90ee012..93488d22 100644 --- a/docs/why-catch.md +++ b/docs/why-catch.md @@ -39,4 +39,4 @@ See the [tutorial](tutorial.md) to get more of a taste of using CATCH in practic --- -[Home](../README.md) \ No newline at end of file +[Home](Readme.md) \ No newline at end of file diff --git a/include/catch.hpp b/include/catch.hpp index 4251cd08..9f82c72d 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -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 diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index e6303d88..bf03ccdf 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -60,6 +60,14 @@ namespace Catch { m_testsAlreadyRun.insert( *it ); } } + std::vector skippedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); + + for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); + it != itEnd; + ++it ) + m_reporter->skipTest( *it ); + context.testGroupEnded( "all tests", totals, 1, 1 ); return totals; } @@ -97,7 +105,7 @@ namespace Catch { std::set 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::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( runner.runTests().assertions.failed ); } catch( std::exception& ex ) { - std::cerr << ex.what() << std::endl; + Catch::cerr() << ex.what() << std::endl; return (std::numeric_limits::max)(); } } diff --git a/include/external/clara.h b/include/external/clara.h index d8e83ac5..ce2ef2ec 100644 --- a/include/external/clara.h +++ b/include/external/clara.h @@ -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 ); } } diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 1285b31f..58591265 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -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(); \ diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp index c7c33845..8b085365 100644 --- a/include/internal/catch_commandline.hpp +++ b/include/internal/catch_commandline.hpp @@ -29,7 +29,28 @@ namespace Catch { config.warnings = static_cast( 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( 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; } diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h index 967b7fc2..aadb0d34 100644 --- a/include/internal/catch_common.h +++ b/include/internal/catch_common.h @@ -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; diff --git a/include/internal/catch_common.hpp b/include/internal/catch_common.hpp index 6147aa5f..8a42d0a0 100644 --- a/include/internal/catch_common.hpp +++ b/include/internal/catch_common.hpp @@ -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__ diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h index 76d0ffda..5ed98c2f 100644 --- a/include/internal/catch_compiler_capabilities.h +++ b/include/internal/catch_compiler_capabilities.h @@ -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 diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp index 1217b9a9..1f3ca64a 100644 --- a/include/internal/catch_config.hpp +++ b/include/internal/catch_config.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #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; diff --git a/include/internal/catch_console_colour.hpp b/include/internal/catch_console_colour.hpp index 4caed07c..f0a8a697 100644 --- a/include/internal/catch_console_colour.hpp +++ b/include/internal/catch_console_colour.hpp @@ -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; }; diff --git a/include/internal/catch_console_colour_impl.hpp b/include/internal/catch_console_colour_impl.hpp index 5f215062..2c4b36c3 100644 --- a/include/internal/catch_console_colour_impl.hpp +++ b/include/internal/catch_console_colour_impl.hpp @@ -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 @@ -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 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( _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 diff --git a/include/internal/catch_context_impl.hpp b/include/internal/catch_context_impl.hpp index 75bbfb0c..a495503c 100644 --- a/include/internal/catch_context_impl.hpp +++ b/include/internal/catch_context_impl.hpp @@ -60,7 +60,7 @@ namespace Catch { std::string testName = getResultCapture()->getCurrentTestName(); std::map::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, true ); throw std::domain_error( "Unknown stream: " + streamName ); diff --git a/include/internal/catch_debugger.hpp b/include/internal/catch_debugger.hpp index 49c485ff..4151aec7 100644 --- a/include/internal/catch_debugger.hpp +++ b/include/internal/catch_debugger.hpp @@ -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 diff --git a/include/internal/catch_exception_translator_registry.hpp b/include/internal/catch_exception_translator_registry.hpp index a1cc7050..29ddf8e7 100644 --- a/include/internal/catch_exception_translator_registry.hpp +++ b/include/internal/catch_exception_translator_registry.hpp @@ -35,7 +35,7 @@ namespace Catch { throw; } @catch (NSException *exception) { - return toString( [exception description] ); + return Catch::toString( [exception description] ); } #else throw; diff --git a/include/internal/catch_fatal_condition.hpp b/include/internal/catch_fatal_condition.hpp new file mode 100644 index 00000000..dd21d590 --- /dev/null +++ b/include/internal/catch_fatal_condition.hpp @@ -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 + +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( "", -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 diff --git a/include/internal/catch_impl.hpp b/include/internal/catch_impl.hpp index cc03ae08..24a8c3f8 100644 --- a/include/internal/catch_impl.hpp +++ b/include/internal/catch_impl.hpp @@ -16,7 +16,7 @@ #pragma clang diagnostic ignored "-Wweak-vtables" #endif -#include "catch_runner.hpp" +#include "../catch_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__ diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h index 6565f0e6..bdbcfb2f 100644 --- a/include/internal/catch_interfaces_capture.h +++ b/include/internal/catch_interfaces_capture.h @@ -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(); diff --git a/include/internal/catch_interfaces_config.h b/include/internal/catch_interfaces_config.h index c7610d99..1281bd7e 100644 --- a/include/internal/catch_interfaces_config.h +++ b/include/internal/catch_interfaces_config.h @@ -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; }; } diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h index 872b65c5..5296177a 100644 --- a/include/internal/catch_interfaces_reporter.h +++ b/include/internal/catch_interfaces_reporter.h @@ -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; }; diff --git a/include/internal/catch_interfaces_testcase.h b/include/internal/catch_interfaces_testcase.h index 21ed3c3a..a23ff9f4 100644 --- a/include/internal/catch_interfaces_testcase.h +++ b/include/internal/catch_interfaces_testcase.h @@ -28,7 +28,7 @@ namespace Catch { struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases ) const = 0; + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; }; } diff --git a/include/internal/catch_legacy_reporter_adapter.h b/include/internal/catch_legacy_reporter_adapter.h index fb579c7c..72c43d7d 100644 --- a/include/internal/catch_legacy_reporter_adapter.h +++ b/include/internal/catch_legacy_reporter_adapter.h @@ -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 m_legacyReporter; diff --git a/include/internal/catch_legacy_reporter_adapter.hpp b/include/internal/catch_legacy_reporter_adapter.hpp index 09f73b28..6034581e 100644 --- a/include/internal/catch_legacy_reporter_adapter.hpp +++ b/include/internal/catch_legacy_reporter_adapter.hpp @@ -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 diff --git a/include/internal/catch_list.hpp b/include/internal/catch_list.hpp index 53cd37d6..1c510ef8 100644 --- a/include/internal/catch_list.hpp +++ b/include/internal/catch_list.hpp @@ -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(); } diff --git a/include/internal/catch_objc.hpp b/include/internal/catch_objc.hpp index 88b5ef78..7e315c22 100644 --- a/include/internal/catch_objc.hpp +++ b/include/internal/catch_objc.hpp @@ -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 diff --git a/include/internal/catch_reenable_warnings.h b/include/internal/catch_reenable_warnings.h index 07765f4b..33574e05 100644 --- a/include/internal/catch_reenable_warnings.h +++ b/include/internal/catch_reenable_warnings.h @@ -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 diff --git a/include/internal/catch_result_type.h b/include/internal/catch_result_type.h index ce00ef03..31ad3e60 100644 --- a/include/internal/catch_result_type.h +++ b/include/internal/catch_result_type.h @@ -25,7 +25,9 @@ namespace Catch { Exception = 0x100 | FailureBit, ThrewException = Exception | 1, - DidntThrowException = Exception | 2 + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit }; }; diff --git a/include/internal/catch_runner_impl.hpp b/include/internal/catch_runner_impl.hpp index fa4f3193..e6893518 100644 --- a/include/internal/catch_runner_impl.hpp +++ b/include/internal/catch_runner_impl.hpp @@ -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 #include @@ -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::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::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 ) diff --git a/include/internal/catch_section.h b/include/internal/catch_section.h index f83d828b..d8b3ae42 100644 --- a/include/internal/catch_section.h +++ b/include/internal/catch_section.h @@ -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; diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h index 70ddb58c..402a6617 100644 --- a/include/internal/catch_stream.h +++ b/include/internal/catch_stream.h @@ -28,6 +28,9 @@ namespace Catch { private: bool isOwned; }; + + std::ostream& cout(); + std::ostream& cerr(); } #endif // TWOBLUECUBES_CATCH_STREAM_H_INCLUDED diff --git a/include/internal/catch_stream.hpp b/include/internal/catch_stream.hpp index adfacbf1..604ed97b 100644 --- a/include/internal/catch_stream.hpp +++ b/include/internal/catch_stream.hpp @@ -15,6 +15,7 @@ #include #include +#include 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 diff --git a/include/internal/catch_suppress_warnings.h b/include/internal/catch_suppress_warnings.h index cc36c073..7351f63b 100644 --- a/include/internal/catch_suppress_warnings.h +++ b/include/internal/catch_suppress_warnings.h @@ -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 diff --git a/include/internal/catch_tag_alias_registry.hpp b/include/internal/catch_tag_alias_registry.hpp index fea7ce9c..e5ad11b2 100644 --- a/include/internal/catch_tag_alias_registry.hpp +++ b/include/internal/catch_tag_alias_registry.hpp @@ -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); } } diff --git a/include/internal/catch_test_case_info.hpp b/include/internal/catch_test_case_info.hpp index e3fa1f7d..308ddc74 100644 --- a/include/internal/catch_test_case_info.hpp +++ b/include/internal/catch_test_case_info.hpp @@ -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; diff --git a/include/internal/catch_test_case_registry_impl.hpp b/include/internal/catch_test_case_registry_impl.hpp index ecffa2e5..21165a30 100644 --- a/include/internal/catch_test_case_registry_impl.hpp +++ b/include/internal/catch_test_case_registry_impl.hpp @@ -17,10 +17,18 @@ #include #include #include +#include namespace Catch { class TestRegistry : public ITestCaseRegistry { + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i& matchingTestCases ) const { + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { + for( std::vector::const_iterator it = m_functionsInOrder.begin(), itEnd = m_functionsInOrder.end(); it != itEnd; ++it ) { - 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& matchingTestCases ) { + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + RandomNumberGenerator rng; + std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + } std::set m_functions; std::vector m_functionsInOrder; std::vector m_nonHiddenFunctions; diff --git a/include/internal/catch_test_registry.hpp b/include/internal/catch_test_registry.hpp index 73de60b4..d12411d4 100644 --- a/include/internal/catch_test_registry.hpp +++ b/include/internal/catch_test_registry.hpp @@ -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 { diff --git a/include/internal/catch_timer.h b/include/internal/catch_timer.h index 015f88bc..22e9e635 100644 --- a/include/internal/catch_timer.h +++ b/include/internal/catch_timer.h @@ -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; diff --git a/include/internal/catch_timer.hpp b/include/internal/catch_timer.hpp index b60fa2b5..47d9536b 100644 --- a/include/internal/catch_timer.hpp +++ b/include/internal/catch_timer.hpp @@ -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( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); } uint64_t t; - QueryPerformanceCounter((LARGE_INTEGER*)&t); + QueryPerformanceCounter( reinterpret_cast( &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(getCurrentTicks() - m_ticks); } unsigned int Timer::getElapsedMilliseconds() const { - return static_cast((getCurrentTicks() - m_ticks)/1000); + return static_cast(getElapsedMicroseconds()/1000); } double Timer::getElapsedSeconds() const { - return (getCurrentTicks() - m_ticks)/1000000.0; + return getElapsedMicroseconds()/1000000.0; } } // namespace Catch diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h index e8e38296..8e6e1581 100644 --- a/include/internal/catch_tostring.h +++ b/include/internal/catch_tostring.h @@ -21,9 +21,50 @@ #include "catch_objc_arc.hpp" #endif +#ifdef CATCH_CPP11_OR_GREATER +#include +#include +#endif + namespace Catch { + +// Why we're here. +template +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::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif template struct StringMakerBase { +#if defined(CATCH_CPP11_OR_GREATER) template - static std::string convert( T const& ) { return "{?}"; } + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif }; template<> @@ -89,9 +158,6 @@ namespace Detail { } // end namespace Detail -template -std::string toString( T const& value ); - template struct StringMaker : Detail::StringMakerBase::value> {}; @@ -122,12 +188,60 @@ namespace Detail { std::string rangeToString( InputIterator first, InputIterator last ); } +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + template -struct StringMaker > { - static std::string convert( std::vector const& v ) { - return Detail::rangeToString( v.begin(), v.end() ); +std::string toString( std::vector 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::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); } }; +#endif namespace Detail { template @@ -148,33 +262,6 @@ std::string toString( T const& value ) { return StringMaker::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 @@ -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(); diff --git a/include/internal/catch_tostring.hpp b/include/internal/catch_tostring.hpp index f9369f1e..c4b3f152 100644 --- a/include/internal/catch_tostring.hpp +++ b/include/internal/catch_tostring.hpp @@ -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( 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( value ) ); + return Catch::toString( static_cast( value ) ); } template diff --git a/include/internal/catch_totals.hpp b/include/internal/catch_totals.hpp index 75386ae8..551e2947 100644 --- a/include/internal/catch_totals.hpp +++ b/include/internal/catch_totals.hpp @@ -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; diff --git a/include/internal/catch_version.hpp b/include/internal/catch_version.hpp index db7a7ec8..9507b38a 100644 --- a/include/internal/catch_version.hpp +++ b/include/internal/catch_version.hpp @@ -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 diff --git a/include/internal/catch_xmlwriter.hpp b/include/internal/catch_xmlwriter.hpp index 52d66bce..d47c2b4d 100644 --- a/include/internal/catch_xmlwriter.hpp +++ b/include/internal/catch_xmlwriter.hpp @@ -8,8 +8,9 @@ #ifndef TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED +#include "../internal/catch_stream.h" + #include -#include #include #include @@ -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 ) diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp index ddbc63b7..865dc29e 100644 --- a/include/reporters/catch_reporter_bases.hpp +++ b/include/reporters/catch_reporter_bases.hpp @@ -10,6 +10,8 @@ #include "../internal/catch_interfaces_reporter.h" +#include + namespace Catch { struct StreamingReporterBase : SharedImpl { @@ -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 m_config; std::ostream& stream; @@ -183,6 +189,8 @@ namespace Catch { } virtual void testRunEndedCumulative() = 0; + virtual void skipTest( TestCaseInfo const& ) {} + Ptr m_config; std::ostream& stream; std::vector m_assertions; @@ -198,6 +206,16 @@ namespace Catch { }; + template + 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 diff --git a/include/reporters/catch_reporter_compact.hpp b/include/reporters/catch_reporter_compact.hpp index 7a6353e6..a5a17297 100644 --- a/include/reporters/catch_reporter_compact.hpp +++ b/include/reporters/catch_reporter_compact.hpp @@ -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" ); diff --git a/include/reporters/catch_reporter_console.hpp b/include/reporters/catch_reporter_console.hpp index 7246d328..16896f4c 100644 --- a/include/reporters/catch_reporter_console.hpp +++ b/include/reporters/catch_reporter_console.hpp @@ -13,8 +13,6 @@ #include "../internal/catch_reporter_registrars.hpp" #include "../internal/catch_console_colour.hpp" -#include - 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 - 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; diff --git a/include/reporters/catch_reporter_junit.hpp b/include/reporters/catch_reporter_junit.hpp index 63f7e148..f9524aaf 100644 --- a/include/reporters/catch_reporter_junit.hpp +++ b/include/reporters/catch_reporter_junit.hpp @@ -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: diff --git a/include/reporters/catch_reporter_teamcity.hpp b/include/reporters/catch_reporter_teamcity.hpp new file mode 100644 index 00000000..0647244f --- /dev/null +++ b/include/reporters/catch_reporter_teamcity.hpp @@ -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 + +#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::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::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 diff --git a/include/reporters/catch_reporter_xml.hpp b/include/reporters/catch_reporter_xml.hpp index aa2cfeda..d8cb1dd1 100644 --- a/include/reporters/catch_reporter_xml.hpp +++ b/include/reporters/catch_reporter_xml.hpp @@ -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 { + 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 tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::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 diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt index c31ec32b..240e1ebe 100644 --- a/projects/CMake/CMakeLists.txt +++ b/projects/CMake/CMakeLists.txt @@ -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 diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 3b67d501..16b9b0a7 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -1,6 +1,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -CatchSelfTest is a host application. +CatchSelfTest is a (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: ............................................................................... @@ -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: ............................................................................... @@ -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: ............................................................................... @@ -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: ............................................................................... @@ -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 diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index d7bd8232..e254c3c3 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -1,8 +1,88 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -CatchSelfTest is a host application. +CatchSelfTest is a (develop) host application. Run with -? for options +------------------------------------------------------------------------------- +toString(enum) +------------------------------------------------------------------------------- +EnumToString.cpp: +............................................................................... + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e0) == "0" ) +with expansion: + "0" == "0" + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e1) == "1" ) +with expansion: + "1" == "1" + +------------------------------------------------------------------------------- +toString(enum w/operator<<) +------------------------------------------------------------------------------- +EnumToString.cpp: +............................................................................... + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e0) == "E2{0}" ) +with expansion: + "E2{0}" == "E2{0}" + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e1) == "E2{1}" ) +with expansion: + "E2{1}" == "E2{1}" + +------------------------------------------------------------------------------- +toString(enum class) +------------------------------------------------------------------------------- +EnumToString.cpp: +............................................................................... + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e0) == "0" ) +with expansion: + "0" == "0" + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e1) == "1" ) +with expansion: + "1" == "1" + +------------------------------------------------------------------------------- +toString(enum class w/operator<<) +------------------------------------------------------------------------------- +EnumToString.cpp: +............................................................................... + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e0) == "E2/V0" ) +with expansion: + "E2/V0" == "E2/V0" + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e1) == "E2/V1" ) +with expansion: + "E2/V1" == "E2/V1" + +EnumToString.cpp:: +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:: PASSED: REQUIRE( Factorial(10) == 3628800 ) with expansion: - 0x == 3628800 + 0x == 0x ------------------------------------------------------------------------------- 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: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK_NOTHROW( parseIntoConfig( argv, config ) ) + +TestMain.cpp:: +PASSED: + REQUIRE( config.forceColour ) +with expansion: + true + +------------------------------------------------------------------------------- +Process can be configured on command line + force-colour + without --force-colour +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK_NOTHROW( parseIntoConfig( argv, config ) ) + +TestMain.cpp:: +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: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK( replaceInPlace( letters, "b", "z" ) ) +with expansion: + true + +TestMain.cpp:: +PASSED: + CHECK( letters == "azcdefcg" ) +with expansion: + "azcdefcg" == "azcdefcg" + +------------------------------------------------------------------------------- +replaceInPlace + replace two chars +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK( replaceInPlace( letters, "c", "z" ) ) +with expansion: + true + +TestMain.cpp:: +PASSED: + CHECK( letters == "abzdefzg" ) +with expansion: + "abzdefzg" == "abzdefzg" + +------------------------------------------------------------------------------- +replaceInPlace + replace first char +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK( replaceInPlace( letters, "a", "z" ) ) +with expansion: + true + +TestMain.cpp:: +PASSED: + CHECK( letters == "zbcdefcg" ) +with expansion: + "zbcdefcg" == "zbcdefcg" + +------------------------------------------------------------------------------- +replaceInPlace + replace last char +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK( replaceInPlace( letters, "g", "z" ) ) +with expansion: + true + +TestMain.cpp:: +PASSED: + CHECK( letters == "abcdefcz" ) +with expansion: + "abcdefcz" == "abcdefcz" + +------------------------------------------------------------------------------- +replaceInPlace + replace all chars +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK( replaceInPlace( letters, letters, "replaced" ) ) +with expansion: + true + +TestMain.cpp:: +PASSED: + CHECK( letters == "replaced" ) +with expansion: + "replaced" == "replaced" + +------------------------------------------------------------------------------- +replaceInPlace + replace no chars +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK_FALSE( replaceInPlace( letters, "x", "z" ) ) +with expansion: + !false + +TestMain.cpp:: +PASSED: + CHECK( letters == letters ) +with expansion: + "abcdefcg" == "abcdefcg" + +------------------------------------------------------------------------------- +replaceInPlace + escape ' +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK( replaceInPlace( s, "'", "|'" ) ) +with expansion: + true + +TestMain.cpp:: +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: ............................................................................... @@ -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: ............................................................................... @@ -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: ............................................................................... @@ -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: ............................................................................... @@ -5905,6 +6154,234 @@ TrickyTests.cpp: TrickyTests.cpp:: PASSED: +------------------------------------------------------------------------------- +toString( has_toString ) +------------------------------------------------------------------------------- +ToStringWhich.cpp: +............................................................................... + +ToStringWhich.cpp:: +PASSED: + REQUIRE( Catch::toString( item ) == "toString( has_toString )" ) +with expansion: + "toString( has_toString )" + == + "toString( has_toString )" + +------------------------------------------------------------------------------- +toString( has_maker ) +------------------------------------------------------------------------------- +ToStringWhich.cpp: +............................................................................... + +ToStringWhich.cpp:: +PASSED: + REQUIRE( Catch::toString( item ) == "StringMaker" ) +with expansion: + "StringMaker" + == + "StringMaker" + +------------------------------------------------------------------------------- +toString( has_maker_and_toString ) +------------------------------------------------------------------------------- +ToStringWhich.cpp: +............................................................................... + +ToStringWhich.cpp:: +PASSED: + REQUIRE( Catch::toString( item ) == "toString( has_maker_and_toString )" ) +with expansion: + "toString( has_maker_and_toString )" + == + "toString( has_maker_and_toString )" + +------------------------------------------------------------------------------- +toString( vectors +............................................................................... + +ToStringWhich.cpp:: +PASSED: + REQUIRE( Catch::toString( v ) == "{ {?} }" ) +with expansion: + "{ {?} }" == "{ {?} }" + +------------------------------------------------------------------------------- +toString( vectors +............................................................................... + +ToStringWhich.cpp:: +PASSED: + REQUIRE( Catch::toString( v ) == "{ StringMaker }" ) +with expansion: + "{ StringMaker }" + == + "{ StringMaker }" + +------------------------------------------------------------------------------- +toString( vectors +............................................................................... + +ToStringWhich.cpp:: +PASSED: + REQUIRE( Catch::toString( v ) == "{ StringMaker }" ) +with expansion: + "{ StringMaker }" + == + "{ StringMaker }" + +------------------------------------------------------------------------------- +std::pair -> toString +------------------------------------------------------------------------------- +ToStringPair.cpp: +............................................................................... + +ToStringPair.cpp:: +PASSED: + REQUIRE( Catch::toString( value ) == "{ 34, \"xyzzy\" }" ) +with expansion: + "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" + +------------------------------------------------------------------------------- +std::pair -> toString +------------------------------------------------------------------------------- +ToStringPair.cpp: +............................................................................... + +ToStringPair.cpp:: +PASSED: + REQUIRE( Catch::toString(value) == "{ 34, \"xyzzy\" }" ) +with expansion: + "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" + +------------------------------------------------------------------------------- +std::vector > -> toString +------------------------------------------------------------------------------- +ToStringPair.cpp: +............................................................................... + +ToStringPair.cpp:: +PASSED: + REQUIRE( Catch::toString( pr ) == "{ { \"green\", 55 } }" ) +with expansion: + "{ { "green", 55 } }" + == + "{ { "green", 55 } }" + +------------------------------------------------------------------------------- +pair > -> toString +------------------------------------------------------------------------------- +ToStringPair.cpp: +............................................................................... + +ToStringPair.cpp:: +PASSED: + REQUIRE( Catch::toString( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" ) +with expansion: + "{ { 42, "Arthur" }, { "Ford", 24 } }" + == + "{ { 42, "Arthur" }, { "Ford", 24 } }" + +------------------------------------------------------------------------------- +vector -> toString +------------------------------------------------------------------------------- +ToStringVector.cpp: +............................................................................... + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(vv) == "{ }" ) +with expansion: + "{ }" == "{ }" + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(vv) == "{ 42 }" ) +with expansion: + "{ 42 }" == "{ 42 }" + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(vv) == "{ 42, 512 }" ) +with expansion: + "{ 42, 512 }" == "{ 42, 512 }" + +------------------------------------------------------------------------------- +vector -> toString +------------------------------------------------------------------------------- +ToStringVector.cpp: +............................................................................... + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(vv) == "{ }" ) +with expansion: + "{ }" == "{ }" + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(vv) == "{ \"hello\" }" ) +with expansion: + "{ "hello" }" == "{ "hello" }" + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(vv) == "{ \"hello\", \"world\" }" ) +with expansion: + "{ "hello", "world" }" + == + "{ "hello", "world" }" + +------------------------------------------------------------------------------- +vector -> toString +------------------------------------------------------------------------------- +ToStringVector.cpp: +............................................................................... + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(vv) == "{ }" ) +with expansion: + "{ }" == "{ }" + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(vv) == "{ 42 }" ) +with expansion: + "{ 42 }" == "{ 42 }" + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(vv) == "{ 42, 512 }" ) +with expansion: + "{ 42, 512 }" == "{ 42, 512 }" + +------------------------------------------------------------------------------- +vec> -> toString +------------------------------------------------------------------------------- +ToStringVector.cpp: +............................................................................... + +ToStringVector.cpp:: +PASSED: + REQUIRE( Catch::toString(v) == "{ }" ) +with expansion: + "{ }" == "{ }" + +ToStringVector.cpp:: +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: +............................................................................... + +ToStringTuple.cpp:: +PASSED: + CHECK( "{ }" == Catch::toString(type{}) ) +with expansion: + "{ }" == "{ }" + +ToStringTuple.cpp:: +PASSED: + CHECK( "{ }" == Catch::toString(value) ) +with expansion: + "{ }" == "{ }" + +------------------------------------------------------------------------------- +tuple +------------------------------------------------------------------------------- +ToStringTuple.cpp: +............................................................................... + +ToStringTuple.cpp:: +PASSED: + CHECK( "{ 0 }" == Catch::toString(type{0}) ) +with expansion: + "{ 0 }" == "{ 0 }" + +------------------------------------------------------------------------------- +tuple +------------------------------------------------------------------------------- +ToStringTuple.cpp: +............................................................................... + +ToStringTuple.cpp:: +PASSED: + CHECK( "1.2f" == Catch::toString(float(1.2)) ) +with expansion: + "1.2f" == "1.2f" + +ToStringTuple.cpp:: +PASSED: + CHECK( "{ 1.2f, 0 }" == Catch::toString(type{1.2,0}) ) +with expansion: + "{ 1.2f, 0 }" == "{ 1.2f, 0 }" + +------------------------------------------------------------------------------- +tuple +------------------------------------------------------------------------------- +ToStringTuple.cpp: +............................................................................... + +ToStringTuple.cpp:: +PASSED: + CHECK( "{ \"hello\", \"world\" }" == Catch::toString(type{"hello","world"}) ) +with expansion: + "{ "hello", "world" }" + == + "{ "hello", "world" }" + +------------------------------------------------------------------------------- +tuple,tuple<>,float> +------------------------------------------------------------------------------- +ToStringTuple.cpp: +............................................................................... + +ToStringTuple.cpp:: +PASSED: + CHECK( "{ { 42 }, { }, 1.2f }" == Catch::toString(value) ) +with expansion: + "{ { 42 }, { }, 1.2f }" + == + "{ { 42 }, { }, 1.2f }" + +------------------------------------------------------------------------------- +tuple +------------------------------------------------------------------------------- +ToStringTuple.cpp: +............................................................................... + +ToStringTuple.cpp:: +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 diff --git a/projects/SelfTest/Baselines/console.swa4.approved.txt b/projects/SelfTest/Baselines/console.swa4.approved.txt index ac06c1c7..c8993019 100644 --- a/projects/SelfTest/Baselines/console.swa4.approved.txt +++ b/projects/SelfTest/Baselines/console.swa4.approved.txt @@ -1,8 +1,88 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -CatchSelfTest is a host application. +CatchSelfTest is a (develop) host application. Run with -? for options +------------------------------------------------------------------------------- +toString(enum) +------------------------------------------------------------------------------- +EnumToString.cpp: +............................................................................... + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e0) == "0" ) +with expansion: + "0" == "0" + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e1) == "1" ) +with expansion: + "1" == "1" + +------------------------------------------------------------------------------- +toString(enum w/operator<<) +------------------------------------------------------------------------------- +EnumToString.cpp: +............................................................................... + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e0) == "E2{0}" ) +with expansion: + "E2{0}" == "E2{0}" + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e1) == "E2{1}" ) +with expansion: + "E2{1}" == "E2{1}" + +------------------------------------------------------------------------------- +toString(enum class) +------------------------------------------------------------------------------- +EnumToString.cpp: +............................................................................... + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e0) == "0" ) +with expansion: + "0" == "0" + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e1) == "1" ) +with expansion: + "1" == "1" + +------------------------------------------------------------------------------- +toString(enum class w/operator<<) +------------------------------------------------------------------------------- +EnumToString.cpp: +............................................................................... + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e0) == "E2/V0" ) +with expansion: + "E2/V0" == "E2/V0" + +EnumToString.cpp:: +PASSED: + CHECK( Catch::toString(e1) == "E2/V1" ) +with expansion: + "E2/V1" == "E2/V1" + +EnumToString.cpp:: +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 diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index d0e29857..48b84679 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,5 +1,9 @@ - + + + + + @@ -469,6 +473,8 @@ MiscTests.cpp: + + @@ -481,6 +487,13 @@ MiscTests.cpp: + + + + + + + hello @@ -490,9 +503,9 @@ hello - - - + + + TrickyTests.cpp: @@ -500,7 +513,7 @@ TrickyTests.cpp: TrickyTests.cpp: - + TrickyTests.cpp: @@ -529,6 +542,20 @@ TrickyTests.cpp: + + + + + + + + + + + + + + @@ -560,6 +587,12 @@ TrickyTests.cpp: + + + + + + diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index 498f899e..4d14a677 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -1,7 +1,93 @@ + + + + Catch::toString(e0) == "0" + + + "0" == "0" + + + + + Catch::toString(e1) == "1" + + + "1" == "1" + + + + + + + + Catch::toString(e0) == "E2{0}" + + + "E2{0}" == "E2{0}" + + + + + Catch::toString(e1) == "E2{1}" + + + "E2{1}" == "E2{1}" + + + + + + + + Catch::toString(e0) == "0" + + + "0" == "0" + + + + + Catch::toString(e1) == "1" + + + "1" == "1" + + + + + + + + Catch::toString(e0) == "E2/V0" + + + "E2/V0" == "E2/V0" + + + + + Catch::toString(e1) == "E2/V1" + + + "E2/V1" == "E2/V1" + + + + + Catch::toString(e3) == "Unknown enum value 10" + + + "Unknown enum value 10" +== +"Unknown enum value 10" + + + + - + d == Approx( 1.23 ) @@ -9,7 +95,7 @@ 1.23 == Approx( 1.23 ) - + d != Approx( 1.22 ) @@ -17,7 +103,7 @@ 1.23 != Approx( 1.22 ) - + d != Approx( 1.24 ) @@ -25,7 +111,7 @@ 1.23 != Approx( 1.24 ) - + Approx( d ) == 1.23 @@ -33,7 +119,7 @@ Approx( 1.23 ) == 1.23 - + Approx( d ) != 1.22 @@ -41,7 +127,7 @@ Approx( 1.23 ) != 1.22 - + Approx( d ) != 1.24 @@ -52,7 +138,7 @@ - + d != Approx( 1.231 ) @@ -60,7 +146,7 @@ 1.23 != Approx( 1.231 ) - + d == Approx( 1.231 ).epsilon( 0.1 ) @@ -71,7 +157,7 @@ - + 1.23f == Approx( 1.23f ) @@ -79,7 +165,7 @@ 1.23f == Approx( 1.2300000191 ) - + 0.0f == Approx( 0.0f ) @@ -90,7 +176,7 @@ - + 1 == Approx( 1 ) @@ -98,7 +184,7 @@ 1 == Approx( 1.0 ) - + 0 == Approx( 0 ) @@ -109,7 +195,7 @@ - + 1.0f == Approx( 1 ) @@ -117,7 +203,7 @@ 1.0f == Approx( 1.0 ) - + 0 == Approx( dZero) @@ -125,7 +211,7 @@ 0 == Approx( 0.0 ) - + 0 == Approx( dSmall ).epsilon( 0.001 ) @@ -133,7 +219,7 @@ 0 == Approx( 0.00001 ) - + 1.234f == Approx( dMedium ) @@ -141,7 +227,7 @@ 1.234f == Approx( 1.234 ) - + dMedium == Approx( 1.234f ) @@ -152,7 +238,7 @@ - + d == approx( 1.23 ) @@ -160,7 +246,7 @@ 1.23 == Approx( 1.23 ) - + d == approx( 1.22 ) @@ -168,7 +254,7 @@ 1.23 == Approx( 1.22 ) - + d == approx( 1.24 ) @@ -176,7 +262,7 @@ 1.23 == Approx( 1.24 ) - + d != approx( 1.25 ) @@ -184,7 +270,7 @@ 1.23 != Approx( 1.25 ) - + approx( d ) == 1.23 @@ -192,7 +278,7 @@ Approx( 1.23 ) == 1.23 - + approx( d ) == 1.22 @@ -200,7 +286,7 @@ Approx( 1.23 ) == 1.22 - + approx( d ) == 1.24 @@ -208,7 +294,7 @@ Approx( 1.23 ) == 1.24 - + approx( d ) != 1.25 @@ -219,7 +305,7 @@ - + divide( 22, 7 ) == Approx( 3.141 ).epsilon( 0.001 ) @@ -227,7 +313,7 @@ 3.1428571429 == Approx( 3.141 ) - + divide( 22, 7 ) != Approx( 3.141 ).epsilon( 0.0001 ) @@ -238,7 +324,7 @@ - + s == "hello" @@ -249,7 +335,7 @@ - + s == "world" @@ -260,7 +346,7 @@ - + m_a == 1 @@ -271,7 +357,7 @@ - + m_a == 2 @@ -282,7 +368,7 @@ - + data.int_seven == 7 @@ -290,7 +376,7 @@ 7 == 7 - + data.float_nine_point_one == Approx( 9.1f ) @@ -298,7 +384,7 @@ 9.1f == Approx( 9.1000003815 ) - + data.double_pi == Approx( 3.1415926535 ) @@ -306,7 +392,7 @@ 3.1415926535 == Approx( 3.1415926535 ) - + data.str_hello == "hello" @@ -314,7 +400,7 @@ "hello" == "hello" - + "hello" == data.str_hello @@ -322,7 +408,7 @@ "hello" == "hello" - + data.str_hello.size() == 5 @@ -330,7 +416,7 @@ 5 == 5 - + x == Approx( 1.3 ) @@ -341,7 +427,7 @@ - + data.int_seven == 6 @@ -349,7 +435,7 @@ 7 == 6 - + data.int_seven == 8 @@ -357,7 +443,7 @@ 7 == 8 - + data.int_seven == 0 @@ -365,7 +451,7 @@ 7 == 0 - + data.float_nine_point_one == Approx( 9.11f ) @@ -373,7 +459,7 @@ 9.1f == Approx( 9.1099996567 ) - + data.float_nine_point_one == Approx( 9.0f ) @@ -381,7 +467,7 @@ 9.1f == Approx( 9.0 ) - + data.float_nine_point_one == Approx( 1 ) @@ -389,7 +475,7 @@ 9.1f == Approx( 1.0 ) - + data.float_nine_point_one == Approx( 0 ) @@ -397,7 +483,7 @@ 9.1f == Approx( 0.0 ) - + data.double_pi == Approx( 3.1415 ) @@ -405,7 +491,7 @@ 3.1415926535 == Approx( 3.1415 ) - + data.str_hello == "goodbye" @@ -413,7 +499,7 @@ "hello" == "goodbye" - + data.str_hello == "hell" @@ -421,7 +507,7 @@ "hello" == "hell" - + data.str_hello == "hello1" @@ -429,7 +515,7 @@ "hello" == "hello1" - + data.str_hello.size() == 6 @@ -437,7 +523,7 @@ 5 == 6 - + x == Approx( 1.301 ) @@ -445,10 +531,10 @@ 1.3 == Approx( 1.301 ) - + - + data.int_seven != 6 @@ -456,7 +542,7 @@ 7 != 6 - + data.int_seven != 8 @@ -464,7 +550,7 @@ 7 != 8 - + data.float_nine_point_one != Approx( 9.11f ) @@ -472,7 +558,7 @@ 9.1f != Approx( 9.1099996567 ) - + data.float_nine_point_one != Approx( 9.0f ) @@ -480,7 +566,7 @@ 9.1f != Approx( 9.0 ) - + data.float_nine_point_one != Approx( 1 ) @@ -488,7 +574,7 @@ 9.1f != Approx( 1.0 ) - + data.float_nine_point_one != Approx( 0 ) @@ -496,7 +582,7 @@ 9.1f != Approx( 0.0 ) - + data.double_pi != Approx( 3.1415 ) @@ -504,7 +590,7 @@ 3.1415926535 != Approx( 3.1415 ) - + data.str_hello != "goodbye" @@ -512,7 +598,7 @@ "hello" != "goodbye" - + data.str_hello != "hell" @@ -520,7 +606,7 @@ "hello" != "hell" - + data.str_hello != "hello1" @@ -528,7 +614,7 @@ "hello" != "hello1" - + data.str_hello.size() != 6 @@ -539,7 +625,7 @@ - + data.int_seven != 7 @@ -547,7 +633,7 @@ 7 != 7 - + data.float_nine_point_one != Approx( 9.1f ) @@ -555,7 +641,7 @@ 9.1f != Approx( 9.1000003815 ) - + data.double_pi != Approx( 3.1415926535 ) @@ -563,7 +649,7 @@ 3.1415926535 != Approx( 3.1415926535 ) - + data.str_hello != "hello" @@ -571,7 +657,7 @@ "hello" != "hello" - + data.str_hello.size() != 5 @@ -582,7 +668,7 @@ - + data.int_seven < 8 @@ -590,7 +676,7 @@ 7 < 8 - + data.int_seven > 6 @@ -598,7 +684,7 @@ 7 > 6 - + data.int_seven > 0 @@ -606,7 +692,7 @@ 7 > 0 - + data.int_seven > -1 @@ -614,7 +700,7 @@ 7 > -1 - + data.int_seven >= 7 @@ -622,7 +708,7 @@ 7 >= 7 - + data.int_seven >= 6 @@ -630,7 +716,7 @@ 7 >= 6 - + data.int_seven <= 7 @@ -638,7 +724,7 @@ 7 <= 7 - + data.int_seven <= 8 @@ -646,7 +732,7 @@ 7 <= 8 - + data.float_nine_point_one > 9 @@ -654,7 +740,7 @@ 9.1f > 9 - + data.float_nine_point_one < 10 @@ -662,7 +748,7 @@ 9.1f < 10 - + data.float_nine_point_one < 9.2 @@ -670,7 +756,7 @@ 9.1f < 9.2 - + data.str_hello <= "hello" @@ -678,7 +764,7 @@ "hello" <= "hello" - + data.str_hello >= "hello" @@ -686,7 +772,7 @@ "hello" >= "hello" - + data.str_hello < "hellp" @@ -694,7 +780,7 @@ "hello" < "hellp" - + data.str_hello < "zebra" @@ -702,7 +788,7 @@ "hello" < "zebra" - + data.str_hello > "hellm" @@ -710,7 +796,7 @@ "hello" > "hellm" - + data.str_hello > "a" @@ -721,7 +807,7 @@ - + data.int_seven > 7 @@ -729,7 +815,7 @@ 7 > 7 - + data.int_seven < 7 @@ -737,7 +823,7 @@ 7 < 7 - + data.int_seven > 8 @@ -745,7 +831,7 @@ 7 > 8 - + data.int_seven < 6 @@ -753,7 +839,7 @@ 7 < 6 - + data.int_seven < 0 @@ -761,7 +847,7 @@ 7 < 0 - + data.int_seven < -1 @@ -769,7 +855,7 @@ 7 < -1 - + data.int_seven >= 8 @@ -777,7 +863,7 @@ 7 >= 8 - + data.int_seven <= 6 @@ -785,7 +871,7 @@ 7 <= 6 - + data.float_nine_point_one < 9 @@ -793,7 +879,7 @@ 9.1f < 9 - + data.float_nine_point_one > 10 @@ -801,7 +887,7 @@ 9.1f > 10 - + data.float_nine_point_one > 9.2 @@ -809,7 +895,7 @@ 9.1f > 9.2 - + data.str_hello > "hello" @@ -817,7 +903,7 @@ "hello" > "hello" - + data.str_hello < "hello" @@ -825,7 +911,7 @@ "hello" < "hello" - + data.str_hello > "hellp" @@ -833,7 +919,7 @@ "hello" > "hellp" - + data.str_hello > "z" @@ -841,7 +927,7 @@ "hello" > "z" - + data.str_hello < "hellm" @@ -849,7 +935,7 @@ "hello" < "hellm" - + data.str_hello < "a" @@ -857,7 +943,7 @@ "hello" < "a" - + data.str_hello >= "z" @@ -865,7 +951,7 @@ "hello" >= "z" - + data.str_hello <= "a" @@ -876,7 +962,7 @@ - + i == 1 @@ -884,7 +970,7 @@ 1 == 1 - + ui == 2 @@ -892,7 +978,7 @@ 2 == 2 - + l == 3 @@ -900,7 +986,7 @@ 3 == 3 - + ul == 4 @@ -908,7 +994,7 @@ 4 == 4 - + c == 5 @@ -916,7 +1002,7 @@ 5 == 5 - + uc == 6 @@ -924,7 +1010,7 @@ 6 == 6 - + 1 == i @@ -932,7 +1018,7 @@ 1 == 1 - + 2 == ui @@ -940,7 +1026,7 @@ 2 == 2 - + 3 == l @@ -948,7 +1034,7 @@ 3 == 3 - + 4 == ul @@ -956,7 +1042,7 @@ 4 == 4 - + 5 == c @@ -964,7 +1050,7 @@ 5 == 5 - + 6 == uc @@ -972,7 +1058,7 @@ 6 == 6 - + (std::numeric_limits<unsigned long>::max)() > ul @@ -983,7 +1069,7 @@ - + long_var == unsigned_char_var @@ -991,7 +1077,7 @@ 1 == 1 - + long_var == unsigned_short_var @@ -999,7 +1085,7 @@ 1 == 1 - + long_var == unsigned_int_var @@ -1007,7 +1093,7 @@ 1 == 1 - + long_var == unsigned_long_var @@ -1018,7 +1104,7 @@ - + unsigned_char_var == 1 @@ -1026,7 +1112,7 @@ 1 == 1 - + unsigned_short_var == 1 @@ -1034,7 +1120,7 @@ 1 == 1 - + unsigned_int_var == 1 @@ -1042,7 +1128,7 @@ 1 == 1 - + unsigned_long_var == 1 @@ -1053,7 +1139,7 @@ - + ( -1 > 2u ) @@ -1061,7 +1147,7 @@ true - + -1 > 2u @@ -1069,7 +1155,7 @@ -1 > 2 - + ( 2u < -1 ) @@ -1077,7 +1163,7 @@ true - + 2u < -1 @@ -1085,7 +1171,7 @@ 2 < -1 - + ( minInt > 2u ) @@ -1093,7 +1179,7 @@ true - + minInt > 2u @@ -1104,7 +1190,7 @@ - + 54 == 6*9 @@ -1115,7 +1201,7 @@ - + p == __null @@ -1123,7 +1209,7 @@ __null == 0 - + p == pNULL @@ -1131,7 +1217,7 @@ __null == __null - + p != __null @@ -1139,7 +1225,7 @@ 0x != 0 - + cp != __null @@ -1147,7 +1233,7 @@ 0x != 0 - + cpc != __null @@ -1155,7 +1241,7 @@ 0x != 0 - + returnsNull() == __null @@ -1163,7 +1249,7 @@ {null string} == 0 - + returnsConstNull() == __null @@ -1171,7 +1257,7 @@ {null string} == 0 - + __null != p @@ -1182,7 +1268,7 @@ - + false == false @@ -1190,7 +1276,7 @@ false == false - + true == true @@ -1198,7 +1284,7 @@ true == true - + !false @@ -1206,7 +1292,7 @@ true - + !false @@ -1214,7 +1300,7 @@ !false - + !falseValue @@ -1222,7 +1308,7 @@ true - + !falseValue @@ -1230,7 +1316,7 @@ !false - + !(1 == 2) @@ -1238,7 +1324,7 @@ true - + !1 == 2 @@ -1249,7 +1335,7 @@ - + false != false @@ -1257,7 +1343,7 @@ false != false - + true != true @@ -1265,7 +1351,7 @@ true != true - + !true @@ -1273,7 +1359,7 @@ false - + !true @@ -1281,7 +1367,7 @@ !true - + !trueValue @@ -1289,7 +1375,7 @@ false - + !trueValue @@ -1297,7 +1383,7 @@ !true - + !(1 == 1) @@ -1305,7 +1391,7 @@ false - + !1 == 1 @@ -1316,7 +1402,7 @@ - + thisThrows() @@ -1324,7 +1410,7 @@ thisThrows() - + thisDoesntThrow() @@ -1332,7 +1418,7 @@ thisDoesntThrow() - + thisThrows() @@ -1343,18 +1429,18 @@ - + thisThrows() thisThrows() - + expected exception - + thisDoesntThrow() @@ -1362,27 +1448,27 @@ thisDoesntThrow() - + thisThrows() thisThrows() - + expected exception - + unexpected exception - + 1 == 1 @@ -1390,14 +1476,14 @@ 1 == 1 - + {Unknown expression after the reported line} {Unknown expression after the reported line} - + unexpected exception @@ -1405,7 +1491,7 @@
- + unexpected exception @@ -1413,92 +1499,92 @@ - + thisThrows() == 0 thisThrows() == 0 - + expected exception - + thisThrows() == 0 thisThrows() == 0 - + expected exception - + thisThrows() == 0 thisThrows() == 0 - + expected exception - + - + custom exception - + throwCustom() throwCustom() - + custom exception - not std - + throwCustom() throwCustom() - + custom exception - not std - + 3.14 - + thisFunctionNotImplemented( 7 ) @@ -1509,7 +1595,7 @@ - + multiply( i, 2 ) == i*2 @@ -1517,7 +1603,7 @@ 2 == 2 - + multiply( j, 2 ) == j*2 @@ -1525,7 +1611,7 @@ 200 == 200 - + multiply( i, 2 ) == i*2 @@ -1533,7 +1619,7 @@ 4 == 4 - + multiply( j, 2 ) == j*2 @@ -1541,7 +1627,7 @@ 200 == 200 - + multiply( i, 2 ) == i*2 @@ -1549,7 +1635,7 @@ 6 == 6 - + multiply( j, 2 ) == j*2 @@ -1557,7 +1643,7 @@ 200 == 200 - + multiply( i, 2 ) == i*2 @@ -1565,7 +1651,7 @@ 8 == 8 - + multiply( j, 2 ) == j*2 @@ -1573,7 +1659,7 @@ 200 == 200 - + multiply( i, 2 ) == i*2 @@ -1581,7 +1667,7 @@ 10 == 10 - + multiply( j, 2 ) == j*2 @@ -1589,7 +1675,7 @@ 200 == 200 - + multiply( i, 2 ) == i*2 @@ -1597,7 +1683,7 @@ 30 == 30 - + multiply( j, 2 ) == j*2 @@ -1605,7 +1691,7 @@ 200 == 200 - + multiply( i, 2 ) == i*2 @@ -1613,7 +1699,7 @@ 40 == 40 - + multiply( j, 2 ) == j*2 @@ -1621,7 +1707,7 @@ 200 == 200 - + multiply( i, 2 ) == i*2 @@ -1629,7 +1715,7 @@ 42 == 42 - + multiply( j, 2 ) == j*2 @@ -1637,7 +1723,7 @@ 200 == 200 - + multiply( i, 2 ) == i*2 @@ -1645,7 +1731,7 @@ 72 == 72 - + multiply( j, 2 ) == j*2 @@ -1653,7 +1739,7 @@ 200 == 200 - + multiply( i, 2 ) == i*2 @@ -1661,7 +1747,7 @@ 2 == 2 - + multiply( j, 2 ) == j*2 @@ -1669,7 +1755,7 @@ 202 == 202 - + multiply( i, 2 ) == i*2 @@ -1677,7 +1763,7 @@ 4 == 4 - + multiply( j, 2 ) == j*2 @@ -1685,7 +1771,7 @@ 202 == 202 - + multiply( i, 2 ) == i*2 @@ -1693,7 +1779,7 @@ 6 == 6 - + multiply( j, 2 ) == j*2 @@ -1701,7 +1787,7 @@ 202 == 202 - + multiply( i, 2 ) == i*2 @@ -1709,7 +1795,7 @@ 8 == 8 - + multiply( j, 2 ) == j*2 @@ -1717,7 +1803,7 @@ 202 == 202 - + multiply( i, 2 ) == i*2 @@ -1725,7 +1811,7 @@ 10 == 10 - + multiply( j, 2 ) == j*2 @@ -1733,7 +1819,7 @@ 202 == 202 - + multiply( i, 2 ) == i*2 @@ -1741,7 +1827,7 @@ 30 == 30 - + multiply( j, 2 ) == j*2 @@ -1749,7 +1835,7 @@ 202 == 202 - + multiply( i, 2 ) == i*2 @@ -1757,7 +1843,7 @@ 40 == 40 - + multiply( j, 2 ) == j*2 @@ -1765,7 +1851,7 @@ 202 == 202 - + multiply( i, 2 ) == i*2 @@ -1773,7 +1859,7 @@ 42 == 42 - + multiply( j, 2 ) == j*2 @@ -1781,7 +1867,7 @@ 202 == 202 - + multiply( i, 2 ) == i*2 @@ -1789,7 +1875,7 @@ 72 == 72 - + multiply( j, 2 ) == j*2 @@ -1797,7 +1883,7 @@ 202 == 202 - + multiply( i, 2 ) == i*2 @@ -1805,7 +1891,7 @@ 2 == 2 - + multiply( j, 2 ) == j*2 @@ -1813,7 +1899,7 @@ 204 == 204 - + multiply( i, 2 ) == i*2 @@ -1821,7 +1907,7 @@ 4 == 4 - + multiply( j, 2 ) == j*2 @@ -1829,7 +1915,7 @@ 204 == 204 - + multiply( i, 2 ) == i*2 @@ -1837,7 +1923,7 @@ 6 == 6 - + multiply( j, 2 ) == j*2 @@ -1845,7 +1931,7 @@ 204 == 204 - + multiply( i, 2 ) == i*2 @@ -1853,7 +1939,7 @@ 8 == 8 - + multiply( j, 2 ) == j*2 @@ -1861,7 +1947,7 @@ 204 == 204 - + multiply( i, 2 ) == i*2 @@ -1869,7 +1955,7 @@ 10 == 10 - + multiply( j, 2 ) == j*2 @@ -1877,7 +1963,7 @@ 204 == 204 - + multiply( i, 2 ) == i*2 @@ -1885,7 +1971,7 @@ 30 == 30 - + multiply( j, 2 ) == j*2 @@ -1893,7 +1979,7 @@ 204 == 204 - + multiply( i, 2 ) == i*2 @@ -1901,7 +1987,7 @@ 40 == 40 - + multiply( j, 2 ) == j*2 @@ -1909,7 +1995,7 @@ 204 == 204 - + multiply( i, 2 ) == i*2 @@ -1917,7 +2003,7 @@ 42 == 42 - + multiply( j, 2 ) == j*2 @@ -1925,7 +2011,7 @@ 204 == 204 - + multiply( i, 2 ) == i*2 @@ -1933,7 +2019,7 @@ 72 == 72 - + multiply( j, 2 ) == j*2 @@ -1941,7 +2027,7 @@ 204 == 204 - + multiply( i, 2 ) == i*2 @@ -1949,7 +2035,7 @@ 2 == 2 - + multiply( j, 2 ) == j*2 @@ -1957,7 +2043,7 @@ 206 == 206 - + multiply( i, 2 ) == i*2 @@ -1965,7 +2051,7 @@ 4 == 4 - + multiply( j, 2 ) == j*2 @@ -1973,7 +2059,7 @@ 206 == 206 - + multiply( i, 2 ) == i*2 @@ -1981,7 +2067,7 @@ 6 == 6 - + multiply( j, 2 ) == j*2 @@ -1989,7 +2075,7 @@ 206 == 206 - + multiply( i, 2 ) == i*2 @@ -1997,7 +2083,7 @@ 8 == 8 - + multiply( j, 2 ) == j*2 @@ -2005,7 +2091,7 @@ 206 == 206 - + multiply( i, 2 ) == i*2 @@ -2013,7 +2099,7 @@ 10 == 10 - + multiply( j, 2 ) == j*2 @@ -2021,7 +2107,7 @@ 206 == 206 - + multiply( i, 2 ) == i*2 @@ -2029,7 +2115,7 @@ 30 == 30 - + multiply( j, 2 ) == j*2 @@ -2037,7 +2123,7 @@ 206 == 206 - + multiply( i, 2 ) == i*2 @@ -2045,7 +2131,7 @@ 40 == 40 - + multiply( j, 2 ) == j*2 @@ -2053,7 +2139,7 @@ 206 == 206 - + multiply( i, 2 ) == i*2 @@ -2061,7 +2147,7 @@ 42 == 42 - + multiply( j, 2 ) == j*2 @@ -2069,7 +2155,7 @@ 206 == 206 - + multiply( i, 2 ) == i*2 @@ -2077,7 +2163,7 @@ 72 == 72 - + multiply( j, 2 ) == j*2 @@ -2085,7 +2171,7 @@ 206 == 206 - + multiply( i, 2 ) == i*2 @@ -2093,7 +2179,7 @@ 2 == 2 - + multiply( j, 2 ) == j*2 @@ -2101,7 +2187,7 @@ 208 == 208 - + multiply( i, 2 ) == i*2 @@ -2109,7 +2195,7 @@ 4 == 4 - + multiply( j, 2 ) == j*2 @@ -2117,7 +2203,7 @@ 208 == 208 - + multiply( i, 2 ) == i*2 @@ -2125,7 +2211,7 @@ 6 == 6 - + multiply( j, 2 ) == j*2 @@ -2133,7 +2219,7 @@ 208 == 208 - + multiply( i, 2 ) == i*2 @@ -2141,7 +2227,7 @@ 8 == 8 - + multiply( j, 2 ) == j*2 @@ -2149,7 +2235,7 @@ 208 == 208 - + multiply( i, 2 ) == i*2 @@ -2157,7 +2243,7 @@ 10 == 10 - + multiply( j, 2 ) == j*2 @@ -2165,7 +2251,7 @@ 208 == 208 - + multiply( i, 2 ) == i*2 @@ -2173,7 +2259,7 @@ 30 == 30 - + multiply( j, 2 ) == j*2 @@ -2181,7 +2267,7 @@ 208 == 208 - + multiply( i, 2 ) == i*2 @@ -2189,7 +2275,7 @@ 40 == 40 - + multiply( j, 2 ) == j*2 @@ -2197,7 +2283,7 @@ 208 == 208 - + multiply( i, 2 ) == i*2 @@ -2205,7 +2291,7 @@ 42 == 42 - + multiply( j, 2 ) == j*2 @@ -2213,7 +2299,7 @@ 208 == 208 - + multiply( i, 2 ) == i*2 @@ -2221,7 +2307,7 @@ 72 == 72 - + multiply( j, 2 ) == j*2 @@ -2229,7 +2315,7 @@ 208 == 208 - + multiply( i, 2 ) == i*2 @@ -2237,7 +2323,7 @@ 2 == 2 - + multiply( j, 2 ) == j*2 @@ -2245,7 +2331,7 @@ 210 == 210 - + multiply( i, 2 ) == i*2 @@ -2253,7 +2339,7 @@ 4 == 4 - + multiply( j, 2 ) == j*2 @@ -2261,7 +2347,7 @@ 210 == 210 - + multiply( i, 2 ) == i*2 @@ -2269,7 +2355,7 @@ 6 == 6 - + multiply( j, 2 ) == j*2 @@ -2277,7 +2363,7 @@ 210 == 210 - + multiply( i, 2 ) == i*2 @@ -2285,7 +2371,7 @@ 8 == 8 - + multiply( j, 2 ) == j*2 @@ -2293,7 +2379,7 @@ 210 == 210 - + multiply( i, 2 ) == i*2 @@ -2301,7 +2387,7 @@ 10 == 10 - + multiply( j, 2 ) == j*2 @@ -2309,7 +2395,7 @@ 210 == 210 - + multiply( i, 2 ) == i*2 @@ -2317,7 +2403,7 @@ 30 == 30 - + multiply( j, 2 ) == j*2 @@ -2325,7 +2411,7 @@ 210 == 210 - + multiply( i, 2 ) == i*2 @@ -2333,7 +2419,7 @@ 40 == 40 - + multiply( j, 2 ) == j*2 @@ -2341,7 +2427,7 @@ 210 == 210 - + multiply( i, 2 ) == i*2 @@ -2349,7 +2435,7 @@ 42 == 42 - + multiply( j, 2 ) == j*2 @@ -2357,7 +2443,7 @@ 210 == 210 - + multiply( i, 2 ) == i*2 @@ -2365,7 +2451,7 @@ 72 == 72 - + multiply( j, 2 ) == j*2 @@ -2373,7 +2459,7 @@ 210 == 210 - + multiply( i, 2 ) == i*2 @@ -2381,7 +2467,7 @@ 2 == 2 - + multiply( j, 2 ) == j*2 @@ -2389,7 +2475,7 @@ 212 == 212 - + multiply( i, 2 ) == i*2 @@ -2397,7 +2483,7 @@ 4 == 4 - + multiply( j, 2 ) == j*2 @@ -2405,7 +2491,7 @@ 212 == 212 - + multiply( i, 2 ) == i*2 @@ -2413,7 +2499,7 @@ 6 == 6 - + multiply( j, 2 ) == j*2 @@ -2421,7 +2507,7 @@ 212 == 212 - + multiply( i, 2 ) == i*2 @@ -2429,7 +2515,7 @@ 8 == 8 - + multiply( j, 2 ) == j*2 @@ -2437,7 +2523,7 @@ 212 == 212 - + multiply( i, 2 ) == i*2 @@ -2445,7 +2531,7 @@ 10 == 10 - + multiply( j, 2 ) == j*2 @@ -2453,7 +2539,7 @@ 212 == 212 - + multiply( i, 2 ) == i*2 @@ -2461,7 +2547,7 @@ 30 == 30 - + multiply( j, 2 ) == j*2 @@ -2469,7 +2555,7 @@ 212 == 212 - + multiply( i, 2 ) == i*2 @@ -2477,7 +2563,7 @@ 40 == 40 - + multiply( j, 2 ) == j*2 @@ -2485,7 +2571,7 @@ 212 == 212 - + multiply( i, 2 ) == i*2 @@ -2493,7 +2579,7 @@ 42 == 42 - + multiply( j, 2 ) == j*2 @@ -2501,7 +2587,7 @@ 212 == 212 - + multiply( i, 2 ) == i*2 @@ -2509,7 +2595,7 @@ 72 == 72 - + multiply( j, 2 ) == j*2 @@ -2517,7 +2603,7 @@ 212 == 212 - + multiply( i, 2 ) == i*2 @@ -2525,7 +2611,7 @@ 2 == 2 - + multiply( j, 2 ) == j*2 @@ -2533,7 +2619,7 @@ 214 == 214 - + multiply( i, 2 ) == i*2 @@ -2541,7 +2627,7 @@ 4 == 4 - + multiply( j, 2 ) == j*2 @@ -2549,7 +2635,7 @@ 214 == 214 - + multiply( i, 2 ) == i*2 @@ -2557,7 +2643,7 @@ 6 == 6 - + multiply( j, 2 ) == j*2 @@ -2565,7 +2651,7 @@ 214 == 214 - + multiply( i, 2 ) == i*2 @@ -2573,7 +2659,7 @@ 8 == 8 - + multiply( j, 2 ) == j*2 @@ -2581,7 +2667,7 @@ 214 == 214 - + multiply( i, 2 ) == i*2 @@ -2589,7 +2675,7 @@ 10 == 10 - + multiply( j, 2 ) == j*2 @@ -2597,7 +2683,7 @@ 214 == 214 - + multiply( i, 2 ) == i*2 @@ -2605,7 +2691,7 @@ 30 == 30 - + multiply( j, 2 ) == j*2 @@ -2613,7 +2699,7 @@ 214 == 214 - + multiply( i, 2 ) == i*2 @@ -2621,7 +2707,7 @@ 40 == 40 - + multiply( j, 2 ) == j*2 @@ -2629,7 +2715,7 @@ 214 == 214 - + multiply( i, 2 ) == i*2 @@ -2637,7 +2723,7 @@ 42 == 42 - + multiply( j, 2 ) == j*2 @@ -2645,7 +2731,7 @@ 214 == 214 - + multiply( i, 2 ) == i*2 @@ -2653,7 +2739,7 @@ 72 == 72 - + multiply( j, 2 ) == j*2 @@ -2664,7 +2750,7 @@ - + i->first == i->second-1 @@ -2672,7 +2758,7 @@ 0 == 0 - + i->first == i->second-1 @@ -2689,7 +2775,7 @@ this is a warning - + @@ -2701,7 +2787,7 @@ so should this - + a == 1 @@ -2712,7 +2798,7 @@ - + a == 2 @@ -2723,7 +2809,7 @@ this message should be logged - + a == 1 @@ -2734,7 +2820,7 @@ and this, but later - + a == 0 @@ -2742,7 +2828,7 @@ 2 == 0 - + a == 2 @@ -2787,10 +2873,10 @@
- +
- + i < 10 @@ -2798,7 +2884,7 @@ 0 < 10 - + i < 10 @@ -2806,7 +2892,7 @@ 1 < 10 - + i < 10 @@ -2814,7 +2900,7 @@ 2 < 10 - + i < 10 @@ -2822,7 +2908,7 @@ 3 < 10 - + i < 10 @@ -2830,7 +2916,7 @@ 4 < 10 - + i < 10 @@ -2838,7 +2924,7 @@ 5 < 10 - + i < 10 @@ -2846,7 +2932,7 @@ 6 < 10 - + i < 10 @@ -2854,7 +2940,7 @@ 7 < 10 - + i < 10 @@ -2862,7 +2948,7 @@ 8 < 10 - + i < 10 @@ -2876,7 +2962,7 @@ i := 10 - + i < 10 @@ -2887,7 +2973,7 @@ - + 1 == 2 @@ -2898,7 +2984,7 @@ - + @@ -2913,7 +2999,7 @@ i := 7 - + false @@ -2930,11 +3016,11 @@ toString(p): 0x - +
- + a != b @@ -2942,7 +3028,7 @@ 1 != 2 - + b != a @@ -2953,7 +3039,7 @@
- + a != b @@ -2967,7 +3053,7 @@
- + a != b @@ -2975,7 +3061,7 @@ 1 != 2 - + b != a @@ -2984,7 +3070,7 @@
- + a != b @@ -3001,7 +3087,7 @@
- + a == b @@ -3031,11 +3117,11 @@
- +
- + b > a @@ -3051,7 +3137,7 @@ Testing if fib[0] (1) is even - + ( fib[i] % 2 ) == 0 @@ -3062,7 +3148,7 @@ Testing if fib[1] (1) is even - + ( fib[i] % 2 ) == 0 @@ -3070,7 +3156,7 @@ 1 == 0 - + ( fib[i] % 2 ) == 0 @@ -3081,7 +3167,7 @@ Testing if fib[3] (3) is even - + ( fib[i] % 2 ) == 0 @@ -3092,7 +3178,7 @@ Testing if fib[4] (5) is even - + ( fib[i] % 2 ) == 0 @@ -3100,7 +3186,7 @@ 1 == 0 - + ( fib[i] % 2 ) == 0 @@ -3111,7 +3197,7 @@ Testing if fib[6] (13) is even - + ( fib[i] % 2 ) == 0 @@ -3122,7 +3208,7 @@ Testing if fib[7] (21) is even - + ( fib[i] % 2 ) == 0 @@ -3133,10 +3219,10 @@ - + - + makeString( false ) != static_cast<char*>(__null) @@ -3144,7 +3230,7 @@ "valid string" != {null string} - + makeString( true ) == static_cast<char*>(__null) @@ -3155,7 +3241,7 @@ - + flag @@ -3163,7 +3249,7 @@ true - + testCheckedIf( true ) @@ -3174,7 +3260,7 @@ - + flag @@ -3182,7 +3268,7 @@ false - + testCheckedIf( false ) @@ -3193,7 +3279,7 @@ - + flag @@ -3201,7 +3287,7 @@ true - + testCheckedElse( true ) @@ -3212,7 +3298,7 @@ - + flag @@ -3220,7 +3306,7 @@ false - + testCheckedElse( false ) @@ -3237,13 +3323,13 @@
- +
3 - + false @@ -3254,7 +3340,7 @@ - + x == 0 @@ -3265,7 +3351,7 @@ - + testStringForMatching() Contains( "string" ) @@ -3273,7 +3359,7 @@ "this string contains 'abc' as a substring" contains: "string" - + testStringForMatching() Contains( "abc" ) @@ -3281,7 +3367,7 @@ "this string contains 'abc' as a substring" contains: "abc" - + testStringForMatching() StartsWith( "this" ) @@ -3289,7 +3375,7 @@ "this string contains 'abc' as a substring" starts with: "this" - + testStringForMatching() EndsWith( "substring" ) @@ -3300,7 +3386,7 @@ - + testStringForMatching() Contains( "not there" ) @@ -3311,7 +3397,7 @@ - + testStringForMatching() StartsWith( "string" ) @@ -3322,7 +3408,7 @@ - + testStringForMatching() EndsWith( "this" ) @@ -3333,7 +3419,7 @@ - + testStringForMatching() Equals( "something else" ) @@ -3344,7 +3430,7 @@ - + "" Equals(__null) @@ -3355,7 +3441,7 @@ - + testStringForMatching() AllOf( Catch::Contains( "string" ), Catch::Contains( "abc" ) ) @@ -3366,7 +3452,7 @@ - + testStringForMatching() AnyOf( Catch::Contains( "string" ), Catch::Contains( "not there" ) ) @@ -3374,7 +3460,7 @@ "this string contains 'abc' as a substring" ( contains: "string" or contains: "not there" ) - + testStringForMatching() AnyOf( Catch::Contains( "not there" ), Catch::Contains( "string" ) ) @@ -3385,7 +3471,7 @@ - + testStringForMatching() Equals( "this string contains 'abc' as a substring" ) @@ -3396,7 +3482,7 @@ - + Factorial(0) == 1 @@ -3404,7 +3490,7 @@ 1 == 1 - + Factorial(1) == 1 @@ -3412,7 +3498,7 @@ 1 == 1 - + Factorial(2) == 2 @@ -3420,7 +3506,7 @@ 2 == 2 - + Factorial(3) == 6 @@ -3428,33 +3514,33 @@ 6 == 6 - + Factorial(10) == 3628800 - 0x == 3628800 + 0x == 0x - + This one ran - + - + - + - + v.size() == 5 @@ -3462,7 +3548,7 @@ 5 == 5 - + v.capacity() >= 5 @@ -3471,7 +3557,7 @@
- + v.size() == 10 @@ -3479,7 +3565,7 @@ 10 == 10 - + v.capacity() >= 10 @@ -3489,7 +3575,7 @@
- + v.size() == 5 @@ -3497,7 +3583,7 @@ 5 == 5 - + v.capacity() >= 5 @@ -3506,7 +3592,7 @@
- + v.size() == 0 @@ -3514,7 +3600,7 @@ 0 == 0 - + v.capacity() >= 5 @@ -3523,7 +3609,7 @@
- + v.capacity() == 0 @@ -3535,7 +3621,7 @@
- + v.size() == 5 @@ -3543,7 +3629,7 @@ 5 == 5 - + v.capacity() >= 5 @@ -3552,7 +3638,7 @@
- + v.size() == 5 @@ -3560,7 +3646,7 @@ 5 == 5 - + v.capacity() >= 10 @@ -3570,7 +3656,7 @@
- + v.size() == 5 @@ -3578,7 +3664,7 @@ 5 == 5 - + v.capacity() >= 5 @@ -3587,7 +3673,7 @@
- + v.size() == 5 @@ -3595,7 +3681,7 @@ 5 == 5 - + v.capacity() >= 5 @@ -3623,7 +3709,7 @@ - + s1 == s2 @@ -3641,7 +3727,7 @@ - + result == "\"wide load\"" @@ -3652,7 +3738,7 @@ - + result == "\"wide load\"" @@ -3663,7 +3749,7 @@ - + result == "\"wide load\"" @@ -3674,7 +3760,7 @@ - + result == "\"wide load\"" @@ -3686,7 +3772,7 @@
- + parseIntoConfig( argv, config ) @@ -3694,7 +3780,7 @@ parseIntoConfig( argv, config ) - + config.shouldDebugBreak == false @@ -3702,7 +3788,7 @@ false == false - + config.abortAfter == -1 @@ -3710,7 +3796,7 @@ -1 == -1 - + config.noThrow == false @@ -3718,7 +3804,7 @@ false == false - + config.reporterName.empty() @@ -3730,7 +3816,7 @@
- + parseIntoConfig( argv, config ) @@ -3738,7 +3824,7 @@ parseIntoConfig( argv, config ) - + cfg.testSpec().matches( fakeTestCase( "notIncluded" ) ) == false @@ -3746,7 +3832,7 @@ false == false - + cfg.testSpec().matches( fakeTestCase( "test1" ) ) @@ -3760,7 +3846,7 @@
- + parseIntoConfig( argv, config ) @@ -3768,7 +3854,7 @@ parseIntoConfig( argv, config ) - + cfg.testSpec().matches( fakeTestCase( "test1" ) ) == false @@ -3776,7 +3862,7 @@ false == false - + cfg.testSpec().matches( fakeTestCase( "alwaysIncluded" ) ) @@ -3790,7 +3876,7 @@
- + parseIntoConfig( argv, config ) @@ -3798,7 +3884,7 @@ parseIntoConfig( argv, config ) - + cfg.testSpec().matches( fakeTestCase( "test1" ) ) == false @@ -3806,7 +3892,7 @@ false == false - + cfg.testSpec().matches( fakeTestCase( "alwaysIncluded" ) ) @@ -3820,7 +3906,7 @@
- + parseIntoConfig( argv, config ) @@ -3828,7 +3914,7 @@ parseIntoConfig( argv, config ) - + config.reporterName == "console" @@ -3842,7 +3928,7 @@
- + parseIntoConfig( argv, config ) @@ -3850,7 +3936,7 @@ parseIntoConfig( argv, config ) - + config.reporterName == "xml" @@ -3864,7 +3950,7 @@
- + parseIntoConfig( argv, config ) @@ -3872,7 +3958,7 @@ parseIntoConfig( argv, config ) - + config.reporterName == "junit" @@ -3886,7 +3972,7 @@
- + parseIntoConfig( argv, config ) @@ -3894,7 +3980,7 @@ parseIntoConfig( argv, config ) - + config.shouldDebugBreak == true @@ -3908,7 +3994,7 @@
- + parseIntoConfig( argv, config ) @@ -3916,7 +4002,7 @@ parseIntoConfig( argv, config ) - + config.shouldDebugBreak @@ -3930,7 +4016,7 @@
- + parseIntoConfig( argv, config ) @@ -3938,7 +4024,7 @@ parseIntoConfig( argv, config ) - + config.abortAfter == 1 @@ -3952,7 +4038,7 @@
- + parseIntoConfig( argv, config ) @@ -3960,7 +4046,7 @@ parseIntoConfig( argv, config ) - + config.abortAfter == 2 @@ -3974,7 +4060,7 @@
- + parseIntoConfigAndReturnError( argv, config ) Contains( "greater than zero" ) @@ -3989,7 +4075,7 @@
- + parseIntoConfigAndReturnError( argv, config ) Contains( "-x" ) @@ -4004,7 +4090,7 @@
- + parseIntoConfig( argv, config ) @@ -4012,7 +4098,7 @@ parseIntoConfig( argv, config ) - + config.noThrow == true @@ -4026,7 +4112,7 @@
- + parseIntoConfig( argv, config ) @@ -4034,7 +4120,7 @@ parseIntoConfig( argv, config ) - + config.noThrow == true @@ -4048,7 +4134,7 @@
- + parseIntoConfig( argv, config ) @@ -4056,7 +4142,7 @@ parseIntoConfig( argv, config ) - + config.outputFilename == "filename.ext" @@ -4070,7 +4156,7 @@
- + parseIntoConfig( argv, config ) @@ -4078,7 +4164,7 @@ parseIntoConfig( argv, config ) - + config.outputFilename == "filename.ext" @@ -4092,7 +4178,7 @@
- + parseIntoConfig( argv, config ) @@ -4100,7 +4186,7 @@ parseIntoConfig( argv, config ) - + config.abortAfter == 1 @@ -4108,7 +4194,7 @@ 1 == 1 - + config.shouldDebugBreak @@ -4116,7 +4202,7 @@ true - + config.noThrow == true @@ -4128,12 +4214,56 @@
+
+
+ + + parseIntoConfig( argv, config ) + + + parseIntoConfig( argv, config ) + + + + + config.forceColour + + + true + + + +
+ +
+
+
+ + + parseIntoConfig( argv, config ) + + + parseIntoConfig( argv, config ) + + + + + !config.forceColour + + + true + + + +
+ +
- + Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString @@ -4143,7 +4273,7 @@ "one two three four" - + Text( testString, TextAttributes().setWidth( 18 ) ).toString() == testString @@ -4159,7 +4289,7 @@
- + Text( testString, TextAttributes().setWidth( 17 ) ).toString() == "one two three\nfour" @@ -4171,7 +4301,7 @@ four" four" - + Text( testString, TextAttributes().setWidth( 16 ) ).toString() == "one two three\nfour" @@ -4183,7 +4313,7 @@ four" four" - + Text( testString, TextAttributes().setWidth( 14 ) ).toString() == "one two three\nfour" @@ -4195,7 +4325,7 @@ four" four" - + Text( testString, TextAttributes().setWidth( 13 ) ).toString() == "one two three\nfour" @@ -4207,7 +4337,7 @@ four" four" - + Text( testString, TextAttributes().setWidth( 12 ) ).toString() == "one two\nthree four" @@ -4225,7 +4355,7 @@ three four"
- + Text( testString, TextAttributes().setWidth( 9 ) ).toString() == "one two\nthree\nfour" @@ -4239,7 +4369,7 @@ three four" - + Text( testString, TextAttributes().setWidth( 8 ) ).toString() == "one two\nthree\nfour" @@ -4253,7 +4383,7 @@ three four" - + Text( testString, TextAttributes().setWidth( 7 ) ).toString() == "one two\nthree\nfour" @@ -4273,7 +4403,7 @@ four"
- + Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one\ntwo\nthree\nfour" @@ -4289,7 +4419,7 @@ three four" - + Text( testString, TextAttributes().setWidth( 5 ) ).toString() == "one\ntwo\nthree\nfour" @@ -4311,7 +4441,7 @@ four"
- + Text( "abcdef", TextAttributes().setWidth( 4 ) ).toString() == "abc-\ndef" @@ -4323,7 +4453,7 @@ def" def" - + Text( "abcdefg", TextAttributes().setWidth( 4 ) ).toString() == "abc-\ndefg" @@ -4335,7 +4465,7 @@ defg" defg" - + Text( "abcdefgh", TextAttributes().setWidth( 4 ) ).toString() == "abc-\ndef-\ngh" @@ -4349,7 +4479,7 @@ def- gh" - + Text( testString, TextAttributes().setWidth( 4 ) ).toString() == "one\ntwo\nthr-\nee\nfour" @@ -4367,7 +4497,7 @@ ee four" - + Text( testString, TextAttributes().setWidth( 3 ) ).toString() == "one\ntwo\nth-\nree\nfo-\nur" @@ -4393,7 +4523,7 @@ ur"
- + text.size() == 4 @@ -4401,7 +4531,7 @@ ur" 4 == 4 - + text[0] == "one" @@ -4409,7 +4539,7 @@ ur" "one" == "one" - + text[1] == "two" @@ -4417,7 +4547,7 @@ ur" "two" == "two" - + text[2] == "three" @@ -4425,7 +4555,7 @@ ur" "three" == "three" - + text[3] == "four" @@ -4439,7 +4569,7 @@ ur"
- + text.toString() == " one two\n three\n four" @@ -4459,7 +4589,7 @@ ur"
- + Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString @@ -4471,7 +4601,7 @@ three four" three four" - + Text( testString, TextAttributes().setWidth( 18 ) ).toString() == testString @@ -4483,7 +4613,7 @@ three four" three four" - + Text( testString, TextAttributes().setWidth( 10 ) ).toString() == testString @@ -4501,7 +4631,7 @@ three four"
- + Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef\n" @@ -4513,7 +4643,7 @@ three four" " - + Text( "abcdef", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" @@ -4521,7 +4651,7 @@ three four" "abcdef" == "abcdef" - + Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef\n" @@ -4539,7 +4669,7 @@ three four"
- + Text( testString, TextAttributes().setWidth( 9 ) ).toString() == "one two\nthree\nfour" @@ -4553,7 +4683,7 @@ three four" - + Text( testString, TextAttributes().setWidth( 8 ) ).toString() == "one two\nthree\nfour" @@ -4567,7 +4697,7 @@ three four" - + Text( testString, TextAttributes().setWidth( 7 ) ).toString() == "one two\nthree\nfour" @@ -4587,7 +4717,7 @@ four"
- + Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one\ntwo\nthree\nfour" @@ -4608,7 +4738,7 @@ four"
- + Text( testString, TextAttributes().setWidth( 15 ) ).toString() == "one two three\n four\n five\n six" @@ -4628,11 +4758,147 @@ four"
- + +
+ + + replaceInPlace( letters, "b", "z" ) + + + true + + + + + letters == "azcdefcg" + + + "azcdefcg" == "azcdefcg" + + + +
+
+ + + replaceInPlace( letters, "c", "z" ) + + + true + + + + + letters == "abzdefzg" + + + "abzdefzg" == "abzdefzg" + + + +
+
+ + + replaceInPlace( letters, "a", "z" ) + + + true + + + + + letters == "zbcdefcg" + + + "zbcdefcg" == "zbcdefcg" + + + +
+
+ + + replaceInPlace( letters, "g", "z" ) + + + true + + + + + letters == "abcdefcz" + + + "abcdefcz" == "abcdefcz" + + + +
+
+ + + replaceInPlace( letters, letters, "replaced" ) + + + true + + + + + letters == "replaced" + + + "replaced" == "replaced" + + + +
+
+ + + !replaceInPlace( letters, "x", "z" ) + + + !false + + + + + letters == letters + + + "abcdefcg" == "abcdefcg" + + + +
+
+ + + replaceInPlace( s, "'", "|'" ) + + + true + + + + + s == "didn|'t" + + + "didn|'t" == "didn|'t" + + + +
+ + + - + Text( "hi there" ).toString() == "hi there" @@ -4640,7 +4906,7 @@ four" "hi there" == "hi there" - + Text( "hi there", narrow ).toString() == "hi\nthere" @@ -4655,7 +4921,7 @@ there" - + t.toString() EndsWith( "... message truncated due to excessive size" ) @@ -5666,7 +5932,7 @@ there" - + (std::pair<int, int>( 1, 2 )) == aNicePair @@ -5676,20 +5942,20 @@ there" - + Uncomment the code in this test to check that it gives a sensible compiler error - + - + Uncomment the code in this test to check that it gives a sensible compiler error - + - - + + &o1 == &o2 @@ -5697,7 +5963,7 @@ there" 0x == 0x - + o1 == o2 @@ -5707,8 +5973,8 @@ there" - - + + std::string( "first" ) == "second" @@ -5719,7 +5985,7 @@ there" - + i++ == 7 @@ -5727,7 +5993,7 @@ there" 7 == 7 - + i++ == 8 @@ -5738,7 +6004,7 @@ there" - + 0x == o @@ -5749,7 +6015,7 @@ there" - + t == 1u @@ -5760,7 +6026,7 @@ there" - + 0x == bit30and31 @@ -5771,7 +6037,7 @@ there" - + obj.prop != __null @@ -5783,7 +6049,7 @@ there"
- + is_true<true>::value == true @@ -5791,7 +6057,7 @@ there" true == true - + true == is_true<true>::value @@ -5802,7 +6068,7 @@ there"
- + is_true<false>::value == false @@ -5810,7 +6076,7 @@ there" false == false - + false == is_true<false>::value @@ -5821,7 +6087,7 @@ there"
- + !is_true<false>::value @@ -5832,7 +6098,7 @@ there"
- + !!is_true<true>::value @@ -5843,7 +6109,7 @@ there"
- + is_true<true>::value @@ -5851,7 +6117,7 @@ there" true - + !is_true<false>::value @@ -5864,7 +6130,7 @@ there" - + True @@ -5872,7 +6138,7 @@ there" true - + !False @@ -5880,7 +6146,7 @@ there" true - + !False @@ -5891,7 +6157,7 @@ there" - + Catch::alwaysTrue() @@ -5900,7 +6166,7 @@ there"
- + Catch::alwaysTrue() @@ -5909,7 +6175,7 @@ there"
- + Catch::alwaysTrue() @@ -5921,7 +6187,7 @@ there"
- + Catch::alwaysTrue() @@ -5930,7 +6196,7 @@ there"
- + Catch::alwaysTrue() @@ -5939,7 +6205,7 @@ there"
- + Catch::alwaysTrue() @@ -5954,7 +6220,7 @@ there" - + s == "7" @@ -5965,7 +6231,7 @@ there" - + a @@ -5973,7 +6239,7 @@ there" true - + a == &foo @@ -5984,7 +6250,7 @@ there" - + m == &S::f @@ -5997,7 +6263,7 @@ there" - + p == 0 @@ -6008,7 +6274,7 @@ there" - + ptr.get() == nullptr @@ -6030,9 +6296,237 @@ there" + + + + Catch::toString( item ) == "toString( has_toString )" + + + "toString( has_toString )" +== +"toString( has_toString )" + + + + + + + + Catch::toString( item ) == "StringMaker<has_maker>" + + + "StringMaker<has_maker>" +== +"StringMaker<has_maker>" + + + + + + + + Catch::toString( item ) == "toString( has_maker_and_toString )" + + + "toString( has_maker_and_toString )" +== +"toString( has_maker_and_toString )" + + + + + + + + Catch::toString( v ) == "{ {?} }" + + + "{ {?} }" == "{ {?} }" + + + + + + + + Catch::toString( v ) == "{ StringMaker<has_maker> }" + + + "{ StringMaker<has_maker> }" +== +"{ StringMaker<has_maker> }" + + + + + + + + Catch::toString( v ) == "{ StringMaker<has_maker_and_toString> }" + + + "{ StringMaker<has_maker_and_toString> }" +== +"{ StringMaker<has_maker_and_toString> }" + + + + + + + + Catch::toString( value ) == "{ 34, \"xyzzy\" }" + + + "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" + + + + + + + + Catch::toString(value) == "{ 34, \"xyzzy\" }" + + + "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" + + + + + + + + Catch::toString( pr ) == "{ { \"green\", 55 } }" + + + "{ { "green", 55 } }" +== +"{ { "green", 55 } }" + + + + + + + + Catch::toString( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" + + + "{ { 42, "Arthur" }, { "Ford", 24 } }" +== +"{ { 42, "Arthur" }, { "Ford", 24 } }" + + + + + + + + Catch::toString(vv) == "{ }" + + + "{ }" == "{ }" + + + + + Catch::toString(vv) == "{ 42 }" + + + "{ 42 }" == "{ 42 }" + + + + + Catch::toString(vv) == "{ 42, 512 }" + + + "{ 42, 512 }" == "{ 42, 512 }" + + + + + + + + Catch::toString(vv) == "{ }" + + + "{ }" == "{ }" + + + + + Catch::toString(vv) == "{ \"hello\" }" + + + "{ "hello" }" == "{ "hello" }" + + + + + Catch::toString(vv) == "{ \"hello\", \"world\" }" + + + "{ "hello", "world" }" +== +"{ "hello", "world" }" + + + + + + + + Catch::toString(vv) == "{ }" + + + "{ }" == "{ }" + + + + + Catch::toString(vv) == "{ 42 }" + + + "{ 42 }" == "{ 42 }" + + + + + Catch::toString(vv) == "{ 42, 512 }" + + + "{ 42, 512 }" == "{ 42, 512 }" + + + + + + + + Catch::toString(v) == "{ }" + + + "{ }" == "{ }" + + + + + Catch::toString(v) == "{ { \"hello\" }, { \"world\" } }" + + + "{ { "hello" }, { "world" } }" +== +"{ { "hello" }, { "world" } }" + + + +
- + spec.hasFilters() == false @@ -6040,7 +6534,7 @@ there" false == false - + spec.matches( tcA ) == false @@ -6048,7 +6542,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6059,7 +6553,7 @@ there"
- + spec.hasFilters() == false @@ -6067,7 +6561,7 @@ there" false == false - + spec.matches(tcA ) == false @@ -6075,7 +6569,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6086,7 +6580,7 @@ there"
- + spec.hasFilters() == false @@ -6094,7 +6588,7 @@ there" false == false - + spec.matches( tcA ) == false @@ -6102,7 +6596,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6113,7 +6607,7 @@ there"
- + spec.hasFilters() == true @@ -6121,7 +6615,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6129,7 +6623,7 @@ there" false == false - + spec.matches( tcB ) == true @@ -6140,7 +6634,7 @@ there"
- + spec.hasFilters() == true @@ -6148,7 +6642,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6156,7 +6650,7 @@ there" false == false - + spec.matches( tcB ) == true @@ -6167,7 +6661,7 @@ there"
- + spec.hasFilters() == true @@ -6175,7 +6669,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6183,7 +6677,7 @@ there" false == false - + spec.matches( tcB ) == true @@ -6191,7 +6685,7 @@ there" true == true - + spec.matches( tcC ) == false @@ -6202,7 +6696,7 @@ there"
- + spec.hasFilters() == true @@ -6210,7 +6704,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6218,7 +6712,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6226,7 +6720,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -6234,7 +6728,7 @@ there" true == true - + spec.matches( tcD ) == false @@ -6242,7 +6736,7 @@ there" false == false - + parseTestSpec( "*a" ).matches( tcA ) == true @@ -6253,7 +6747,7 @@ there"
- + spec.hasFilters() == true @@ -6261,7 +6755,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6269,7 +6763,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6277,7 +6771,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -6285,7 +6779,7 @@ there" true == true - + spec.matches( tcD ) == false @@ -6293,7 +6787,7 @@ there" false == false - + parseTestSpec( "a*" ).matches( tcA ) == true @@ -6304,7 +6798,7 @@ there"
- + spec.hasFilters() == true @@ -6312,7 +6806,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6320,7 +6814,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6328,7 +6822,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -6336,7 +6830,7 @@ there" true == true - + spec.matches( tcD ) == true @@ -6344,7 +6838,7 @@ there" true == true - + parseTestSpec( "*a*" ).matches( tcA ) == true @@ -6355,7 +6849,7 @@ there"
- + spec.hasFilters() == true @@ -6363,7 +6857,7 @@ there" true == true - + spec.matches( tcA ) == true @@ -6371,7 +6865,7 @@ there" true == true - + spec.matches( tcB ) == false @@ -6382,7 +6876,7 @@ there"
- + spec.hasFilters() == true @@ -6390,7 +6884,7 @@ there" true == true - + spec.matches( tcA ) == true @@ -6398,7 +6892,7 @@ there" true == true - + spec.matches( tcB ) == false @@ -6409,7 +6903,7 @@ there"
- + spec.hasFilters() == true @@ -6417,7 +6911,7 @@ there" true == true - + spec.matches( tcA ) == true @@ -6425,7 +6919,7 @@ there" true == true - + spec.matches( tcB ) == false @@ -6436,7 +6930,7 @@ there"
- + spec.hasFilters() == true @@ -6444,7 +6938,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6452,7 +6946,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6460,7 +6954,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -6468,7 +6962,7 @@ there" true == true - + spec.matches( tcD ) == true @@ -6479,7 +6973,7 @@ there"
- + spec.hasFilters() == true @@ -6487,7 +6981,7 @@ there" true == true - + spec.matches( tcA ) == true @@ -6495,7 +6989,7 @@ there" true == true - + spec.matches( tcB ) == true @@ -6503,7 +6997,7 @@ there" true == true - + spec.matches( tcC ) == true @@ -6511,7 +7005,7 @@ there" true == true - + spec.matches( tcD ) == true @@ -6522,7 +7016,7 @@ there"
- + spec.hasFilters() == true @@ -6530,7 +7024,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6538,7 +7032,7 @@ there" false == false - + spec.matches( tcB ) == true @@ -6546,7 +7040,7 @@ there" true == true - + spec.matches( tcC ) == false @@ -6557,7 +7051,7 @@ there"
- + spec.hasFilters() == true @@ -6565,7 +7059,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6573,7 +7067,7 @@ there" false == false - + spec.matches( tcB ) == true @@ -6581,7 +7075,7 @@ there" true == true - + spec.matches( tcC ) == true @@ -6592,7 +7086,7 @@ there"
- + spec.hasFilters() == true @@ -6600,7 +7094,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6608,7 +7102,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6616,7 +7110,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -6627,7 +7121,7 @@ there"
- + spec.hasFilters() == true @@ -6635,7 +7129,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6643,7 +7137,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6651,7 +7145,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -6662,7 +7156,7 @@ there"
- + spec.hasFilters() == true @@ -6670,7 +7164,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6678,7 +7172,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6686,7 +7180,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -6694,7 +7188,7 @@ there" true == true - + spec.matches( tcD ) == false @@ -6705,7 +7199,7 @@ there"
- + spec.hasFilters() == true @@ -6713,7 +7207,7 @@ there" true == true - + spec.matches( tcA ) == true @@ -6721,7 +7215,7 @@ there" true == true - + spec.matches( tcB ) == false @@ -6729,7 +7223,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -6740,7 +7234,7 @@ there"
- + spec.hasFilters() == true @@ -6748,7 +7242,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6756,7 +7250,7 @@ there" false == false - + spec.matches( tcB ) == true @@ -6764,7 +7258,7 @@ there" true == true - + spec.matches( tcC ) == false @@ -6775,7 +7269,7 @@ there"
- + spec.hasFilters() == true @@ -6783,7 +7277,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6791,7 +7285,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6799,7 +7293,7 @@ there" false == false - + spec.matches( tcC ) == false @@ -6807,7 +7301,7 @@ there" false == false - + spec.matches( tcD ) == true @@ -6818,7 +7312,7 @@ there"
- + spec.hasFilters() == true @@ -6826,7 +7320,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -6834,7 +7328,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -6842,7 +7336,7 @@ there" false == false - + spec.matches( tcC ) == false @@ -6850,7 +7344,7 @@ there" false == false - + spec.matches( tcD ) == true @@ -6861,7 +7355,7 @@ there"
- + spec.hasFilters() == true @@ -6869,7 +7363,7 @@ there" true == true - + spec.matches( tcA ) == true @@ -6877,7 +7371,7 @@ there" true == true - + spec.matches( tcB ) == false @@ -6885,7 +7379,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -6893,7 +7387,7 @@ there" true == true - + spec.matches( tcD ) == true @@ -6904,7 +7398,7 @@ there"
- + spec.hasFilters() == true @@ -6912,7 +7406,7 @@ there" true == true - + spec.matches( tcA ) == true @@ -6920,7 +7414,7 @@ there" true == true - + spec.matches( tcB ) == true @@ -6928,7 +7422,7 @@ there" true == true - + spec.matches( tcC ) == false @@ -6936,7 +7430,7 @@ there" false == false - + spec.matches( tcD ) == false @@ -6947,7 +7441,7 @@ there"
- + spec.hasFilters() == true @@ -6955,7 +7449,7 @@ there" true == true - + spec.matches( tcA ) == true @@ -6963,7 +7457,7 @@ there" true == true - + spec.matches( tcB ) == true @@ -6971,7 +7465,7 @@ there" true == true - + spec.matches( tcC ) == true @@ -6979,7 +7473,7 @@ there" true == true - + spec.matches( tcD ) == false @@ -6990,7 +7484,7 @@ there"
- + spec.hasFilters() == true @@ -6998,7 +7492,7 @@ there" true == true - + spec.matches( tcA ) == true @@ -7006,7 +7500,7 @@ there" true == true - + spec.matches( tcB ) == true @@ -7014,7 +7508,7 @@ there" true == true - + spec.matches( tcC ) == true @@ -7022,7 +7516,7 @@ there" true == true - + spec.matches( tcD ) == false @@ -7033,7 +7527,7 @@ there"
- + spec.hasFilters() == true @@ -7041,7 +7535,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -7049,7 +7543,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -7057,7 +7551,7 @@ there" false == false - + spec.matches( tcC ) == true @@ -7065,7 +7559,7 @@ there" true == true - + spec.matches( tcD ) == false @@ -7076,7 +7570,7 @@ there"
- + spec.hasFilters() == false @@ -7084,7 +7578,7 @@ there" false == false - + spec.matches( tcA ) == false @@ -7092,7 +7586,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -7100,7 +7594,7 @@ there" false == false - + spec.matches( tcC ) == false @@ -7108,7 +7602,7 @@ there" false == false - + spec.matches( tcD ) == false @@ -7119,7 +7613,7 @@ there"
- + spec.hasFilters() == false @@ -7127,7 +7621,7 @@ there" false == false - + spec.matches( tcA ) == false @@ -7135,7 +7629,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -7143,7 +7637,7 @@ there" false == false - + spec.matches( tcC ) == false @@ -7151,7 +7645,7 @@ there" false == false - + spec.matches( tcD ) == false @@ -7162,7 +7656,7 @@ there"
- + spec.hasFilters() == true @@ -7170,7 +7664,7 @@ there" true == true - + spec.matches( tcA ) == false @@ -7178,7 +7672,7 @@ there" false == false - + spec.matches( tcB ) == false @@ -7186,7 +7680,7 @@ there" false == false - + spec.matches( tcC ) == false @@ -7194,7 +7688,7 @@ there" false == false - + spec.matches( tcD ) == true @@ -7206,9 +7700,97 @@ there"
+ + + + "{ }" == Catch::toString(type{}) + + + "{ }" == "{ }" + + + + + "{ }" == Catch::toString(value) + + + "{ }" == "{ }" + + + + + + + + "{ 0 }" == Catch::toString(type{0}) + + + "{ 0 }" == "{ 0 }" + + + + + + + + "1.2f" == Catch::toString(float(1.2)) + + + "1.2f" == "1.2f" + + + + + "{ 1.2f, 0 }" == Catch::toString(type{1.2,0}) + + + "{ 1.2f, 0 }" == "{ 1.2f, 0 }" + + + + + + + + "{ \"hello\", \"world\" }" == Catch::toString(type{"hello","world"}) + + + "{ "hello", "world" }" +== +"{ "hello", "world" }" + + + + + + + + "{ { 42 }, { }, 1.2f }" == Catch::toString(value) + + + "{ { 42 }, { }, 1.2f }" +== +"{ { 42 }, { }, 1.2f }" + + + + + + + + "{ nullptr, 42, \"Catch me\" }" == Catch::toString(value) + + + "{ nullptr, 42, "Catch me" }" +== +"{ nullptr, 42, "Catch me" }" + + + +
- + what Contains( "[@zzz]" ) @@ -7218,7 +7800,7 @@ there" Redefined at file:10" contains: "[@zzz]" - + what Contains( "file" ) @@ -7228,7 +7810,7 @@ there" Redefined at file:10" contains: "file" - + what Contains( "2" ) @@ -7238,7 +7820,7 @@ there" Redefined at file:10" contains: "2" - + what Contains( "10" ) @@ -7251,7 +7833,7 @@ there"
- + registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) ) @@ -7259,7 +7841,7 @@ there" registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) ) - + registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) ) @@ -7267,7 +7849,7 @@ there" registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) ) - + registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) ) @@ -7275,7 +7857,7 @@ there" registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) ) - + registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) @@ -7303,7 +7885,7 @@ there"
- + itDoesThis() @@ -7312,7 +7894,7 @@ there"
- + itDoesThat() @@ -7332,7 +7914,7 @@ there"
- + v.size() == 0 @@ -7342,7 +7924,7 @@ there"
- + v.size() == 10 @@ -7350,7 +7932,7 @@ there" 10 == 10 - + v.capacity() >= 10 @@ -7360,7 +7942,7 @@ there"
- + v.size() == 5 @@ -7368,7 +7950,7 @@ there" 5 == 5 - + v.capacity() >= 10 @@ -7387,7 +7969,7 @@ there"
- + v.size() == 0 @@ -7397,7 +7979,7 @@ there"
- + v.capacity() >= 10 @@ -7405,7 +7987,7 @@ there" 10 >= 10 - + v.size() == 0 @@ -7435,7 +8017,7 @@ there"
- + before == 0 @@ -7445,7 +8027,7 @@ there"
- + after > before @@ -7462,7 +8044,7 @@ there" - + !testCaseTracker.isCompleted() @@ -7471,7 +8053,7 @@ there"
- + !testCaseTracker.isCompleted() @@ -7479,7 +8061,7 @@ there" !false - + testCaseTracker.isCompleted() @@ -7489,7 +8071,7 @@ there"
- + !testCaseTracker.isCompleted() @@ -7498,7 +8080,7 @@ there"
- + testCaseTracker.enterSection( section1Name ) @@ -7506,7 +8088,7 @@ there" true - + !testCaseTracker.isCompleted() @@ -7514,7 +8096,7 @@ there" !false - + testCaseTracker.isCompleted() @@ -7522,7 +8104,7 @@ there" true - + !testCaseTracker.enterSection( section1Name ) @@ -7532,7 +8114,7 @@ there"
- + !testCaseTracker.isCompleted() @@ -7541,7 +8123,7 @@ there"
- + testCaseTracker.enterSection( section1Name ) @@ -7549,7 +8131,7 @@ there" true - + !testCaseTracker.enterSection( section2Name ) @@ -7557,7 +8139,7 @@ there" !false - + !testCaseTracker.isCompleted() @@ -7565,7 +8147,7 @@ there" !false - + !testCaseTracker.enterSection( section1Name ) @@ -7573,7 +8155,7 @@ there" !false - + testCaseTracker.enterSection( section2Name ) @@ -7581,7 +8163,7 @@ there" true - + testCaseTracker.isCompleted() @@ -7591,7 +8173,7 @@ there"
- + !testCaseTracker.isCompleted() @@ -7600,7 +8182,7 @@ there"
- + testCaseTracker.enterSection( section1Name ) @@ -7608,7 +8190,7 @@ there" true - + testCaseTracker.enterSection( section2Name ) @@ -7616,7 +8198,7 @@ there" true - + !testCaseTracker.isCompleted() @@ -7624,7 +8206,7 @@ there" !false - + testCaseTracker.isCompleted() @@ -7636,7 +8218,7 @@ there"
- + - + diff --git a/projects/SelfTest/EnumToString.cpp b/projects/SelfTest/EnumToString.cpp new file mode 100644 index 00000000..6917d8ae --- /dev/null +++ b/projects/SelfTest/EnumToString.cpp @@ -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(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( e2 ) ) { + case static_cast( EnumClass2::EnumClass2Value0 ): + return os << "E2/V0"; + case static_cast( EnumClass2::EnumClass2Value1 ): + return os << "E2/V1"; + default: + return os << "Unknown enum value " << static_cast( 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(10); + CHECK( Catch::toString(e3) == "Unknown enum value 10" ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#endif // CATCH_CPP11_OR_GREATER + diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index b229c766..86bd4f39 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -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 ); +//} diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index edc8aa1f..7cb7ca42 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -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 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; } } diff --git a/projects/SelfTest/ToStringPair.cpp b/projects/SelfTest/ToStringPair.cpp new file mode 100644 index 00000000..8f510700 --- /dev/null +++ b/projects/SelfTest/ToStringPair.cpp @@ -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 + struct StringMaker > { + static std::string convert( const std::pair& pair ) { + std::ostringstream oss; + oss << "{ " + << toString( pair.first ) + << ", " + << toString( pair.second ) + << " }"; + return oss.str(); + } + }; +} + +TEST_CASE( "std::pair -> toString", "[toString][pair]" ) { + std::pair value( 34, "xyzzy" ); + REQUIRE( Catch::toString( value ) == "{ 34, \"xyzzy\" }" ); +} + +TEST_CASE( "std::pair -> toString", "[toString][pair]" ) { + std::pair value( 34, "xyzzy" ); + REQUIRE( Catch::toString(value) == "{ 34, \"xyzzy\" }" ); +} + +TEST_CASE( "std::vector > -> toString", "[toString][pair]" ) { + std::vector > 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 > -> toString", "[toString][pair]" ) { + typedef std::pair left_t; + typedef std::pair right_t; + + left_t left( 42, "Arthur" ); + right_t right( "Ford", 24 ); + + std::pair pair( left, right ); + REQUIRE( Catch::toString( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" ); +} diff --git a/projects/SelfTest/ToStringTuple.cpp b/projects/SelfTest/ToStringTuple.cpp new file mode 100644 index 00000000..012ee665 --- /dev/null +++ b/projects/SelfTest/ToStringTuple.cpp @@ -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", "[toString][tuple]" ) +{ + typedef std::tuple type; + CHECK( "{ 0 }" == Catch::toString(type{0}) ); +} + + +TEST_CASE( "tuple", "[toString][tuple]" ) +{ + typedef std::tuple type; + CHECK( "1.2f" == Catch::toString(float(1.2)) ); + CHECK( "{ 1.2f, 0 }" == Catch::toString(type{1.2,0}) ); +} + +TEST_CASE( "tuple", "[toString][tuple]" ) +{ + typedef std::tuple type; + CHECK( "{ \"hello\", \"world\" }" == Catch::toString(type{"hello","world"}) ); +} + +TEST_CASE( "tuple,tuple<>,float>", "[toString][tuple]" ) +{ + typedef std::tuple,std::tuple<>,float> type; + type value { std::tuple{42}, {}, 1.2f }; + CHECK( "{ { 42 }, { }, 1.2f }" == Catch::toString(value) ); +} + +TEST_CASE( "tuple", "[toString][tuple]" ) +{ + typedef std::tuple type; + type value { nullptr, 42, "Catch me" }; + CHECK( "{ nullptr, 42, \"Catch me\" }" == Catch::toString(value) ); +} + +#endif /* #ifdef CATCH_CPP11_OR_GREATER */ + diff --git a/projects/SelfTest/ToStringVector.cpp b/projects/SelfTest/ToStringVector.cpp new file mode 100644 index 00000000..44790605 --- /dev/null +++ b/projects/SelfTest/ToStringVector.cpp @@ -0,0 +1,77 @@ +#include "catch.hpp" +#include + + +// vedctor +TEST_CASE( "vector -> toString", "[toString][vector]" ) +{ + std::vector 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 -> toString", "[toString][vector]" ) +{ + std::vector 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 + struct minimal_allocator { + typedef T value_type; + typedef std::size_t size_type; + T *allocate( size_type n ) { + return static_cast( ::operator new( n * sizeof(T) ) ); + } + void deallocate( T *p, size_type /*n*/ ) { + ::operator delete( static_cast(p) ); + } + template + bool operator==( const minimal_allocator& ) const { return true; } + template + bool operator!=( const minimal_allocator& ) const { return false; } + }; +} + +TEST_CASE( "vector -> toString", "[toString][vector,allocator]" ) { + std::vector > 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> -> toString", "[toString][vector,allocator]" ) { + typedef std::vector > inner; + typedef std::vector 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 diff --git a/projects/SelfTest/ToStringWhich.cpp b/projects/SelfTest/ToStringWhich.cpp new file mode 100644 index 00000000..1d4aa892 --- /dev/null +++ b/projects/SelfTest/ToStringWhich.cpp @@ -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 { + static std::string convert( const has_maker& ) { + return "StringMaker"; + } + }; + template<> + struct StringMaker { + static std::string convert( const has_maker_and_toString& ) { + return "StringMaker"; + } + }; +} + +// 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" ); +} + +// 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 v(1); + // This invokes template toString which actually gives us '{ ? }' + REQUIRE( Catch::toString( v ) == "{ {?} }" ); +} + +TEST_CASE( "toString( vectors v(1); + REQUIRE( Catch::toString( v ) == "{ StringMaker }" ); +} + + +TEST_CASE( "toString( vectors v(1); + // Note: This invokes the template toString -> StringMaker + REQUIRE( Catch::toString( v ) == "{ StringMaker }" ); +} diff --git a/projects/SelfTest/TrickyTests.cpp b/projects/SelfTest/TrickyTests.cpp index a1676570..462718db 100644 --- a/projects/SelfTest/TrickyTests.cpp +++ b/projects/SelfTest/TrickyTests.cpp @@ -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][.]" ) { diff --git a/projects/SelfTest/makefile b/projects/SelfTest/makefile index f828c526..0a29372c 100644 --- a/projects/SelfTest/makefile +++ b/projects/SelfTest/makefile @@ -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 + diff --git a/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj index 31fc5253..6658ca69 100644 --- a/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj +++ b/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj @@ -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 = ""; }; 262E7399184673A800CAC268 /* catch_reporter_bases.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_bases.hpp; sourceTree = ""; }; 262E739A1846759000CAC268 /* catch_common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_common.hpp; sourceTree = ""; }; + 263F7A4519A66608009474C2 /* catch_fatal_condition.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_fatal_condition.hpp; sourceTree = ""; }; + 263F7A4619B6FCBF009474C2 /* EnumToString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = EnumToString.cpp; path = ../../../SelfTest/EnumToString.cpp; sourceTree = ""; }; + 263F7A4819B6FE1E009474C2 /* ToStringPair.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringPair.cpp; path = ../../../SelfTest/ToStringPair.cpp; sourceTree = ""; }; + 263F7A4919B6FE1E009474C2 /* ToStringVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringVector.cpp; path = ../../../SelfTest/ToStringVector.cpp; sourceTree = ""; }; + 263F7A4A19B6FE1E009474C2 /* ToStringWhich.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringWhich.cpp; path = ../../../SelfTest/ToStringWhich.cpp; sourceTree = ""; }; 263FD06017AF8DF200988A20 /* catch_timer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_timer.hpp; sourceTree = ""; }; 263FD06117AF8DF200988A20 /* catch_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_timer.h; sourceTree = ""; }; 2656C21F1925E5100040DB02 /* catch_test_spec_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_test_spec_parser.hpp; sourceTree = ""; }; @@ -87,6 +97,8 @@ 26847E5C16BBACB60043B9C1 /* catch_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_message.hpp; sourceTree = ""; }; 26847E5D16BBADB40043B9C1 /* catch_message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_message.cpp; path = ../../../SelfTest/SurrogateCpps/catch_message.cpp; sourceTree = ""; }; 268F47B018A93F7800D8C14F /* catch_clara.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_clara.h; sourceTree = ""; }; + 2691574A1A4480C50054F1ED /* catch_reporter_teamcity.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_teamcity.hpp; sourceTree = ""; }; + 2691574B1A532A280054F1ED /* ToStringTuple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToStringTuple.cpp; path = ../../../SelfTest/ToStringTuple.cpp; sourceTree = ""; }; 26926E8318D7777D004E10F2 /* clara.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = clara.h; path = ../../../../include/external/clara.h; sourceTree = ""; }; 26926E8418D77809004E10F2 /* tbc_text_format.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tbc_text_format.h; path = ../../../../include/external/tbc_text_format.h; sourceTree = ""; }; 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SectionTrackerTests.cpp; path = ../../../SelfTest/SectionTrackerTests.cpp; sourceTree = ""; }; @@ -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 = ""; @@ -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; diff --git a/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.xcworkspace/xcshareddata/CatchSelfTest.xccheckout b/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.xcworkspace/xcshareddata/CatchSelfTest.xccheckout deleted file mode 100644 index 149325a9..00000000 --- a/projects/XCode/CatchSelfTest/CatchSelfTest.xcodeproj/project.xcworkspace/xcshareddata/CatchSelfTest.xccheckout +++ /dev/null @@ -1,41 +0,0 @@ - - - - - IDESourceControlProjectFavoriteDictionaryKey - - IDESourceControlProjectIdentifier - 034502BF-F920-4DB6-82F5-71E61E50118C - IDESourceControlProjectName - CatchSelfTest - IDESourceControlProjectOriginsDictionary - - 01DD8CA9-7DC3-46BC-B998-EFF40EA3485F - ssh://github.com/philsquared/Catch.git - - IDESourceControlProjectPath - projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.xcworkspace - IDESourceControlProjectRelativeInstallPathDictionary - - 01DD8CA9-7DC3-46BC-B998-EFF40EA3485F - ../../../../.. - - IDESourceControlProjectURL - ssh://github.com/philsquared/Catch.git - IDESourceControlProjectVersion - 110 - IDESourceControlProjectWCCIdentifier - 01DD8CA9-7DC3-46BC-B998-EFF40EA3485F - IDESourceControlProjectWCConfigurations - - - IDESourceControlRepositoryExtensionIdentifierKey - public.vcs.git - IDESourceControlWCCIdentifierKey - 01DD8CA9-7DC3-46BC-B998-EFF40EA3485F - IDESourceControlWCCName - Catch - - - - diff --git a/scripts/approvalTests.py b/scripts/approvalTests.py index 329c99b5..f2ffea5c 100644 --- a/scripts/approvalTests.py +++ b/scripts/approvalTests.py @@ -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) + "" + m.group(3) + line = m.group(2) + m.group(3) + m2 = filelineParser.match( line ) + if m2: + line = m2.group(1) + "" + 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) + "" + 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 ) ) diff --git a/single_include/catch.hpp b/single_include/catch.hpp index 6b8dfb5e..29647904 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,6 +1,6 @@ /* - * CATCH v1.0 build 53 (master branch) - * Generated: 2014-08-20 08:08:19.533804 + * CATCH v1.1 build 14 (develop branch) + * Generated: 2015-03-04 18:32:24.627737 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -18,26 +18,31 @@ #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 -#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 @@ -135,6 +140,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 @@ -176,8 +185,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(); @@ -215,6 +232,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 ); @@ -237,6 +255,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; @@ -467,7 +486,7 @@ namespace Catch { struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases ) const = 0; + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; }; } @@ -603,7 +622,9 @@ namespace Catch { Exception = 0x100 | FailureBit, ThrewException = Exception | 1, - DidntThrowException = Exception | 2 + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit }; }; @@ -1034,9 +1055,49 @@ inline id performOptionalSelector( id obj, SEL sel ) { #endif +#ifdef CATCH_CPP11_OR_GREATER +#include +#include +#endif + namespace Catch { + +// Why we're here. +template +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 @@ -1077,10 +1138,38 @@ namespace Detail { #endif +#if defined(CATCH_CPP11_OR_GREATER) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif template struct StringMakerBase { +#if defined(CATCH_CPP11_OR_GREATER) template - static std::string convert( T const& ) { return "{?}"; } + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif }; template<> @@ -1102,9 +1191,6 @@ namespace Detail { } // end namespace Detail -template -std::string toString( T const& value ); - template struct StringMaker : Detail::StringMakerBase::value> {}; @@ -1135,12 +1221,59 @@ namespace Detail { std::string rangeToString( InputIterator first, InputIterator last ); } +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + template -struct StringMaker > { - static std::string convert( std::vector const& v ) { - return Detail::rangeToString( v.begin(), v.end() ); +std::string toString( std::vector 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::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); } }; +#endif namespace Detail { template @@ -1161,44 +1294,15 @@ std::string toString( T const& value ) { return StringMaker::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 std::string rangeToString( InputIterator first, InputIterator last ) { 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(); @@ -1395,6 +1499,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(); @@ -1575,7 +1681,7 @@ namespace Catch { 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(); \ @@ -1636,6 +1742,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; @@ -1688,7 +1797,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; @@ -1702,7 +1811,7 @@ namespace Catch { namespace Catch { - class Section { + class Section : NonCopyable { public: Section( SectionInfo const& info ); ~Section(); @@ -1711,15 +1820,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; @@ -2694,7 +2794,7 @@ return @ desc; \ #endif -#ifdef CATCH_CONFIG_RUNNER +#ifdef CATCH_IMPL // #included from: internal/catch_impl.hpp #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED @@ -2706,7 +2806,7 @@ return @ desc; \ #pragma clang diagnostic ignored "-Wweak-vtables" #endif -// #included from: catch_runner.hpp +// #included from: ../catch_runner.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp @@ -2962,6 +3062,11 @@ namespace Catch { Always, Never }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; class TestSpec; @@ -2979,6 +3084,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; }; } @@ -3004,12 +3112,16 @@ namespace Catch { private: bool isOwned; }; + + std::ostream& cout(); + std::ostream& cerr(); } #include #include #include #include +#include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 @@ -3029,10 +3141,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; @@ -3045,12 +3160,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; @@ -3068,12 +3186,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() ); @@ -3084,7 +3202,7 @@ namespace Catch { } virtual ~Config() { - m_os.rdbuf( std::cout.rdbuf() ); + m_os.rdbuf( Catch::cout().rdbuf() ); m_stream.release(); } @@ -3106,7 +3224,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 ) { @@ -3132,6 +3250,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; @@ -3760,7 +3881,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 ) { @@ -3788,7 +3909,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; } @@ -3930,7 +4051,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 ); } } @@ -4028,7 +4149,28 @@ namespace Catch { config.warnings = static_cast( 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( 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? @@ -4140,6 +4282,18 @@ namespace Catch { .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; } @@ -4313,10 +4467,6 @@ namespace Catch { namespace Catch { - namespace Detail { - struct IColourImpl; - } - struct Colour { enum Code { None = 0, @@ -4362,7 +4512,6 @@ namespace Catch { static void use( Code _colourCode ); private: - static Detail::IColourImpl* impl(); bool m_moved; }; @@ -4592,11 +4741,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; }; struct IReporterFactory { @@ -4624,9 +4776,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(); } @@ -4647,15 +4799,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; } @@ -4671,7 +4823,7 @@ namespace Catch { ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - std::cout << testCaseInfo.name << std::endl; + Catch::cout() << testCaseInfo.name << std::endl; } return matchedTests; } @@ -4697,9 +4849,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(); } @@ -4733,14 +4885,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; @@ -4752,13 +4904,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(); } @@ -4915,6 +5067,81 @@ using SectionTracking::TestCaseTracker; } // namespace Catch +// #included from: catch_fatal_condition.hpp +#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 + +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( "", -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 + #include #include @@ -5102,6 +5329,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 { @@ -5123,12 +5381,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(); } @@ -5136,20 +5394,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::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; @@ -5165,7 +5412,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::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 ) @@ -5253,7 +5525,7 @@ namespace Catch { Totals totals; - context.testGroupStarting( "", 1, 1 ); // deprecated? + context.testGroupStarting( "all tests", 1, 1 ); // deprecated? TestSpec testSpec = m_config->testSpec(); if( !testSpec.hasFilters() ) @@ -5276,7 +5548,15 @@ namespace Catch { m_testsAlreadyRun.insert( *it ); } } - context.testGroupEnded( "", totals, 1, 1 ); + std::vector skippedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); + + for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); + it != itEnd; + ++it ) + m_reporter->skipTest( *it ); + + context.testGroupEnded( "all tests", totals, 1, 1 ); return totals; } @@ -5313,7 +5593,7 @@ namespace Catch { std::set m_testsAlreadyRun; }; - class Session { + class Session : NonCopyable { static bool alreadyInstantiated; public: @@ -5324,7 +5604,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; @@ -5334,15 +5614,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 ) { @@ -5356,11 +5636,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::max)(); } return 0; @@ -5386,6 +5666,9 @@ namespace Catch { try { config(); // Force config to be constructed + + std::srand( m_configData.rngSeed ); + Runner runner( m_config ); // Handle list request @@ -5395,7 +5678,7 @@ namespace Catch { return static_cast( runner.runTests().assertions.failed ); } catch( std::exception& ex ) { - std::cerr << ex.what() << std::endl; + Catch::cerr() << ex.what() << std::endl; return (std::numeric_limits::max)(); } } @@ -5436,10 +5719,18 @@ namespace Catch { #include #include #include +#include namespace Catch { class TestRegistry : public ITestCaseRegistry { + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i& matchingTestCases ) const { + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { + for( std::vector::const_iterator it = m_functionsInOrder.begin(), itEnd = m_functionsInOrder.end(); it != itEnd; ++it ) { - 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& matchingTestCases ) { + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + RandomNumberGenerator rng; + std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + } std::set m_functions; std::vector m_functionsInOrder; std::vector m_nonHiddenFunctions; @@ -5613,7 +5924,7 @@ namespace Catch { throw; } @catch (NSException *exception) { - return toString( [exception description] ); + return Catch::toString( [exception description] ); } #else throw; @@ -5760,6 +6071,7 @@ namespace Catch { #include #include +#include namespace Catch { @@ -5823,6 +6135,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 } namespace Catch { @@ -5872,7 +6193,7 @@ namespace Catch { std::string testName = getResultCapture()->getCurrentTestName(); std::map::const_iterator it = - m_generatorsByTestName.find( testName ); + m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second : NULL; @@ -5908,8 +6229,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, true ); throw std::domain_error( "Unknown stream: " + streamName ); @@ -5924,14 +6245,35 @@ namespace Catch { // #included from: catch_console_colour_impl.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED -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 @@ -5946,7 +6288,7 @@ namespace Catch { namespace Detail { namespace Catch { namespace { - class Win32ColourImpl : public Detail::IColourImpl { + class Win32ColourImpl : public IColourImpl { public: Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) { @@ -5983,11 +6325,7 @@ namespace { WORD originalAttributes; }; - inline bool shouldUseColourForPlatform() { - return true; - } - - static Detail::IColourImpl* platformColourInstance() { + IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; return &s_instance; } @@ -5995,7 +6333,7 @@ namespace { } // end anon namespace } // end namespace Catch -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// #include @@ -6006,7 +6344,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 ) { @@ -6027,53 +6365,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 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( _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 @@ -6238,7 +6571,7 @@ namespace Catch { namespace Catch { inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( tag == "." || + if( startsWith( tag, "." ) || tag == "hide" || tag == "!hide" ) return TestCaseInfo::IsHidden; @@ -6252,19 +6585,19 @@ namespace Catch { return TestCaseInfo::None; } inline bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + return TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); } inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { 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); } @@ -6292,14 +6625,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; @@ -6417,7 +6751,7 @@ namespace Catch { namespace Catch { // These numbers are maintained by a script - Version libraryVersion( 1, 0, 53, "master" ); + Version libraryVersion( 1, 1, 14, "develop" ); } // #included from: catch_message.hpp @@ -6501,6 +6835,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 m_legacyReporter; @@ -6574,6 +6909,8 @@ namespace Catch void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { m_legacyReporter->EndTesting( testRunStats.totals ); } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } } // #included from: catch_timer.hpp @@ -6615,14 +6952,14 @@ namespace Catch { void Timer::start() { m_ticks = getCurrentTicks(); } - unsigned int Timer::getElapsedNanoseconds() const { + unsigned int Timer::getElapsedMicroseconds() const { return static_cast(getCurrentTicks() - m_ticks); } unsigned int Timer::getElapsedMilliseconds() const { - return static_cast((getCurrentTicks() - m_ticks)/1000); + return static_cast(getElapsedMicroseconds()/1000); } double Timer::getElapsedSeconds() const { - return (getCurrentTicks() - m_ticks)/1000000.0; + return getElapsedMicroseconds()/1000000.0; } } // namespace Catch @@ -6660,6 +6997,20 @@ 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 ) @@ -6687,6 +7038,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__ @@ -6781,7 +7135,7 @@ namespace Catch { 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; } @@ -6822,7 +7176,7 @@ namespace Catch { 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 @@ -6834,6 +7188,8 @@ namespace Catch { namespace Detail { + std::string unprintableString = "{?}"; + namespace { struct Endianness { enum Arch { Big, Little }; @@ -6892,7 +7248,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( value[i] ) : '?'; - return toString( s ); + return Catch::toString( s ); } std::string toString( const char* const value ) { @@ -6915,7 +7271,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(); } @@ -6929,7 +7288,7 @@ std::string toString( unsigned long value ) { } std::string toString( unsigned int value ) { - return toString( static_cast( value ) ); + return Catch::toString( static_cast( value ) ); } template @@ -7195,7 +7554,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); } } @@ -7208,6 +7567,8 @@ namespace Catch { // #included from: catch_reporter_bases.hpp #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED +#include + namespace Catch { struct StreamingReporterBase : SharedImpl { @@ -7240,7 +7601,6 @@ namespace Catch { } virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { currentTestCaseInfo.reset(); - assert( m_sectionStack.empty() ); } virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { currentGroupInfo.reset(); @@ -7251,6 +7611,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 m_config; std::ostream& stream; @@ -7380,6 +7745,8 @@ namespace Catch { } virtual void testRunEndedCumulative() = 0; + virtual void skipTest( TestCaseInfo const& ) {} + Ptr m_config; std::ostream& stream; std::vector m_assertions; @@ -7395,6 +7762,16 @@ namespace Catch { }; + template + 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 // #included from: ../internal/catch_reporter_registrars.hpp @@ -7464,7 +7841,6 @@ namespace Catch { #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include -#include #include #include @@ -7507,7 +7883,7 @@ namespace Catch { XmlWriter() : m_tagIsOpen( false ), m_needsNewline( false ), - m_os( &std::cout ) + m_os( &Catch::cout() ) {} XmlWriter( std::ostream& os ) @@ -7677,81 +8053,90 @@ namespace Catch { } namespace Catch { - class XmlReporter : public SharedImpl { + 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 tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::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 ); @@ -7759,58 +8144,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 // #included from: ../reporters/catch_reporter_junit.hpp @@ -7937,7 +8360,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 ); @@ -7970,6 +8393,7 @@ namespace Catch { std::string elementName; switch( result.getResultType() ) { case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: elementName = "error"; break; case ResultWas::ExplicitFailure: @@ -8028,8 +8452,6 @@ namespace Catch { // #included from: ../reporters/catch_reporter_console.hpp #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED -#include - namespace Catch { struct ConsoleReporter : StreamingReporterBase { @@ -8164,6 +8586,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"; @@ -8281,6 +8708,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() { @@ -8452,15 +8882,6 @@ namespace Catch { void printSummaryDivider() { stream << getLineOfChars<'-'>() << "\n"; } - template - 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; @@ -8569,6 +8990,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" ); @@ -8798,8 +9226,6 @@ namespace Catch { Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} - - INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter ) } #ifdef __clang__ @@ -8988,9 +9414,13 @@ using Catch::Detail::Approx; #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_SINGLE_INCLUDE_CATCH_HPP_INCLUDED