mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-12 16:35:40 +02:00
Compare commits
55 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ce37f48ffa | ||
![]() |
090fc74cca | ||
![]() |
f58ff0c540 | ||
![]() |
a600bfeb75 | ||
![]() |
8cad76a749 | ||
![]() |
1a3f6d829b | ||
![]() |
b524fa7cd8 | ||
![]() |
5121b5b058 | ||
![]() |
1e5176bd69 | ||
![]() |
7dd4f2977a | ||
![]() |
50c95a0143 | ||
![]() |
0dabd951ba | ||
![]() |
7ae96c710b | ||
![]() |
70d3c937c3 | ||
![]() |
38af8d7035 | ||
![]() |
c97ada1910 | ||
![]() |
615aa071a8 | ||
![]() |
af0b03abd2 | ||
![]() |
15816c5760 | ||
![]() |
f11a45aa67 | ||
![]() |
bcaa2f9646 | ||
![]() |
efab3ca8b2 | ||
![]() |
60f8ebec49 | ||
![]() |
e1dbb7cf64 | ||
![]() |
02a69b449f | ||
![]() |
c390c4cb9f | ||
![]() |
60a9ac7e65 | ||
![]() |
c06afe438e | ||
![]() |
73872207db | ||
![]() |
51860f1568 | ||
![]() |
dab1d9d222 | ||
![]() |
4ce11d63a6 | ||
![]() |
99c2ea594c | ||
![]() |
51107d7cbd | ||
![]() |
83f4b39680 | ||
![]() |
b1171bd1f2 | ||
![]() |
6c23a6582b | ||
![]() |
7bcb42496d | ||
![]() |
184865358c | ||
![]() |
225e90d8ba | ||
![]() |
31c23b9489 | ||
![]() |
f347611403 | ||
![]() |
1efd8d3067 | ||
![]() |
876af874f3 | ||
![]() |
e7bcbb35c0 | ||
![]() |
4a04682e49 | ||
![]() |
3b98a0166f | ||
![]() |
877fd523bc | ||
![]() |
a1e9b841ff | ||
![]() |
3b7511e564 | ||
![]() |
ffc4a9dc14 | ||
![]() |
7c8b93eac3 | ||
![]() |
40dbdf6cb2 | ||
![]() |
70f43d719b | ||
![]() |
a281173099 |
29
.github/issue_template.md
vendored
Normal file
29
.github/issue_template.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
## Description
|
||||
<!--
|
||||
If your issue is a bugreport, this means describing what you did,
|
||||
what did you want to happen and what actually did happen.
|
||||
|
||||
If your issue is a feature request, describe the feature and why do you
|
||||
want it.
|
||||
-->
|
||||
|
||||
|
||||
### Steps to reproduce
|
||||
<!--
|
||||
This is only relevant for bug reports, but if you do have one,
|
||||
please provide a minimal set of steps to reproduce the problem.
|
||||
|
||||
Usually this means providing a small and self-contained code using Catch
|
||||
and specifying compiler flags/tools used if relevant.
|
||||
-->
|
||||
|
||||
|
||||
### Extra information
|
||||
<!--
|
||||
Fill in any extra information that might be important for your issue.
|
||||
|
||||
If your issue is a bugreport, definitely fill out at least the following.
|
||||
-->
|
||||
* Catch version: **v42.42.42**
|
||||
* Operating System: **Joe's discount operating system**
|
||||
* Compiler+version: **Hidden Dragon v1.2.3**
|
25
.github/pull_request_template.md
vendored
Normal file
25
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
Please do not submit pull requests changing the `version.hpp`
|
||||
or the single-include `catch.hpp` file, these are changed
|
||||
only when a new release is made.
|
||||
-->
|
||||
|
||||
|
||||
## Description
|
||||
<!--
|
||||
Describe the what and the why of your pull request. Remember that these two
|
||||
are usually a bit different. As an example, if you have made various changes
|
||||
to decrease the number of new strings allocated, thats what. The why probably
|
||||
was that you have a large set of tests and found that this speeds them up.
|
||||
-->
|
||||
|
||||
## GitHub Issues
|
||||
<!--
|
||||
If this PR was motivated by some existing issues, reference them here.
|
||||
|
||||
If it is a simple bug-fix, please also add a line like 'Closes #123'
|
||||
to your commit message, so that it is automatically closed.
|
||||
If it is not, don't, as it might take several iterations for a feature
|
||||
to be done properly. If in doubt, leave it open and reference it in the
|
||||
PR itself, so that maintainers can decide.
|
||||
-->
|
@@ -119,12 +119,12 @@ matrix:
|
||||
|
||||
# 3/ OSX Clang Builds
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: COMPILER='ccache clang++' BUILD_TYPE='Debug'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: COMPILER='ccache clang++' BUILD_TYPE='Release'
|
||||
|
||||
@@ -145,7 +145,7 @@ install:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz"
|
||||
mkdir cmake && travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
||||
mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
||||
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
|
||||
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
which cmake || brew install cmake
|
||||
|
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(CatchSelfTest)
|
||||
|
||||
@@ -7,6 +7,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
# define some folders
|
||||
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
|
||||
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
|
||||
set(HEADER_DIR ${CATCH_DIR}/include)
|
||||
|
||||
if(USE_CPP11)
|
||||
@@ -91,6 +92,7 @@ set(IMPL_SOURCES
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_streambuf.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_spec.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_xmlwriter.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_case_tracker.cpp
|
||||
)
|
||||
CheckFileList(IMPL_SOURCES ${SELF_TEST_DIR}/SurrogateCpps)
|
||||
|
||||
@@ -102,7 +104,7 @@ set(TOP_LEVEL_HEADERS
|
||||
${HEADER_DIR}/catch_with_main.hpp
|
||||
)
|
||||
CheckFileList(TOP_LEVEL_HEADERS ${HEADER_DIR})
|
||||
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(EXTERNAL_HEADERS
|
||||
${HEADER_DIR}/external/clara.h
|
||||
@@ -110,7 +112,7 @@ set(EXTERNAL_HEADERS
|
||||
)
|
||||
CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external)
|
||||
|
||||
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(INTERNAL_HEADERS
|
||||
${HEADER_DIR}/internal/catch_approx.hpp
|
||||
@@ -220,13 +222,32 @@ set(HEADERS
|
||||
)
|
||||
|
||||
|
||||
set(BENCH_SOURCES
|
||||
${BENCHMARK_DIR}/BenchMain.cpp
|
||||
${BENCHMARK_DIR}/StringificationBench.cpp
|
||||
)
|
||||
CheckFileList(BENCH_SOURCES ${BENCHMARK_DIR})
|
||||
|
||||
# Provide some groupings for IDEs
|
||||
SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
|
||||
SOURCE_GROUP("Surrogates" FILES ${IMPL_SOURCES})
|
||||
SOURCE_GROUP("Benchmarks" FILES ${BENCH_SOURCES})
|
||||
|
||||
# configure the executable
|
||||
include_directories(${HEADER_DIR})
|
||||
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${HEADERS})
|
||||
add_executable(Benchmark ${BENCH_SOURCES} ${HEADERS})
|
||||
|
||||
# Add desired warnings
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
||||
target_compile_options( SelfTest PRIVATE -Wall -Wextra )
|
||||
target_compile_options( Benchmark PRIVATE -Wall -Wextra )
|
||||
endif()
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
|
||||
target_compile_options( SelfTest PRIVATE /W4 )
|
||||
target_compile_options( Benchmark PRIVATE /W4 )
|
||||
endif()
|
||||
|
||||
|
||||
# configure unit tests via CTest
|
||||
enable_testing()
|
||||
@@ -237,3 +258,5 @@ set_tests_properties(ListTests PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ test c
|
||||
|
||||
add_test(NAME ListTags COMMAND SelfTest --list-tags)
|
||||
set_tests_properties(ListTags PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ tags")
|
||||
|
||||
install(DIRECTORY "single_include/" DESTINATION "include/catch/")
|
||||
|
@@ -1,10 +1,10 @@
|
||||

|
||||
|
||||
*v1.6.1*
|
||||
*v1.7.0*
|
||||
|
||||
Build status (on Travis CI) [](https://travis-ci.org/philsquared/Catch)
|
||||
|
||||
<a href="https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp">The latest, single header, version can be downloaded directly using this link</a>
|
||||
<a href="https://github.com/philsquared/Catch/releases/download/v1.7.0/catch.hpp">The latest, single header, version can be downloaded directly using this link</a>
|
||||
|
||||
## What's the Catch?
|
||||
|
||||
|
@@ -34,6 +34,15 @@ Example:
|
||||
REQUIRE_FALSE( thisReturnsFalse() );
|
||||
```
|
||||
|
||||
Do note that "overly complex" expressions cannot be decomposed and thus will not compile. This is done partly for practical reasons (to keep the underlying expression template machinery to minimum) and partly for philosophical reasons (assertions should be simple and deterministic).
|
||||
|
||||
Examples:
|
||||
* `CHECK(a == 1 && b == 2);`
|
||||
This expression is too complex because of the `&&` operator. If you want to check that 2 or more properties hold, you can either put the expression into parenthesis, which stops decomposition from working, or you need to decompose the expression into two assertions: `CHECK( a == 1 ); CHECK( b == 2);`
|
||||
* `CHECK( a == 2 || b == 1 );`
|
||||
This expression is too complex because of the `||` operator. If you want to check that one of several properties hold, you can put the expression into parenthesis (unlike with `&&`, expression decomposition into several `CHECK`s is not possible).
|
||||
|
||||
|
||||
### 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.
|
||||
|
@@ -69,7 +69,7 @@ ExternalProject_Add(
|
||||
|
||||
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
|
||||
ExternalProject_Get_Property(catch source_dir)
|
||||
set(CATCH_INCLUDE_DIR ${source_dir}/include CACHE INTERNAL "Path to include folder for Catch")
|
||||
set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch")
|
||||
```
|
||||
|
||||
If you put it in, e.g., `${PROJECT_SRC_DIR}/${EXT_PROJECTS_DIR}/catch/`, you can use it in your project by adding the following to your root CMake file:
|
||||
|
@@ -17,6 +17,9 @@ Click one of the followings links to take you straight to that option - or scrol
|
||||
<a href="#warnings"> ` -w, --warn`</a><br />
|
||||
<a href="#reporting-timings"> ` -d, --durations`</a><br />
|
||||
<a href="#input-file"> ` -f, --input-file`</a><br />
|
||||
<a href="#run-section"> ` -c, --section`</a><br />
|
||||
<a href="#filenames-as-tags"> ` -#, --filenames-as-tags`</a><br />
|
||||
|
||||
|
||||
</br>
|
||||
|
||||
@@ -217,6 +220,59 @@ In either case the actual value for the seed is printed as part of Catch's outpu
|
||||
|
||||
Prints the command line arguments to stdout
|
||||
|
||||
|
||||
<a id="run-section"></a>
|
||||
## Specify the section to run
|
||||
<pre>-s, --section <section name></pre>
|
||||
|
||||
To limit execution to a specific section within a test case, use this option one or more times.
|
||||
To narrow to sub-sections use multiple instances, where each subsequent instance specifies a deeper nesting level.
|
||||
|
||||
E.g. if you have:
|
||||
|
||||
<pre>
|
||||
TEST_CASE( "Test" ) {
|
||||
SECTION( "sa" ) {
|
||||
SECTION( "sb" ) {
|
||||
/*...*/
|
||||
}
|
||||
SECTION( "sc" ) {
|
||||
/*...*/
|
||||
}
|
||||
}
|
||||
SECTION( "sd" ) {
|
||||
/*...*/
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
Then you can run `sb` with:
|
||||
<pre>./MyExe Test -c sa -c sb</pre>
|
||||
|
||||
Or run just `sd` with:
|
||||
<pre>./MyExe Test -c sd</pre>
|
||||
|
||||
To run all of `sa`, including `sb` and `sc` use:
|
||||
<pre>./MyExe Test -c sa</pre>
|
||||
|
||||
There are some limitations of this feature to be aware of:
|
||||
- Code outside of sections being skipped will still be executed - e.g. any set-up code in the TEST_CASE before the
|
||||
start of the first section.</br>
|
||||
- At time of writing, wildcards are not supported in section names.
|
||||
- If you specify a section without narrowing to a test case first then all test cases will be executed
|
||||
(but only matching sections within them).
|
||||
|
||||
|
||||
<a id="filenames-as-tags"></a>
|
||||
## Filenames as tags
|
||||
<pre>-#, --filenames-as-tags</pre>
|
||||
|
||||
When this option is used then every test is given an additional tag which is formed of the unqualified
|
||||
filename it is found in, with any extension stripped, prefixed with the `#` character.
|
||||
|
||||
So, for example, tests within the file `~\Dev\MyProject\Ferrets.cpp` would be tagged `[#Ferrets]`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
||||
|
@@ -62,6 +62,7 @@ This can be useful on certain platforms that do not provide ```std::cout``` and
|
||||
CATCH_CONFIG_CPP11_OVERRIDE // CATCH_OVERRIDE expands to override (for virtual function implementations)
|
||||
CATCH_CONFIG_CPP11_UNIQUE_PTR // Use std::unique_ptr instead of std::auto_ptr
|
||||
CATCH_CONFIG_CPP11_SHUFFLE // Use std::shuffle instead of std::random_shuffle
|
||||
CATCH_CONFIG_CPP11_TYPE_TRAITS // Use std::enable_if and <type_traits>
|
||||
|
||||
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.
|
||||
|
@@ -24,7 +24,7 @@ int main( int argc, char* argv[] )
|
||||
|
||||
// global clean-up...
|
||||
|
||||
return result;
|
||||
return ( result < 0xff ? result : 0xff );
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,11 @@ int main( int argc, char* argv[] )
|
||||
// overrides command line args
|
||||
// only do this if you know you need to
|
||||
|
||||
return session.run();
|
||||
int numFailed = session.run();
|
||||
// Note that on unices only the lower 8 bits are usually used, clamping
|
||||
// the return value to 255 prevents false negative when some multiple
|
||||
// of 256 tests has failed
|
||||
return ( numFailed < 0xff ? numFailed : 0xff );
|
||||
}
|
||||
```
|
||||
|
||||
|
@@ -1,4 +1,37 @@
|
||||
# 1.6.1
|
||||
# 1.7.0
|
||||
|
||||
### Features/ Changes:
|
||||
* Catch now runs significantly faster for passing tests
|
||||
* Microbenchmark focused on Catch's overhead went from ~3.4s to ~0.7s.
|
||||
* Real world test using [JSON for Modern C++](https://github.com/nlohmann/json)'s test suite went from ~6m 25s to ~4m 14s.
|
||||
* Catch can now run specific sections within test cases.
|
||||
* For now the support is only basic (no wildcards or tags), for details see the [documentation](docs/command-line.md).
|
||||
* Catch now supports SEH on Windows as well as signals on Linux.
|
||||
* After receiving a signal, Catch reports failing assertion and then passes the signal onto the previous handler.
|
||||
* Approx can be used to compare values against strong typedefs (available in C++11 mode only).
|
||||
* Strong typedefs mean types that are explicitly convertible to double.
|
||||
* CHECK macro no longer stops executing section if an exception happens.
|
||||
* Certain characters (space, tab, etc) are now pretty printed.
|
||||
* This means that a `char c = ' '; REQUIRE(c == '\t');` would be printed as `' ' == '\t'`, instead of ` == 9`.
|
||||
|
||||
### Fixes:
|
||||
* Text formatting no longer attempts to access out-of-bounds characters under certain conditions.
|
||||
* THROW family of assertions no longer trigger `-Wunused-value` on expressions containing explicit cast.
|
||||
* Breaking into debugger under OS X works again and no longer required `DEBUG` to be defined.
|
||||
* Compilation no longer breaks under certain compiler if a lambda is used inside assertion macro.
|
||||
|
||||
### Other:
|
||||
* Catch's CMakeLists now defines install command.
|
||||
* Catch's CMakeLists now generates projects with warnings enabled.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Older versions
|
||||
Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history
|
||||
|
||||
## 1.6.1
|
||||
|
||||
### Features/ Changes:
|
||||
* Catch now supports breaking into debugger on Linux
|
||||
@@ -18,10 +51,6 @@
|
||||
* This can be disabled if needed, see [documentation](docs/configuration.md) for details.
|
||||
|
||||
|
||||
|
||||
# Older versions
|
||||
Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history
|
||||
|
||||
## 1.6.0
|
||||
|
||||
### Cmake/ projects:
|
||||
|
@@ -42,6 +42,8 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
|
||||
|
||||
* `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in the your tests.
|
||||
|
||||
* `[!nonportable]` - Indicates that behaviour may vary between platforms or compilers.
|
||||
|
||||
* `[#<filename>]` - running with `-#` or `--filenames-as-tags` causes Catch to add the filename, prefixed with `#` (and with any extension stripped) as a tag. e.g. tests in testfile.cpp would all be tagged `[#testfile]`.
|
||||
|
||||
* `[@<alias>]` - tag aliases all begin with `@` (see below).
|
||||
|
111
include/external/tbc_text_format.h
vendored
111
include/external/tbc_text_format.h
vendored
@@ -37,19 +37,16 @@ namespace Tbc {
|
||||
TextAttributes()
|
||||
: initialIndent( std::string::npos ),
|
||||
indent( 0 ),
|
||||
width( consoleWidth-1 ),
|
||||
tabChar( '\t' )
|
||||
width( consoleWidth-1 )
|
||||
{}
|
||||
|
||||
TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
|
||||
TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
|
||||
TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
|
||||
TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
|
||||
|
||||
std::size_t initialIndent; // indent of first line, or npos
|
||||
std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
|
||||
std::size_t width; // maximum width of text, including indent. Longer text will wrap
|
||||
char tabChar; // If this char is seen the indent is changed to current pos
|
||||
};
|
||||
|
||||
class Text {
|
||||
@@ -57,63 +54,80 @@ namespace Tbc {
|
||||
Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
|
||||
: attr( _attr )
|
||||
{
|
||||
std::string wrappableChars = " [({.,/|\\-";
|
||||
std::size_t indent = _attr.initialIndent != std::string::npos
|
||||
? _attr.initialIndent
|
||||
: _attr.indent;
|
||||
std::string remainder = _str;
|
||||
const std::string wrappableBeforeChars = "[({<\t";
|
||||
const std::string wrappableAfterChars = "])}>-,./|\\";
|
||||
const std::string wrappableInsteadOfChars = " \n\r";
|
||||
std::string indent = _attr.initialIndent != std::string::npos
|
||||
? std::string( _attr.initialIndent, ' ' )
|
||||
: std::string( _attr.indent, ' ' );
|
||||
|
||||
typedef std::string::const_iterator iterator;
|
||||
iterator it = _str.begin();
|
||||
const iterator strEnd = _str.end();
|
||||
|
||||
while( it != strEnd ) {
|
||||
|
||||
while( !remainder.empty() ) {
|
||||
if( lines.size() >= 1000 ) {
|
||||
lines.push_back( "... message truncated due to excessive size" );
|
||||
return;
|
||||
}
|
||||
std::size_t tabPos = std::string::npos;
|
||||
std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
|
||||
std::size_t pos = remainder.find_first_of( '\n' );
|
||||
if( pos <= width ) {
|
||||
width = pos;
|
||||
}
|
||||
pos = remainder.find_last_of( _attr.tabChar, width );
|
||||
if( pos != std::string::npos ) {
|
||||
tabPos = pos;
|
||||
if( remainder[width] == '\n' )
|
||||
width--;
|
||||
remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
|
||||
}
|
||||
|
||||
if( width == remainder.size() ) {
|
||||
spliceLine( indent, remainder, width );
|
||||
}
|
||||
else if( remainder[width] == '\n' ) {
|
||||
spliceLine( indent, remainder, width );
|
||||
if( width <= 1 || remainder.size() != 1 )
|
||||
remainder = remainder.substr( 1 );
|
||||
indent = _attr.indent;
|
||||
}
|
||||
else {
|
||||
pos = remainder.find_last_of( wrappableChars, width );
|
||||
if( pos != std::string::npos && pos > 0 ) {
|
||||
spliceLine( indent, remainder, pos );
|
||||
if( remainder[0] == ' ' )
|
||||
remainder = remainder.substr( 1 );
|
||||
|
||||
std::string suffix;
|
||||
std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) );
|
||||
iterator itEnd = it+width;
|
||||
iterator itNext = _str.end();
|
||||
|
||||
iterator itNewLine = std::find( it, itEnd, '\n' );
|
||||
if( itNewLine != itEnd )
|
||||
itEnd = itNewLine;
|
||||
|
||||
if( itEnd != strEnd ) {
|
||||
bool foundWrapPoint = false;
|
||||
iterator findIt = itEnd;
|
||||
do {
|
||||
if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) {
|
||||
itEnd = findIt+1;
|
||||
itNext = findIt+1;
|
||||
foundWrapPoint = true;
|
||||
}
|
||||
else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) {
|
||||
itEnd = findIt;
|
||||
itNext = findIt;
|
||||
foundWrapPoint = true;
|
||||
}
|
||||
else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) {
|
||||
itNext = findIt+1;
|
||||
itEnd = findIt;
|
||||
foundWrapPoint = true;
|
||||
}
|
||||
if( findIt == it )
|
||||
break;
|
||||
else
|
||||
--findIt;
|
||||
}
|
||||
while( !foundWrapPoint );
|
||||
|
||||
if( !foundWrapPoint ) {
|
||||
// No good wrap char, so we'll break mid word and add a hyphen
|
||||
--itEnd;
|
||||
itNext = itEnd;
|
||||
suffix = "-";
|
||||
}
|
||||
else {
|
||||
spliceLine( indent, remainder, width-1 );
|
||||
lines.back() += "-";
|
||||
while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos )
|
||||
--itEnd;
|
||||
}
|
||||
if( lines.size() == 1 )
|
||||
indent = _attr.indent;
|
||||
if( tabPos != std::string::npos )
|
||||
indent += tabPos;
|
||||
}
|
||||
lines.push_back( indent + std::string( it, itEnd ) + suffix );
|
||||
|
||||
if( indent.size() != _attr.indent )
|
||||
indent = std::string( _attr.indent, ' ' );
|
||||
it = itNext;
|
||||
}
|
||||
}
|
||||
|
||||
void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
|
||||
lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
|
||||
_remainder = _remainder.substr( _pos );
|
||||
}
|
||||
|
||||
|
||||
typedef std::vector<std::string>::const_iterator const_iterator;
|
||||
|
||||
@@ -138,6 +152,7 @@ namespace Tbc {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::string str;
|
||||
TextAttributes attr;
|
||||
|
@@ -13,6 +13,10 @@
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
@@ -41,6 +45,53 @@ namespace Detail {
|
||||
return approx;
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator == ( const T& lhs, Approx const& rhs ) {
|
||||
// Thanks to Richard Harris for his help refining this formula
|
||||
auto lhs_v = double(lhs);
|
||||
return fabs( lhs_v - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs_v), fabs(rhs.m_value) ) );
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator == ( Approx const& lhs, const T& rhs ) {
|
||||
return operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator != ( T lhs, Approx const& rhs ) {
|
||||
return !operator==( lhs, rhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator != ( Approx const& lhs, T rhs ) {
|
||||
return !operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator <= ( T lhs, Approx const& rhs )
|
||||
{
|
||||
return double(lhs) < rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator <= ( Approx const& lhs, T rhs )
|
||||
{
|
||||
return lhs.m_value < double(rhs) || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator >= ( T lhs, Approx const& rhs )
|
||||
{
|
||||
return double(lhs) > rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator >= ( Approx const& lhs, T rhs )
|
||||
{
|
||||
return lhs.m_value > double(rhs) || lhs == rhs;
|
||||
}
|
||||
#else
|
||||
friend bool operator == ( double lhs, Approx const& rhs ) {
|
||||
// Thanks to Richard Harris for his help refining this formula
|
||||
return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
|
||||
@@ -77,6 +128,7 @@ namespace Detail {
|
||||
{
|
||||
return lhs.m_value > rhs || lhs == rhs;
|
||||
}
|
||||
#endif
|
||||
|
||||
Approx& epsilon( double newEpsilon ) {
|
||||
m_epsilon = newEpsilon;
|
||||
|
@@ -13,6 +13,27 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
|
||||
|
||||
struct DecomposedExpression
|
||||
{
|
||||
virtual ~DecomposedExpression() {}
|
||||
virtual bool isBinaryExpression() const {
|
||||
return false;
|
||||
}
|
||||
virtual void reconstructExpression( std::string& dest ) const = 0;
|
||||
|
||||
// Only simple binary comparisons can be decomposed.
|
||||
// If more complex check is required then wrap sub-expressions in parentheses.
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
|
||||
};
|
||||
|
||||
struct AssertionInfo
|
||||
{
|
||||
AssertionInfo() {}
|
||||
@@ -29,11 +50,41 @@ namespace Catch {
|
||||
|
||||
struct AssertionResultData
|
||||
{
|
||||
AssertionResultData() : resultType( ResultWas::Unknown ) {}
|
||||
AssertionResultData() : decomposedExpression( CATCH_NULL )
|
||||
, resultType( ResultWas::Unknown )
|
||||
, negated( false )
|
||||
, parenthesized( false ) {}
|
||||
|
||||
std::string reconstructedExpression;
|
||||
void negate( bool parenthesize ) {
|
||||
negated = !negated;
|
||||
parenthesized = parenthesize;
|
||||
if( resultType == ResultWas::Ok )
|
||||
resultType = ResultWas::ExpressionFailed;
|
||||
else if( resultType == ResultWas::ExpressionFailed )
|
||||
resultType = ResultWas::Ok;
|
||||
}
|
||||
|
||||
std::string const& reconstructExpression() const {
|
||||
if( decomposedExpression != CATCH_NULL ) {
|
||||
decomposedExpression->reconstructExpression( reconstructedExpression );
|
||||
if( parenthesized ) {
|
||||
reconstructedExpression.insert( 0, 1, '(' );
|
||||
reconstructedExpression.append( 1, ')' );
|
||||
}
|
||||
if( negated ) {
|
||||
reconstructedExpression.insert( 0, 1, '!' );
|
||||
}
|
||||
decomposedExpression = CATCH_NULL;
|
||||
}
|
||||
return reconstructedExpression;
|
||||
}
|
||||
|
||||
mutable DecomposedExpression const* decomposedExpression;
|
||||
mutable std::string reconstructedExpression;
|
||||
std::string message;
|
||||
ResultWas::OfType resultType;
|
||||
bool negated;
|
||||
bool parenthesized;
|
||||
};
|
||||
|
||||
class AssertionResult {
|
||||
@@ -60,6 +111,8 @@ namespace Catch {
|
||||
std::string getMessage() const;
|
||||
SourceLineInfo getSourceInfo() const;
|
||||
std::string getTestMacroName() const;
|
||||
void discardDecomposedExpression() const;
|
||||
void expandDecomposedExpression() const;
|
||||
|
||||
protected:
|
||||
AssertionInfo m_info;
|
||||
|
@@ -56,7 +56,7 @@ namespace Catch {
|
||||
|
||||
std::string AssertionResult::getExpression() const {
|
||||
if( isFalseTest( m_info.resultDisposition ) )
|
||||
return "!" + m_info.capturedExpression;
|
||||
return '!' + m_info.capturedExpression;
|
||||
else
|
||||
return m_info.capturedExpression;
|
||||
}
|
||||
@@ -72,7 +72,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpandedExpression() const {
|
||||
return m_resultData.reconstructedExpression;
|
||||
return m_resultData.reconstructExpression();
|
||||
}
|
||||
|
||||
std::string AssertionResult::getMessage() const {
|
||||
@@ -86,6 +86,14 @@ namespace Catch {
|
||||
return m_info.macroName;
|
||||
}
|
||||
|
||||
void AssertionResult::discardDecomposedExpression() const {
|
||||
m_resultData.decomposedExpression = CATCH_NULL;
|
||||
}
|
||||
|
||||
void AssertionResult::expandDecomposedExpression() const {
|
||||
m_resultData.reconstructExpression();
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
|
||||
|
@@ -37,10 +37,11 @@
|
||||
( __catchResult <= expr ).endExpression(); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
|
||||
__catchResult.useActiveException( resultDisposition ); \
|
||||
} \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::alwaysFalse( sizeof(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
} while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
|
||||
@@ -57,7 +58,7 @@
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
||||
try { \
|
||||
expr; \
|
||||
static_cast<void>(expr); \
|
||||
__catchResult.captureResult( Catch::ResultWas::Ok ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
@@ -72,7 +73,7 @@
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
|
||||
if( __catchResult.allowThrows() ) \
|
||||
try { \
|
||||
expr; \
|
||||
static_cast<void>(expr); \
|
||||
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
@@ -89,7 +90,7 @@
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
||||
if( __catchResult.allowThrows() ) \
|
||||
try { \
|
||||
expr; \
|
||||
static_cast<void>(expr); \
|
||||
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( exceptionType ) { \
|
||||
@@ -132,13 +133,7 @@
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
|
||||
try { \
|
||||
std::string matcherAsString = (matcher).toString(); \
|
||||
__catchResult \
|
||||
.setLhs( Catch::toString( arg ) ) \
|
||||
.setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
|
||||
.setOp( "matches" ) \
|
||||
.setResultType( (matcher).match( arg ) ); \
|
||||
__catchResult.captureExpression(); \
|
||||
__catchResult.captureMatch( arg, matcher, #matcher ); \
|
||||
} catch( ... ) { \
|
||||
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
|
||||
} \
|
||||
|
@@ -23,13 +23,14 @@ namespace Catch {
|
||||
config.abortAfter = x;
|
||||
}
|
||||
inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
|
||||
inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
|
||||
inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
|
||||
|
||||
inline void addWarning( ConfigData& config, std::string const& _warning ) {
|
||||
if( _warning == "NoAssertions" )
|
||||
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
|
||||
else
|
||||
throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
|
||||
throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
|
||||
}
|
||||
inline void setOrder( ConfigData& config, std::string const& order ) {
|
||||
if( startsWith( "declared", order ) )
|
||||
@@ -39,7 +40,7 @@ namespace Catch {
|
||||
else if( startsWith( "random", order ) )
|
||||
config.runOrder = RunTests::InRandomOrder;
|
||||
else
|
||||
throw std::runtime_error( "Unrecognised ordering: '" + order + "'" );
|
||||
throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
|
||||
}
|
||||
inline void setRngSeed( ConfigData& config, std::string const& seed ) {
|
||||
if( seed == "time" ) {
|
||||
@@ -64,7 +65,7 @@ namespace Catch {
|
||||
}
|
||||
inline void setUseColour( ConfigData& config, std::string const& value ) {
|
||||
std::string mode = toLower( value );
|
||||
|
||||
|
||||
if( mode == "yes" )
|
||||
config.useColour = UseColour::Yes;
|
||||
else if( mode == "no" )
|
||||
@@ -85,10 +86,10 @@ namespace Catch {
|
||||
std::string line;
|
||||
while( std::getline( f, line ) ) {
|
||||
line = trim(line);
|
||||
if( !line.empty() && !startsWith( line, "#" ) ) {
|
||||
if( !startsWith( line, "\"" ) )
|
||||
line = "\"" + line + "\"";
|
||||
addTestOrTags( config, line + "," );
|
||||
if( !line.empty() && !startsWith( line, '#' ) ) {
|
||||
if( !startsWith( line, '"' ) )
|
||||
line = '"' + line + '"';
|
||||
addTestOrTags( config, line + ',' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,6 +177,10 @@ namespace Catch {
|
||||
.describe( "adds a tag for the filename" )
|
||||
.bind( &ConfigData::filenamesAsTags );
|
||||
|
||||
cli["-c"]["--section"]
|
||||
.describe( "specify section to run" )
|
||||
.bind( &addSectionToRun, "section name" );
|
||||
|
||||
// Less common commands which don't have a short form
|
||||
cli["--list-test-names-only"]
|
||||
.describe( "list all/matching test cases names only" )
|
||||
@@ -196,7 +201,7 @@ namespace Catch {
|
||||
cli["--force-colour"]
|
||||
.describe( "force colourised output (deprecated)" )
|
||||
.bind( &forceColour );
|
||||
|
||||
|
||||
cli["--use-colour"]
|
||||
.describe( "should output be colourised" )
|
||||
.bind( &setUseColour, "yes|no" );
|
||||
|
@@ -79,7 +79,10 @@ namespace Catch {
|
||||
}
|
||||
|
||||
bool startsWith( std::string const& s, std::string const& prefix );
|
||||
bool startsWith( std::string const& s, char prefix );
|
||||
bool endsWith( std::string const& s, std::string const& suffix );
|
||||
bool endsWith( std::string const& s, char suffix );
|
||||
bool contains( std::string const& s, std::string const& infix );
|
||||
bool contains( std::string const& s, std::string const& infix );
|
||||
void toLowerInPlace( std::string& s );
|
||||
std::string toLower( std::string const& s );
|
||||
@@ -99,8 +102,8 @@ namespace Catch {
|
||||
|
||||
SourceLineInfo();
|
||||
SourceLineInfo( char const* _file, std::size_t _line );
|
||||
SourceLineInfo( SourceLineInfo const& other );
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
SourceLineInfo(SourceLineInfo const& other) = default;
|
||||
SourceLineInfo( SourceLineInfo && ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo && ) = default;
|
||||
@@ -109,15 +112,16 @@ namespace Catch {
|
||||
bool operator == ( SourceLineInfo const& other ) const;
|
||||
bool operator < ( SourceLineInfo const& other ) const;
|
||||
|
||||
std::string file;
|
||||
char const* file;
|
||||
std::size_t line;
|
||||
};
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
|
||||
|
||||
// This is just here to avoid compiler warnings with macro constants and boolean literals
|
||||
inline bool alwaysTrue( std::size_t = 0 ) { return true; }
|
||||
inline bool alwaysFalse( std::size_t = 0 ) { return false; }
|
||||
inline bool isTrue( bool value ){ return value; }
|
||||
inline bool alwaysTrue() { return true; }
|
||||
inline bool alwaysFalse() { return false; }
|
||||
|
||||
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
|
||||
|
||||
|
@@ -10,17 +10,28 @@
|
||||
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
bool startsWith( std::string const& s, std::string const& prefix ) {
|
||||
return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
|
||||
return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
|
||||
}
|
||||
bool startsWith( std::string const& s, char prefix ) {
|
||||
return !s.empty() && s[0] == prefix;
|
||||
}
|
||||
bool endsWith( std::string const& s, std::string const& suffix ) {
|
||||
return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
|
||||
return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
|
||||
}
|
||||
bool endsWith( std::string const& s, char suffix ) {
|
||||
return !s.empty() && s[s.size()-1] == suffix;
|
||||
}
|
||||
bool contains( std::string const& s, std::string const& infix ) {
|
||||
return s.find( infix ) != std::string::npos;
|
||||
}
|
||||
bool contains( std::string const& s, char infix ) {
|
||||
return s.find(infix) != std::string::npos;
|
||||
}
|
||||
char toLowerCh(char c) {
|
||||
return static_cast<char>( ::tolower( c ) );
|
||||
}
|
||||
@@ -37,7 +48,7 @@ namespace Catch {
|
||||
std::string::size_type start = str.find_first_not_of( whitespaceChars );
|
||||
std::string::size_type end = str.find_last_not_of( whitespaceChars );
|
||||
|
||||
return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
|
||||
return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
|
||||
}
|
||||
|
||||
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
|
||||
@@ -60,29 +71,25 @@ namespace Catch {
|
||||
{}
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
|
||||
os << pluraliser.m_count << " " << pluraliser.m_label;
|
||||
os << pluraliser.m_count << ' ' << pluraliser.m_label;
|
||||
if( pluraliser.m_count != 1 )
|
||||
os << "s";
|
||||
os << 's';
|
||||
return os;
|
||||
}
|
||||
|
||||
SourceLineInfo::SourceLineInfo() : line( 0 ){}
|
||||
SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){}
|
||||
SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
|
||||
: file( _file ),
|
||||
line( _line )
|
||||
{}
|
||||
SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
|
||||
: file( other.file ),
|
||||
line( other.line )
|
||||
{}
|
||||
bool SourceLineInfo::empty() const {
|
||||
return file.empty();
|
||||
return file[0] == '\0';
|
||||
}
|
||||
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
|
||||
return line == other.line && file == other.file;
|
||||
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
|
||||
}
|
||||
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
|
||||
return line < other.line || ( line == other.line && file < other.file );
|
||||
return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
|
||||
}
|
||||
|
||||
void seedRng( IConfig const& config ) {
|
||||
@@ -95,16 +102,16 @@ namespace Catch {
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
||||
#ifndef __GNUG__
|
||||
os << info.file << "(" << info.line << ")";
|
||||
os << info.file << '(' << info.line << ')';
|
||||
#else
|
||||
os << info.file << ":" << info.line;
|
||||
os << info.file << ':' << info.line;
|
||||
#endif
|
||||
return os;
|
||||
}
|
||||
|
||||
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
|
||||
std::ostringstream oss;
|
||||
oss << locationInfo << ": Internal Catch error: '" << message << "'";
|
||||
oss << locationInfo << ": Internal Catch error: '" << message << '\'';
|
||||
if( alwaysTrue() )
|
||||
throw std::logic_error( oss.str() );
|
||||
}
|
||||
|
@@ -19,6 +19,8 @@
|
||||
// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
|
||||
// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
|
||||
// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
|
||||
// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported?
|
||||
// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported?
|
||||
|
||||
// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
|
||||
|
||||
@@ -116,6 +118,7 @@
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
|
||||
#endif
|
||||
|
||||
#endif // _MSC_VER
|
||||
@@ -184,6 +187,9 @@
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
|
||||
# endif
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
|
||||
# endif
|
||||
|
||||
#endif // __cplusplus >= 201103L
|
||||
|
||||
@@ -224,6 +230,9 @@
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_SHUFFLE
|
||||
#endif
|
||||
# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_TYPE_TRAITS
|
||||
# endif
|
||||
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||
|
@@ -74,6 +74,7 @@ namespace Catch {
|
||||
|
||||
std::vector<std::string> reporterNames;
|
||||
std::vector<std::string> testsOrTags;
|
||||
std::vector<std::string> sectionsToRun;
|
||||
};
|
||||
|
||||
|
||||
@@ -115,7 +116,8 @@ namespace Catch {
|
||||
|
||||
bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
||||
|
||||
std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
|
||||
std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
|
||||
std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
|
||||
|
||||
int abortAfter() const { return m_data.abortAfter; }
|
||||
|
||||
|
@@ -23,14 +23,12 @@ namespace Catch{
|
||||
|
||||
// The following code snippet based on:
|
||||
// http://cocoawithlove.com/2008/03/break-into-debugger.html
|
||||
#ifdef DEBUG
|
||||
#if defined(__ppc64__) || defined(__ppc__)
|
||||
#define CATCH_TRAP() \
|
||||
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
|
||||
: : : "memory","r0","r3","r4" )
|
||||
#else
|
||||
#define CATCH_TRAP() _asm__("int $3\n" : : )
|
||||
#endif
|
||||
#if defined(__ppc64__) || defined(__ppc__)
|
||||
#define CATCH_TRAP() \
|
||||
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
|
||||
: : : "memory","r0","r3","r4" )
|
||||
#else
|
||||
#define CATCH_TRAP() __asm__("int $3\n" : : )
|
||||
#endif
|
||||
|
||||
#elif defined(CATCH_PLATFORM_LINUX)
|
||||
|
@@ -12,7 +12,8 @@
|
||||
|
||||
// Standard C/C++ main entry point
|
||||
int main (int argc, char * argv[]) {
|
||||
return Catch::Session().run( argc, argv );
|
||||
int result = Catch::Session().run( argc, argv );
|
||||
return ( result < 0xff ? result : 0xff );
|
||||
}
|
||||
|
||||
#else // __OBJC__
|
||||
@@ -30,7 +31,7 @@ int main (int argc, char * const argv[]) {
|
||||
[pool drain];
|
||||
#endif
|
||||
|
||||
return result;
|
||||
return ( result < 0xff ? result : 0xff );
|
||||
}
|
||||
|
||||
#endif // __OBJC__
|
||||
|
@@ -14,90 +14,155 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Wraps the LHS of an expression and captures the operator and RHS (if any) -
|
||||
// wrapping them all in a ResultBuilder object
|
||||
template<typename T>
|
||||
class ExpressionLhs {
|
||||
ExpressionLhs& operator = ( ExpressionLhs const& );
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
|
||||
# endif
|
||||
template<typename LhsT, Internal::Operator Op, typename RhsT>
|
||||
class BinaryExpression;
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
class MatchExpression;
|
||||
|
||||
// Wraps the LHS of an expression and overloads comparison operators
|
||||
// for also capturing those and RHS (if any)
|
||||
template<typename T>
|
||||
class ExpressionLhs : public DecomposedExpression {
|
||||
public:
|
||||
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
ExpressionLhs( ExpressionLhs const& ) = default;
|
||||
ExpressionLhs( ExpressionLhs && ) = default;
|
||||
# endif
|
||||
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator == ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
|
||||
operator == ( RhsT const& rhs ) const {
|
||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator != ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
|
||||
operator != ( RhsT const& rhs ) const {
|
||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator < ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsLessThan, RhsT const&>
|
||||
operator < ( RhsT const& rhs ) const {
|
||||
return captureExpression<Internal::IsLessThan>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator > ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
|
||||
operator > ( RhsT const& rhs ) const {
|
||||
return captureExpression<Internal::IsGreaterThan>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator <= ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
|
||||
operator <= ( RhsT const& rhs ) const {
|
||||
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator >= ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
|
||||
operator >= ( RhsT const& rhs ) const {
|
||||
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
|
||||
}
|
||||
|
||||
ResultBuilder& operator == ( bool rhs ) {
|
||||
BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) const {
|
||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
||||
}
|
||||
|
||||
ResultBuilder& operator != ( bool rhs ) {
|
||||
BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) const {
|
||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
||||
}
|
||||
|
||||
void endExpression() {
|
||||
bool value = m_lhs ? true : false;
|
||||
m_truthy = m_lhs ? true : false;
|
||||
m_rb
|
||||
.setLhs( Catch::toString( value ) )
|
||||
.setResultType( value )
|
||||
.endExpression();
|
||||
.setResultType( m_truthy )
|
||||
.endExpression( *this );
|
||||
}
|
||||
|
||||
// Only simple binary expressions are allowed on the LHS.
|
||||
// If more complex compositions are required then place the sub expression in parentheses
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
|
||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
||||
dest = Catch::toString( m_truthy );
|
||||
}
|
||||
|
||||
private:
|
||||
template<Internal::Operator Op, typename RhsT>
|
||||
ResultBuilder& captureExpression( RhsT const& rhs ) {
|
||||
return m_rb
|
||||
.setResultType( Internal::compare<Op>( m_lhs, rhs ) )
|
||||
.setLhs( Catch::toString( m_lhs ) )
|
||||
.setRhs( Catch::toString( rhs ) )
|
||||
.setOp( Internal::OperatorTraits<Op>::getName() );
|
||||
BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
|
||||
return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
|
||||
}
|
||||
|
||||
template<Internal::Operator Op>
|
||||
BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
|
||||
return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
|
||||
}
|
||||
|
||||
private:
|
||||
ResultBuilder& m_rb;
|
||||
T m_lhs;
|
||||
bool m_truthy;
|
||||
};
|
||||
|
||||
template<typename LhsT, Internal::Operator Op, typename RhsT>
|
||||
class BinaryExpression : public DecomposedExpression {
|
||||
public:
|
||||
BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
|
||||
: m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
|
||||
|
||||
void endExpression() const {
|
||||
m_rb
|
||||
.setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
|
||||
.endExpression( *this );
|
||||
}
|
||||
|
||||
virtual bool isBinaryExpression() const CATCH_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
||||
std::string lhs = Catch::toString( m_lhs );
|
||||
std::string rhs = Catch::toString( m_rhs );
|
||||
char delim = lhs.size() + rhs.size() < 40 &&
|
||||
lhs.find('\n') == std::string::npos &&
|
||||
rhs.find('\n') == std::string::npos ? ' ' : '\n';
|
||||
dest.reserve( 7 + lhs.size() + rhs.size() );
|
||||
// 2 for spaces around operator
|
||||
// 2 for operator
|
||||
// 2 for parentheses (conditionally added later)
|
||||
// 1 for negation (conditionally added later)
|
||||
dest = lhs;
|
||||
dest += delim;
|
||||
dest += Internal::OperatorTraits<Op>::getName();
|
||||
dest += delim;
|
||||
dest += rhs;
|
||||
}
|
||||
|
||||
private:
|
||||
ResultBuilder& m_rb;
|
||||
LhsT m_lhs;
|
||||
RhsT m_rhs;
|
||||
};
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
class MatchExpression : public DecomposedExpression {
|
||||
public:
|
||||
MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
|
||||
: m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
|
||||
|
||||
virtual bool isBinaryExpression() const CATCH_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
||||
std::string matcherAsString = m_matcher.toString();
|
||||
dest = Catch::toString( m_arg );
|
||||
dest += ' ';
|
||||
if( matcherAsString == Detail::unprintableString )
|
||||
dest += m_matcherString;
|
||||
else
|
||||
dest += matcherAsString;
|
||||
}
|
||||
|
||||
private:
|
||||
ArgT m_arg;
|
||||
MatcherT m_matcher;
|
||||
char const* m_matcherString;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -12,25 +12,78 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Report the error condition then exit the process
|
||||
inline void fatal( std::string const& message, int exitCode ) {
|
||||
// Report the error condition
|
||||
inline void reportFatal( std::string const& message ) {
|
||||
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 ) /////////////////////////////////////////
|
||||
|
||||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#undef NOMINMAX
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SignalDefs { DWORD id; const char* name; };
|
||||
extern SignalDefs signalDefs[];
|
||||
// There is no 1-1 mapping between signals and windows exceptions.
|
||||
// Windows can easily distinguish between SO and SigSegV,
|
||||
// but SigInt, SigTerm, etc are handled differently.
|
||||
SignalDefs signalDefs[] = {
|
||||
{ EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
|
||||
{ EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
|
||||
{ EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
|
||||
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
|
||||
};
|
||||
|
||||
struct FatalConditionHandler {
|
||||
void reset() {}
|
||||
};
|
||||
|
||||
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
|
||||
if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
|
||||
reportFatal(signalDefs[i].name);
|
||||
}
|
||||
}
|
||||
// If its not an exception we care about, pass it along.
|
||||
// This stops us from eating debugger breaks etc.
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// 32k seems enough for Catch to handle stack overflow,
|
||||
// but the value was found experimentally, so there is no strong guarantee
|
||||
FatalConditionHandler():m_isSet(true), m_guaranteeSize(32 * 1024), m_exceptionHandlerHandle(CATCH_NULL) {
|
||||
// Register as first handler in current chain
|
||||
m_exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
|
||||
// Pass in guarantee size to be filled
|
||||
SetThreadStackGuarantee(&m_guaranteeSize);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (m_isSet) {
|
||||
// Unregister handler and restore the old guarantee
|
||||
RemoveVectoredExceptionHandler(m_exceptionHandlerHandle);
|
||||
SetThreadStackGuarantee(&m_guaranteeSize);
|
||||
m_exceptionHandlerHandle = CATCH_NULL;
|
||||
m_isSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
~FatalConditionHandler() {
|
||||
reset();
|
||||
}
|
||||
private:
|
||||
bool m_isSet;
|
||||
ULONG m_guaranteeSize;
|
||||
PVOID m_exceptionHandlerHandle;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
@@ -40,7 +93,10 @@ namespace Catch {
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SignalDefs { int id; const char* name; };
|
||||
struct SignalDefs {
|
||||
int id;
|
||||
const char* name;
|
||||
};
|
||||
extern SignalDefs signalDefs[];
|
||||
SignalDefs signalDefs[] = {
|
||||
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
||||
@@ -49,35 +105,68 @@ namespace Catch {
|
||||
{ SIGSEGV, "SIGSEGV - Segmentation violation signal" },
|
||||
{ SIGTERM, "SIGTERM - Termination request signal" },
|
||||
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
|
||||
};
|
||||
};
|
||||
|
||||
struct FatalConditionHandler {
|
||||
|
||||
static bool isSet;
|
||||
static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
|
||||
static stack_t oldSigStack;
|
||||
static char altStackMem[SIGSTKSZ];
|
||||
|
||||
static void handleSignal( int sig ) {
|
||||
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
|
||||
if( sig == signalDefs[i].id )
|
||||
fatal( signalDefs[i].name, -sig );
|
||||
fatal( "<unknown signal>", -sig );
|
||||
std::string name = "<unknown signal>";
|
||||
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
|
||||
SignalDefs &def = signalDefs[i];
|
||||
if (sig == def.id) {
|
||||
name = def.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
reset();
|
||||
reportFatal(name);
|
||||
raise( 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;
|
||||
FatalConditionHandler() {
|
||||
isSet = true;
|
||||
stack_t sigStack;
|
||||
sigStack.ss_sp = altStackMem;
|
||||
sigStack.ss_size = SIGSTKSZ;
|
||||
sigStack.ss_flags = 0;
|
||||
sigaltstack(&sigStack, &oldSigStack);
|
||||
struct sigaction sa = { 0 };
|
||||
|
||||
sa.sa_handler = handleSignal;
|
||||
sa.sa_flags = SA_ONSTACK;
|
||||
for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
|
||||
sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool m_isSet;
|
||||
|
||||
~FatalConditionHandler() {
|
||||
reset();
|
||||
}
|
||||
static void reset() {
|
||||
if( isSet ) {
|
||||
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
|
||||
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
|
||||
sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
|
||||
}
|
||||
// Return the old stack
|
||||
sigaltstack(&oldSigStack, CATCH_NULL);
|
||||
isSet = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool FatalConditionHandler::isSet = false;
|
||||
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
|
||||
stack_t FatalConditionHandler::oldSigStack = {};
|
||||
char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
|
||||
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // not Windows
|
||||
|
@@ -41,7 +41,7 @@ namespace Catch {
|
||||
Auto,
|
||||
Yes,
|
||||
No
|
||||
}; };
|
||||
}; };
|
||||
|
||||
class TestSpec;
|
||||
|
||||
@@ -62,6 +62,8 @@ namespace Catch {
|
||||
virtual RunTests::InWhatOrder runOrder() const = 0;
|
||||
virtual unsigned int rngSeed() const = 0;
|
||||
virtual UseColour::YesOrNo useColour() const = 0;
|
||||
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -248,7 +248,7 @@ namespace Catch
|
||||
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
|
||||
|
||||
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
|
||||
|
||||
|
||||
virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
|
||||
};
|
||||
|
||||
|
@@ -51,9 +51,9 @@ namespace Catch {
|
||||
}
|
||||
|
||||
if( !config.testSpec().hasFilters() )
|
||||
Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
|
||||
Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
|
||||
else
|
||||
Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
|
||||
Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
|
||||
return matchedTests;
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ namespace Catch {
|
||||
++it ) {
|
||||
matchedTests++;
|
||||
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
|
||||
if( startsWith( testCaseInfo.name, "#" ) )
|
||||
Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl;
|
||||
if( startsWith( testCaseInfo.name, '#' ) )
|
||||
Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl;
|
||||
else
|
||||
Catch::cout() << testCaseInfo.name << std::endl;
|
||||
}
|
||||
@@ -132,9 +132,9 @@ namespace Catch {
|
||||
.setInitialIndent( 0 )
|
||||
.setIndent( oss.str().size() )
|
||||
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
|
||||
Catch::cout() << oss.str() << wrapper << "\n";
|
||||
Catch::cout() << oss.str() << wrapper << '\n';
|
||||
}
|
||||
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
|
||||
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
|
||||
return tagCounts.size();
|
||||
}
|
||||
|
||||
@@ -153,9 +153,9 @@ namespace Catch {
|
||||
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
|
||||
Catch::cout() << " "
|
||||
<< it->first
|
||||
<< ":"
|
||||
<< ':'
|
||||
<< std::string( maxNameLen - it->first.size() + 2, ' ' )
|
||||
<< wrapper << "\n";
|
||||
<< wrapper << '\n';
|
||||
}
|
||||
Catch::cout() << std::endl;
|
||||
return factories.size();
|
||||
|
@@ -184,7 +184,7 @@ namespace Matchers {
|
||||
{
|
||||
return m_caseSensitivity == CaseSensitive::No
|
||||
? " (case insensitive)"
|
||||
: "";
|
||||
: std::string();
|
||||
}
|
||||
CaseSensitive::Choice m_caseSensitivity;
|
||||
std::string m_str;
|
||||
@@ -202,7 +202,7 @@ namespace Matchers {
|
||||
return m_data.m_str == m_data.adjustString( expr );;
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
||||
return "equals: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
|
||||
}
|
||||
|
||||
CasedString m_data;
|
||||
@@ -219,7 +219,7 @@ namespace Matchers {
|
||||
return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos;
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
||||
return "contains: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
|
||||
}
|
||||
|
||||
CasedString m_data;
|
||||
@@ -237,7 +237,7 @@ namespace Matchers {
|
||||
return startsWith( m_data.adjustString( expr ), m_data.m_str );
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
||||
return "starts with: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
|
||||
}
|
||||
|
||||
CasedString m_data;
|
||||
@@ -254,7 +254,7 @@ namespace Matchers {
|
||||
return endsWith( m_data.adjustString( expr ), m_data.m_str );
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
||||
return "ends with: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
|
||||
}
|
||||
|
||||
CasedString m_data;
|
||||
|
@@ -74,7 +74,7 @@ namespace Catch {
|
||||
return new T( config );
|
||||
}
|
||||
virtual std::string getDescription() const {
|
||||
return "";
|
||||
return std::string();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -19,22 +19,20 @@ namespace Catch {
|
||||
|
||||
template<typename T> class ExpressionLhs;
|
||||
|
||||
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
|
||||
|
||||
struct CopyableStream {
|
||||
CopyableStream() {}
|
||||
CopyableStream( CopyableStream const& other ) {
|
||||
oss << other.oss.str();
|
||||
}
|
||||
CopyableStream& operator=( CopyableStream const& other ) {
|
||||
oss.str("");
|
||||
oss.str(std::string());
|
||||
oss << other.oss.str();
|
||||
return *this;
|
||||
}
|
||||
std::ostringstream oss;
|
||||
};
|
||||
|
||||
class ResultBuilder {
|
||||
class ResultBuilder : public DecomposedExpression {
|
||||
public:
|
||||
ResultBuilder( char const* macroName,
|
||||
SourceLineInfo const& lineInfo,
|
||||
@@ -52,19 +50,15 @@ namespace Catch {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
|
||||
|
||||
ResultBuilder& setResultType( ResultWas::OfType result );
|
||||
ResultBuilder& setResultType( bool result );
|
||||
ResultBuilder& setLhs( std::string const& lhs );
|
||||
ResultBuilder& setRhs( std::string const& rhs );
|
||||
ResultBuilder& setOp( std::string const& op );
|
||||
|
||||
void endExpression();
|
||||
void endExpression( DecomposedExpression const& expr );
|
||||
|
||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
|
||||
|
||||
std::string reconstructExpression() const;
|
||||
AssertionResult build() const;
|
||||
AssertionResult build( DecomposedExpression const& expr ) const;
|
||||
|
||||
void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
|
||||
void captureResult( ResultWas::OfType resultType );
|
||||
@@ -76,14 +70,12 @@ namespace Catch {
|
||||
bool shouldDebugBreak() const;
|
||||
bool allowThrows() const;
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
|
||||
|
||||
private:
|
||||
AssertionInfo m_assertionInfo;
|
||||
AssertionResultData m_data;
|
||||
struct ExprComponents {
|
||||
ExprComponents() : testFalse( false ) {}
|
||||
bool testFalse;
|
||||
std::string lhs, rhs, op;
|
||||
} m_exprComponents;
|
||||
CopyableStream m_stream;
|
||||
|
||||
bool m_shouldDebugBreak;
|
||||
@@ -106,6 +98,14 @@ namespace Catch {
|
||||
return ExpressionLhs<bool>( *this, value );
|
||||
}
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
|
||||
char const* matcherString ) {
|
||||
MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
|
||||
setResultType( matcher.match( arg ) );
|
||||
endExpression( expr );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
||||
|
@@ -41,22 +41,10 @@ namespace Catch {
|
||||
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
|
||||
return *this;
|
||||
}
|
||||
ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
|
||||
m_exprComponents.lhs = lhs;
|
||||
return *this;
|
||||
}
|
||||
ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
|
||||
m_exprComponents.rhs = rhs;
|
||||
return *this;
|
||||
}
|
||||
ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
|
||||
m_exprComponents.op = op;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ResultBuilder::endExpression() {
|
||||
m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition );
|
||||
captureExpression();
|
||||
void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
|
||||
AssertionResult result = build( expr );
|
||||
handleResult( result );
|
||||
}
|
||||
|
||||
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
|
||||
@@ -69,6 +57,7 @@ namespace Catch {
|
||||
setResultType( resultType );
|
||||
captureExpression();
|
||||
}
|
||||
|
||||
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
|
||||
if( expectedMessage.empty() )
|
||||
captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() );
|
||||
@@ -78,7 +67,7 @@ namespace Catch {
|
||||
|
||||
void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) {
|
||||
|
||||
assert( m_exprComponents.testFalse == false );
|
||||
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
|
||||
AssertionResultData data = m_data;
|
||||
data.resultType = ResultWas::Ok;
|
||||
data.reconstructedExpression = m_assertionInfo.capturedExpression;
|
||||
@@ -96,6 +85,7 @@ namespace Catch {
|
||||
AssertionResult result = build();
|
||||
handleResult( result );
|
||||
}
|
||||
|
||||
void ResultBuilder::handleResult( AssertionResult const& result )
|
||||
{
|
||||
getResultCapture().assertionEnded( result );
|
||||
@@ -107,6 +97,7 @@ namespace Catch {
|
||||
m_shouldThrow = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ResultBuilder::react() {
|
||||
if( m_shouldThrow )
|
||||
throw Catch::TestFailureException();
|
||||
@@ -117,43 +108,32 @@ namespace Catch {
|
||||
|
||||
AssertionResult ResultBuilder::build() const
|
||||
{
|
||||
assert( m_data.resultType != ResultWas::Unknown );
|
||||
return build( *this );
|
||||
}
|
||||
|
||||
// CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
|
||||
// a temporary DecomposedExpression, which in turn holds references to
|
||||
// operands, possibly temporary as well.
|
||||
// It should immediately be passed to handleResult; if the expression
|
||||
// needs to be reported, its string expansion must be composed before
|
||||
// the temporaries are destroyed.
|
||||
AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
|
||||
{
|
||||
assert( m_data.resultType != ResultWas::Unknown );
|
||||
AssertionResultData data = m_data;
|
||||
|
||||
// Flip bool results if testFalse is set
|
||||
if( m_exprComponents.testFalse ) {
|
||||
if( data.resultType == ResultWas::Ok )
|
||||
data.resultType = ResultWas::ExpressionFailed;
|
||||
else if( data.resultType == ResultWas::ExpressionFailed )
|
||||
data.resultType = ResultWas::Ok;
|
||||
// Flip bool results if FalseTest flag is set
|
||||
if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
|
||||
data.negate( expr.isBinaryExpression() );
|
||||
}
|
||||
|
||||
data.message = m_stream.oss.str();
|
||||
data.reconstructedExpression = reconstructExpression();
|
||||
if( m_exprComponents.testFalse ) {
|
||||
if( m_exprComponents.op == "" )
|
||||
data.reconstructedExpression = "!" + data.reconstructedExpression;
|
||||
else
|
||||
data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
|
||||
}
|
||||
data.decomposedExpression = &expr; // for lazy reconstruction
|
||||
return AssertionResult( m_assertionInfo, data );
|
||||
}
|
||||
std::string ResultBuilder::reconstructExpression() const {
|
||||
if( m_exprComponents.op == "" )
|
||||
return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.lhs;
|
||||
else if( m_exprComponents.op == "matches" )
|
||||
return m_exprComponents.lhs + " " + m_exprComponents.rhs;
|
||||
else if( m_exprComponents.op != "!" ) {
|
||||
if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
|
||||
m_exprComponents.lhs.find("\n") == std::string::npos &&
|
||||
m_exprComponents.rhs.find("\n") == std::string::npos )
|
||||
return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
|
||||
else
|
||||
return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
|
||||
}
|
||||
else
|
||||
return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
|
||||
|
||||
void ResultBuilder::reconstructExpression( std::string& dest ) const {
|
||||
dest = m_assertionInfo.capturedExpression;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -97,10 +97,11 @@ namespace Catch {
|
||||
|
||||
|
||||
do {
|
||||
m_trackerContext.startRun();
|
||||
ITracker& rootTracker = m_trackerContext.startRun();
|
||||
dynamic_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
|
||||
do {
|
||||
m_trackerContext.startCycle();
|
||||
m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name );
|
||||
m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
|
||||
runCurrentTest( redirectedCout, redirectedCerr );
|
||||
}
|
||||
while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
|
||||
@@ -146,7 +147,7 @@ namespace Catch {
|
||||
m_messages.clear();
|
||||
|
||||
// Reset working state
|
||||
m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
|
||||
m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
|
||||
m_lastResult = result;
|
||||
}
|
||||
|
||||
@@ -155,10 +156,7 @@ namespace Catch {
|
||||
Counts& assertions
|
||||
)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
|
||||
|
||||
ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() );
|
||||
ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
|
||||
if( !sectionTracker.isOpen() )
|
||||
return false;
|
||||
m_activeSections.push_back( §ionTracker );
|
||||
@@ -217,7 +215,7 @@ namespace Catch {
|
||||
virtual std::string getCurrentTestName() const {
|
||||
return m_activeTestCase
|
||||
? m_activeTestCase->getTestCaseInfo().name
|
||||
: "";
|
||||
: std::string();
|
||||
}
|
||||
|
||||
virtual const AssertionResult* getLastResult() const {
|
||||
@@ -247,11 +245,11 @@ namespace Catch {
|
||||
deltaTotals.testCases.failed = 1;
|
||||
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
||||
deltaTotals,
|
||||
"",
|
||||
"",
|
||||
std::string(),
|
||||
std::string(),
|
||||
false ) );
|
||||
m_totals.testCases.failed++;
|
||||
testGroupEnded( "", m_totals, 1, 1 );
|
||||
testGroupEnded( std::string(), m_totals, 1, 1 );
|
||||
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
|
||||
}
|
||||
|
||||
@@ -270,7 +268,7 @@ namespace Catch {
|
||||
Counts prevAssertions = m_totals.assertions;
|
||||
double duration = 0;
|
||||
try {
|
||||
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
|
||||
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal );
|
||||
|
||||
seedRng( *m_config );
|
||||
|
||||
|
@@ -61,7 +61,7 @@ namespace Catch {
|
||||
m_ofs.open( filename.c_str() );
|
||||
if( m_ofs.fail() ) {
|
||||
std::ostringstream oss;
|
||||
oss << "Unable to open file: '" << filename << "'";
|
||||
oss << "Unable to open file: '" << filename << '\'';
|
||||
throw std::domain_error( oss.str() );
|
||||
}
|
||||
}
|
||||
|
@@ -43,7 +43,7 @@ namespace Catch {
|
||||
|
||||
void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
|
||||
|
||||
if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) {
|
||||
if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
|
||||
std::ostringstream oss;
|
||||
oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
|
||||
throw std::domain_error( oss.str().c_str() );
|
||||
@@ -51,7 +51,7 @@ namespace Catch {
|
||||
if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
|
||||
std::ostringstream oss;
|
||||
oss << "error: tag alias, \"" << alias << "\" already registered.\n"
|
||||
<< "\tFirst seen at " << find(alias)->lineInfo << "\n"
|
||||
<< "\tFirst seen at " << find(alias)->lineInfo << '\n'
|
||||
<< "\tRedefined at " << lineInfo;
|
||||
throw std::domain_error( oss.str().c_str() );
|
||||
}
|
||||
|
@@ -29,7 +29,8 @@ namespace Catch {
|
||||
IsHidden = 1 << 1,
|
||||
ShouldFail = 1 << 2,
|
||||
MayFail = 1 << 3,
|
||||
Throws = 1 << 4
|
||||
Throws = 1 << 4,
|
||||
NonPortable = 1 << 5
|
||||
};
|
||||
|
||||
TestCaseInfo( std::string const& _name,
|
||||
|
@@ -16,7 +16,7 @@
|
||||
namespace Catch {
|
||||
|
||||
inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
|
||||
if( startsWith( tag, "." ) ||
|
||||
if( startsWith( tag, '.' ) ||
|
||||
tag == "hide" ||
|
||||
tag == "!hide" )
|
||||
return TestCaseInfo::IsHidden;
|
||||
@@ -26,6 +26,8 @@ namespace Catch {
|
||||
return TestCaseInfo::ShouldFail;
|
||||
else if( tag == "!mayfail" )
|
||||
return TestCaseInfo::MayFail;
|
||||
else if( tag == "!nonportable" )
|
||||
return TestCaseInfo::NonPortable;
|
||||
else
|
||||
return TestCaseInfo::None;
|
||||
}
|
||||
@@ -100,7 +102,7 @@ namespace Catch {
|
||||
|
||||
std::ostringstream oss;
|
||||
for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
|
||||
oss << "[" << *it << "]";
|
||||
oss << '[' << *it << ']';
|
||||
std::string lcaseTag = toLower( *it );
|
||||
testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
|
||||
testCaseInfo.lcaseTags.insert( lcaseTag );
|
||||
|
@@ -78,7 +78,7 @@ namespace Catch {
|
||||
|
||||
ss << Colour( Colour::Red )
|
||||
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
|
||||
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
|
||||
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
|
||||
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
|
||||
|
||||
throw std::runtime_error(ss.str());
|
||||
@@ -110,7 +110,7 @@ namespace Catch {
|
||||
|
||||
virtual void registerTest( TestCase const& testCase ) {
|
||||
std::string name = testCase.getTestCaseInfo().name;
|
||||
if( name == "" ) {
|
||||
if( name.empty() ) {
|
||||
std::ostringstream oss;
|
||||
oss << "Anonymous test case " << ++m_unnamedCount;
|
||||
return registerTest( testCase.withName( oss.str() ) );
|
||||
@@ -159,7 +159,7 @@ namespace Catch {
|
||||
|
||||
inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
|
||||
std::string className = classOrQualifiedMethodName;
|
||||
if( startsWith( className, "&" ) )
|
||||
if( startsWith( className, '&' ) )
|
||||
{
|
||||
std::size_t lastColons = className.rfind( "::" );
|
||||
std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
|
||||
|
@@ -15,15 +15,26 @@
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
namespace Catch {
|
||||
namespace TestCaseTracking {
|
||||
|
||||
struct NameAndLocation {
|
||||
std::string name;
|
||||
SourceLineInfo location;
|
||||
|
||||
NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
|
||||
: name( _name ),
|
||||
location( _location )
|
||||
{}
|
||||
};
|
||||
|
||||
struct ITracker : SharedImpl<> {
|
||||
virtual ~ITracker();
|
||||
|
||||
// static queries
|
||||
virtual std::string name() const = 0;
|
||||
virtual NameAndLocation const& nameAndLocation() const = 0;
|
||||
|
||||
// dynamic queries
|
||||
virtual bool isComplete() const = 0; // Successfully completed or failed
|
||||
@@ -39,15 +50,15 @@ namespace TestCaseTracking {
|
||||
virtual void markAsNeedingAnotherRun() = 0;
|
||||
|
||||
virtual void addChild( Ptr<ITracker> const& child ) = 0;
|
||||
virtual ITracker* findChild( std::string const& name ) = 0;
|
||||
virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
|
||||
virtual void openChild() = 0;
|
||||
|
||||
|
||||
// Debug/ checking
|
||||
virtual bool isSectionTracker() const = 0;
|
||||
virtual bool isIndexTracker() const = 0;
|
||||
};
|
||||
|
||||
class TrackerContext {
|
||||
class TrackerContext {
|
||||
|
||||
enum RunState {
|
||||
NotStarted,
|
||||
@@ -110,30 +121,32 @@ namespace TestCaseTracking {
|
||||
Failed
|
||||
};
|
||||
class TrackerHasName {
|
||||
std::string m_name;
|
||||
NameAndLocation m_nameAndLocation;
|
||||
public:
|
||||
TrackerHasName( std::string const& name ) : m_name( name ) {}
|
||||
TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
|
||||
bool operator ()( Ptr<ITracker> const& tracker ) {
|
||||
return tracker->name() == m_name;
|
||||
return
|
||||
tracker->nameAndLocation().name == m_nameAndLocation.name &&
|
||||
tracker->nameAndLocation().location == m_nameAndLocation.location;
|
||||
}
|
||||
};
|
||||
typedef std::vector<Ptr<ITracker> > Children;
|
||||
std::string m_name;
|
||||
NameAndLocation m_nameAndLocation;
|
||||
TrackerContext& m_ctx;
|
||||
ITracker* m_parent;
|
||||
Children m_children;
|
||||
CycleState m_runState;
|
||||
public:
|
||||
TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent )
|
||||
: m_name( name ),
|
||||
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
: m_nameAndLocation( nameAndLocation ),
|
||||
m_ctx( ctx ),
|
||||
m_parent( parent ),
|
||||
m_runState( NotStarted )
|
||||
{}
|
||||
virtual ~TrackerBase();
|
||||
|
||||
virtual std::string name() const CATCH_OVERRIDE {
|
||||
return m_name;
|
||||
virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE {
|
||||
return m_nameAndLocation;
|
||||
}
|
||||
virtual bool isComplete() const CATCH_OVERRIDE {
|
||||
return m_runState == CompletedSuccessfully || m_runState == Failed;
|
||||
@@ -153,8 +166,8 @@ namespace TestCaseTracking {
|
||||
m_children.push_back( child );
|
||||
}
|
||||
|
||||
virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE {
|
||||
Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) );
|
||||
virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE {
|
||||
Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
|
||||
return( it != m_children.end() )
|
||||
? it->get()
|
||||
: CATCH_NULL;
|
||||
@@ -174,7 +187,7 @@ namespace TestCaseTracking {
|
||||
|
||||
virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
|
||||
virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
|
||||
|
||||
|
||||
void open() {
|
||||
m_runState = Executing;
|
||||
moveToThis();
|
||||
@@ -232,59 +245,83 @@ namespace TestCaseTracking {
|
||||
};
|
||||
|
||||
class SectionTracker : public TrackerBase {
|
||||
std::vector<std::string> m_filters;
|
||||
public:
|
||||
SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent )
|
||||
: TrackerBase( name, ctx, parent )
|
||||
{}
|
||||
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
: TrackerBase( nameAndLocation, ctx, parent )
|
||||
{
|
||||
if( parent ) {
|
||||
while( !parent->isSectionTracker() )
|
||||
parent = &parent->parent();
|
||||
|
||||
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
|
||||
addNextFilters( parentSection.m_filters );
|
||||
}
|
||||
}
|
||||
virtual ~SectionTracker();
|
||||
|
||||
virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
|
||||
|
||||
static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
|
||||
|
||||
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
|
||||
SectionTracker* section = CATCH_NULL;
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( ITracker* childTracker = currentTracker.findChild( name ) ) {
|
||||
if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isSectionTracker() );
|
||||
section = static_cast<SectionTracker*>( childTracker );
|
||||
}
|
||||
else {
|
||||
section = new SectionTracker( name, ctx, ¤tTracker );
|
||||
section = new SectionTracker( nameAndLocation, ctx, ¤tTracker );
|
||||
currentTracker.addChild( section );
|
||||
}
|
||||
if( !ctx.completedCycle() && !section->isComplete() ) {
|
||||
|
||||
section->open();
|
||||
}
|
||||
if( !ctx.completedCycle() )
|
||||
section->tryOpen();
|
||||
return *section;
|
||||
}
|
||||
|
||||
void tryOpen() {
|
||||
if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
|
||||
open();
|
||||
}
|
||||
|
||||
void addInitialFilters( std::vector<std::string> const& filters ) {
|
||||
if( !filters.empty() ) {
|
||||
m_filters.push_back(""); // Root - should never be consulted
|
||||
m_filters.push_back(""); // Test Case - not a section filter
|
||||
std::copy( filters.begin(), filters.end(), std::back_inserter( m_filters ) );
|
||||
}
|
||||
}
|
||||
void addNextFilters( std::vector<std::string> const& filters ) {
|
||||
if( filters.size() > 1 )
|
||||
std::copy( filters.begin()+1, filters.end(), std::back_inserter( m_filters ) );
|
||||
}
|
||||
};
|
||||
|
||||
class IndexTracker : public TrackerBase {
|
||||
int m_size;
|
||||
int m_index;
|
||||
public:
|
||||
IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size )
|
||||
: TrackerBase( name, ctx, parent ),
|
||||
IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
|
||||
: TrackerBase( nameAndLocation, ctx, parent ),
|
||||
m_size( size ),
|
||||
m_index( -1 )
|
||||
{}
|
||||
virtual ~IndexTracker();
|
||||
|
||||
virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
|
||||
|
||||
static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
|
||||
|
||||
static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
|
||||
IndexTracker* tracker = CATCH_NULL;
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( ITracker* childTracker = currentTracker.findChild( name ) ) {
|
||||
if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isIndexTracker() );
|
||||
tracker = static_cast<IndexTracker*>( childTracker );
|
||||
}
|
||||
else {
|
||||
tracker = new IndexTracker( name, ctx, ¤tTracker, size );
|
||||
tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size );
|
||||
currentTracker.addChild( tracker );
|
||||
}
|
||||
|
||||
@@ -312,7 +349,7 @@ namespace TestCaseTracking {
|
||||
};
|
||||
|
||||
inline ITracker& TrackerContext::startRun() {
|
||||
m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL );
|
||||
m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL );
|
||||
m_currentTracker = CATCH_NULL;
|
||||
m_runState = Executing;
|
||||
return *m_rootTracker;
|
||||
|
@@ -87,6 +87,8 @@ namespace Catch {
|
||||
m_start = start;
|
||||
}
|
||||
void escape() {
|
||||
if( m_mode == None )
|
||||
m_start = m_pos;
|
||||
m_mode = EscapedName;
|
||||
m_escapeChars.push_back( m_pos );
|
||||
}
|
||||
@@ -95,7 +97,7 @@ namespace Catch {
|
||||
void addPattern() {
|
||||
std::string token = subString();
|
||||
for( size_t i = 0; i < m_escapeChars.size(); ++i )
|
||||
token = token.substr( 0, m_escapeChars[i] ) + token.substr( m_escapeChars[i]+1 );
|
||||
token = token.substr( 0, m_escapeChars[i]-i ) + token.substr( m_escapeChars[i]+1-i );
|
||||
m_escapeChars.clear();
|
||||
if( startsWith( token, "exclude:" ) ) {
|
||||
m_exclusion = true;
|
||||
|
@@ -69,7 +69,7 @@ std::string toString( std::string const& value ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return "\"" + s + "\"";
|
||||
return '"' + s + '"';
|
||||
}
|
||||
std::string toString( std::wstring const& value ) {
|
||||
|
||||
@@ -90,19 +90,19 @@ std::string toString( char* const value ) {
|
||||
|
||||
std::string toString( const wchar_t* const value )
|
||||
{
|
||||
return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
|
||||
return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
|
||||
}
|
||||
|
||||
std::string toString( wchar_t* const value )
|
||||
{
|
||||
return Catch::toString( static_cast<const wchar_t*>( value ) );
|
||||
return Catch::toString( static_cast<const wchar_t*>( value ) );
|
||||
}
|
||||
|
||||
std::string toString( int value ) {
|
||||
std::ostringstream oss;
|
||||
oss << value;
|
||||
if( value > Detail::hexThreshold )
|
||||
oss << " (0x" << std::hex << value << ")";
|
||||
oss << " (0x" << std::hex << value << ')';
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ std::string toString( unsigned long value ) {
|
||||
std::ostringstream oss;
|
||||
oss << value;
|
||||
if( value > Detail::hexThreshold )
|
||||
oss << " (0x" << std::hex << value << ")";
|
||||
oss << " (0x" << std::hex << value << ')';
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ std::string toString( const double value ) {
|
||||
return fpToString( value, 10 );
|
||||
}
|
||||
std::string toString( const float value ) {
|
||||
return fpToString( value, 5 ) + "f";
|
||||
return fpToString( value, 5 ) + 'f';
|
||||
}
|
||||
|
||||
std::string toString( bool value ) {
|
||||
@@ -146,9 +146,19 @@ std::string toString( bool value ) {
|
||||
}
|
||||
|
||||
std::string toString( char value ) {
|
||||
return value < ' '
|
||||
? toString( static_cast<unsigned int>( value ) )
|
||||
: Detail::makeString( value );
|
||||
if ( value == '\r' )
|
||||
return "'\\r'";
|
||||
if ( value == '\f' )
|
||||
return "'\\f'";
|
||||
if ( value == '\n' )
|
||||
return "'\\n'";
|
||||
if ( value == '\t' )
|
||||
return "'\\t'";
|
||||
if ( '\0' <= value && value < ' ' )
|
||||
return toString( static_cast<unsigned int>( value ) );
|
||||
char chstr[] = "' '";
|
||||
chstr[1] = value;
|
||||
return chstr;
|
||||
}
|
||||
|
||||
std::string toString( signed char value ) {
|
||||
@@ -164,14 +174,14 @@ std::string toString( long long value ) {
|
||||
std::ostringstream oss;
|
||||
oss << value;
|
||||
if( value > Detail::hexThreshold )
|
||||
oss << " (0x" << std::hex << value << ")";
|
||||
oss << " (0x" << std::hex << value << ')';
|
||||
return oss.str();
|
||||
}
|
||||
std::string toString( unsigned long long value ) {
|
||||
std::ostringstream oss;
|
||||
oss << value;
|
||||
if( value > Detail::hexThreshold )
|
||||
oss << " (0x" << std::hex << value << ")";
|
||||
oss << " (0x" << std::hex << value << ')';
|
||||
return oss.str();
|
||||
}
|
||||
#endif
|
||||
|
@@ -26,18 +26,18 @@ namespace Catch {
|
||||
{}
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, Version const& version ) {
|
||||
os << version.majorVersion << "."
|
||||
<< version.minorVersion << "."
|
||||
os << version.majorVersion << '.'
|
||||
<< version.minorVersion << '.'
|
||||
<< version.patchNumber;
|
||||
|
||||
if( !version.branchName.empty() ) {
|
||||
os << "-" << version.branchName
|
||||
<< "." << version.buildNumber;
|
||||
os << '-' << version.branchName
|
||||
<< '.' << version.buildNumber;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
Version libraryVersion( 1, 6, 1, "", 0 );
|
||||
Version libraryVersion( 1, 7, 0, "", 0 );
|
||||
|
||||
}
|
||||
|
||||
|
@@ -27,11 +27,11 @@ namespace Catch
|
||||
m_wildcard( NoWildcard ),
|
||||
m_pattern( adjustCase( pattern ) )
|
||||
{
|
||||
if( startsWith( m_pattern, "*" ) ) {
|
||||
if( startsWith( m_pattern, '*' ) ) {
|
||||
m_pattern = m_pattern.substr( 1 );
|
||||
m_wildcard = WildcardAtStart;
|
||||
}
|
||||
if( endsWith( m_pattern, "*" ) ) {
|
||||
if( endsWith( m_pattern, '*' ) ) {
|
||||
m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
|
||||
m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
|
||||
}
|
||||
|
@@ -136,7 +136,7 @@ namespace Catch {
|
||||
XmlWriter& startElement( std::string const& name ) {
|
||||
ensureTagClosed();
|
||||
newlineIfNecessary();
|
||||
stream() << m_indent << "<" << name;
|
||||
stream() << m_indent << '<' << name;
|
||||
m_tags.push_back( name );
|
||||
m_indent += " ";
|
||||
m_tagIsOpen = true;
|
||||
@@ -165,12 +165,12 @@ namespace Catch {
|
||||
|
||||
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
|
||||
if( !name.empty() && !attribute.empty() )
|
||||
stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\"";
|
||||
stream() << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
|
||||
return *this;
|
||||
}
|
||||
|
||||
XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
|
||||
stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
|
||||
stream() << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace Catch {
|
||||
|
||||
XmlWriter& writeBlankLine() {
|
||||
ensureTagClosed();
|
||||
stream() << "\n";
|
||||
stream() << '\n';
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ namespace Catch {
|
||||
|
||||
void newlineIfNecessary() {
|
||||
if( m_needsNewline ) {
|
||||
stream() << "\n";
|
||||
stream() << '\n';
|
||||
m_needsNewline = false;
|
||||
}
|
||||
}
|
||||
|
@@ -108,12 +108,12 @@ namespace Catch {
|
||||
|
||||
struct BySectionInfo {
|
||||
BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
|
||||
BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
|
||||
BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
|
||||
bool operator() ( Ptr<SectionNode> const& node ) const {
|
||||
return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
|
||||
}
|
||||
private:
|
||||
void operator=( BySectionInfo const& );
|
||||
void operator=( BySectionInfo const& );
|
||||
SectionInfo const& m_other;
|
||||
};
|
||||
|
||||
@@ -170,6 +170,12 @@ namespace Catch {
|
||||
assert( !m_sectionStack.empty() );
|
||||
SectionNode& sectionNode = *m_sectionStack.back();
|
||||
sectionNode.assertions.push_back( assertionStats );
|
||||
// AssertionResult holds a pointer to a temporary DecomposedExpression,
|
||||
// which getExpandedExpression() calls to build the expression string.
|
||||
// Our section stack copy of the assertionResult will likely outlive the
|
||||
// temporary, so it must be expanded or discarded now to avoid calling
|
||||
// a destroyed object later.
|
||||
prepareExpandedExpression( sectionNode.assertions.back().assertionResult );
|
||||
return true;
|
||||
}
|
||||
virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
|
||||
@@ -204,6 +210,13 @@ namespace Catch {
|
||||
|
||||
virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
|
||||
|
||||
virtual void prepareExpandedExpression( AssertionResult& result ) const {
|
||||
if( result.isOk() )
|
||||
result.discardDecomposedExpression();
|
||||
else
|
||||
result.expandDecomposedExpression();
|
||||
}
|
||||
|
||||
Ptr<IConfig const> m_config;
|
||||
std::ostream& stream;
|
||||
std::vector<AssertionStats> m_assertions;
|
||||
|
@@ -34,7 +34,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
virtual void noMatchingTestCases( std::string const& spec ) {
|
||||
stream << "No test cases matched '" << spec << "'" << std::endl;
|
||||
stream << "No test cases matched '" << spec << '\'' << std::endl;
|
||||
}
|
||||
|
||||
virtual void assertionStarting( AssertionInfo const& ) {
|
||||
@@ -61,7 +61,7 @@ namespace Catch {
|
||||
|
||||
virtual void testRunEnded( TestRunStats const& _testRunStats ) {
|
||||
printTotals( _testRunStats.totals );
|
||||
stream << "\n" << std::endl;
|
||||
stream << '\n' << std::endl;
|
||||
StreamingReporterBase::testRunEnded( _testRunStats );
|
||||
}
|
||||
|
||||
@@ -161,26 +161,26 @@ namespace Catch {
|
||||
|
||||
void printSourceInfo() const {
|
||||
Colour colourGuard( Colour::FileName );
|
||||
stream << result.getSourceInfo() << ":";
|
||||
stream << result.getSourceInfo() << ':';
|
||||
}
|
||||
|
||||
void printResultType( Colour::Code colour, std::string passOrFail ) const {
|
||||
if( !passOrFail.empty() ) {
|
||||
{
|
||||
Colour colourGuard( colour );
|
||||
stream << " " << passOrFail;
|
||||
stream << ' ' << passOrFail;
|
||||
}
|
||||
stream << ":";
|
||||
stream << ':';
|
||||
}
|
||||
}
|
||||
|
||||
void printIssue( std::string issue ) const {
|
||||
stream << " " << issue;
|
||||
stream << ' ' << issue;
|
||||
}
|
||||
|
||||
void printExpressionWas() {
|
||||
if( result.hasExpression() ) {
|
||||
stream << ";";
|
||||
stream << ';';
|
||||
{
|
||||
Colour colour( dimColour() );
|
||||
stream << " expression was:";
|
||||
@@ -191,7 +191,7 @@ namespace Catch {
|
||||
|
||||
void printOriginalExpression() const {
|
||||
if( result.hasExpression() ) {
|
||||
stream << " " << result.getExpression();
|
||||
stream << ' ' << result.getExpression();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace Catch {
|
||||
|
||||
void printMessage() {
|
||||
if ( itMessage != messages.end() ) {
|
||||
stream << " '" << itMessage->message << "'";
|
||||
stream << " '" << itMessage->message << '\'';
|
||||
++itMessage;
|
||||
}
|
||||
}
|
||||
@@ -222,13 +222,13 @@ namespace Catch {
|
||||
|
||||
{
|
||||
Colour colourGuard( colour );
|
||||
stream << " with " << pluralise( N, "message" ) << ":";
|
||||
stream << " with " << pluralise( N, "message" ) << ':';
|
||||
}
|
||||
|
||||
for(; itMessage != itEnd; ) {
|
||||
// If this assertion is a warning ignore any INFO messages
|
||||
if( printInfoMessages || itMessage->type != ResultWas::Info ) {
|
||||
stream << " '" << itMessage->message << "'";
|
||||
stream << " '" << itMessage->message << '\'';
|
||||
if ( ++itMessage != itEnd ) {
|
||||
Colour colourGuard( dimColour() );
|
||||
stream << " and";
|
||||
@@ -254,7 +254,7 @@ namespace Catch {
|
||||
// - green: Passed [both/all] N tests cases with M assertions.
|
||||
|
||||
std::string bothOrAll( std::size_t count ) const {
|
||||
return count == 1 ? "" : count == 2 ? "both " : "all " ;
|
||||
return count == 1 ? std::string() : count == 2 ? "both " : "all " ;
|
||||
}
|
||||
|
||||
void printTotals( const Totals& totals ) const {
|
||||
@@ -265,12 +265,12 @@ namespace Catch {
|
||||
Colour colour( Colour::ResultError );
|
||||
const std::string qualify_assertions_failed =
|
||||
totals.assertions.failed == totals.assertions.total() ?
|
||||
bothOrAll( totals.assertions.failed ) : "";
|
||||
bothOrAll( totals.assertions.failed ) : std::string();
|
||||
stream <<
|
||||
"Failed " << bothOrAll( totals.testCases.failed )
|
||||
<< pluralise( totals.testCases.failed, "test case" ) << ", "
|
||||
"failed " << qualify_assertions_failed <<
|
||||
pluralise( totals.assertions.failed, "assertion" ) << ".";
|
||||
pluralise( totals.assertions.failed, "assertion" ) << '.';
|
||||
}
|
||||
else if( totals.assertions.total() == 0 ) {
|
||||
stream <<
|
||||
@@ -282,14 +282,14 @@ namespace Catch {
|
||||
Colour colour( Colour::ResultError );
|
||||
stream <<
|
||||
"Failed " << pluralise( totals.testCases.failed, "test case" ) << ", "
|
||||
"failed " << pluralise( totals.assertions.failed, "assertion" ) << ".";
|
||||
"failed " << pluralise( totals.assertions.failed, "assertion" ) << '.';
|
||||
}
|
||||
else {
|
||||
Colour colour( Colour::ResultSuccess );
|
||||
stream <<
|
||||
"Passed " << bothOrAll( totals.testCases.passed )
|
||||
<< pluralise( totals.testCases.passed, "test case" ) <<
|
||||
" with " << pluralise( totals.assertions.passed, "assertion" ) << ".";
|
||||
" with " << pluralise( totals.assertions.passed, "assertion" ) << '.';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -27,7 +27,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
|
||||
stream << "No test cases matched '" << spec << "'" << std::endl;
|
||||
stream << "No test cases matched '" << spec << '\'' << std::endl;
|
||||
}
|
||||
|
||||
virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {
|
||||
@@ -69,12 +69,12 @@ namespace Catch {
|
||||
}
|
||||
if( m_headerPrinted ) {
|
||||
if( m_config->showDurations() == ShowDurations::Always )
|
||||
stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
|
||||
stream << "Completed in " << _sectionStats.durationInSeconds << 's' << std::endl;
|
||||
m_headerPrinted = false;
|
||||
}
|
||||
else {
|
||||
if( m_config->showDurations() == ShowDurations::Always )
|
||||
stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
|
||||
stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << 's' << std::endl;
|
||||
}
|
||||
StreamingReporterBase::sectionEnded( _sectionStats );
|
||||
}
|
||||
@@ -88,7 +88,7 @@ namespace Catch {
|
||||
printSummaryDivider();
|
||||
stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
|
||||
printTotals( _testGroupStats.totals );
|
||||
stream << "\n" << std::endl;
|
||||
stream << '\n' << std::endl;
|
||||
}
|
||||
StreamingReporterBase::testGroupEnded( _testGroupStats );
|
||||
}
|
||||
@@ -180,13 +180,13 @@ namespace Catch {
|
||||
printSourceInfo();
|
||||
if( stats.totals.assertions.total() > 0 ) {
|
||||
if( result.isOk() )
|
||||
stream << "\n";
|
||||
stream << '\n';
|
||||
printResultType();
|
||||
printOriginalExpression();
|
||||
printReconstructedExpression();
|
||||
}
|
||||
else {
|
||||
stream << "\n";
|
||||
stream << '\n';
|
||||
}
|
||||
printMessage();
|
||||
}
|
||||
@@ -203,25 +203,25 @@ namespace Catch {
|
||||
Colour colourGuard( Colour::OriginalExpression );
|
||||
stream << " ";
|
||||
stream << result.getExpressionInMacro();
|
||||
stream << "\n";
|
||||
stream << '\n';
|
||||
}
|
||||
}
|
||||
void printReconstructedExpression() const {
|
||||
if( result.hasExpandedExpression() ) {
|
||||
stream << "with expansion:\n";
|
||||
Colour colourGuard( Colour::ReconstructedExpression );
|
||||
stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n";
|
||||
stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n';
|
||||
}
|
||||
}
|
||||
void printMessage() const {
|
||||
if( !messageLabel.empty() )
|
||||
stream << messageLabel << ":" << "\n";
|
||||
stream << messageLabel << ':' << '\n';
|
||||
for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
|
||||
it != itEnd;
|
||||
++it ) {
|
||||
// If this assertion is a warning ignore any INFO messages
|
||||
if( printInfoMessages || it->type != ResultWas::Info )
|
||||
stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n";
|
||||
stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n';
|
||||
}
|
||||
}
|
||||
void printSourceInfo() const {
|
||||
@@ -253,7 +253,7 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
void lazyPrintRunInfo() {
|
||||
stream << "\n" << getLineOfChars<'~'>() << "\n";
|
||||
stream << '\n' << getLineOfChars<'~'>() << '\n';
|
||||
Colour colour( Colour::SecondaryText );
|
||||
stream << currentTestRunInfo->name
|
||||
<< " is a Catch v" << libraryVersion << " host application.\n"
|
||||
@@ -287,19 +287,19 @@ namespace Catch {
|
||||
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
|
||||
|
||||
if( !lineInfo.empty() ){
|
||||
stream << getLineOfChars<'-'>() << "\n";
|
||||
stream << getLineOfChars<'-'>() << '\n';
|
||||
Colour colourGuard( Colour::FileName );
|
||||
stream << lineInfo << "\n";
|
||||
stream << lineInfo << '\n';
|
||||
}
|
||||
stream << getLineOfChars<'.'>() << "\n" << std::endl;
|
||||
stream << getLineOfChars<'.'>() << '\n' << std::endl;
|
||||
}
|
||||
|
||||
void printClosedHeader( std::string const& _name ) {
|
||||
printOpenHeader( _name );
|
||||
stream << getLineOfChars<'.'>() << "\n";
|
||||
stream << getLineOfChars<'.'>() << '\n';
|
||||
}
|
||||
void printOpenHeader( std::string const& _name ) {
|
||||
stream << getLineOfChars<'-'>() << "\n";
|
||||
stream << getLineOfChars<'-'>() << '\n';
|
||||
{
|
||||
Colour colourGuard( Colour::Headers );
|
||||
printHeaderString( _name );
|
||||
@@ -316,7 +316,7 @@ namespace Catch {
|
||||
i = 0;
|
||||
stream << Text( _string, TextAttributes()
|
||||
.setIndent( indent+i)
|
||||
.setInitialIndent( indent ) ) << "\n";
|
||||
.setInitialIndent( indent ) ) << '\n';
|
||||
}
|
||||
|
||||
struct SummaryColumn {
|
||||
@@ -331,9 +331,9 @@ namespace Catch {
|
||||
std::string row = oss.str();
|
||||
for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
|
||||
while( it->size() < row.size() )
|
||||
*it = " " + *it;
|
||||
*it = ' ' + *it;
|
||||
while( it->size() > row.size() )
|
||||
row = " " + row;
|
||||
row = ' ' + row;
|
||||
}
|
||||
rows.push_back( row );
|
||||
return *this;
|
||||
@@ -353,8 +353,8 @@ namespace Catch {
|
||||
stream << Colour( Colour::ResultSuccess ) << "All tests passed";
|
||||
stream << " ("
|
||||
<< pluralise( totals.assertions.passed, "assertion" ) << " in "
|
||||
<< pluralise( totals.testCases.passed, "test case" ) << ")"
|
||||
<< "\n";
|
||||
<< pluralise( totals.testCases.passed, "test case" ) << ')'
|
||||
<< '\n';
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -389,10 +389,10 @@ namespace Catch {
|
||||
else if( value != "0" ) {
|
||||
stream << Colour( Colour::LightGrey ) << " | ";
|
||||
stream << Colour( it->colour )
|
||||
<< value << " " << it->label;
|
||||
<< value << ' ' << it->label;
|
||||
}
|
||||
}
|
||||
stream << "\n";
|
||||
stream << '\n';
|
||||
}
|
||||
|
||||
static std::size_t makeRatio( std::size_t number, std::size_t total ) {
|
||||
@@ -428,10 +428,10 @@ namespace Catch {
|
||||
else {
|
||||
stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
|
||||
}
|
||||
stream << "\n";
|
||||
stream << '\n';
|
||||
}
|
||||
void printSummaryDivider() {
|
||||
stream << getLineOfChars<'-'>() << "\n";
|
||||
stream << getLineOfChars<'-'>() << '\n';
|
||||
}
|
||||
|
||||
private:
|
||||
|
@@ -146,7 +146,7 @@ namespace Catch {
|
||||
SectionNode const& sectionNode ) {
|
||||
std::string name = trim( sectionNode.stats.sectionInfo.name );
|
||||
if( !rootName.empty() )
|
||||
name = rootName + "/" + name;
|
||||
name = rootName + '/' + name;
|
||||
|
||||
if( !sectionNode.assertions.empty() ||
|
||||
!sectionNode.stdOut.empty() ||
|
||||
@@ -224,14 +224,14 @@ namespace Catch {
|
||||
|
||||
std::ostringstream oss;
|
||||
if( !result.getMessage().empty() )
|
||||
oss << result.getMessage() << "\n";
|
||||
oss << result.getMessage() << '\n';
|
||||
for( std::vector<MessageInfo>::const_iterator
|
||||
it = stats.infoMessages.begin(),
|
||||
itEnd = stats.infoMessages.end();
|
||||
it != itEnd;
|
||||
++it )
|
||||
if( it->type == ResultWas::Info )
|
||||
oss << it->message << "\n";
|
||||
oss << it->message << '\n';
|
||||
|
||||
oss << "at " << result.getSourceInfo();
|
||||
xml.writeText( oss.str(), false );
|
||||
|
@@ -118,11 +118,11 @@ public: // IStreamingReporter
|
||||
++it )
|
||||
(*it)->skipTest( testInfo );
|
||||
}
|
||||
|
||||
|
||||
virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
|
||||
|
@@ -96,7 +96,7 @@ namespace Catch {
|
||||
if( assertionResult.hasExpression() ) {
|
||||
m_xml.startElement( "Expression" )
|
||||
.writeAttribute( "success", assertionResult.succeeded() )
|
||||
.writeAttribute( "type", assertionResult.getTestMacroName() )
|
||||
.writeAttribute( "type", assertionResult.getTestMacroName() )
|
||||
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
|
||||
.writeAttribute( "line", assertionResult.getSourceInfo().line );
|
||||
|
||||
|
9
projects/Benchmark/BenchMain.cpp
Normal file
9
projects/Benchmark/BenchMain.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Created by Martin on 16/01/2017.
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
46
projects/Benchmark/StringificationBench.cpp
Normal file
46
projects/Benchmark/StringificationBench.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Created by Martin on 16/01/2017.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE("Successful tests -- REQUIRE", "[Success]") {
|
||||
const size_t sz = 1 * 1024 * 1024;
|
||||
|
||||
|
||||
std::vector<size_t> vec; vec.reserve(sz);
|
||||
for (size_t i = 0; i < sz; ++i){
|
||||
vec.push_back(i);
|
||||
REQUIRE(vec.back() == i);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE("Successful tests -- CHECK", "[Success]") {
|
||||
const size_t sz = 1 * 1024 * 1024;
|
||||
|
||||
|
||||
std::vector<size_t> vec; vec.reserve(sz);
|
||||
for (size_t i = 0; i < sz; ++i){
|
||||
vec.push_back(i);
|
||||
CHECK(vec.back() == i);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE("Unsuccessful tests -- CHECK", "[Failure]") {
|
||||
const size_t sz = 1024 * 1024;
|
||||
|
||||
|
||||
std::vector<size_t> vec; vec.reserve(sz);
|
||||
for (size_t i = 0; i < sz; ++i){
|
||||
vec.push_back(i);
|
||||
CHECK(vec.size() == i);
|
||||
}
|
||||
}
|
4
projects/Benchmark/readme.txt
Normal file
4
projects/Benchmark/readme.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
This is very much a work in progress.
|
||||
The past results are standardized to a developer's machine,
|
||||
the benchmarking script is basic and there are only 3 benchmarks,
|
||||
but this should get better in time. For now, at least there is something to go by.
|
@@ -0,0 +1,3 @@
|
||||
Successful tests -- CHECK: median: 3.38116 (s), stddev: 0.11567366292001534 (s)
|
||||
Successful tests -- REQUIRE: median: 3.479955 (s), stddev: 0.16295972890734556 (s)
|
||||
Unsuccessful tests -- CHECK: median: 1.966895 (s), stddev: 0.06323488524716572 (s)
|
@@ -0,0 +1,3 @@
|
||||
Successful tests -- CHECK: median: 1.30312 (s), stddev: 0.08759818557862176 (s)
|
||||
Successful tests -- REQUIRE: median: 1.341535 (s), stddev: 0.1479193390143576 (s)
|
||||
Unsuccessful tests -- CHECK: median: 1.967755 (s), stddev: 0.07921104121269959 (s)
|
@@ -0,0 +1,3 @@
|
||||
Successful tests -- CHECK: median: 1.2982 (s), stddev: 0.019540648829214084 (s)
|
||||
Successful tests -- REQUIRE: median: 1.30102 (s), stddev: 0.014758430547392974 (s)
|
||||
Unsuccessful tests -- CHECK: median: 15.520199999999999 (s), stddev: 0.09536359426485094 (s)
|
@@ -0,0 +1,3 @@
|
||||
Successful tests -- CHECK: median: 0.7689014999999999 (s), stddev: 0.02127512078801068 (s)
|
||||
Successful tests -- REQUIRE: median: 0.772845 (s), stddev: 0.03011638381365052 (s)
|
||||
Unsuccessful tests -- CHECK: median: 15.49 (s), stddev: 0.536088571143903 (s)
|
@@ -0,0 +1,3 @@
|
||||
Successful tests -- CHECK: median: 0.775769 (s), stddev: 0.014802129132136525 (s)
|
||||
Successful tests -- REQUIRE: median: 0.785235 (s), stddev: 0.03532672836834896 (s)
|
||||
Unsuccessful tests -- CHECK: median: 15.156600000000001 (s), stddev: 0.2832375673450742 (s)
|
@@ -140,3 +140,48 @@ TEST_CASE( "Approximate PI", "[Approx][PI]" )
|
||||
REQUIRE( divide( 22, 7 ) == Approx( 3.141 ).epsilon( 0.001 ) );
|
||||
REQUIRE( divide( 22, 7 ) != Approx( 3.141 ).epsilon( 0.0001 ) );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
|
||||
class StrongDoubleTypedef
|
||||
{
|
||||
double d_ = 0.0;
|
||||
|
||||
public:
|
||||
explicit StrongDoubleTypedef(double d) : d_(d) {}
|
||||
explicit operator double() const { return d_; }
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<( std::ostream& os, StrongDoubleTypedef td ) {
|
||||
return os << "StrongDoubleTypedef(" << static_cast<double>(td) << ")";
|
||||
}
|
||||
|
||||
TEST_CASE
|
||||
(
|
||||
"Comparison with explicitly convertible types",
|
||||
"[Approx]"
|
||||
)
|
||||
{
|
||||
StrongDoubleTypedef td(10.0);
|
||||
|
||||
REQUIRE(td == Approx(10.0));
|
||||
REQUIRE(Approx(10.0) == td);
|
||||
|
||||
REQUIRE(td != Approx(11.0));
|
||||
REQUIRE(Approx(11.0) != td);
|
||||
|
||||
REQUIRE(td <= Approx(10.0));
|
||||
REQUIRE(td <= Approx(11.0));
|
||||
REQUIRE(Approx(10.0) <= td);
|
||||
REQUIRE(Approx(9.0) <= td);
|
||||
|
||||
REQUIRE(td >= Approx(9.0));
|
||||
REQUIRE(td >= Approx(10.0));
|
||||
REQUIRE(Approx(10.0) >= td);
|
||||
REQUIRE(Approx(11.0) >= td);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -88,10 +88,10 @@ struct Fixture
|
||||
}
|
||||
|
||||
SCENARIO_METHOD(Fixture,
|
||||
"BDD tests requiring Fixtures to provide commonly-accessed data or methods",
|
||||
"[bdd][fixtures]") {
|
||||
"BDD tests requiring Fixtures to provide commonly-accessed data or methods",
|
||||
"[bdd][fixtures]") {
|
||||
const int before(counter());
|
||||
GIVEN("No operations precede me") {
|
||||
GIVEN("No operations precede me") {
|
||||
REQUIRE(before == 0);
|
||||
WHEN("We get the count") {
|
||||
const int after(counter());
|
||||
|
@@ -584,11 +584,11 @@ MiscTests.cpp:<line number>: FAILED:
|
||||
CHECK( s1 == s2 )
|
||||
with expansion:
|
||||
"if ($b == 10) {
|
||||
$a= 20;
|
||||
$a = 20;
|
||||
}"
|
||||
==
|
||||
"if ($b == 10) {
|
||||
$a = 20;
|
||||
$a = 20;
|
||||
}
|
||||
"
|
||||
|
||||
@@ -613,8 +613,7 @@ due to unexpected exception with message:
|
||||
unexpected exception
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
When unchecked exceptions are thrown during a CHECK the test should abort and
|
||||
fail
|
||||
When unchecked exceptions are thrown during a CHECK the test should continue
|
||||
-------------------------------------------------------------------------------
|
||||
ExceptionTests.cpp:<line number>
|
||||
...............................................................................
|
||||
@@ -830,6 +829,6 @@ with expansion:
|
||||
"first" == "second"
|
||||
|
||||
===============================================================================
|
||||
test cases: 159 | 115 passed | 42 failed | 2 failed as expected
|
||||
assertions: 909 | 813 passed | 78 failed | 18 failed as expected
|
||||
test cases: 157 | 113 passed | 42 failed | 2 failed as expected
|
||||
assertions: 913 | 817 passed | 78 failed | 18 failed as expected
|
||||
|
||||
|
@@ -2932,13 +2932,9 @@ TestMain.cpp:<line number>
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef\n" )
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef" )
|
||||
with expansion:
|
||||
"abcdef
|
||||
"
|
||||
==
|
||||
"abcdef
|
||||
"
|
||||
"abcdef" == "abcdef"
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
@@ -2948,13 +2944,19 @@ with expansion:
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef\n" )
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" )
|
||||
with expansion:
|
||||
"abcdef
|
||||
"
|
||||
"abcdef" == "abcdef"
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 5 ) ).toString() == "abcd-\nef" )
|
||||
with expansion:
|
||||
"abcd-
|
||||
ef"
|
||||
==
|
||||
"abcdef
|
||||
"
|
||||
"abcd-
|
||||
ef"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Long strings can be wrapped
|
||||
@@ -3024,24 +3026,107 @@ with expansion:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Long strings can be wrapped
|
||||
With tabs
|
||||
With wrap-before/ after characters
|
||||
No wrapping
|
||||
-------------------------------------------------------------------------------
|
||||
TestMain.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 15 ) ).toString() == "one two three\n four\n five\n six" )
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString )
|
||||
with expansion:
|
||||
"one two three
|
||||
four
|
||||
five
|
||||
six"
|
||||
"one,two(three) <here>"
|
||||
==
|
||||
"one two three
|
||||
four
|
||||
five
|
||||
six"
|
||||
"one,two(three) <here>"
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 24 ) ).toString() == testString )
|
||||
with expansion:
|
||||
"one,two(three) <here>"
|
||||
==
|
||||
"one,two(three) <here>"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Long strings can be wrapped
|
||||
With wrap-before/ after characters
|
||||
Wrap before
|
||||
-------------------------------------------------------------------------------
|
||||
TestMain.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 11 ) ).toString() == "one,two\n(three)\n<here>" )
|
||||
with expansion:
|
||||
"one,two
|
||||
(three)
|
||||
<here>"
|
||||
==
|
||||
"one,two
|
||||
(three)
|
||||
<here>"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Long strings can be wrapped
|
||||
With wrap-before/ after characters
|
||||
Wrap after
|
||||
-------------------------------------------------------------------------------
|
||||
TestMain.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one,\ntwo\n(thre-\ne)\n<here>" )
|
||||
with expansion:
|
||||
"one,
|
||||
two
|
||||
(thre-
|
||||
e)
|
||||
<here>"
|
||||
==
|
||||
"one,
|
||||
two
|
||||
(thre-
|
||||
e)
|
||||
<here>"
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 5 ) ).toString() == "one,\ntwo\n(thr-\nee)\n<her-\ne>" )
|
||||
with expansion:
|
||||
"one,
|
||||
two
|
||||
(thr-
|
||||
ee)
|
||||
<her-
|
||||
e>"
|
||||
==
|
||||
"one,
|
||||
two
|
||||
(thr-
|
||||
ee)
|
||||
<her-
|
||||
e>"
|
||||
|
||||
TestMain.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 4 ) ).toString() == "one,\ntwo\n(th-\nree)\n<he-\nre>" )
|
||||
with expansion:
|
||||
"one,
|
||||
two
|
||||
(th-
|
||||
ree)
|
||||
<he-
|
||||
re>"
|
||||
==
|
||||
"one,
|
||||
two
|
||||
(th-
|
||||
ree)
|
||||
<he-
|
||||
re>"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Long text is truncted
|
||||
@@ -6458,11 +6543,11 @@ MiscTests.cpp:<line number>: FAILED:
|
||||
CHECK( s1 == s2 )
|
||||
with expansion:
|
||||
"if ($b == 10) {
|
||||
$a= 20;
|
||||
$a = 20;
|
||||
}"
|
||||
==
|
||||
"if ($b == 10) {
|
||||
$a = 20;
|
||||
$a = 20;
|
||||
}
|
||||
"
|
||||
|
||||
@@ -6478,36 +6563,32 @@ PASSED:
|
||||
CHECK_THAT( what, Contains( "[@zzz]" ) )
|
||||
with expansion:
|
||||
"error: tag alias, "[@zzz]" already registered.
|
||||
First seen at file:2
|
||||
Redefined at file:10" contains: "
|
||||
[@zzz]"
|
||||
First seen at file:2
|
||||
Redefined at file:10" contains: "[@zzz]"
|
||||
|
||||
TagAliasTests.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK_THAT( what, Contains( "file" ) )
|
||||
with expansion:
|
||||
"error: tag alias, "[@zzz]" already registered.
|
||||
First seen at file:2
|
||||
Redefined at file:10" contains:
|
||||
"file"
|
||||
First seen at file:2
|
||||
Redefined at file:10" contains: "file"
|
||||
|
||||
TagAliasTests.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK_THAT( what, Contains( "2" ) )
|
||||
with expansion:
|
||||
"error: tag alias, "[@zzz]" already registered.
|
||||
First seen at file:2
|
||||
Redefined at file:10" contains:
|
||||
"2"
|
||||
First seen at file:2
|
||||
Redefined at file:10" contains: "2"
|
||||
|
||||
TagAliasTests.cpp:<line number>:
|
||||
PASSED:
|
||||
CHECK_THAT( what, Contains( "10" ) )
|
||||
with expansion:
|
||||
"error: tag alias, "[@zzz]" already registered.
|
||||
First seen at file:2
|
||||
Redefined at file:10" contains:
|
||||
"10"
|
||||
First seen at file:2
|
||||
Redefined at file:10" contains: "10"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Tag alias can be registered against tag patterns
|
||||
@@ -7701,8 +7782,7 @@ due to unexpected exception with message:
|
||||
unexpected exception
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
When unchecked exceptions are thrown during a CHECK the test should abort and
|
||||
fail
|
||||
When unchecked exceptions are thrown during a CHECK the test should continue
|
||||
-------------------------------------------------------------------------------
|
||||
ExceptionTests.cpp:<line number>
|
||||
...............................................................................
|
||||
@@ -8676,32 +8756,6 @@ with expansion:
|
||||
==
|
||||
"{ StringMaker<has_maker> }"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
toString( vectors<has_maker_and_toString )
|
||||
-------------------------------------------------------------------------------
|
||||
ToStringWhich.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
ToStringWhich.cpp:<line number>:
|
||||
PASSED:
|
||||
REQUIRE( Catch::toString( v ) == "{ StringMaker<has_maker_and_toString> }" )
|
||||
with expansion:
|
||||
"{ StringMaker<has_maker_and_toString> }"
|
||||
==
|
||||
"{ StringMaker<has_maker_and_toString> }"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
toString( vectors<has_toString )
|
||||
-------------------------------------------------------------------------------
|
||||
ToStringWhich.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
ToStringWhich.cpp:<line number>:
|
||||
PASSED:
|
||||
REQUIRE( Catch::toString( v ) == "{ {?} }" )
|
||||
with expansion:
|
||||
"{ {?} }" == "{ {?} }"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
toString(enum w/operator<<)
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -8971,6 +9025,6 @@ MiscTests.cpp:<line number>:
|
||||
PASSED:
|
||||
|
||||
===============================================================================
|
||||
test cases: 159 | 114 passed | 43 failed | 2 failed as expected
|
||||
assertions: 911 | 813 passed | 80 failed | 18 failed as expected
|
||||
test cases: 157 | 112 passed | 43 failed | 2 failed as expected
|
||||
assertions: 915 | 817 passed | 80 failed | 18 failed as expected
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.1" encoding="UTF-8"?>
|
||||
<testsuites>
|
||||
<testsuite name="<exe-name>" errors="13" failures="68" tests="912" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testsuite name="<exe-name>" errors="13" failures="68" tests="916" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testcase classname="global" name="# A test name that starts with a #" time="{duration}"/>
|
||||
<testcase classname="global" name="'Not' checks that should fail" time="{duration}">
|
||||
<failure message="false != false" type="CHECK">
|
||||
@@ -242,7 +242,9 @@ ConditionTests.cpp:<line number>
|
||||
<testcase classname="Long strings can be wrapped" name="With newlines/Trailing newline" time="{duration}"/>
|
||||
<testcase classname="Long strings can be wrapped" name="With newlines/Wrapped once" time="{duration}"/>
|
||||
<testcase classname="Long strings can be wrapped" name="With newlines/Wrapped twice" time="{duration}"/>
|
||||
<testcase classname="Long strings can be wrapped" name="With tabs" time="{duration}"/>
|
||||
<testcase classname="Long strings can be wrapped" name="With wrap-before/ after characters/No wrapping" time="{duration}"/>
|
||||
<testcase classname="Long strings can be wrapped" name="With wrap-before/ after characters/Wrap before" time="{duration}"/>
|
||||
<testcase classname="Long strings can be wrapped" name="With wrap-before/ after characters/Wrap after" time="{duration}"/>
|
||||
<testcase classname="global" name="Long text is truncted" time="{duration}"/>
|
||||
<testcase classname="global" name="ManuallyRegistered" time="{duration}"/>
|
||||
<testcase classname="global" name="Matchers can be (AllOf) composed with the && operator" time="{duration}"/>
|
||||
@@ -500,7 +502,7 @@ unexpected exception
|
||||
ExceptionTests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="global" name="When unchecked exceptions are thrown during a CHECK the test should abort and fail" time="{duration}">
|
||||
<testcase classname="global" name="When unchecked exceptions are thrown during a CHECK the test should continue" time="{duration}">
|
||||
<error message="thisThrows() == 0" type="CHECK">
|
||||
expected exception
|
||||
ExceptionTests.cpp:<line number>
|
||||
@@ -652,8 +654,6 @@ TrickyTests.cpp:<line number>
|
||||
<testcase classname="global" name="toString( has_maker_and_toString )" time="{duration}"/>
|
||||
<testcase classname="global" name="toString( has_toString )" time="{duration}"/>
|
||||
<testcase classname="global" name="toString( vectors<has_maker )" time="{duration}"/>
|
||||
<testcase classname="global" name="toString( vectors<has_maker_and_toString )" time="{duration}"/>
|
||||
<testcase classname="global" name="toString( vectors<has_toString )" time="{duration}"/>
|
||||
<testcase classname="global" name="toString(enum w/operator<<)" time="{duration}"/>
|
||||
<testcase classname="global" name="toString(enum)" time="{duration}"/>
|
||||
<testcase classname="global" name="vector<int> -> toString" time="{duration}"/>
|
||||
|
@@ -2987,14 +2987,10 @@ three four"
|
||||
<Section name="Trailing newline">
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef\n"
|
||||
Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"abcdef
|
||||
"
|
||||
==
|
||||
"abcdef
|
||||
"
|
||||
"abcdef" == "abcdef"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
@@ -3007,19 +3003,27 @@ three four"
|
||||
</Expression>
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef\n"
|
||||
Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"abcdef
|
||||
"
|
||||
==
|
||||
"abcdef
|
||||
"
|
||||
"abcdef" == "abcdef"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="3" failures="0" expectedFailures="0"/>
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( "abcdef\n", TextAttributes().setWidth( 5 ) ).toString() == "abcd-\nef"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"abcd-
|
||||
ef"
|
||||
==
|
||||
"abcd-
|
||||
ef"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="4" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<OverallResults successes="3" failures="0" expectedFailures="0"/>
|
||||
<OverallResults successes="4" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="With newlines">
|
||||
<Section name="Wrapped once">
|
||||
@@ -3091,25 +3095,116 @@ four"
|
||||
</Section>
|
||||
<OverallResults successes="1" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="With tabs">
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( testString, TextAttributes().setWidth( 15 ) ).toString() == "one two three\n four\n five\n six"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"one two three
|
||||
four
|
||||
five
|
||||
six"
|
||||
<Section name="With wrap-before/ after characters">
|
||||
<Section name="No wrapping">
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString
|
||||
</Original>
|
||||
<Expanded>
|
||||
"one,two(three) <here>"
|
||||
==
|
||||
"one two three
|
||||
four
|
||||
five
|
||||
six"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
"one,two(three) <here>"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( testString, TextAttributes().setWidth( 24 ) ).toString() == testString
|
||||
</Original>
|
||||
<Expanded>
|
||||
"one,two(three) <here>"
|
||||
==
|
||||
"one,two(three) <here>"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="2" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<OverallResults successes="2" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="With wrap-before/ after characters">
|
||||
<Section name="Wrap before">
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( testString, TextAttributes().setWidth( 11 ) ).toString() == "one,two\n(three)\n<here>"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"one,two
|
||||
(three)
|
||||
<here>"
|
||||
==
|
||||
"one,two
|
||||
(three)
|
||||
<here>"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="1" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<OverallResults successes="1" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<Section name="With wrap-before/ after characters">
|
||||
<Section name="Wrap after">
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one,\ntwo\n(thre-\ne)\n<here>"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"one,
|
||||
two
|
||||
(thre-
|
||||
e)
|
||||
<here>"
|
||||
==
|
||||
"one,
|
||||
two
|
||||
(thre-
|
||||
e)
|
||||
<here>"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( testString, TextAttributes().setWidth( 5 ) ).toString() == "one,\ntwo\n(thr-\nee)\n<her-\ne>"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"one,
|
||||
two
|
||||
(thr-
|
||||
ee)
|
||||
<her-
|
||||
e>"
|
||||
==
|
||||
"one,
|
||||
two
|
||||
(thr-
|
||||
ee)
|
||||
<her-
|
||||
e>"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TestMain.cpp" >
|
||||
<Original>
|
||||
Text( testString, TextAttributes().setWidth( 4 ) ).toString() == "one,\ntwo\n(th-\nree)\n<he-\nre>"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"one,
|
||||
two
|
||||
(th-
|
||||
ree)
|
||||
<he-
|
||||
re>"
|
||||
==
|
||||
"one,
|
||||
two
|
||||
(th-
|
||||
ree)
|
||||
<he-
|
||||
re>"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="3" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<OverallResults successes="3" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="Long text is truncted">
|
||||
@@ -8183,7 +8278,7 @@ there"
|
||||
</Exception>
|
||||
<OverallResult success="false"/>
|
||||
</TestCase>
|
||||
<TestCase name="When unchecked exceptions are thrown during a CHECK the test should abort and fail">
|
||||
<TestCase name="When unchecked exceptions are thrown during a CHECK the test should continue">
|
||||
<Expression success="false" type="CHECK" filename="projects/<exe-name>/ExceptionTests.cpp" >
|
||||
<Original>
|
||||
thisThrows() == 0
|
||||
@@ -9151,30 +9246,6 @@ there"
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="toString( vectors<has_maker_and_toString )">
|
||||
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/ToStringWhich.cpp" >
|
||||
<Original>
|
||||
Catch::toString( v ) == "{ StringMaker<has_maker_and_toString> }"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"{ StringMaker<has_maker_and_toString> }"
|
||||
==
|
||||
"{ StringMaker<has_maker_and_toString> }"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="toString( vectors<has_toString )">
|
||||
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/ToStringWhich.cpp" >
|
||||
<Original>
|
||||
Catch::toString( v ) == "{ {?} }"
|
||||
</Original>
|
||||
<Expanded>
|
||||
"{ {?} }" == "{ {?} }"
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<TestCase name="toString(enum w/operator<<)">
|
||||
<Expression success="true" type="CHECK" filename="projects/<exe-name>/EnumToString.cpp" >
|
||||
<Original>
|
||||
@@ -9432,7 +9503,7 @@ there"
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<OverallResults successes="813" failures="81" expectedFailures="18"/>
|
||||
<OverallResults successes="817" failures="81" expectedFailures="18"/>
|
||||
</Group>
|
||||
<OverallResults successes="813" failures="80" expectedFailures="18"/>
|
||||
<OverallResults successes="817" failures="80" expectedFailures="18"/>
|
||||
</Catch>
|
||||
|
@@ -210,29 +210,29 @@ TEST_CASE( "Comparisons with int literals don't warn when mixing signed/ unsigne
|
||||
|
||||
TEST_CASE( "comparisons between int variables", "" )
|
||||
{
|
||||
long long_var = 1L;
|
||||
unsigned char unsigned_char_var = 1;
|
||||
unsigned short unsigned_short_var = 1;
|
||||
unsigned int unsigned_int_var = 1;
|
||||
unsigned long unsigned_long_var = 1L;
|
||||
long long_var = 1L;
|
||||
unsigned char unsigned_char_var = 1;
|
||||
unsigned short unsigned_short_var = 1;
|
||||
unsigned int unsigned_int_var = 1;
|
||||
unsigned long unsigned_long_var = 1L;
|
||||
|
||||
REQUIRE( long_var == unsigned_char_var );
|
||||
REQUIRE( long_var == unsigned_short_var );
|
||||
REQUIRE( long_var == unsigned_int_var );
|
||||
REQUIRE( long_var == unsigned_long_var );
|
||||
REQUIRE( long_var == unsigned_char_var );
|
||||
REQUIRE( long_var == unsigned_short_var );
|
||||
REQUIRE( long_var == unsigned_int_var );
|
||||
REQUIRE( long_var == unsigned_long_var );
|
||||
}
|
||||
|
||||
TEST_CASE( "comparisons between const int variables", "" )
|
||||
{
|
||||
const unsigned char unsigned_char_var = 1;
|
||||
const unsigned short unsigned_short_var = 1;
|
||||
const unsigned int unsigned_int_var = 1;
|
||||
const unsigned long unsigned_long_var = 1L;
|
||||
const unsigned char unsigned_char_var = 1;
|
||||
const unsigned short unsigned_short_var = 1;
|
||||
const unsigned int unsigned_int_var = 1;
|
||||
const unsigned long unsigned_long_var = 1L;
|
||||
|
||||
REQUIRE( unsigned_char_var == 1 );
|
||||
REQUIRE( unsigned_short_var == 1 );
|
||||
REQUIRE( unsigned_int_var == 1 );
|
||||
REQUIRE( unsigned_long_var == 1 );
|
||||
REQUIRE( unsigned_char_var == 1 );
|
||||
REQUIRE( unsigned_short_var == 1 );
|
||||
REQUIRE( unsigned_int_var == 1 );
|
||||
REQUIRE( unsigned_long_var == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Comparisons between unsigned ints and negative signed ints match c++ standard behaviour", "" )
|
||||
|
@@ -15,9 +15,9 @@ namespace
|
||||
{
|
||||
inline int thisThrows()
|
||||
{
|
||||
if( Catch::alwaysTrue() )
|
||||
throw std::domain_error( "expected exception" );
|
||||
return 1;
|
||||
if( Catch::alwaysTrue() )
|
||||
throw std::domain_error( "expected exception" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
int thisDoesntThrow()
|
||||
@@ -26,60 +26,64 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "When checked exceptions are thrown they can be expected or unexpected", "" )
|
||||
TEST_CASE( "When checked exceptions are thrown they can be expected or unexpected", "[!throws]" )
|
||||
{
|
||||
REQUIRE_THROWS_AS( thisThrows(), std::domain_error );
|
||||
REQUIRE_NOTHROW( thisDoesntThrow() );
|
||||
REQUIRE_THROWS( thisThrows() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Expected exceptions that don't throw or unexpected exceptions fail the test", "[.][failing]" )
|
||||
TEST_CASE( "Expected exceptions that don't throw or unexpected exceptions fail the test", "[.][failing][!throws]" )
|
||||
{
|
||||
CHECK_THROWS_AS( thisThrows(), std::string );
|
||||
CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error );
|
||||
CHECK_NOTHROW( thisThrows() );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown directly they are always failures", "[.][failing]" )
|
||||
TEST_CASE( "When unchecked exceptions are thrown directly they are always failures", "[.][failing][!throws]" )
|
||||
{
|
||||
if( Catch::alwaysTrue() )
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
if( Catch::alwaysTrue() )
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "An unchecked exception reports the line of the last assertion", "[.][failing]" )
|
||||
TEST_CASE( "An unchecked exception reports the line of the last assertion", "[.][failing][!throws]" )
|
||||
{
|
||||
CHECK( 1 == 1 );
|
||||
if( Catch::alwaysTrue() )
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
if( Catch::alwaysTrue() )
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown from sections they are always failures", "[.][failing]" )
|
||||
TEST_CASE( "When unchecked exceptions are thrown from sections they are always failures", "[.][failing][!throws]" )
|
||||
{
|
||||
SECTION( "section name", "" )
|
||||
{
|
||||
if( Catch::alwaysTrue() )
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
if( Catch::alwaysTrue() )
|
||||
throw std::domain_error( "unexpected exception" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown from functions they are always failures", "[.][failing]" )
|
||||
TEST_CASE( "When unchecked exceptions are thrown from functions they are always failures", "[.][failing][!throws]" )
|
||||
{
|
||||
CHECK( thisThrows() == 0 );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown during a REQUIRE the test should abort fail", "[.][failing]" )
|
||||
TEST_CASE( "When unchecked exceptions are thrown during a REQUIRE the test should abort fail", "[.][failing][!throws]" )
|
||||
{
|
||||
REQUIRE( thisThrows() == 0 );
|
||||
FAIL( "This should never happen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown during a CHECK the test should abort and fail", "[.][failing]" )
|
||||
TEST_CASE( "When unchecked exceptions are thrown during a CHECK the test should continue", "[.][failing][!throws]" )
|
||||
{
|
||||
CHECK( thisThrows() == 0 );
|
||||
FAIL( "This should never happen" );
|
||||
try {
|
||||
CHECK(thisThrows() == 0);
|
||||
}
|
||||
catch(...) {
|
||||
FAIL( "This should never happen" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "When unchecked exceptions are thrown, but caught, they do not affect the test", "" )
|
||||
TEST_CASE( "When unchecked exceptions are thrown, but caught, they do not affect the test", "[!throws]" )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -139,50 +143,50 @@ CATCH_TRANSLATE_EXCEPTION( double& ex )
|
||||
return Catch::toString( ex );
|
||||
}
|
||||
|
||||
TEST_CASE("Non-std exceptions can be translated", "[.][failing]" )
|
||||
TEST_CASE("Non-std exceptions can be translated", "[.][failing][!throws]" )
|
||||
{
|
||||
if( Catch::alwaysTrue() )
|
||||
throw CustomException( "custom exception" );
|
||||
if( Catch::alwaysTrue() )
|
||||
throw CustomException( "custom exception" );
|
||||
}
|
||||
|
||||
TEST_CASE("Custom std-exceptions can be custom translated", "[.][failing]" )
|
||||
TEST_CASE("Custom std-exceptions can be custom translated", "[.][failing][!throws]" )
|
||||
{
|
||||
if( Catch::alwaysTrue() )
|
||||
throw CustomException( "custom std exception" );
|
||||
}
|
||||
|
||||
inline void throwCustom() {
|
||||
if( Catch::alwaysTrue() )
|
||||
throw CustomException( "custom exception - not std" );
|
||||
if( Catch::alwaysTrue() )
|
||||
throw CustomException( "custom exception - not std" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Custom exceptions can be translated when testing for nothrow", "[.][failing]" )
|
||||
TEST_CASE( "Custom exceptions can be translated when testing for nothrow", "[.][failing][!throws]" )
|
||||
{
|
||||
REQUIRE_NOTHROW( throwCustom() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Custom exceptions can be translated when testing for throwing as something else", "[.][failing]" )
|
||||
TEST_CASE( "Custom exceptions can be translated when testing for throwing as something else", "[.][failing][!throws]" )
|
||||
{
|
||||
REQUIRE_THROWS_AS( throwCustom(), std::exception );
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "Unexpected exceptions can be translated", "[.][failing]" )
|
||||
TEST_CASE( "Unexpected exceptions can be translated", "[.][failing][!throws]" )
|
||||
{
|
||||
if( Catch::alwaysTrue() )
|
||||
throw double( 3.14 );
|
||||
if( Catch::alwaysTrue() )
|
||||
throw double( 3.14 );
|
||||
}
|
||||
|
||||
inline int thisFunctionNotImplemented( int ) {
|
||||
CATCH_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
TEST_CASE( "NotImplemented exception", "" )
|
||||
TEST_CASE( "NotImplemented exception", "[!throws]" )
|
||||
{
|
||||
REQUIRE_THROWS( thisFunctionNotImplemented( 7 ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "Exception messages can be tested for", "" ) {
|
||||
TEST_CASE( "Exception messages can be tested for", "[!throws]" ) {
|
||||
using namespace Catch::Matchers;
|
||||
SECTION( "exact match" )
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
|
||||
@@ -196,7 +200,7 @@ TEST_CASE( "Exception messages can be tested for", "" ) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Mismatching exception messages failing the test", "[.][failing]" ) {
|
||||
TEST_CASE( "Mismatching exception messages failing the test", "[.][failing][!throws]" ) {
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "should fail" );
|
||||
REQUIRE_THROWS_WITH( thisThrows(), "expected exception" );
|
||||
|
@@ -36,16 +36,21 @@ using namespace Catch;
|
||||
// REQUIRE( C_A_T_C_H_Context().i() == 42 );
|
||||
//}
|
||||
|
||||
Catch::TestCaseTracking::NameAndLocation makeNAL( std::string const& name ) {
|
||||
return Catch::TestCaseTracking::NameAndLocation( name, Catch::SourceLineInfo() );
|
||||
}
|
||||
|
||||
TEST_CASE( "Tracker", "" ) {
|
||||
|
||||
TrackerContext ctx;
|
||||
ctx.startRun();
|
||||
ctx.startCycle();
|
||||
|
||||
ITracker& testCase = SectionTracker::acquire( ctx, "Testcase" );
|
||||
|
||||
ITracker& testCase = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase.isOpen() );
|
||||
|
||||
ITracker& s1 = SectionTracker::acquire( ctx, "S1" );
|
||||
ITracker& s1 = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1.isOpen() );
|
||||
|
||||
SECTION( "successfully close one section", "" ) {
|
||||
@@ -70,10 +75,10 @@ TEST_CASE( "Tracker", "" ) {
|
||||
|
||||
SECTION( "re-enter after failed section", "" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() == false );
|
||||
|
||||
testCase2.close();
|
||||
@@ -83,13 +88,13 @@ TEST_CASE( "Tracker", "" ) {
|
||||
}
|
||||
SECTION( "re-enter after failed section and find next section", "" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() == false );
|
||||
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
s2.close();
|
||||
@@ -104,7 +109,7 @@ TEST_CASE( "Tracker", "" ) {
|
||||
SECTION( "successfully close one section, then find another", "" ) {
|
||||
s1.close();
|
||||
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() == false );
|
||||
|
||||
testCase.close();
|
||||
@@ -112,13 +117,13 @@ TEST_CASE( "Tracker", "" ) {
|
||||
|
||||
SECTION( "Re-enter - skips S1 and enters S2", "" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() == false );
|
||||
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2b.isOpen() );
|
||||
|
||||
REQUIRE( ctx.completedCycle() == false );
|
||||
@@ -145,13 +150,13 @@ TEST_CASE( "Tracker", "" ) {
|
||||
|
||||
// Need a final cycle
|
||||
ctx.startCycle();
|
||||
ITracker& testCase3 = SectionTracker::acquire( ctx, "Testcase" );
|
||||
ITracker& testCase3 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase3.isOpen() );
|
||||
|
||||
ITracker& s1c = SectionTracker::acquire( ctx, "S1" );
|
||||
ITracker& s1c = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1c.isOpen() == false );
|
||||
|
||||
ITracker& s2c = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2c = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2c.isOpen() == false );
|
||||
|
||||
testCase3.close();
|
||||
@@ -161,7 +166,7 @@ TEST_CASE( "Tracker", "" ) {
|
||||
}
|
||||
|
||||
SECTION( "open a nested section", "" ) {
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
s2.close();
|
||||
@@ -177,7 +182,7 @@ TEST_CASE( "Tracker", "" ) {
|
||||
}
|
||||
|
||||
SECTION( "start a generator", "" ) {
|
||||
IndexTracker& g1 = IndexTracker::acquire( ctx, "G1", 2 );
|
||||
IndexTracker& g1 = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1.isOpen() );
|
||||
REQUIRE( g1.index() == 0 );
|
||||
|
||||
@@ -193,14 +198,14 @@ TEST_CASE( "Tracker", "" ) {
|
||||
|
||||
SECTION( "Re-enter for second generation", "" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() );
|
||||
|
||||
|
||||
IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 );
|
||||
IndexTracker& g1b = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1b.isOpen() );
|
||||
REQUIRE( g1b.index() == 1 );
|
||||
|
||||
@@ -214,7 +219,7 @@ TEST_CASE( "Tracker", "" ) {
|
||||
}
|
||||
}
|
||||
SECTION( "Start a new inner section", "" ) {
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
s2.close();
|
||||
@@ -228,19 +233,19 @@ TEST_CASE( "Tracker", "" ) {
|
||||
|
||||
SECTION( "Re-enter for second generation", "" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() );
|
||||
|
||||
// generator - next value
|
||||
IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 );
|
||||
IndexTracker& g1b = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1b.isOpen() );
|
||||
REQUIRE( g1b.index() == 1 );
|
||||
|
||||
// inner section again
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2b.isOpen() );
|
||||
|
||||
s2b.close();
|
||||
@@ -256,7 +261,7 @@ TEST_CASE( "Tracker", "" ) {
|
||||
}
|
||||
|
||||
SECTION( "Fail an inner section", "" ) {
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
s2.fail();
|
||||
@@ -271,19 +276,19 @@ TEST_CASE( "Tracker", "" ) {
|
||||
|
||||
SECTION( "Re-enter for second generation", "" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, "Testcase" );
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, "S1" );
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() );
|
||||
|
||||
// generator - still same value
|
||||
IndexTracker& g1b = IndexTracker::acquire( ctx, "G1", 2 );
|
||||
IndexTracker& g1b = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1b.isOpen() );
|
||||
REQUIRE( g1b.index() == 0 );
|
||||
|
||||
// inner section again - this time won't open
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2b.isOpen() == false );
|
||||
|
||||
s1b.close();
|
||||
@@ -295,19 +300,19 @@ TEST_CASE( "Tracker", "" ) {
|
||||
|
||||
// Another cycle - now should complete
|
||||
ctx.startCycle();
|
||||
ITracker& testCase3 = SectionTracker::acquire( ctx, "Testcase" );
|
||||
ITracker& testCase3 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase3.isOpen() );
|
||||
|
||||
ITracker& s1c = SectionTracker::acquire( ctx, "S1" );
|
||||
ITracker& s1c = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1c.isOpen() );
|
||||
|
||||
// generator - now next value
|
||||
IndexTracker& g1c = IndexTracker::acquire( ctx, "G1", 2 );
|
||||
IndexTracker& g1c = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1c.isOpen() );
|
||||
REQUIRE( g1c.index() == 1 );
|
||||
|
||||
// inner section - now should open again
|
||||
ITracker& s2c = SectionTracker::acquire( ctx, "S2" );
|
||||
ITracker& s2c = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2c.isOpen() );
|
||||
|
||||
s2c.close();
|
||||
|
@@ -0,0 +1,2 @@
|
||||
// This file is only here to verify (to the extent possible) the self sufficiency of the header
|
||||
#include "internal/catch_test_case_tracker.hpp"
|
@@ -196,13 +196,13 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
|
||||
}
|
||||
|
||||
SECTION( "use-colour", "") {
|
||||
|
||||
|
||||
using Catch::UseColour;
|
||||
|
||||
|
||||
SECTION( "without option", "" ) {
|
||||
const char* argv[] = { "test" };
|
||||
CHECK_NOTHROW( parseIntoConfig( argv, config ) );
|
||||
|
||||
|
||||
REQUIRE( config.useColour == UseColour::Auto );
|
||||
}
|
||||
|
||||
@@ -216,14 +216,14 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
|
||||
SECTION( "yes", "" ) {
|
||||
const char* argv[] = { "test", "--use-colour", "yes" };
|
||||
CHECK_NOTHROW( parseIntoConfig( argv, config ) );
|
||||
|
||||
|
||||
REQUIRE( config.useColour == UseColour::Yes );
|
||||
}
|
||||
|
||||
SECTION( "no", "" ) {
|
||||
const char* argv[] = { "test", "--use-colour", "no" };
|
||||
CHECK_NOTHROW( parseIntoConfig( argv, config ) );
|
||||
|
||||
|
||||
REQUIRE( config.useColour == UseColour::No );
|
||||
}
|
||||
|
||||
@@ -299,9 +299,10 @@ TEST_CASE( "Long strings can be wrapped", "[wrap]" ) {
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 10 ) ).toString() == testString );
|
||||
}
|
||||
SECTION( "Trailing newline" , "" ) {
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef\n" );
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef" );
|
||||
CHECK( Text( "abcdef", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" );
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef\n" );
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" );
|
||||
CHECK( Text( "abcdef\n", TextAttributes().setWidth( 5 ) ).toString() == "abcd-\nef" );
|
||||
}
|
||||
SECTION( "Wrapped once", "" ) {
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 9 ) ).toString() == "one two\nthree\nfour" );
|
||||
@@ -313,16 +314,23 @@ TEST_CASE( "Long strings can be wrapped", "[wrap]" ) {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "With tabs", "" ) {
|
||||
SECTION( "With wrap-before/ after characters", "" ) {
|
||||
std::string testString = "one,two(three) <here>";
|
||||
|
||||
// guide: 1234567890123456789
|
||||
std::string testString = "one two \tthree four five six";
|
||||
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 15 ) ).toString()
|
||||
== "one two three\n four\n five\n six" );
|
||||
SECTION( "No wrapping", "" ) {
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString );
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 24 ) ).toString() == testString );
|
||||
}
|
||||
SECTION( "Wrap before", "" ) {
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 11 ) ).toString() == "one,two\n(three)\n<here>" );
|
||||
}
|
||||
SECTION( "Wrap after", "" ) {
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one,\ntwo\n(thre-\ne)\n<here>" );
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 5 ) ).toString() == "one,\ntwo\n(thr-\nee)\n<her-\ne>" );
|
||||
CHECK( Text( testString, TextAttributes().setWidth( 4 ) ).toString() == "one,\ntwo\n(th-\nree)\n<he-\nre>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
using namespace Catch;
|
||||
|
@@ -37,19 +37,21 @@ TEST_CASE( "toString( has_toString )", "[toString]" ) {
|
||||
}
|
||||
|
||||
// Call the overload
|
||||
TEST_CASE( "toString( has_maker )", "[toString]" ) {
|
||||
TEST_CASE( "toString( has_maker )", "toString]" ) {
|
||||
has_maker item;
|
||||
REQUIRE( Catch::toString( item ) == "StringMaker<has_maker>" );
|
||||
}
|
||||
|
||||
// Call the overload
|
||||
TEST_CASE( "toString( has_maker_and_toString )", "[toString]" ) {
|
||||
TEST_CASE( "toString( has_maker_and_toString )", "[.][toString]" ) {
|
||||
has_maker_and_toString item;
|
||||
REQUIRE( Catch::toString( item ) == "toString( has_maker_and_toString )" );
|
||||
}
|
||||
|
||||
// Vectors...
|
||||
TEST_CASE( "toString( vectors<has_toString )", "[toString]" ) {
|
||||
|
||||
// Don't run this in approval tests as it is sensitive to two phase lookup differences
|
||||
TEST_CASE( "toString( vectors<has_toString )", "[.][toString][!nonportable]" ) {
|
||||
std::vector<has_toString> v(1);
|
||||
// This invokes template<T> toString which actually gives us '{ ? }'
|
||||
REQUIRE( Catch::toString( v ) == "{ {?} }" );
|
||||
@@ -61,7 +63,8 @@ TEST_CASE( "toString( vectors<has_maker )", "[toString]" ) {
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "toString( vectors<has_maker_and_toString )", "[toString]" ) {
|
||||
// Don't run this in approval tests as it is sensitive to two phase lookup differences
|
||||
TEST_CASE( "toString( vectors<has_maker_and_toString )", "[.][toString][!nonportable]" ) {
|
||||
std::vector<has_maker_and_toString> v(1);
|
||||
// Note: This invokes the template<T> toString -> StringMaker
|
||||
REQUIRE( Catch::toString( v ) == "{ StringMaker<has_maker_and_toString> }" );
|
||||
|
10
scripts/approvalTests.py
Normal file → Executable file
10
scripts/approvalTests.py
Normal file → Executable file
@@ -137,15 +137,15 @@ print("Running approvals against executable:")
|
||||
print(" " + cmdPath)
|
||||
|
||||
# Standard console reporter
|
||||
approve("console.std", ["~[c++11]", "--order", "lex"])
|
||||
approve("console.std", ["~[c++11]~[!nonportable]", "--order", "lex"])
|
||||
# console reporter, include passes, warn about No Assertions
|
||||
approve("console.sw", ["~[c++11]", "-s", "-w", "NoAssertions", "--order", "lex"])
|
||||
approve("console.sw", ["~[c++11]~[!nonportable]", "-s", "-w", "NoAssertions", "--order", "lex"])
|
||||
# console reporter, include passes, warn about No Assertions, limit failures to first 4
|
||||
approve("console.swa4", ["~[c++11]", "-s", "-w", "NoAssertions", "-x", "4", "--order", "lex"])
|
||||
approve("console.swa4", ["~[c++11]~[!nonportable]", "-s", "-w", "NoAssertions", "-x", "4", "--order", "lex"])
|
||||
# junit reporter, include passes, warn about No Assertions
|
||||
approve("junit.sw", ["~[c++11]", "-s", "-w", "NoAssertions", "-r", "junit", "--order", "lex"])
|
||||
approve("junit.sw", ["~[c++11]~[!nonportable]", "-s", "-w", "NoAssertions", "-r", "junit", "--order", "lex"])
|
||||
# xml reporter, include passes, warn about No Assertions
|
||||
approve("xml.sw", ["~[c++11]", "-s", "-w", "NoAssertions", "-r", "xml", "--order", "lex"])
|
||||
approve("xml.sw", ["~[c++11]~[!nonportable]", "-s", "-w", "NoAssertions", "-r", "xml", "--order", "lex"])
|
||||
|
||||
if overallResult != 0:
|
||||
print("If these differenecs are expected run approve.py to approve new baselines")
|
||||
|
0
scripts/approve.py
Normal file → Executable file
0
scripts/approve.py
Normal file → Executable file
56
scripts/benchmarkRunner.py
Executable file
56
scripts/benchmarkRunner.py
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess, os, sys
|
||||
import xml.etree.ElementTree as ET
|
||||
from collections import defaultdict
|
||||
from statistics import median, stdev
|
||||
from datetime import datetime
|
||||
|
||||
def get_commit_hash():
|
||||
res = subprocess.run('git rev-parse HEAD'.split(), check=True, stdout=subprocess.PIPE, universal_newlines=True)
|
||||
return res.stdout.strip()
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print('Usage: {} benchmark-binary'.format(sys.argv[0]))
|
||||
exit(1)
|
||||
|
||||
|
||||
num_runs = 10
|
||||
data = defaultdict(list)
|
||||
|
||||
|
||||
def parse_file(file):
|
||||
|
||||
def recursive_search(node):
|
||||
if node.tag == 'TestCase':
|
||||
results = node.find('OverallResult')
|
||||
time = results.get('durationInSeconds')
|
||||
data[node.get('name')].append(float(time))
|
||||
elif node.tag in ('Group', 'Catch'):
|
||||
for child in node:
|
||||
recursive_search(child)
|
||||
|
||||
tree = ET.parse(file)
|
||||
recursive_search(tree.getroot())
|
||||
|
||||
def run_benchmarks(binary):
|
||||
call = [binary] + '-d yes -r xml -o'.split()
|
||||
for i in range(num_runs):
|
||||
file = 'temp{}.xml'.format(i)
|
||||
print('Run number {}'.format(i))
|
||||
subprocess.run(call + [file])
|
||||
parse_file(file)
|
||||
# Remove file right after parsing, because benchmark output can be big
|
||||
os.remove(file)
|
||||
|
||||
|
||||
# Run benchmarks
|
||||
run_benchmarks(sys.argv[1])
|
||||
|
||||
result_file = '{:%Y-%m-%dT%H-%M-%S}-{}.result'.format(datetime.now(), get_commit_hash())
|
||||
|
||||
|
||||
print('Writing results to {}'.format(result_file))
|
||||
with open(result_file, 'w') as file:
|
||||
for k in sorted(data):
|
||||
file.write('{}: median: {} (s), stddev: {} (s)\n'.format(k, median(data[k]), stdev(data[k])))
|
1
scripts/fixTrailingWhitespace.py → scripts/fixWhitespace.py
Normal file → Executable file
1
scripts/fixTrailingWhitespace.py → scripts/fixWhitespace.py
Normal file → Executable file
@@ -24,6 +24,7 @@ def fixFile( path ):
|
||||
changed = 0
|
||||
for line in f:
|
||||
trimmed = line.rstrip() + "\n"
|
||||
trimmed = trimmed.replace('\t', ' ')
|
||||
if trimmed != line:
|
||||
changed = changed +1
|
||||
lines.append( trimmed )
|
0
scripts/generateSingleHeader.py
Normal file → Executable file
0
scripts/generateSingleHeader.py
Normal file → Executable file
0
scripts/majorRelease.py
Normal file → Executable file
0
scripts/majorRelease.py
Normal file → Executable file
0
scripts/minorRelease.py
Normal file → Executable file
0
scripts/minorRelease.py
Normal file → Executable file
0
scripts/patchRelease.py
Normal file → Executable file
0
scripts/patchRelease.py
Normal file → Executable file
@@ -75,6 +75,8 @@ class Version:
|
||||
f.write( line + "\n" )
|
||||
|
||||
def updateReadmeFile(self):
|
||||
versionParser = re.compile( r'\*v\d+\.\d+\.\d+\*' )
|
||||
downloadParser = re.compile( r'<a href=\"https://github.com/philsquared/Catch/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
|
||||
f = open( readmePath, 'r' )
|
||||
lines = []
|
||||
for line in f:
|
||||
@@ -82,8 +84,7 @@ class Version:
|
||||
f.close()
|
||||
f = open( readmePath, 'w' )
|
||||
for line in lines:
|
||||
if line.startswith( "*v" ):
|
||||
f.write( '*v{0}*\n'.format( self.getVersionString() ) )
|
||||
else:
|
||||
f.write( line + "\n" )
|
||||
line = versionParser.sub( '*v{0}*'.format(self.getVersionString()), line)
|
||||
line = downloadParser.sub( r'<a href="https://github.com/philsquared/Catch/releases/download/v{0}/catch.hpp">'.format(self.getVersionString()) , line)
|
||||
f.write( line + "\n" )
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user