Compare commits

...

107 Commits

Author SHA1 Message Date
6860c8def0 v1.12.2 2018-05-14 15:15:28 +02:00
3255ee6312 Add missing <cassert> includes
Until recently we were probably getting it from some transitive
include, but it broke. Because all files should include what
they use anyway, adding `#include <cassert>` to all files that
use `assert()` without including it is the best solution.

Fixes #1249
2018-04-22 20:36:41 +02:00
74effafca7 v1.12.1 2018-03-02 21:22:10 +01:00
7d0cfd27ce Fix deprecation warning in ~ScopedMessage 2018-02-25 21:29:01 +01:00
3fe4d394a5 Wrap all uses in min and max in extra parentheses
This prevents `min` and `max` macros from windows headers (!@#$)
from breaking compilation.

Related to #1191
2018-02-23 13:06:52 +01:00
b97e9a2f8b Update path for catch-classic vcpkg's portfile 2018-01-12 11:06:09 +01:00
34f7cfe046 v1.12.0 2018-01-12 09:59:21 +01:00
07b9bda1d2 Revert backport of new evaluate layer to fix C++98 compilation
The backport fixed some bugs (ie #981), but caused strict C++98
(and MSVC 9) compilers to fail. This means that we will
reintroduce some issues but get back compatibility with obsolete
compilers. People using newer ones can keep using Catch2.

This reverts commit b6e7c9bd7a.
This reverts commit b7bd52cc98.

Should fix #1103
2017-12-07 20:02:47 +01:00
84e8b696b1 Include Info messages in xml reporter even without -s 2017-12-06 16:11:12 +00:00
2d91035404 Update assertions.md
scale more detailed explained; have to be adapted to PR #1068 if necessary
2017-11-01 13:32:08 +01:00
2a3606f8e3 v1.11.0 2017-10-31 13:55:48 +01:00
a6cf19abff Make Approx::margin inclusive
Fixes #952, related to #980
2017-10-30 21:33:29 +01:00
06586b7180 Update test-cases-and-sections.md
some clarification and typo correction
2017-10-26 13:57:18 +02:00
93b3d2cb8f Fix very minor typo
it's -> its
2017-10-24 20:00:27 +02:00
a90473df28 Update build-systems.md
typo correction
2017-10-24 19:59:59 +02:00
c9d9699ca8 adds flushes to the output stream of teamcity reporter, making the test output more responsive. 2017-10-17 16:42:05 +02:00
296955c437 RandomNumberGenerator::result_type should be unsigned (#1050)
`result_type` must be unsigned:
http://en.cppreference.com/w/cpp/concept/UniformRandomBitGenerator

Using a signed type causes an infinite loop working with MS Visual Studio 2017, targetting: v140, WindowsTargetPlatformVersion 10.0.15063.0, Debug, x64
2017-10-15 18:30:40 +02:00
664cbf702c added PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS option 2017-10-15 17:58:39 +02:00
fb6700df54 Fix documentation crosslink in configuration.md 2017-10-14 08:36:44 +02:00
da6c2a6914 Fixed expansion of _FALSE binary expression
- see #1051
2017-10-13 19:44:20 +01:00
9c07718b5f Update handling of __JETBRAINS_IDE__ macro
1. Use it to conditionally define CATCH_INTERNAL_CONFIG_COUNTER, not
   CATCH_CONFIG_COUNTER, as __JETBRAINS_IDE__ is similar to
   compiler-provided macros, not to user-provided ones.

2. Since __COUNTER__ will work starting with CLion 2017.3, use it
   when possible (and hopefully remove this check altogether
   at some point).
2017-09-07 18:00:04 +02:00
5ca44b6872 Minor - added header-only flag in conan
See header-only guidelines: 
http://conanio.readthedocs.io/en/latest/howtos/header_only.html?highlight=header%20only
Its borderline cosmetic, but it does have a purpose.
2017-08-28 12:18:54 +02:00
a04bd6d436 Remove duplicate CLI option
The "use-colour" option was accidentally duplicated as part of commit
feaf355 (Implemented libidentify support).
2017-08-28 12:16:23 +02:00
784f6dfb34 Fix updateVcpkgPackage 2017-08-27 11:43:55 +02:00
7818e2666d v1.10.0 2017-08-26 15:34:18 +02:00
cd30dd1a70 Workaround raw string literal bug in VS2017 2017-08-26 15:14:27 +02:00
8e8c0c1675 Tweaked how failedButOk assertions are recorded
- fixes issue where sections in !shouldfail or !mayfail test cases that have failing assertions where marked as failed instead of failedButOk
2017-08-25 11:37:49 +01:00
b6e7c9bd7a Specialise removeConst for nullptr 2017-08-24 23:07:44 +02:00
180d9242f5 Suppress more signed/ unsigned mismatches during Evaluator calls on MSVC 2017-08-24 23:07:03 +02:00
b7bd52cc98 Cherry-picked "evaluate" refactoring from dev-modernize branch
- fixed up NULL comparisons to allow for NULL being a long
- should address #981
2017-08-24 23:07:03 +02:00
b07a2bdf87 Refactor release scripts, automatically update Wandbox on release 2017-08-24 21:59:06 +02:00
c03e8fce92 Explicitly ignore return value of getchar
This silences MSVC warning about ignored return value
2017-08-22 22:06:37 +02:00
27640a5a96 Added Clara and TextFlowCpp to open source users 2017-08-17 10:49:56 +01:00
dd3867bbcd Create CODE_OF_CONDUCT.md 2017-08-17 07:45:12 +01:00
387f8d254d Removed unnecessary single quotes 2017-08-15 19:41:46 +01:00
c65eccd68e Added --libidentify and --wait-for-keypress to docs 2017-08-15 19:39:38 +01:00
61c5675c11 Removed inadvertent use of auto merged from dev-modernise 2017-08-15 19:34:10 +01:00
70e4af9d44 Implemented wait-for-keypress option 2017-08-15 14:12:11 +01:00
8f41bdb92d Add open-source user 2017-08-13 17:55:50 +02:00
7fa5d9ca94 Removed redundant processName argument from libIdentify call 2017-08-11 22:03:09 +01:00
feaf355489 Implemented libidentify support
- see https://github.com/janwilmans/LibIdentify
2017-08-11 19:55:55 +01:00
2ce6c74f8f v1.9.7 2017-08-11 00:01:20 +02:00
9688891868 Fix issue with fatal errors and non-failing assertions
Fixes #990
2017-08-10 21:44:54 +02:00
4f21bb72ff Add tests for #961 2017-08-10 21:38:07 +02:00
b435e0d7c7 Make default reporter configurable at compile time
Closes #978
2017-08-10 16:45:38 +02:00
ba0a09fd9e Update documentation with changes from 7e4038d 2017-08-10 16:43:17 +02:00
7e4038d848 Capture std::clog writes and combine them with std::cerr writes (#989)
This also introduces Catch::clog() method to allow embedded targets
to override std::clog usage with their own stream (presumably null-sink),
similarly to how Catch::cout() and Catch::cerr() are used.

Fixes #989
2017-08-09 15:28:40 +02:00
92d714ee12 Update updateVcpkgPackage script for the new port format 2017-08-08 23:04:39 +02:00
705a1bf527 Add wandbox to release process documentation
Also some formatting and wording changes.
2017-08-08 23:04:10 +02:00
d5613fb18a Update matchers docs to reflect namespace usage 2017-08-03 19:11:21 +02:00
62875c857e Add a landing page link to wandbox with catch preloaded
Idea shamelessly stolen from nlohmann/json
2017-08-01 23:45:35 +02:00
ec2074e558 Adding more flexibility into the cmake catch parsing script (#971)
* Adding more flexibility into the cmake catch parsing script
2017-08-01 17:33:53 +02:00
7575749e56 Fix compilation error on older compilers 2017-08-01 17:21:06 +02:00
8a2ff20982 Address some of the Resharper finds for Catch 1
Closes #957 as the other findings are mostly noise that is pointless
to fix in a branch that will be soon EoLd.
2017-07-31 12:31:45 +02:00
d3377c791d Initial support for native IBM i ILE C++ (#976)
* - Initial support for native IBM i ILE C++

Signed-off-by: zeromem <zeromem2@gmail.com>
2017-07-31 10:47:42 +02:00
c5dfa73d56 Disable build broken by travis changes
It should be reenabled later, but I don't have time to investigate
right now.
2017-07-29 08:45:52 +02:00
d65091fa06 Fix for JUnit reporter when using dynamically generated sections (#963)
* BySectionInfo should also take into account the section name in addition to the source code line
2017-07-23 17:13:44 +02:00
7a22bad763 Addressed some static analysis warnings
Based on findings in #957
2017-07-19 09:50:08 +02:00
8ebe94ca2e Added NOLINT annotations to selectively suppress clang_tidy warnings 2017-07-10 18:43:07 +01:00
106d7e2a74 Initialize JunitReporter::unexpectedExceptions in constructor
This is not needed for correctness, but will prevent PVS warning
from triggering, and there is basically no performance difference.

Closes #951
2017-07-10 10:30:17 +02:00
a53ea30723 Eliminate some work when results won't be reported. 2017-07-07 01:34:12 +02:00
8d380a7399 added 'args' argument parser library 2017-07-05 15:55:28 +02:00
3083de9ea6 Fix typo in README 2017-07-05 15:54:38 +02:00
431e8d06e7 Added survey monkey link 2017-07-04 09:10:36 +01:00
6f32db35af Update tutorial.md 2017-06-28 20:54:31 +02:00
7013e388f7 #926 Update Conan test version by release
Signed-off-by: Uilian Ries <uilianries@gmail.com>
2017-06-28 16:45:42 +01:00
0270afb21b Updated license 2017-06-28 16:44:46 +01:00
df7c5622b9 Merge branch 'feature/conan' of https://github.com/uilianries/Catch 2017-06-27 11:48:55 +01:00
ee67ac6b7c v1.9.6 2017-06-27 12:21:48 +02:00
8a14af701e If --list-extra-info is specified with --list-test-names-only, only output one list 2017-06-25 17:12:29 +02:00
07c6bfc3b9 --extra-info -> --list-extra-info, behaves like other --list-* flags 2017-06-25 17:12:29 +02:00
616f7235ef add --extra-info flag
this will add line info to test lists, and test descriptions to the long
form of the test list
2017-06-25 17:12:29 +02:00
396ecf6021 Cache std::ostringstream between assertions.
This is not thread safe, but I think that was already true of Catch.
The construction/destruction of the std::ostringstream is where the
vast majority of time is spent per assertion.  A simple test of
100000000 CHECK()s is reduced from around 60s to 7.4s
2017-06-25 15:53:59 +02:00
3491804598 #926 Update Conan version by release
- Update release scripts to increment Conan version

Signed-off-by: Uilian Ries <uilianries@gmail.com>
2017-06-23 16:03:36 -03:00
6234e3d54d #926 Conan recipe for Catch single header
- Insert catch.hpp (single header) to package
- Copy BDDTests and TrickyTest to validate Catch package

Signed-off-by: Uilian Ries <uilianries@gmail.com>
2017-06-23 10:34:56 -03:00
a6cdcd43aa Added "How to test changes in PR" section to documentation
Also linked it from PR template.

Closes #936
2017-06-22 18:56:10 +02:00
dcab8a5971 Performance improvement in AssertionInfo.
By using char const * instead of std::string we avoid significant
copying per assertion.  In a simple loop with 10000000 CHECKS on
my system, this reduces the run time from 9.8s to 6s.
2017-06-22 18:03:47 +02:00
017a63da62 v1.9.5 2017-06-15 13:08:26 +02:00
b90d0b7267 Disable deprecation warning of std::uncaught_exception
We might prefer to use `std::uncaught_exceptions` in the future, but I
would prefer not to bring in more configuration into Catch Classic

Closes #927
2017-06-15 11:43:31 +02:00
efba988ccc Fix how GCC version is detected when checking for __COUNTER__
Fixes #928
2017-06-13 18:20:59 +02:00
004228efb2 Merge pull request #855 from kainjow/objc-tostring-link
Fix Catch::toString() linker error when main() is compiled as C++
2017-06-11 23:06:38 +01:00
e0aaba6cf8 Actually link #923 from the documentation 2017-06-06 16:46:46 +02:00
a09bef23ed Refer to #923 in reporter documentation 2017-06-06 16:43:14 +02:00
3e018ef131 Add link to external gcov/lcov example to documentation
An alternate take on #916, that better slots into the existing
documentation.

Closes #916
2017-06-04 12:17:59 +02:00
adb66f55a7 Don't include warning headers from catch_xmlwriter.hpp
This prevents Catch from disabling `Wpadded` for Clang inside test files
(files that do not define either `CATCH_CONFIG_MAIN` or
`CATCH_CONFIG_RUNNER`).

catch_suppress_warnings.h and catch_reenable_warnings.h should be
included only once*, so that the stitching script includes them as the
first and last header respectively, since it only includes each header
once. This caused a bug, where the first one was included properly, but
the second one was included prematurely, from catch_xmlwriter.hpp, and
thus was guarded by `CATCH_IMPL`.

* At least until the stitching script is changed to accomodate common
warning disabling header.

Fixes #871
2017-06-02 19:10:57 +02:00
377c9a746d Cosmetic fixes (whitespace and spelling) 2017-05-27 14:42:54 +02:00
ea48ae0f75 Add test for #914 (stringify truthy exprs in standard way) 2017-05-27 14:42:05 +02:00
2d1739b429 ExpressionLhs reconstruction based on value, not truthiness (#914)
Types which are truthy, but have more information than the truthiness in their string conversion were showing up as 'true' or 'false' instead of showing the underlying type's string value.
2017-05-27 14:09:43 +02:00
1c59034be4 Merge pull request #911 from dvirtz/master
CTest integration script enhancements
2017-05-27 13:52:55 +02:00
52a84788e0 Add Inscopix to commercial users
Closes #918
2017-05-27 12:23:35 +02:00
3e328f55fc Merge pull request #913 from Carrotstrip/master
fixed spelling error in tutorial.md
2017-05-21 11:17:25 +02:00
b18e67522f fixed spelling error 2017-05-20 15:10:42 -04:00
4b086bd5b5 added target name to test name and labels 2017-05-18 16:00:18 +03:00
aac594aae3 add option to print debug messages 2017-05-18 15:53:35 +03:00
a49fa0edbe use absolute path to test files - accroding to CMake docs EXISTS behavior is well-defined only for full paths. 2017-05-18 15:51:44 +03:00
d271683c14 Added release process notes/checklist/explanation 2017-05-16 21:33:58 +02:00
0bb8e1247e Merge branch 'master' of https://github.com/awglyde/Catch 2017-05-16 16:09:51 +02:00
32d97caf42 Fixed missing ` in tag documentation 2017-05-16 15:45:44 +02:00
bc93b29789 Expanded tag documentation
It now mentions that most characters are valid as part of tag and other
details.

Closes  #909
2017-05-16 15:28:53 +02:00
df5cf2d323 Minor fixup in updateVcpkgPackage.py 2017-05-16 14:34:55 +02:00
b62c0256b2 Merge branch 'master' of https://github.com/philsquared/Catch 2017-05-16 14:34:27 +02:00
1ea84cb734 Expanded logging documentation
Closes #884
2017-05-16 14:34:20 +02:00
2a5d3736e8 Merge pull request #908 from pJunger/patch-1
Typo: Added namespace in method testCaseEnded
2017-05-16 14:05:31 +02:00
d4e0b1d093 Added namespace in method testCaseEnded
Did not compile as is
2017-05-14 14:11:47 +02:00
e8b31108d6 Fix Catch::toString() linker error when main() is compiled as C++
Fixes #278
2017-03-14 11:54:14 -07:00
d8f45cd5f1 changing tabs to spaces 2017-03-06 10:55:00 -05:00
3afd077b55 teamcity reporter should time durations explicitly 2017-03-06 10:35:03 -05:00
90 changed files with 1896 additions and 529 deletions

View File

@ -2,6 +2,9 @@
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.
Before submitting a PR you should probably read the contributor documentation
at docs/contributing.md. It will tell you how to properly test your changes.
-->

View File

@ -192,15 +192,15 @@ matrix:
env: COMPILER='g++-6' BUILD_TYPE='Debug' CPP14=1
# 4b/ Linux C++14 Clang builds
- os: linux
compiler: clang
addons: *clang38
env: COMPILER='clang++-3.8' BUILD_TYPE='Release' CPP14=1
- os: linux
compiler: clang
addons: *clang38
env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' CPP14=1
# - os: linux
# compiler: clang
# addons: *clang38
# env: COMPILER='clang++-3.8' BUILD_TYPE='Release' CPP14=1
#
# - os: linux
# compiler: clang
# addons: *clang38
# env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' CPP14=1
# 5/ OSX Clang Builds

View File

@ -59,6 +59,7 @@ set(TEST_SOURCES
${SELF_TEST_DIR}/CmdLineTests.cpp
${SELF_TEST_DIR}/CompilationTests.cpp
${SELF_TEST_DIR}/ConditionTests.cpp
${SELF_TEST_DIR}/DecompositionTests.cpp
${SELF_TEST_DIR}/EnumToString.cpp
${SELF_TEST_DIR}/ExceptionTests.cpp
${SELF_TEST_DIR}/GeneratorTests.cpp

46
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at github@philnash.me. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -3,8 +3,9 @@
[![Github Releases](https://img.shields.io/github/release/philsquared/catch.svg)](https://github.com/philsquared/catch/releases)
[![Build Status](https://travis-ci.org/philsquared/Catch.svg?branch=master)](https://travis-ci.org/philsquared/Catch)
[![Build status](https://ci.appveyor.com/api/projects/status/hrtk60hv6tw6fght/branch/master?svg=true)](https://ci.appveyor.com/project/philsquared/catch/branch/master)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/jG7wnHX9VAcxpSHy)
<a href="https://github.com/philsquared/Catch/releases/download/v1.9.4/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.12.2/catch.hpp">The latest, single header, version can be downloaded directly using this link</a>
## What's the Catch?
@ -21,3 +22,7 @@ This documentation comprises these three parts:
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/philsquared/Catch/issues)
* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)
* See [who else is using Catch](docs/opensource-users.md)
## Help us out
We're currently running [a survey](https://www.surveymonkey.co.uk/r/TLLYQJW) to help us shape the future of Catch.
Please take a few moments to fill it out (there's only ten questions).

19
conanfile.py Normal file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env python
from conans import ConanFile
class CatchConan(ConanFile):
name = "Catch"
version = "1.12.2"
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
author = "philsquared"
generators = "cmake"
exports_sources = "single_include/*"
url = "https://github.com/philsquared/Catch"
license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt"
def package(self):
self.copy(pattern="catch.hpp", src="single_include", dst="include")
def package_id(self):
self.info.header_only()

View File

@ -25,13 +25,39 @@
# #
# include(ParseAndAddCatchTests) #
# ParseAndAddCatchTests(${PROJECT_NAME}) #
# #
# The following variables affect the behavior of the script: #
# #
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
# -- enables debug messages #
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
# -- adds fixture class name to the test name #
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
# -- adds cmake target name to the test name #
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
# #
#==================================================================================================#
cmake_minimum_required(VERSION 2.8.8)
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
function(PrintDebugMessage)
if(PARSE_CATCH_TESTS_VERBOSE)
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
endif()
endfunction()
# This removes the contents between
# - block comments (i.e. /* ... */)
# - full line comments (i.e. // ... )
# - block comments (i.e. /* ... */)
# - full line comments (i.e. // ... )
# contents have been read into '${CppCode}'.
# !keep partial line comments
function(RemoveComments CppCode)
@ -47,10 +73,13 @@ endfunction()
# Worker function
function(ParseFile SourceFile TestTarget)
# According to CMake docs EXISTS behavior is well-defined only for full paths.
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
if(NOT EXISTS ${SourceFile})
message(WARNING "Cannot find source file: ${SourceFile}")
return()
endif()
PrintDebugMessage("parsing ${SourceFile}")
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
# Remove block and fullline comments
@ -59,6 +88,15 @@ function(ParseFile SourceFile TestTarget)
# Find definition of test names
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
)
endif()
foreach(TestName ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
@ -86,30 +124,62 @@ function(ParseFile SourceFile TestTarget)
if("${TestType}" STREQUAL "SCENARIO")
set(Name "Scenario: ${Name}")
endif()
if(TestFixture)
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
set(CTestName "${TestFixture}:${Name}")
else()
set(CTestName "${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
set(CTestName "${TestTarget}:${CTestName}")
endif()
# add target to labels to enable running all tests added from this target
set(Labels ${TestTarget})
if(TestStringsLength EQUAL 2)
list(GET TestStrings 1 Tags)
string(TOLOWER "${Tags}" Tags)
# remove target from labels if the test is hidden
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
list(REMOVE_ITEM Labels ${TestTarget})
endif()
string(REPLACE "]" ";" Tags "${Tags}")
string(REPLACE "[" "" Tags "${Tags}")
endif()
# Add the test and set its properties
add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Tags}")
list(APPEND Labels ${Tags})
list(FIND Labels "!hide" IndexOfHideLabel)
set(HiddenTagFound OFF)
foreach(label ${Labels})
string(REGEX MATCH "^!hide|^\\." result ${label})
if(result)
set(HiddenTagFound ON)
break()
endif(result)
endforeach(label)
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound})
PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
else()
PrintDebugMessage("Adding test \"${CTestName}\"")
if(Labels)
PrintDebugMessage("Setting labels to ${Labels}")
endif()
# Add the test and set its properties
add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Labels}")
endif()
endforeach()
endfunction()
# entry point
function(ParseAndAddCatchTests TestTarget)
PrintDebugMessage("Started parsing ${TestTarget}")
get_target_property(SourceFiles ${TestTarget} SOURCES)
PrintDebugMessage("Found the following sources: ${SourceFiles}")
foreach(SourceFile ${SourceFiles})
ParseFile(${SourceFile} ${TestTarget})
endforeach()
PrintDebugMessage("Finished parsing ${TestTarget}")
endfunction()

View File

@ -17,7 +17,7 @@ Fine tuning:
Running:
* [Command line](command-line.md)
* [Build systems](build-systems.md)
* [CI and Build system integration](build-systems.md)
FAQ:
* [Why are my tests slow to compile?](slow-compiles.md)

View File

@ -57,7 +57,7 @@ This way `Approx` is constructed with reasonable defaults, covering most simple
* __epsilon__ - epsilon serves to set the percentage by which a result can be erroneous, before it is rejected. By default set to `std::numeric_limits<float>::epsilon()*100`.
* __margin__ - margin serves to set the the absolute value by which a result can be erroneous before it is rejected. By default set to `0.0`.
* __scale__ - scale serves to adjust the base for comparison used by epsilon, can be used when By default set to `1.0`.
* __scale__ - scale serves to adjust the base for comparison used by epsilon. By default set to `1.0`.
#### epsilon example
```cpp
@ -77,7 +77,7 @@ Approx target = Approx(100).margin(5);
```
#### scale
Scale can be useful if the computation leading to the result worked on different scale, than is used by the results (and thus expected errors are on a different scale than would be expected based on the results alone).
Scale can be useful if the computation leading to the result worked on different scale, than is used by the results (and thus expected errors are on a different scale than would be expected based on the results alone), i.e. an additional not scaling difference will be accepted, because | current - target | < eps_rel + eps_abs (while eps_rel = max(current, target) * epsilon, eps_abs = epsilon * scale) will be checked.
## Exceptions
@ -138,4 +138,4 @@ For more details, along with workarounds, see the section on [the limitations pa
---
[Home](Readme.md)
[Home](Readme.md)

View File

@ -1,4 +1,4 @@
# Integration with build systems
# CI and build system integration
Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.
@ -15,7 +15,7 @@ The XML Reporter writes in an XML format that is specific to Catch.
The advantage of this format is that it corresponds well to the way Catch works (especially the more unusual features, such as nested sections) and is a fully streaming format - that is it writes output as it goes, without having to store up all its results before it can start writing.
The disadvantage is that, being specific to Catch, no existing build servers understand the format natively. It can be used as input to an XSLT transformation that could covert it to, say, HTML - although this loses the streaming advantage, of course.
The disadvantage is that, being specific to Catch, no existing build servers understand the format natively. It can be used as input to an XSLT transformation that could convert it to, say, HTML - although this loses the streaming advantage, of course.
## JUnit Reporter
```-r junit```
@ -134,6 +134,10 @@ TEST_CASE("Test3", "[a][b][c]") {
```
would be registered as 3 tests, `Test1`, `Test2` and `Test3`, and ctest 4 labels would be created, `a`, `b`, `c` and `unit`.
### CodeCoverage module (GCOV, LCOV...)
If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/fkromer/catch_cmake_coverage
---
[Home](Readme.md)
[Home](Readme.md)

View File

@ -27,6 +27,8 @@ Click one of the followings links to take you straight to that option - or scrol
<a href="#listing-available-tests-tags-or-reporters"> ` --list-reporters`</a><br />
<a href="#order"> ` --order`</a><br />
<a href="#rng-seed"> ` --rng-seed`</a><br />
<a href="#libidentify"> ` --libidentify`</a><br />
<a href="#wait-for-keypress"> ` --wait-for-keypress`</a><br />
</br>
@ -213,6 +215,20 @@ Alternatively if the keyword ```time``` is provided then the result of calling `
In either case the actual value for the seed is printed as part of Catch's output so if an issue is discovered that is sensitive to test ordering the ordering can be reproduced - even if it was originally seeded from ```std::time(0)```.
<a id="libidentify"></a>
## Identify framework and version according to the libIdentify standard
<pre>--libidentify</pre>
See [The LibIdentify repo for more information and examples](https://github.com/janwilmans/LibIdentify).
<a id="wait-for-keypress"></a>
## Wait for key before continuing
<pre>--wait-for-keypress &lt;start|exit|both&gt;</pre>
Will cause the executable to print a message and wait until the return/ enter key is pressed before continuing -
either before running any tests, after running all tests - or both, depending on the argument.
<a id="usage"></a>
## Usage
<pre>-h, -?, --help</pre>

View File

@ -13,4 +13,4 @@ fact then please let us know - either directly, via a PR or
- Bloomberg
- NASA
- [Inscopix Inc.](https://www.inscopix.com/)

View File

@ -43,12 +43,19 @@ By default a console width of 80 is assumed but this can be controlled by defini
CATCH_CONFIG_NOSTDOUT
Catch does not use ```std::cout``` and ```std::cerr``` directly but gets them from ```Catch::cout()``` and ```Catch::cerr()``` respectively. If the above identifier is defined these functions are left unimplemented and you must implement them yourself. Their signatures are:
Catch does not use ```std::cout```, ```std::cerr``` and ```std::clog``` directly but gets them from ```Catch::cout()```, ```Catch::cerr()``` and ```Catch::clog``` respectively. If the above identifier is defined these functions are left unimplemented and you must implement them yourself. Their signatures are:
std::ostream& cout();
std::ostream& cerr();
std::ostream& clog();
This can be useful on certain platforms that do not provide ```std::cout``` and ```std::cerr```, such as certain embedded systems.
This can be useful on certain platforms that do not provide the standard iostreams, such as certain embedded systems.
# Default reporter
CATCH_CONFIG_DEFAULT_REPORTER <reporter>
The default reporter (reporter used when no reporters are explicitly specified) can be overriden during compilation time by using the above macro. Note that desired value of the macro is a C string and quotes have to be escaped during compilation: `clang++ test.cpp -DCATCH_CONFIG_DEFAULT_REPORTER=\"xml\"`.
# C++ conformance toggles
@ -100,6 +107,7 @@ TEST_CASE ("Error in streamable check") {
CATCH_CONFIG_FAST_COMPILE // Sacrifices some (rather minor) features for compilation speed
CATCH_CONFIG_POSIX_SIGNALS // Enable handling POSIX signals
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support.
@ -116,6 +124,10 @@ Defining this flag speeds up compilation of test files by ~20%, by making 2 chan
`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined, in all translation units that are linked into single test binary, or the behaviour of setting `-b` flag and throwing unexpected exceptions will be unpredictable.
## `CATCH_CONFIG_DISABLE_STRINGIFICATION`
This toggle enables a workaround for VS 2017 bug. For details see
[known limitations](limitations.md#visual-studio-2017----raw-string-literal-in-assert-fails-to-compile).
# Windows header clutter
On Windows Catch includes `windows.h`. To minimize global namespace clutter in the implementation file, it defines `NOMINMAX` and `WIN32_LEAN_AND_MEAN` before including it. You can control this behaviour via two macros:

View File

@ -18,8 +18,8 @@ Ongoing development is currently on _master_. At some point an integration branc
_Users_ of Catch primarily use the single header version. _Maintainers_ should work with the full source (which is still,
primarily, in headers). This can be found in the `include` folder. There are a set of test files, currently under
`projects/SelfTest`. The test app can be built via CMake from the `CMakeLists.txt` file in the root, or you can generate
project files for Visual Studio, XCode, and others (instructions in the `projects` folder). If you have access to CLion
that can work with the CMake file directly.
project files for Visual Studio, XCode, and others (instructions in the `projects` folder). If you have access to CLion,
it can work with the CMake file directly.
As well as the runtime test files you'll also see a `SurrogateCpps` directory under `projects/SelfTest`.
This contains a set of .cpp files that each `#include` a single header.
@ -34,6 +34,25 @@ __When submitting a pull request please do not include changes to the single inc
as these are managed by the scripts!__
## Testing your changes
Obviously all changes to Catch's code should be tested. If you added new functionality, you should add tests covering and
showcasing it. Even if you have only made changes to Catch internals (ie you implemented some performance improvements),
you should still test your changes.
This means 3 things
* Compiling Catch's SelfTest project -- code that does not compile is evidently incorrect. Obviously, you are not expected to
have access to all compilers and platforms Catch supports, Catch's CI pipeline will compile your code using supported compilers
once you open a PR.
* Running the SelfTest binary. There should be no unexpected failures on simple run.
* Running Catch's approval tests. Approval tests compare current output of the SelfTest binary in various configurations against
known good output. Catch's repository provides utility scripts `approvalTests.py` to help you with this. It needs to be passed
the SelfTest binary compiled with your changes, like so: `$ ./scripts/approvalTests.py clang-build/SelfTest`. The output should
be fairly self-explanatory.
*this document is still in-progress...*
---

View File

@ -31,7 +31,7 @@ struct MyListener : Catch::TestEventListenerBase {
// Perform some setup before a test case is run
}
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) override {
virtual void testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override {
// Tear-down after a test case is run
}
};
@ -70,4 +70,4 @@ just look in the source code to see what fields are available.
---
[Home](Readme.md)
[Home](Readme.md)

View File

@ -50,6 +50,38 @@ Both of these solutions have their problems, but should let you wring parallelis
## 3rd party bugs
This section outlines known bugs in 3rd party components (this means compilers, standard libraries, standard runtimes).
### Visual Studio 2017 -- raw string literal in assert fails to compile
There is a known bug in Visual Studio 2017 (VC 15), that causes compilation error when preprocessor attempts to stringize a raw string literal (`#` preprocessor is applied to it). This snippet is sufficient to trigger the compilation error:
```cpp
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
TEST_CASE("test") {
CHECK(std::string(R"("\)") == "\"\\");
}
```
Catch provides a workaround, it is possible to disable stringification of original expressions by defining `CATCH_CONFIG_DISABLE_STRINGIFICATION`:
```cpp
#define CATCH_CONFIG_FAST_COMPILE
#define CATCH_CONFIG_DISABLE_STRINGIFICATION
#include "catch.hpp"
TEST_CASE("test") {
CHECK(std::string(R"("\)") == "\"\\");
}
```
_Do note that this changes the output somewhat_
```
catchwork\test1.cpp(6):
PASSED:
CHECK( Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION )
with expansion:
""\" == ""\"
```
### Visual Studio 2013 -- do-while loop withing range based for fails to compile (C2059)
There is a known bug in Visual Studio 2013 (VC 12), that causes compilation error if range based for is followed by an assertion macro, without enclosing the block in braces. This snippet is sufficient to trigger the error
```cpp

View File

@ -1,6 +1,32 @@
# Logging macros
Additional messages can be logged during a test case.
Additional messages can be logged during a test case. Note that the messages are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
```cpp
TEST_CASE("Foo") {
INFO("Test case start");
for (int i = 0; i < 2; ++i) {
INFO("The number is " << i);
CHECK(i == 0);
}
}
TEST_CASE("Bar") {
INFO("Test case start");
for (int i = 0; i < 2; ++i) {
INFO("The number is " << i);
CHECK(i == i);
}
CHECK(false);
}
```
When the `CHECK` fails in the "Foo" test case, then two messages will be printed.
```
Test case start
The number is 1
```
When the last `CHECK` fails in the "Bar" test case, then only one message will be printed: `Test case start`.
## Streaming macros

View File

@ -13,6 +13,7 @@ which consists of either a single matcher or one or more matchers combined using
For example, to assert that a string ends with a certain substring:
```c++
using Catch::Matchers::EndsWith; // or Catch::EndsWith
std::string str = getStringFromSomewhere();
REQUIRE_THAT( str, EndsWith( "as a service" ) );
```
@ -34,7 +35,7 @@ REQUIRE_THAT( str,
```
## Built in matchers
Currently Catch has some string matchers and some vector matchers.
Currently Catch has some string matchers and some vector matchers. They are in the `Catch::Matchers` and `Catch` namespaces.
The string matchers are `StartsWith`, `EndsWith`, `Contains` and `Equals`. Each of them also takes an optional second argument, that decides case sensitivity (by-default, they are case sensitive).
The vector matchers are `Contains`, `VectorContains` and `Equals`. `VectorContains` looks for a single element in the matched vector, `Contains` looks for a set (vector) of elements inside the matched vector.

View File

@ -1,6 +1,6 @@
# Open Source projects using Catch
Catch is great for open source. With it's [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
it's easy to just drop the header into your project and start writing tests - what's not to like?
As a result Catch is now being used in many Open Source projects, including some quite well known ones.
@ -25,6 +25,9 @@ The core part of the Chakra Javascript engine that powers Microsoft Edge
### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques
### [Clara](https://github.com/philsquared/Clara)
A, single-header-only, type-safe, command line parser - which also prints formatted usage strings.
### [Couchbase-lite-core](https://github.com/couchbase/couchbase-lite-core)
The next-generation core storage and query engine for Couchbase Lite/
@ -52,14 +55,23 @@ A C++ client library for Consul. Consul is a distributed tool for discovering an
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
A library of algorithms for values-distributed-in-time
### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
A small, single-header-only, library for wrapping and composing columns of text
### [Trompeloeil](https://github.com/rollbear/trompeloeil)
A thread safe header only mocking framework for C++14
### [args](https://github.com/Taywee/args)
A simple header-only C++ argument parser library.
## Applications & Tools
### [ArangoDB](https://github.com/arangodb/arangodb)
ArangoDB is a native multi-model database with flexible data models for documents, graphs, and key-values.
### [Giada - Your Hardcore Loop Machine](https://github.com/monocasual/giada)
Minimal, open-source and cross-platform audio tool for live music production.
### [MAME](https://github.com/mamedev/mame)
MAME originally stood for Multiple Arcade Machine Emulator

View File

@ -1,3 +1,104 @@
# 1.12.2
### Fixes
* Fixed missing <cassert> include
# 1.12.1
### Fixes
* Fixed deprecation warning in `ScopedMessage::~ScopedMessage`
* All uses of `min` or `max` identifiers are now wrapped in parentheses
* This avoids problems when Windows headers define `min` and `max` macros
# 1.12.0
### Fixes
* Fixed compilation for strict C++98 mode (ie not gnu++98) and older compilers (#1103)
* `INFO` messages are included in the `xml` reporter output even without `-s` specified.
# 1.11.0
### Fixes
* The original expression in `REQUIRE_FALSE( expr )` is now reporter properly as `!( expr )` (#1051)
* Previously the parentheses were missing and `x != y` would be expanded as `!x != x`
* `Approx::Margin` is now inclusive (#952)
* Previously it was meant and documented as inclusive, but the check itself wasn't
* This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails
* `RandomNumberGenerator::result_type` is now unsigned (#1050)
### Improvements
* `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017)
* When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of
* TeamCity reporter now explicitly flushes output stream after each report (#1057)
* On some platforms, output from redirected streams would show up only after the tests finished running
* `ParseAndAddCatchTests` now can add test files as dependency to CMake configuration
* This means you do not have to manually rerun CMake configuration step to detect new tests
# 1.10.0
### Fixes
* Evaluation layer has been rewritten (backported from Catch 2)
* The new layer is much simpler and fixes some issues (#981)
* Implemented workaround for VS 2017 raw string literal stringification bug (#995)
* Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections
* Previously sections with failing assertions would be marked as failed, not failed-but-ok
### Improvements
* Added [libidentify](https://github.com/janwilmans/LibIdentify) support
* Added "wait-for-keypress" option
# 1.9.7
### Fixes
* Various warnings from clang-tidy, Resharper-C++ and PVS Studio have been addressed (#957)
* Dynamically generated sections are now properly reported (#963)
* Writes to `std::clog` are redirected for reporters (#989)
* Previously only `std::cerr` writes were redirected
* Interleaved writes to `std::cerr` and `std::clog` are combined properly
* Assertions failed before signals/structured exceptions fails test case are properly reported as failed (#990)
### Improvements
* Catch's runtime overhead has been decreased further (#940)
* Added support for IBM i ILE c++ compiler (#976)
* This means that AS/400 is now supported.
* The default reporter can be configured at compile time (#978)
* That is, the reporter used if no reporter is explicitly specified
### Other
* `ParseAndAddCatchTests` cmake script has couple new customization options
# 1.9.6
### Improvements
* Catch's runtime overhead has been significantly decreased (#937, #939)
* Added `--list-extra-info` cli option (#934).
* It lists all tests together with extra information, ie filename, line number and description.
# 1.9.5
### Fixes
* Truthy expressions are now reconstructed properly, not as booleans (#914)
* Various warnings are no longer erroneously suppressed in test files (files that include `catch.hpp`, but do not define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`) (#871)
* Catch no longer fails to link when main is compiled as C++, but linked against Objective-C (#855)
* Fixed incorrect gcc version detection when deciding to use `__COUNTER__` (#928)
* Previously any GCC with minor version less than 3 would be incorrectly classified as not supporting `__COUNTER__`.
* Suppressed C4996 warning caused by upcoming updated to MSVC 2017, marking `std::uncaught_exception` as deprecated. (#927)
### Improvements
* CMake integration script now incorporates debug messages and registers tests in an improved way (#911)
* Various documentation improvements
# 1.9.4
### Fixes

63
docs/release-process.md Normal file
View File

@ -0,0 +1,63 @@
# How to release
When enough changes have accumulated, it is time to release new version of Catch. This document describes the proces in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory.
## Neccessary steps
These steps are neccessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
### Approval testing
Catch's releases are primarily validated against output from previous release, stored in `projects/SelfTest/Baselines`. To validate current sources, build the SelfTest binary and pass it to the `approvalTests.py` script: `approvalTests.py <path/to/SelfTest>`.
There should be no differences, as Approval tests should be updated when changes to Catch are made, but if there are, then they need to be manually reviewed and either approved (using `approve.py`) or Catch requires other fixes.
### Incrementing version number
Catch uses a variant of [semantic versioning](http://semver.org/), with breaking API changes (and thus major version increments) being very rare. Thus, the release will usually increment the patch version, when it only contains couple of bugfixes, or minor version, when it contains new functionality, or larger changes in implementation of current functionality.
After deciding which part of version number should be incremented, you can use one of the `*Release.py` scripts to perform the required changes to Catch.
### Generate updated single-include header
After updating version number, regenerate single-include header using `generateSingleHeader.py`.
### Release notes
Once a release is ready, release notes need to be written. They should summarize changes done since last release. For rough idea of expected notes see previous releases. Once written, release notes should be placed in `docs/release-notes.md`.
### Commit and push update to GitHub
After version number is incremented, single-include header is regenerated and release notes are updated, changes should be commited and pushed to GitHub.
### Release on GitHub
After pushing changes to GitHub, GitHub release *needs* to be created. Tag version and release title should be same as the new version, description should contain the release notes for the current release. Single header version of `catch.hpp` *needs* to be attached as a binary, as that is where the official download link links to. Preferably it should use linux line endings.
## Optional steps
The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they are *should* happen, but they can happen the next day without losing anything significant.
### vcpkg update
Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of neccessary work for you, it creates a branch and commits neccessary changes. You should review these changes, push and open a PR against vcpkg's upstream.
Note that the script assumes you have your fork of vcpkg checked out in a directory next to the directory where you have checked out Catch, like so:
```
GitHub
Catch
vcpkg
```
### Wandbox update
Recently we also included a link to wandbox with preloaded Catch on the main page. Strictly speaking it is unneccessary to update this after every release, Catch usually does not change that much between versions, but it should be kept up to date anyway.

View File

@ -17,7 +17,7 @@ There are four reporters built in to the single include:
* `console` writes as lines of text, formatted to a typical terminal width, with colours if a capable terminal is detected.
* `compact` similar to `console` but optimised for minimal output - each entry on one line
* `junit` writes xml that corresponds to Ant's [junitreport](http://help.catchsoftware.com/display/ET/JUnit+Format) target. Useful for build systems that understand Junit.
* `junit` writes xml that corresponds to Ant's [junitreport](http://help.catchsoftware.com/display/ET/JUnit+Format) target. Useful for build systems that understand Junit. If you are using Jenkins with Catch 1.x, you can improve quality of output by applying changes in [#923](https://github.com/philsquared/Catch/pull/923).
Because of the way the junit format is structured the run must complete before anything is written.
* `xml` writes an xml format tailored to Catch. Unlike `junit` this is a streaming format so results are delivered progressively.

View File

@ -28,7 +28,7 @@ The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects
For more detail on command line selection see [the command line docs](command-line.md#specifying-which-tests-to-run)
Tag names are not case sensitive.
Tag names are not case sensitive and can contain any ASCII characters. This means that tags `[tag with spaces]` and `[I said "good day"]` are both allowed tags and can be filtered on. Escapes are not supported however and `[\]]` is not a valid tag.
### Special Tags
@ -38,19 +38,19 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be excluded when running with `-e` or `--nothrow`.
* `[!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.
* `[!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 your tests.
* `[!shouldfail]` - like `[!mayfail]` but *fails* the test if it *passes*. This can be useful if you want to be notified of accidental, or third-party, fixes.
* `[!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]`.
* `[#<filename>]` - running with `-#` or `--filenames-as-tags` causes Catch to add the filename, prefixed with `#` (and with any extension stripped), as a tag to all contained tests, e.g. tests in testfile.cpp would all be tagged `[#testfile]`.
* `[@<alias>]` - tag aliases all begin with `@` (see below).
## Tag aliases
Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. this can be done, in code, using the following form:
Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. This can be done, in code, using the following form:
CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )

View File

@ -68,7 +68,7 @@ with expansion:
0 == 1
```
Note that we get the actual return value of Factorial(0) printed for us (0) - even though we used a natural expression with the == operator. That let's us immediately see what the problem is.
Note that we get the actual return value of Factorial(0) printed for us (0) - even though we used a natural expression with the == operator. That lets us immediately see what the problem is.
Let's change the factorial function to:
@ -80,7 +80,7 @@ unsigned int Factorial( unsigned int number ) {
Now all the tests pass.
Of course there are still more issues to do deal with. For example we'll hit problems when the return value starts to exceed the range of an unsigned int. With factorials that can happen quite quickly. You might want to add tests for such cases and decide how to handle them. We'll stop short of doing that here.
Of course there are still more issues to deal with. For example we'll hit problems when the return value starts to exceed the range of an unsigned int. With factorials that can happen quite quickly. You might want to add tests for such cases and decide how to handle them. We'll stop short of doing that here.
## What did we do here?

View File

@ -57,16 +57,16 @@
#include <crtdbg.h>
class LeakDetector {
public:
LeakDetector() {
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flag |= _CRTDBG_LEAK_CHECK_DF;
flag |= _CRTDBG_ALLOC_MEM_DF;
_CrtSetDbgFlag(flag);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
// Change this to leaking allocation's number to break there
_CrtSetBreakAlloc(-1);
}
LeakDetector() {
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flag |= _CRTDBG_LEAK_CHECK_DF;
flag |= _CRTDBG_ALLOC_MEM_DF;
_CrtSetDbgFlag(flag);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
// Change this to leaking allocation's number to break there
_CrtSetBreakAlloc(-1);
}
};
#else
class LeakDetector {};

View File

@ -31,10 +31,14 @@ namespace Catch {
return reporter;
}
#if !defined(CATCH_CONFIG_DEFAULT_REPORTER)
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
#endif
Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
std::vector<std::string> reporters = config->getReporterNames();
if( reporters.empty() )
reporters.push_back( "console" );
reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER );
Ptr<IStreamingReporter> reporter;
for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
@ -95,11 +99,11 @@ namespace Catch {
if( lastSlash != std::string::npos )
filename = filename.substr( lastSlash+1 );
std::string::size_type lastDot = filename.find_last_of( "." );
std::string::size_type lastDot = filename.find_last_of( '.' );
if( lastDot != std::string::npos )
filename = filename.substr( 0, lastDot );
tags.insert( "#" + filename );
tags.insert( '#' + filename );
setTags( test, tags );
}
}
@ -130,6 +134,13 @@ namespace Catch {
m_cli.usage( Catch::cout(), processName );
Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
}
void libIdentify() {
Catch::cout()
<< std::left << std::setw(16) << "description: " << "A Catch test executable\n"
<< std::left << std::setw(16) << "category: " << "testframework\n"
<< std::left << std::setw(16) << "framework: " << "Catch Test\n"
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
}
int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
try {
@ -137,6 +148,8 @@ namespace Catch {
m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
if( m_configData.showHelp )
showHelp( m_configData.processName );
if( m_configData.libIdentify )
libIdentify();
m_config.reset();
}
catch( std::exception& ex ) {
@ -193,7 +206,36 @@ namespace Catch {
#endif
int run() {
if( m_configData.showHelp )
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
static_cast<void>(std::getchar());
}
int exitCode = runInternal();
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
static_cast<void>(std::getchar());
}
return exitCode;
}
Clara::CommandLine<ConfigData> const& cli() const {
return m_cli;
}
std::vector<Clara::Parser::Token> const& unusedTokens() const {
return m_unusedTokens;
}
ConfigData& configData() {
return m_configData;
}
Config& config() {
if( !m_config )
m_config = new Config( m_configData );
return *m_config;
}
private:
int runInternal() {
if( m_configData.showHelp || m_configData.libIdentify )
return 0;
try
@ -217,21 +259,6 @@ namespace Catch {
}
}
Clara::CommandLine<ConfigData> const& cli() const {
return m_cli;
}
std::vector<Clara::Parser::Token> const& unusedTokens() const {
return m_unusedTokens;
}
ConfigData& configData() {
return m_configData;
}
Config& config() {
if( !m_config )
m_config = new Config( m_configData );
return *m_config;
}
private:
Clara::CommandLine<ConfigData> m_cli;
std::vector<Clara::Parser::Token> m_unusedTokens;
ConfigData m_configData;

View File

@ -151,7 +151,7 @@ namespace Tbc {
return oss.str();
}
inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
it != itEnd; ++it ) {
if( it != _text.begin() )

View File

@ -29,13 +29,6 @@ namespace Detail {
m_value( value )
{}
Approx( Approx const& other )
: m_epsilon( other.m_epsilon ),
m_margin( other.m_margin ),
m_scale( other.m_scale ),
m_value( other.m_value )
{}
static Approx custom() {
return Approx( 0 );
}
@ -64,7 +57,8 @@ namespace Detail {
if (relativeOK) {
return true;
}
return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin;
return std::fabs(lhs_v - rhs.m_value) <= rhs.m_margin;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
@ -137,7 +131,7 @@ namespace Detail {
if (relativeOK) {
return true;
}
return std::fabs(lhs - rhs.m_value) < rhs.m_margin;
return std::fabs(lhs - rhs.m_value) <= rhs.m_margin;
}
friend bool operator == ( Approx const& lhs, double rhs ) {

View File

@ -33,22 +33,24 @@ namespace Catch {
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& );
private:
DecomposedExpression& operator = (DecomposedExpression const&);
private:
DecomposedExpression& operator = (DecomposedExpression const&);
};
struct AssertionInfo
{
AssertionInfo() {}
AssertionInfo( std::string const& _macroName,
AssertionInfo();
AssertionInfo( char const * _macroName,
SourceLineInfo const& _lineInfo,
std::string const& _capturedExpression,
ResultDisposition::Flags _resultDisposition );
char const * _capturedExpression,
ResultDisposition::Flags _resultDisposition,
char const * _secondArg = "");
std::string macroName;
char const * macroName;
SourceLineInfo lineInfo;
std::string capturedExpression;
char const * capturedExpression;
ResultDisposition::Flags resultDisposition;
char const * secondArg;
};
struct AssertionResultData

View File

@ -13,14 +13,18 @@
namespace Catch {
AssertionInfo::AssertionInfo( std::string const& _macroName,
AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){}
AssertionInfo::AssertionInfo( char const * _macroName,
SourceLineInfo const& _lineInfo,
std::string const& _capturedExpression,
ResultDisposition::Flags _resultDisposition )
char const * _capturedExpression,
ResultDisposition::Flags _resultDisposition,
char const * _secondArg)
: macroName( _macroName ),
lineInfo( _lineInfo ),
capturedExpression( _capturedExpression ),
resultDisposition( _resultDisposition )
resultDisposition( _resultDisposition ),
secondArg( _secondArg )
{}
AssertionResult::AssertionResult() {}
@ -47,24 +51,30 @@ namespace Catch {
}
bool AssertionResult::hasExpression() const {
return !m_info.capturedExpression.empty();
return m_info.capturedExpression[0] != 0;
}
bool AssertionResult::hasMessage() const {
return !m_resultData.message.empty();
}
std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) {
return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"')
? capturedExpression
: std::string(capturedExpression) + ", " + secondArg;
}
std::string AssertionResult::getExpression() const {
if( isFalseTest( m_info.resultDisposition ) )
return '!' + m_info.capturedExpression;
return "!(" + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + ")";
else
return m_info.capturedExpression;
return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
}
std::string AssertionResult::getExpressionInMacro() const {
if( m_info.macroName.empty() )
return m_info.capturedExpression;
if( m_info.macroName[0] == 0 )
return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
else
return m_info.macroName + "( " + m_info.capturedExpression + " )";
return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )";
}
bool AssertionResult::hasExpandedExpression() const {

View File

@ -18,6 +18,12 @@
#include "catch_compiler_capabilities.h"
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
# define CATCH_INTERNAL_STRINGIFY(expr) #expr
#else
# define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
#endif
#if defined(CATCH_CONFIG_FAST_COMPILE)
///////////////////////////////////////////////////////////////////////////////
// We can speedup compilation significantly by breaking into debugger lower in
@ -33,7 +39,7 @@
// the exception before it propagates back up to the runner.
#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
__catchResult.setExceptionGuard(); \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
( __catchResult <= expr ).endExpression(); \
@ -45,9 +51,9 @@
#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
__catchResult.setExceptionGuard(); \
__catchResult.captureMatch( arg, matcher, #matcher ); \
__catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
__catchResult.unsetExceptionGuard(); \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::alwaysFalse() )
@ -60,14 +66,14 @@
// source code rather than in Catch library code
#define INTERNAL_CATCH_REACT( resultBuilder ) \
if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
resultBuilder.react();
resultBuilder.react();
#endif
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
try { \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
( __catchResult <= expr ).endExpression(); \
@ -83,17 +89,17 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
if( Catch::getResultCapture().getLastResult()->succeeded() )
if( Catch::getResultCapture().lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
if( !Catch::getResultCapture().getLastResult()->succeeded() )
if( !Catch::getResultCapture().lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
try { \
static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
@ -107,7 +113,7 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \
if( __catchResult.allowThrows() ) \
try { \
static_cast<void>(expr); \
@ -124,7 +130,7 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
if( __catchResult.allowThrows() ) \
try { \
static_cast<void>(expr); \
@ -168,9 +174,9 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
try { \
__catchResult.captureMatch( arg, matcher, #matcher ); \
__catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
} catch( ... ) { \
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
} \

View File

@ -76,6 +76,19 @@ namespace Catch {
else
throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
}
inline void setWaitForKeypress( ConfigData& config, std::string const& keypress ) {
std::string keypressLc = toLower( keypress );
if( keypressLc == "start" )
config.waitForKeypress = WaitForKeypress::BeforeStart;
else if( keypressLc == "exit" )
config.waitForKeypress = WaitForKeypress::BeforeExit;
else if( keypressLc == "both" )
config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
else
throw std::runtime_error( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
};
inline void forceColour( ConfigData& config ) {
config.useColour = UseColour::Yes;
}
@ -187,6 +200,10 @@ namespace Catch {
.describe( "list all/matching test cases names only" )
.bind( &ConfigData::listTestNamesOnly );
cli["--list-extra-info"]
.describe( "list all/matching test cases with more info" )
.bind( &ConfigData::listExtraInfo );
cli["--list-reporters"]
.describe( "list all reporters" )
.bind( &ConfigData::listReporters );
@ -207,6 +224,14 @@ namespace Catch {
.describe( "should output be colourised" )
.bind( &setUseColour, "yes|no" );
cli["--libidentify"]
.describe( "report name and version according to libidentify standard" )
.bind( &ConfigData::libIdentify );
cli["--wait-for-keypress"]
.describe( "waits for a keypress before exiting" )
.bind( &setWaitForKeypress, "start|exit|both" );
return cli;
}

View File

@ -61,14 +61,14 @@ namespace Catch {
};
template<typename ContainerT>
inline void deleteAll( ContainerT& container ) {
void deleteAll( ContainerT& container ) {
typename ContainerT::const_iterator it = container.begin();
typename ContainerT::const_iterator itEnd = container.end();
for(; it != itEnd; ++it )
delete *it;
}
template<typename AssociativeContainerT>
inline void deleteAllValues( AssociativeContainerT& container ) {
void deleteAllValues( AssociativeContainerT& container ) {
typename AssociativeContainerT::const_iterator it = container.begin();
typename AssociativeContainerT::const_iterator itEnd = container.end();
for(; it != itEnd; ++it )

View File

@ -89,6 +89,10 @@
#endif
#ifdef __OS400__
# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
# define CATCH_CONFIG_COLOUR_NONE
#endif
////////////////////////////////////////////////////////////////////////////////
// Cygwin
@ -170,10 +174,15 @@
// Use __COUNTER__ if the compiler supports it
#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \
( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \
( defined __clang__ && __clang_major__ >= 3 )
#define CATCH_INTERNAL_CONFIG_COUNTER
// Use of __COUNTER__ is suppressed during code analysis in CLion/AppCode 2017.2.x and former,
// because __COUNTER__ is not properly handled by it.
// This does not affect compilation
#if ( !defined __JETBRAINS_IDE__ || __JETBRAINS_IDE__ >= 20170300L )
#define CATCH_INTERNAL_CONFIG_COUNTER
#endif
#endif
@ -254,10 +263,7 @@
#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
# define CATCH_CONFIG_CPP11_UNIQUE_PTR
#endif
// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for
// analytics) because, at time of writing, __COUNTER__ is not properly handled by it.
// This does not affect compilation
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__)
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
# define CATCH_CONFIG_COUNTER
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)

View File

@ -31,25 +31,29 @@ namespace Catch {
listTags( false ),
listReporters( false ),
listTestNamesOnly( false ),
listExtraInfo( false ),
showSuccessfulTests( false ),
shouldDebugBreak( false ),
noThrow( false ),
showHelp( false ),
showInvisibles( false ),
filenamesAsTags( false ),
libIdentify( false ),
abortAfter( -1 ),
rngSeed( 0 ),
verbosity( Verbosity::Normal ),
warnings( WarnAbout::Nothing ),
showDurations( ShowDurations::DefaultForReporter ),
runOrder( RunTests::InDeclarationOrder ),
useColour( UseColour::Auto )
useColour( UseColour::Auto ),
waitForKeypress( WaitForKeypress::Never )
{}
bool listTests;
bool listTags;
bool listReporters;
bool listTestNamesOnly;
bool listExtraInfo;
bool showSuccessfulTests;
bool shouldDebugBreak;
@ -57,6 +61,7 @@ namespace Catch {
bool showHelp;
bool showInvisibles;
bool filenamesAsTags;
bool libIdentify;
int abortAfter;
unsigned int rngSeed;
@ -66,6 +71,7 @@ namespace Catch {
ShowDurations::OrNot showDurations;
RunTests::InWhatOrder runOrder;
UseColour::YesOrNo useColour;
WaitForKeypress::When waitForKeypress;
std::string outputFilename;
std::string name;
@ -109,6 +115,7 @@ namespace Catch {
bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
bool listTags() const { return m_data.listTags; }
bool listReporters() const { return m_data.listReporters; }
bool listExtraInfo() const { return m_data.listExtraInfo; }
std::string getProcessName() const { return m_data.processName; }

View File

@ -26,9 +26,9 @@ namespace Catch{
#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" )
: : : "memory","r0","r3","r4" ) /* NOLINT */
#else
#define CATCH_TRAP() __asm__("int $3\n" : : )
#define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ )
#endif
#elif defined(CATCH_PLATFORM_LINUX)
@ -36,7 +36,7 @@ namespace Catch{
// directly at the location of the failing check instead of breaking inside
// raise() called from it, i.e. one stack frame below.
#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
#define CATCH_TRAP() asm volatile ("int $3")
#define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
#else // Fall back to the generic way.
#include <signal.h>

View File

@ -18,7 +18,7 @@ extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
int main (int argc, char * argv[]) {
#endif
int result = Catch::Session().run( argc, argv );
int result = Catch::Session().run( argc, argv );
return ( result < 0xff ? result : 0xff );
}

View File

@ -11,6 +11,7 @@
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
#pragma warning(disable:4018) // more "signed/unsigned mismatch"
#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
#endif
@ -37,7 +38,7 @@ namespace Internal {
template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
template<typename T>
inline T& opCast(T const& t) { return const_cast<T&>(t); }
T& opCast(T const& t) { return const_cast<T&>(t); }
// nullptr_t support based on pull request #154 from Konstantin Baumann
#ifdef CATCH_CONFIG_CPP11_NULLPTR
@ -48,7 +49,7 @@ namespace Internal {
// So the compare overloads can be operator agnostic we convey the operator as a template
// enum, which is used to specialise an Evaluator for doing the comparison.
template<typename T1, typename T2, Operator Op>
class Evaluator{};
struct Evaluator{};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsEqualTo> {

View File

@ -81,7 +81,7 @@ public:
}
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
dest = Catch::toString( m_truthy );
dest = Catch::toString( m_lhs );
}
private:

View File

@ -28,7 +28,7 @@ namespace Catch {
namespace Catch {
struct FatalConditionHandler {
void reset() {}
void reset() {}
};
}
@ -106,7 +106,7 @@ namespace Catch {
namespace Catch {
struct FatalConditionHandler {
void reset() {}
void reset() {}
};
}

View File

@ -41,6 +41,10 @@ namespace Catch {
virtual void exceptionEarlyReported() = 0;
virtual void handleFatalErrorCondition( std::string const& message ) = 0;
virtual bool lastAssertionPassed() = 0;
virtual void assertionPassed() = 0;
virtual void assertionRun() = 0;
};
IResultCapture& getResultCapture();

View File

@ -42,6 +42,12 @@ namespace Catch {
Yes,
No
}; };
struct WaitForKeypress { enum When {
Never,
BeforeStart = 1,
BeforeExit = 2,
BeforeStartAndExit = BeforeStart | BeforeExit
}; };
class TestSpec;

View File

@ -30,8 +30,9 @@ namespace Catch {
}
std::size_t matchedTests = 0;
TextAttributes nameAttr, tagsAttr;
TextAttributes nameAttr, descAttr, tagsAttr;
nameAttr.setInitialIndent( 2 ).setIndent( 4 );
descAttr.setIndent( 4 );
tagsAttr.setIndent( 6 );
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
@ -46,6 +47,13 @@ namespace Catch {
Colour colourGuard( colour );
Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
if( config.listExtraInfo() ) {
Catch::cout() << " " << testCaseInfo.lineInfo << std::endl;
std::string description = testCaseInfo.description;
if( description.empty() )
description = "(NO DESCRIPTION)";
Catch::cout() << Text( description, descAttr ) << std::endl;
}
if( !testCaseInfo.tags.empty() )
Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
}
@ -69,9 +77,12 @@ namespace Catch {
matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
if( startsWith( testCaseInfo.name, '#' ) )
Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl;
Catch::cout() << '"' << testCaseInfo.name << '"';
else
Catch::cout() << testCaseInfo.name << std::endl;
Catch::cout() << testCaseInfo.name;
if ( config.listExtraInfo() )
Catch::cout() << "\t@" << testCaseInfo.lineInfo;
Catch::cout() << std::endl;
}
return matchedTests;
}
@ -163,7 +174,7 @@ namespace Catch {
inline Option<std::size_t> list( Config const& config ) {
Option<std::size_t> listedCount;
if( config.listTests() )
if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) )
listedCount = listedCount.valueOr(0) + listTests( config );
if( config.listTestNamesOnly() )
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );

View File

@ -147,23 +147,23 @@ namespace Matchers {
// This allows the types to be inferred
// - deprecated: prefer ||, && and !
template<typename T>
inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
return Impl::MatchNotOf<T>( underlyingMatcher );
}
template<typename T>
inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
return Impl::MatchAllOf<T>() && m1 && m2;
}
template<typename T>
inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
return Impl::MatchAllOf<T>() && m1 && m2 && m3;
}
template<typename T>
inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
return Impl::MatchAnyOf<T>() || m1 || m2;
}
template<typename T>
inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
}

View File

@ -37,11 +37,18 @@ namespace Catch {
: m_info( other.m_info )
{}
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
#endif
ScopedMessage::~ScopedMessage() {
if ( !std::uncaught_exception() ){
getResultCapture().popScopedMessage(m_info);
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
} // end namespace Catch

View File

@ -16,7 +16,6 @@ namespace Catch {
{
public:
NotImplementedException( SourceLineInfo const& lineInfo );
NotImplementedException( NotImplementedException const& ) {}
virtual ~NotImplementedException() CATCH_NOEXCEPT {}

View File

@ -104,7 +104,7 @@ namespace Catch {
namespace Matchers {
namespace Impl {
namespace NSStringMatchers {
struct StringHolder : MatcherBase<NSString*>{
StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}

View File

@ -69,7 +69,7 @@ namespace Catch {
T *nullableValue;
union {
char storage[sizeof(T)];
// These are here to force alignment for the storage
long double dummy1;
void (*dummy2)();

View File

@ -47,7 +47,7 @@ namespace Catch {
template<typename T>
ResultBuilder& operator << ( T const& value ) {
m_stream.oss << value;
stream().oss << value;
return *this;
}
@ -80,11 +80,27 @@ namespace Catch {
private:
AssertionInfo m_assertionInfo;
AssertionResultData m_data;
CopyableStream m_stream;
CopyableStream &stream()
{
if(!m_usedStream)
{
m_usedStream = true;
m_stream().oss.str("");
}
return m_stream();
}
static CopyableStream &m_stream()
{
static CopyableStream s;
return s;
}
bool m_shouldDebugBreak;
bool m_shouldThrow;
bool m_guardException;
bool m_usedStream;
};
} // namespace Catch
@ -95,7 +111,7 @@ namespace Catch {
namespace Catch {
template<typename T>
inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
return ExpressionLhs<T const&>( *this, operand );
}
@ -104,7 +120,7 @@ namespace Catch {
}
template<typename ArgT, typename MatcherT>
inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
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 ) );

View File

@ -16,28 +16,26 @@
#include "catch_interfaces_registry_hub.h"
#include "catch_wildcard_pattern.hpp"
#include <cassert>
namespace Catch {
std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) {
return secondArg.empty() || secondArg == "\"\""
? capturedExpression
: capturedExpression + ", " + secondArg;
}
ResultBuilder::ResultBuilder( char const* macroName,
SourceLineInfo const& lineInfo,
char const* capturedExpression,
ResultDisposition::Flags resultDisposition,
char const* secondArg )
: m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ),
: m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ),
m_shouldDebugBreak( false ),
m_shouldThrow( false ),
m_guardException( false )
m_guardException( false ),
m_usedStream( false )
{}
ResultBuilder::~ResultBuilder() {
#if defined(CATCH_CONFIG_FAST_COMPILE)
if ( m_guardException ) {
m_stream.oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
captureResult( ResultWas::ThrewException );
getCurrentContext().getResultCapture()->exceptionEarlyReported();
}
@ -54,13 +52,25 @@ namespace Catch {
}
void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
AssertionResult result = build( expr );
handleResult( result );
// Flip bool results if FalseTest flag is set
if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
m_data.negate( expr.isBinaryExpression() );
}
getResultCapture().assertionRun();
if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok)
{
AssertionResult result = build( expr );
handleResult( result );
}
else
getResultCapture().assertionPassed();
}
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
m_assertionInfo.resultDisposition = resultDisposition;
m_stream.oss << Catch::translateActiveException();
stream().oss << Catch::translateActiveException();
captureResult( ResultWas::ThrewException );
}
@ -82,7 +92,7 @@ namespace Catch {
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
AssertionResultData data = m_data;
data.resultType = ResultWas::Ok;
data.reconstructedExpression = m_assertionInfo.capturedExpression;
data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
std::string actualMessage = Catch::translateActiveException();
if( !matcher.match( actualMessage ) ) {
@ -143,18 +153,14 @@ namespace Catch {
assert( m_data.resultType != ResultWas::Unknown );
AssertionResultData data = m_data;
// Flip bool results if FalseTest flag is set
if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
data.negate( expr.isBinaryExpression() );
}
data.message = m_stream.oss.str();
if(m_usedStream)
data.message = m_stream().oss.str();
data.decomposedExpression = &expr; // for lazy reconstruction
return AssertionResult( m_assertionInfo, data );
}
void ResultBuilder::reconstructExpression( std::string& dest ) const {
dest = m_assertionInfo.capturedExpression;
dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
}
void ResultBuilder::setExceptionGuard() {

View File

@ -22,6 +22,7 @@
#include "catch_result_builder.h"
#include "catch_fatal_condition.hpp"
#include <cassert>
#include <set>
#include <string>
@ -50,6 +51,29 @@ namespace Catch {
std::string& m_targetString;
};
// StdErr has two constituent streams in C++, std::cerr and std::clog
// This means that we need to redirect 2 streams into 1 to keep proper
// order of writes and cannot use StreamRedirect on its own
class StdErrRedirect {
public:
StdErrRedirect(std::string& targetString)
:m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()),
m_targetString(targetString){
cerr().rdbuf(m_oss.rdbuf());
clog().rdbuf(m_oss.rdbuf());
}
~StdErrRedirect() {
m_targetString += m_oss.str();
cerr().rdbuf(m_cerrBuf);
clog().rdbuf(m_clogBuf);
}
private:
std::streambuf* m_cerrBuf;
std::streambuf* m_clogBuf;
std::ostringstream m_oss;
std::string& m_targetString;
};
///////////////////////////////////////////////////////////////////////////
class RunContext : public IResultCapture, public IRunner {
@ -142,7 +166,10 @@ namespace Catch {
m_totals.assertions.passed++;
}
else if( !result.isOk() ) {
m_totals.assertions.failed++;
if( m_activeTestCase->getTestCaseInfo().okToFail() )
m_totals.assertions.failedButOk++;
else
m_totals.assertions.failed++;
}
// We have no use for the return value (whether messages should be cleared), because messages were made scoped
@ -150,10 +177,27 @@ namespace Catch {
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
// Reset working state
m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
m_lastResult = result;
}
virtual bool lastAssertionPassed()
{
return m_totals.assertions.passed == (m_prevPassed + 1);
}
virtual void assertionPassed()
{
m_totals.assertions.passed++;
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}";
m_lastAssertionInfo.macroName = "";
}
virtual void assertionRun()
{
m_prevPassed = m_totals.assertions.passed;
}
virtual bool sectionStarted (
SectionInfo const& sectionInfo,
Counts& assertions
@ -254,6 +298,7 @@ namespace Catch {
Totals deltaTotals;
deltaTotals.testCases.failed = 1;
deltaTotals.assertions.failed = 1;
m_reporter->testCaseEnded( TestCaseStats( testInfo,
deltaTotals,
std::string(),
@ -280,7 +325,7 @@ namespace Catch {
double duration = 0;
m_shouldReportUnexpected = true;
try {
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal );
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
seedRng( *m_config );
@ -288,7 +333,7 @@ namespace Catch {
timer.start();
if( m_reporter->getPreferences().shouldRedirectStdOut ) {
StreamRedirect coutRedir( Catch::cout(), redirectedCout );
StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
StdErrRedirect errRedir( redirectedCerr );
invokeActiveTestCase();
}
else {
@ -300,7 +345,7 @@ namespace Catch {
// This just means the test was aborted due to failure
}
catch(...) {
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
// are reported without translation at the point of origin.
if (m_shouldReportUnexpected) {
makeUnexpectedResultBuilder().useActiveException();
@ -313,12 +358,6 @@ namespace Catch {
Counts assertions = m_totals.assertions - prevAssertions;
bool missingAssertions = testForMissingAssertions( assertions );
if( testCaseInfo.okToFail() ) {
std::swap( assertions.failedButOk, assertions.failed );
m_totals.assertions.failed -= assertions.failedButOk;
m_totals.assertions.failedButOk += assertions.failedButOk;
}
SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
m_reporter->sectionEnded( testCaseSectionStats );
}
@ -332,9 +371,9 @@ namespace Catch {
private:
ResultBuilder makeUnexpectedResultBuilder() const {
return ResultBuilder( m_lastAssertionInfo.macroName.c_str(),
return ResultBuilder( m_lastAssertionInfo.macroName,
m_lastAssertionInfo.lineInfo,
m_lastAssertionInfo.capturedExpression.c_str(),
m_lastAssertionInfo.capturedExpression,
m_lastAssertionInfo.resultDisposition );
}
@ -364,6 +403,7 @@ namespace Catch {
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
size_t m_prevPassed;
bool m_shouldReportUnexpected;
};

View File

@ -30,6 +30,10 @@ namespace Catch {
m_timer.start();
}
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
#endif
Section::~Section() {
if( m_sectionIncluded ) {
SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
@ -39,6 +43,9 @@ namespace Catch {
getResultCapture().sectionEnded( endInfo );
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
// This indicates whether the section should be executed or not
Section::operator bool() const {

View File

@ -21,6 +21,7 @@ namespace Catch {
std::ostream& cout();
std::ostream& cerr();
std::ostream& clog();
struct IStream {

View File

@ -103,6 +103,9 @@ namespace Catch {
std::ostream& cerr() {
return std::cerr;
}
std::ostream& clog() {
return std::clog;
}
#endif
}

View File

@ -22,14 +22,14 @@
namespace Catch {
struct RandomNumberGenerator {
typedef std::ptrdiff_t result_type;
typedef unsigned int result_type;
result_type operator()( result_type n ) const { return std::rand() % n; }
#ifdef CATCH_CONFIG_CPP11_SHUFFLE
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return 1000000; }
result_type operator()() const { return std::rand() % max(); }
static constexpr result_type (min)() { return 0; }
static constexpr result_type (max)() { return 1000000; }
result_type operator()() const { return std::rand() % (max)(); }
#endif
template<typename V>
static void shuffle( V& vector ) {

View File

@ -88,7 +88,7 @@ void registerTestCaseFunction
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
static void TestName(); \
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
static void TestName()
#define INTERNAL_CATCH_TESTCASE( ... ) \
@ -97,7 +97,7 @@ void registerTestCaseFunction
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
///////////////////////////////////////////////////////////////////////////////
@ -107,7 +107,7 @@ void registerTestCaseFunction
struct TestName : ClassName{ \
void test(); \
}; \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
} \
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
void TestName::test()
@ -117,7 +117,7 @@ void registerTestCaseFunction
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); \
Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
#else
@ -125,7 +125,7 @@ void registerTestCaseFunction
#define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
static void TestName(); \
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
static void TestName()
#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
@ -134,7 +134,7 @@ void registerTestCaseFunction
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
///////////////////////////////////////////////////////////////////////////////
@ -144,7 +144,7 @@ void registerTestCaseFunction
struct TestCaseName : ClassName{ \
void test(); \
}; \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
} \
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
void TestCaseName::test()
@ -154,7 +154,7 @@ void registerTestCaseFunction
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); \
Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
#endif

View File

@ -30,7 +30,7 @@ namespace Catch {
ITagAliasRegistry const* m_tagAliases;
public:
TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {}
TestSpecParser& parse( std::string const& arg ) {
m_mode = None;

View File

@ -63,7 +63,7 @@ std::string toString( std::nullptr_t );
#ifdef __OBJC__
std::string toString( NSString const * const& nsstring );
std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
std::string toString( NSString * CATCH_ARC_STRONG & nsstring );
std::string toString( NSObject* const& nsObject );
#endif
@ -153,7 +153,7 @@ namespace Detail {
std::string rawMemoryToString( const void *object, std::size_t size );
template<typename T>
inline std::string rawMemoryToString( const T& object ) {
std::string rawMemoryToString( const T& object ) {
return rawMemoryToString( &object, sizeof(object) );
}

View File

@ -198,7 +198,7 @@ std::string toString( std::nullptr_t ) {
return "nil";
return "@" + toString([nsstring UTF8String]);
}
std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
std::string toString( NSString * CATCH_ARC_STRONG & nsstring ) {
if( !nsstring )
return "nil";
return "@" + toString([nsstring UTF8String]);

View File

@ -25,7 +25,7 @@ namespace Catch {
#else
template <typename T>
struct add_const {
struct add_const {
typedef const T type;
};

View File

@ -38,7 +38,7 @@ namespace Catch {
}
inline Version libraryVersion() {
static Version version( 1, 9, 4, "", 0 );
static Version version( 1, 12, 2, "", 0 );
return version;
}

View File

@ -10,7 +10,6 @@
#include "catch_stream.h"
#include "catch_compiler_capabilities.h"
#include "catch_suppress_warnings.h"
#include <sstream>
#include <string>
@ -241,6 +240,5 @@ namespace Catch {
};
}
#include "catch_reenable_warnings.h"
#endif // TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED

View File

@ -28,7 +28,7 @@ namespace Catch {
// + 1 for null terminator
const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
char buffer[maxDoubleSize];
// Save previous errno, to prevent sprintf from overwriting it
ErrnoGuard guard;
#ifdef _MSC_VER
@ -137,7 +137,8 @@ namespace Catch {
BySectionInfo( SectionInfo const& other ) : m_other( 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;
return ((node->stats.sectionInfo.name == m_other.name) &&
(node->stats.sectionInfo.lineInfo == m_other.lineInfo));
}
private:
void operator=( BySectionInfo const& );

View File

@ -13,6 +13,7 @@
#include "../internal/catch_reporter_registrars.hpp"
#include "../internal/catch_console_colour.hpp"
#include <cassert>
#include <cfloat>
#include <cstdio>

View File

@ -52,6 +52,7 @@ namespace Catch {
JunitReporter( ReporterConfig const& _config )
: CumulativeReporterBase( _config ),
xml( _config.stream() ),
unexpectedExceptions( 0 ),
m_okToFail( false )
{
m_reporterPrefs.shouldRedirectStdOut = true;

View File

@ -14,6 +14,7 @@
// file can be distributed as a single header that works with the main
// Catch single header.
#include <cassert>
#include <cstring>
#ifdef __clang__
@ -141,6 +142,7 @@ namespace Catch {
<< "]\n";
}
}
stream.flush();
return true;
}
@ -150,9 +152,11 @@ namespace Catch {
}
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
m_testTimer.start();
StreamingReporterBase::testCaseStarting( testInfo );
stream << "##teamcity[testStarted name='"
<< escape( testInfo.name ) << "']\n";
stream.flush();
}
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
@ -166,7 +170,9 @@ namespace Catch {
<< escape( testCaseStats.testInfo.name )
<< "' out='" << escape( testCaseStats.stdErr ) << "']\n";
stream << "##teamcity[testFinished name='"
<< escape( testCaseStats.testInfo.name ) << "']\n";
<< escape( testCaseStats.testInfo.name ) << "' duration='"
<< m_testTimer.getElapsedMilliseconds() << "']\n";
stream.flush();
}
private:
@ -205,6 +211,7 @@ namespace Catch {
}
private:
bool m_headerPrintedForThisSection;
Timer m_testTimer;
};
#ifdef CATCH_IMPL

View File

@ -97,12 +97,12 @@ namespace Catch {
bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
if( includeResults ) {
if( includeResults || result.getResultType() == ResultWas::Warning ) {
// Print any info messages in <Info> tags.
for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
it != itEnd;
++it ) {
if( it->type == ResultWas::Info ) {
if( it->type == ResultWas::Info && includeResults ) {
m_xml.scopedElement( "Info" )
.writeText( it->message );
} else if ( it->type == ResultWas::Warning ) {

View File

@ -24,6 +24,8 @@ TEST_CASE
REQUIRE( Approx( d ) == 1.23 );
REQUIRE( Approx( d ) != 1.22 );
REQUIRE( Approx( d ) != 1.24 );
REQUIRE( 0 == Approx(0) );
}
///////////////////////////////////////////////////////////////////////////////
@ -146,11 +148,22 @@ TEST_CASE( "Approximate PI", "[Approx][PI]" )
TEST_CASE( "Absolute margin", "[Approx]" ) {
REQUIRE( 104.0 != Approx(100.0) );
REQUIRE( 104.0 == Approx(100.0).margin(5) );
REQUIRE( 104.0 == Approx(100.0).margin(4) );
REQUIRE( 104.0 != Approx(100.0).margin(3) );
REQUIRE( 100.3 != Approx(100.0) );
REQUIRE( 100.3 == Approx(100.0).margin(0.5) );
}
TEST_CASE("Approx with exactly-representable margin", "[Approx]") {
CHECK( 0.25f == Approx(0.0f).margin(0.25f) );
CHECK( 0.0f == Approx(0.25f).margin(0.25f) );
CHECK( 0.5f == Approx(0.25f).margin(0.25f) );
CHECK( 245.0f == Approx(245.25f).margin(0.25f) );
CHECK( 245.5f == Approx(245.25f).margin(0.25f) );
}
////////////////////////////////////////////////////////////////////////////////
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)

View File

@ -58,6 +58,8 @@ with expansion:
ConditionTests.cpp:<line number>: FAILED:
CHECK_FALSE( true )
with expansion:
!true
ConditionTests.cpp:<line number>: FAILED:
CHECK( !trueValue )
@ -76,8 +78,6 @@ with expansion:
ConditionTests.cpp:<line number>: FAILED:
CHECK_FALSE( 1 == 1 )
with expansion:
!(1 == 1)
-------------------------------------------------------------------------------
A METHOD_AS_TEST_CASE based test run that fails
@ -595,6 +595,17 @@ MessageTests.cpp:<line number>:
warning:
toString(p): 0x<hex digits>
-------------------------------------------------------------------------------
Reconstruction should be based on stringification: #914
-------------------------------------------------------------------------------
DecompositionTests.cpp:<line number>
...............................................................................
DecompositionTests.cpp:<line number>: FAILED:
CHECK( truthy(false) )
with expansion:
Hey, its truthy!
-------------------------------------------------------------------------------
SCOPED_INFO is reset for each loop
-------------------------------------------------------------------------------
@ -611,6 +622,9 @@ with messages:
A string sent directly to stdout
A string sent directly to stderr
Write to std::cerr
Write to std::clog
Interleaved writes to error streams
Message from section one
Message from section two
-------------------------------------------------------------------------------
@ -942,6 +956,6 @@ with expansion:
"first" == "second"
===============================================================================
test cases: 167 | 119 passed | 44 failed | 4 failed as expected
assertions: 967 | 859 passed | 87 failed | 21 failed as expected
test cases: 171 | 122 passed | 45 failed | 4 failed as expected
assertions: 980 | 871 passed | 88 failed | 21 failed as expected

View File

@ -123,6 +123,66 @@ PASSED:
with expansion:
1 == 1
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 0
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 1
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 2
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 3
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 4
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
'Not' checks that should fail
-------------------------------------------------------------------------------
@ -142,6 +202,8 @@ with expansion:
ConditionTests.cpp:<line number>: FAILED:
CHECK_FALSE( true )
with expansion:
!true
ConditionTests.cpp:<line number>: FAILED:
CHECK( !trueValue )
@ -160,8 +222,6 @@ with expansion:
ConditionTests.cpp:<line number>: FAILED:
CHECK_FALSE( 1 == 1 )
with expansion:
!(1 == 1)
-------------------------------------------------------------------------------
'Not' checks that should succeed
@ -186,6 +246,8 @@ with expansion:
ConditionTests.cpp:<line number>:
PASSED:
REQUIRE_FALSE( false )
with expansion:
!false
ConditionTests.cpp:<line number>:
PASSED:
@ -208,8 +270,6 @@ with expansion:
ConditionTests.cpp:<line number>:
PASSED:
REQUIRE_FALSE( 1 == 2 )
with expansion:
!(1 == 2)
-------------------------------------------------------------------------------
(unimplemented) static bools can be evaluated
@ -397,6 +457,12 @@ PASSED:
with expansion:
104.0 == Approx( 100.0 )
ApproxTests.cpp:<line number>:
PASSED:
REQUIRE( 104.0 == Approx(100.0).margin(4) )
with expansion:
104.0 == Approx( 100.0 )
ApproxTests.cpp:<line number>:
PASSED:
REQUIRE( 104.0 != Approx(100.0).margin(3) )
@ -492,6 +558,42 @@ with expansion:
"this string contains 'abc' as a substring" ( contains: "not there" or
contains: "string" )
-------------------------------------------------------------------------------
Approx with exactly-representable margin
-------------------------------------------------------------------------------
ApproxTests.cpp:<line number>
...............................................................................
ApproxTests.cpp:<line number>:
PASSED:
CHECK( 0.25f == Approx(0.0f).margin(0.25f) )
with expansion:
0.25f == Approx( 0.0 )
ApproxTests.cpp:<line number>:
PASSED:
CHECK( 0.0f == Approx(0.25f).margin(0.25f) )
with expansion:
0.0f == Approx( 0.25 )
ApproxTests.cpp:<line number>:
PASSED:
CHECK( 0.5f == Approx(0.25f).margin(0.25f) )
with expansion:
0.5f == Approx( 0.25 )
ApproxTests.cpp:<line number>:
PASSED:
CHECK( 245.0f == Approx(245.25f).margin(0.25f) )
with expansion:
245.0f == Approx( 245.25 )
ApproxTests.cpp:<line number>:
PASSED:
CHECK( 245.5f == Approx(245.25f).margin(0.25f) )
with expansion:
245.5f == Approx( 245.25 )
-------------------------------------------------------------------------------
Approximate PI
-------------------------------------------------------------------------------
@ -819,7 +921,7 @@ TrickyTests.cpp:<line number>:
PASSED:
REQUIRE( a )
with expansion:
true
0x<hex digits>
TrickyTests.cpp:<line number>:
PASSED:
@ -4571,7 +4673,7 @@ TrickyTests.cpp:<line number>:
PASSED:
CHECK( True )
with expansion:
true
1
TrickyTests.cpp:<line number>:
PASSED:
@ -4583,7 +4685,7 @@ TrickyTests.cpp:<line number>:
PASSED:
CHECK_FALSE( False )
with expansion:
!false
!0
-------------------------------------------------------------------------------
Operators at different namespace levels not hijacked by Koenig lookup
@ -6437,6 +6539,17 @@ TestMain.cpp:<line number>:
PASSED:
REQUIRE_THROWS_WITH( parseIntoConfig( argv, config ), Contains( "colour mode must be one of" ) )
-------------------------------------------------------------------------------
Reconstruction should be based on stringification: #914
-------------------------------------------------------------------------------
DecompositionTests.cpp:<line number>
...............................................................................
DecompositionTests.cpp:<line number>: FAILED:
CHECK( truthy(false) )
with expansion:
Hey, its truthy!
-------------------------------------------------------------------------------
SCOPED_INFO is reset for each loop
-------------------------------------------------------------------------------
@ -6775,6 +6888,45 @@ PASSED:
with expansion:
Approx( 1.23 ) != 1.24
ApproxTests.cpp:<line number>:
PASSED:
REQUIRE( 0 == Approx(0) )
with expansion:
0 == Approx( 0.0 )
Write to std::cerr
-------------------------------------------------------------------------------
Standard error is reported and redirected
std::cerr
-------------------------------------------------------------------------------
MessageTests.cpp:<line number>
...............................................................................
No assertions in section 'std::cerr'
Write to std::clog
-------------------------------------------------------------------------------
Standard error is reported and redirected
std::clog
-------------------------------------------------------------------------------
MessageTests.cpp:<line number>
...............................................................................
No assertions in section 'std::clog'
Interleaved writes to error streams
-------------------------------------------------------------------------------
Standard error is reported and redirected
Interleaved writes to cerr and clog
-------------------------------------------------------------------------------
MessageTests.cpp:<line number>
...............................................................................
No assertions in section 'Interleaved writes to cerr and clog'
Message from section one
-------------------------------------------------------------------------------
Standard output from all sections is reported
@ -9472,6 +9624,6 @@ MiscTests.cpp:<line number>:
PASSED:
===============================================================================
test cases: 167 | 118 passed | 45 failed | 4 failed as expected
assertions: 969 | 859 passed | 89 failed | 21 failed as expected
test cases: 171 | 120 passed | 47 failed | 4 failed as expected
assertions: 985 | 871 passed | 93 failed | 21 failed as expected

View File

@ -123,6 +123,66 @@ PASSED:
with expansion:
1 == 1
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 0
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 1
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 2
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 3
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
#961 -- Dynamically created sections should all be reported
Looped section 4
-------------------------------------------------------------------------------
MiscTests.cpp:<line number>
...............................................................................
MiscTests.cpp:<line number>:
PASSED:
with message:
Everything is OK
-------------------------------------------------------------------------------
'Not' checks that should fail
-------------------------------------------------------------------------------
@ -142,8 +202,10 @@ with expansion:
ConditionTests.cpp:<line number>: FAILED:
CHECK_FALSE( true )
with expansion:
!true
===============================================================================
test cases: 6 | 3 passed | 1 failed | 2 failed as expected
assertions: 18 | 11 passed | 4 failed | 3 failed as expected
test cases: 7 | 4 passed | 1 failed | 2 failed as expected
assertions: 23 | 16 passed | 4 failed | 3 failed as expected

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesspanner>
<testsuite name="<exe-name>" errors="13" failures="77" tests="970" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="13" failures="81" tests="986" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testcase classname="global" name="# A test name that starts with a #" time="{duration}"/>
<testcase classname="#748 - captures with unexpected exceptions" name="outside assertions" time="{duration}">
<error type="TEST_CASE">
@ -24,6 +24,11 @@ ExceptionTests.cpp:<line number>
MiscTests.cpp:<line number>
</failure>
</testcase>
<testcase classname="#961 -- Dynamically created sections should all be reported" name="Looped section 0" time="{duration}"/>
<testcase classname="#961 -- Dynamically created sections should all be reported" name="Looped section 1" time="{duration}"/>
<testcase classname="#961 -- Dynamically created sections should all be reported" name="Looped section 2" time="{duration}"/>
<testcase classname="#961 -- Dynamically created sections should all be reported" name="Looped section 3" time="{duration}"/>
<testcase classname="#961 -- Dynamically created sections should all be reported" name="Looped section 4" time="{duration}"/>
<testcase classname="global" name="'Not' checks that should fail" time="{duration}">
<failure message="false != false" type="CHECK">
ConditionTests.cpp:<line number>
@ -94,6 +99,7 @@ ExceptionTests.cpp:<line number>
</testcase>
<testcase classname="global" name="Anonymous test case 1" time="{duration}"/>
<testcase classname="global" name="AnyOf matcher" time="{duration}"/>
<testcase classname="global" name="Approx with exactly-representable margin" time="{duration}"/>
<testcase classname="global" name="Approximate PI" time="{duration}"/>
<testcase classname="global" name="Approximate comparisons with different epsilons" time="{duration}"/>
<testcase classname="global" name="Approximate comparisons with floats" time="{duration}"/>
@ -443,6 +449,11 @@ MessageTests.cpp:<line number>
<testcase classname="Process can be configured on command line" name="use-colour/yes" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="use-colour/no" time="{duration}"/>
<testcase classname="Process can be configured on command line" name="use-colour/error" time="{duration}"/>
<testcase classname="global" name="Reconstruction should be based on stringification: #914" time="{duration}">
<failure message="Hey, its truthy!" type="CHECK">
DecompositionTests.cpp:<line number>
</failure>
</testcase>
<testcase classname="global" name="SCOPED_INFO is reset for each loop" time="{duration}">
<failure message="10 &lt; 10" type="REQUIRE">
current counter 10
@ -470,6 +481,13 @@ A string sent directly to stderr
</system-err>
</testcase>
<testcase classname="global" name="Some simple comparisons between doubles" time="{duration}"/>
<testcase classname="Standard error is reported and redirected" name="Interleaved writes to cerr and clog" time="{duration}">
<system-err>
Write to std::cerr
Write to std::clog
Interleaved writes to error streams
</system-err>
</testcase>
<testcase classname="Standard output from all sections is reported" name="two" time="{duration}">
<system-out>
Message from section one
@ -745,6 +763,9 @@ hello
</system-out>
<system-err>
A string sent directly to stderr
Write to std::cerr
Write to std::clog
Interleaved writes to error streams
</system-err>
</testsuite>
</testsuites>

View File

@ -12,7 +12,7 @@
<Exception filename="projects/<exe-name>/ExceptionTests.cpp" >
expected exception
</Exception>
<OverallResults successes="0" failures="1" expectedFailures="0"/>
<OverallResults successes="0" failures="0" expectedFailures="1"/>
</Section>
<Section name="inside REQUIRE_NOTHROW" filename="projects/<exe-name>/ExceptionTests.cpp" >
<Info>
@ -29,7 +29,7 @@
expected exception
</Exception>
</Expression>
<OverallResults successes="0" failures="1" expectedFailures="0"/>
<OverallResults successes="0" failures="0" expectedFailures="1"/>
</Section>
<Section name="inside REQUIRE_THROWS" filename="projects/<exe-name>/ExceptionTests.cpp" >
<Info>
@ -136,6 +136,24 @@
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="#961 -- Dynamically created sections should all be reported" tags="[.][hide]" filename="projects/<exe-name>/MiscTests.cpp" >
<Section name="Looped section 0" filename="projects/<exe-name>/MiscTests.cpp" >
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Looped section 1" filename="projects/<exe-name>/MiscTests.cpp" >
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Looped section 2" filename="projects/<exe-name>/MiscTests.cpp" >
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Looped section 3" filename="projects/<exe-name>/MiscTests.cpp" >
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Looped section 4" filename="projects/<exe-name>/MiscTests.cpp" >
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="'Not' checks that should fail" tags="[.][failing][hide]" filename="projects/<exe-name>/ConditionTests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/ConditionTests.cpp" >
<Original>
@ -163,7 +181,7 @@
</Expression>
<Expression success="false" type="CHECK_FALSE" filename="projects/<exe-name>/ConditionTests.cpp" >
<Original>
!true
!(true)
</Original>
<Expanded>
!true
@ -179,7 +197,7 @@
</Expression>
<Expression success="false" type="CHECK_FALSE" filename="projects/<exe-name>/ConditionTests.cpp" >
<Original>
!trueValue
!(trueValue)
</Original>
<Expanded>
!true
@ -195,7 +213,7 @@
</Expression>
<Expression success="false" type="CHECK_FALSE" filename="projects/<exe-name>/ConditionTests.cpp" >
<Original>
!1 == 1
!(1 == 1)
</Original>
<Expanded>
!(1 == 1)
@ -230,7 +248,7 @@
</Expression>
<Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/ConditionTests.cpp" >
<Original>
!false
!(false)
</Original>
<Expanded>
!false
@ -246,7 +264,7 @@
</Expression>
<Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/ConditionTests.cpp" >
<Original>
!falseValue
!(falseValue)
</Original>
<Expanded>
!false
@ -262,7 +280,7 @@
</Expression>
<Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/ConditionTests.cpp" >
<Original>
!1 == 2
!(1 == 2)
</Original>
<Expanded>
!(1 == 2)
@ -342,7 +360,7 @@
</Expression>
<Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/TrickyTests.cpp" >
<Original>
!is_true&lt;false>::value
!(is_true&lt;false>::value)
</Original>
<Expanded>
!false
@ -444,6 +462,14 @@
104.0 == Approx( 100.0 )
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
104.0 == Approx(100.0).margin(4)
</Original>
<Expanded>
104.0 == Approx( 100.0 )
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
104.0 != Approx(100.0).margin(3)
@ -547,6 +573,49 @@
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Approx with exactly-representable margin" tags="[Approx]" filename="projects/<exe-name>/ApproxTests.cpp" >
<Expression success="true" type="CHECK" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
0.25f == Approx(0.0f).margin(0.25f)
</Original>
<Expanded>
0.25f == Approx( 0.0 )
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
0.0f == Approx(0.25f).margin(0.25f)
</Original>
<Expanded>
0.0f == Approx( 0.25 )
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
0.5f == Approx(0.25f).margin(0.25f)
</Original>
<Expanded>
0.5f == Approx( 0.25 )
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
245.0f == Approx(245.25f).margin(0.25f)
</Original>
<Expanded>
245.0f == Approx( 245.25 )
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
245.5f == Approx(245.25f).margin(0.25f)
</Original>
<Expanded>
245.5f == Approx( 245.25 )
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Approximate PI" tags="[Approx][PI]" filename="projects/<exe-name>/ApproxTests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
@ -890,7 +959,7 @@
a
</Original>
<Expanded>
true
0x<hex digits>
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/TrickyTests.cpp" >
@ -2690,7 +2759,7 @@
</Expression>
<Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
!d >= Approx( 1.24 )
!(d >= Approx( 1.24 ))
</Original>
<Expanded>
!(1.23 >= Approx( 1.24 ))
@ -2950,7 +3019,7 @@
</Expression>
<Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
!d &lt;= Approx( 1.22 )
!(d &lt;= Approx( 1.22 ))
</Original>
<Expanded>
!(1.23 &lt;= Approx( 1.22 ))
@ -4695,7 +4764,7 @@ re>"
True
</Original>
<Expanded>
true
1
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="projects/<exe-name>/TrickyTests.cpp" >
@ -4708,10 +4777,10 @@ re>"
</Expression>
<Expression success="true" type="CHECK_FALSE" filename="projects/<exe-name>/TrickyTests.cpp" >
<Original>
!False
!(False)
</Original>
<Expanded>
!false
!0
</Expanded>
</Expression>
<OverallResult success="true"/>
@ -6912,6 +6981,17 @@ re>"
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Reconstruction should be based on stringification: #914" tags="[.][Decomposition][failing][hide]" filename="projects/<exe-name>/DecompositionTests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/DecompositionTests.cpp" >
<Original>
truthy(false)
</Original>
<Expanded>
Hey, its truthy!
</Expanded>
</Expression>
<OverallResult success="false"/>
</TestCase>
<TestCase name="SCOPED_INFO is reset for each loop" tags="[.][failing][hide][messages]" filename="projects/<exe-name>/MessageTests.cpp" >
<Info>
current counter 0
@ -7296,8 +7376,34 @@ A string sent directly to stderr
Approx( 1.23 ) != 1.24
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/ApproxTests.cpp" >
<Original>
0 == Approx(0)
</Original>
<Expanded>
0 == Approx( 0.0 )
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Standard error is reported and redirected" tags="[.][hide][messages]" filename="projects/<exe-name>/MessageTests.cpp" >
<Section name="std::cerr" filename="projects/<exe-name>/MessageTests.cpp" >
<OverallResults successes="0" failures="1" expectedFailures="0"/>
</Section>
<Section name="std::clog" filename="projects/<exe-name>/MessageTests.cpp" >
<OverallResults successes="0" failures="1" expectedFailures="0"/>
</Section>
<Section name="Interleaved writes to cerr and clog" filename="projects/<exe-name>/MessageTests.cpp" >
<OverallResults successes="0" failures="1" expectedFailures="0"/>
</Section>
<OverallResult success="false">
<StdErr>
Write to std::cerr
Write to std::clog
Interleaved writes to error streams
</StdErr>
</OverallResult>
</TestCase>
<TestCase name="Standard output from all sections is reported" tags="[.][hide][messages]" filename="projects/<exe-name>/MessageTests.cpp" >
<Section name="one" filename="projects/<exe-name>/MessageTests.cpp" >
<OverallResults successes="0" failures="1" expectedFailures="0"/>
@ -9662,7 +9768,7 @@ spanner <OverallResult success="true"/>
<Section name="replace no chars" filename="projects/<exe-name>/TestMain.cpp" >
<Expression success="true" type="CHECK_FALSE" filename="projects/<exe-name>/TestMain.cpp" >
<Original>
!replaceInPlace( letters, "x", "z" )
!(replaceInPlace( letters, "x", "z" ))
</Original>
<Expanded>
!false
@ -10132,7 +10238,7 @@ spanner <OverallResult success="true"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<OverallResults successes="859" failures="90" expectedFailures="21"/>
<OverallResults successes="871" failures="94" expectedFailures="21"/>
</Group>
<OverallResults successes="859" failures="89" expectedFailures="21"/>
<OverallResults successes="871" failures="93" expectedFailures="21"/>
</Catch>

View File

@ -0,0 +1,28 @@
/*
* Created by Martin on 27/5/2017.
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include <iostream>
struct truthy {
truthy(bool b):m_value(b){}
operator bool() const {
return false;
}
bool m_value;
};
std::ostream& operator<<(std::ostream& o, truthy) {
o << "Hey, its truthy!";
return o;
}
#include "catch.hpp"
TEST_CASE( "Reconstruction should be based on stringification: #914" , "[Decomposition][failing][.]") {
CHECK(truthy(false));
}

View File

@ -99,6 +99,23 @@ TEST_CASE( "Standard output from all sections is reported", "[messages][.]" )
}
}
TEST_CASE( "Standard error is reported and redirected", "[messages][.]" ) {
SECTION( "std::cerr" ) {
std::cerr << "Write to std::cerr" << std::endl;
}
SECTION( "std::clog" ) {
std::clog << "Write to std::clog" << std::endl;
}
SECTION( "Interleaved writes to cerr and clog" ) {
std::cerr << "Inter";
std::clog << "leaved";
std::cerr << ' ';
std::clog << "writes";
std::cerr << " to error";
std::clog << " streams\n";
}
}
TEST_CASE( "SCOPED_INFO is reset for each loop", "[messages][failing][.]" )
{
for( int i=0; i<100; i++ )

View File

@ -403,5 +403,13 @@ static int f() {
TEST_CASE( "#835 -- errno should not be touched by Catch", "[!shouldfail]" ) {
errno = 1;
CHECK(f() == 0);
REQUIRE(errno == 1); // Check that f() doesn't touch errno.
REQUIRE(errno == 1); // Check that f() doesn't touch errno.
}
TEST_CASE( "#961 -- Dynamically created sections should all be reported", "[.]" ) {
for (char i = '0'; i < '5'; ++i) {
SECTION(std::string("Looped section ") + i) {
SUCCEED( "Everything is OK" );
}
}
}

View File

@ -9,7 +9,6 @@
TEST_CASE( "Character pretty printing" ){
//
SECTION("Specifically escaped"){
char tab = '\t';
char newline = '\n';
@ -36,7 +35,7 @@ TEST_CASE( "Character pretty printing" ){
char c = static_cast<char>(i);
REQUIRE(c == i);
}
}
}
}

View File

@ -407,3 +407,9 @@ TEST_CASE( "has printf", "" ) {
// This can cause problems as, currently, stdout itself is not redirect - only the cout (and cerr) buffer
printf( "spanner" );
}
TEST_CASE( "null deref", "[.][failing][!nonportable]" ) {
CHECK( false );
int *x = NULL;
*x = 1;
}

View File

@ -7,5 +7,7 @@ v = Version()
v.incrementBuildNumber()
v.updateVersionFile()
v.updateReadmeFile()
v.updateConanFile()
v.updateConanTestFile()
print( "Updated Version.hpp and README to v{0}".format( v.getVersionString() ) )
print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) )

View File

@ -9,97 +9,100 @@ import datetime
import string
from scriptCommon import catchPath
from releaseCommon import Version
includesParser = re.compile( r'\s*#\s*include\s*"(.*)"' )
guardParser = re.compile( r'\s*#.*TWOBLUECUBES_CATCH_.*_INCLUDED')
defineParser = re.compile( r'\s*#define')
ifParser = re.compile( r'\s*#ifndef TWOBLUECUBES_CATCH_.*_INCLUDED')
endIfParser = re.compile( r'\s*#endif // TWOBLUECUBES_CATCH_.*_INCLUDED')
ifImplParser = re.compile( r'\s*#ifdef CATCH_CONFIG_RUNNER' )
commentParser1 = re.compile( r'^\s*/\*')
commentParser2 = re.compile( r'^ \*')
blankParser = re.compile( r'^\s*$')
seenHeaders = set([])
rootPath = os.path.join( catchPath, 'include/' )
outputPath = os.path.join( catchPath, 'single_include/catch.hpp' )
def generate(v):
includesParser = re.compile( r'\s*#\s*include\s*"(.*)"' )
guardParser = re.compile( r'\s*#.*TWOBLUECUBES_CATCH_.*_INCLUDED')
defineParser = re.compile( r'\s*#define')
ifParser = re.compile( r'\s*#ifndef TWOBLUECUBES_CATCH_.*_INCLUDED')
endIfParser = re.compile( r'\s*#endif // TWOBLUECUBES_CATCH_.*_INCLUDED')
ifImplParser = re.compile( r'\s*#ifdef CATCH_CONFIG_RUNNER' )
commentParser1 = re.compile( r'^\s*/\*')
commentParser2 = re.compile( r'^ \*')
blankParser = re.compile( r'^\s*$')
seenHeaders = set([])
rootPath = os.path.join( catchPath, 'include/' )
outputPath = os.path.join( catchPath, 'single_include/catch.hpp' )
includeImpl = True
for arg in sys.argv[1:]:
arg = string.lower(arg)
if arg == "noimpl":
includeImpl = False
print( "Not including impl code" )
else:
print( "\n** Unrecognised argument: " + arg + " **\n" )
exit(1)
globals = {
'ifdefs' : 0,
'implIfDefs' : -1,
'includeImpl': True
}
out = open( outputPath, 'w' )
ifdefs = 0
implIfDefs = -1
def write( line ):
if includeImpl or implIfDefs == -1:
out.write( line )
def parseFile( path, filename ):
global ifdefs
global implIfDefs
f = open( path + filename, 'r' )
blanks = 0
for line in f:
if ifParser.match( line ):
ifdefs = ifdefs + 1
elif endIfParser.match( line ):
ifdefs = ifdefs - 1
if ifdefs == implIfDefs:
implIfDefs = -1
m = includesParser.match( line )
if m:
header = m.group(1)
headerPath, sep, headerFile = header.rpartition( "/" )
if not headerFile in seenHeaders:
if headerFile != "tbc_text_format.h" and headerFile != "clara.h":
seenHeaders.add( headerFile )
write( "// #included from: {0}\n".format( header ) )
if headerPath == "internal" and path.endswith("internal/"):
headerPath = ""
sep = ""
if os.path.exists( path + headerPath + sep + headerFile ):
parseFile( path + headerPath + sep, headerFile )
else:
parseFile( rootPath + headerPath + sep, headerFile )
for arg in sys.argv[1:]:
arg = string.lower(arg)
if arg == "noimpl":
globals['includeImpl'] = False
print( "Not including impl code" )
else:
if ifImplParser.match(line):
implIfDefs = ifdefs
if (not guardParser.match( line ) or defineParser.match( line ) ) and not commentParser1.match( line )and not commentParser2.match( line ):
if blankParser.match( line ):
blanks = blanks + 1
else:
blanks = 0
if blanks < 2:
write( line.rstrip() + "\n" )
print( "\n** Unrecognised argument: " + arg + " **\n" )
exit(1)
out = open( outputPath, 'w' )
def write( line ):
if globals['includeImpl'] or globals['implIfDefs'] == -1:
out.write( line )
def parseFile( path, filename ):
f = open( path + filename, 'r' )
blanks = 0
for line in f:
if ifParser.match( line ):
globals['ifdefs'] += 1
elif endIfParser.match( line ):
globals['ifdefs'] -= 1
if globals['ifdefs'] == globals['implIfDefs']:
globals['implIfDefs'] = -1
m = includesParser.match( line )
if m:
header = m.group(1)
headerPath, sep, headerFile = header.rpartition( "/" )
if not headerFile in seenHeaders:
if headerFile != "tbc_text_format.h" and headerFile != "clara.h":
seenHeaders.add( headerFile )
write( "// #included from: {0}\n".format( header ) )
if headerPath == "internal" and path.endswith("internal/"):
headerPath = ""
sep = ""
if os.path.exists( path + headerPath + sep + headerFile ):
parseFile( path + headerPath + sep, headerFile )
else:
parseFile( rootPath + headerPath + sep, headerFile )
else:
if ifImplParser.match(line):
globals['implIfDefs'] = globals['ifdefs']
if (not guardParser.match( line ) or defineParser.match( line ) ) and not commentParser1.match( line )and not commentParser2.match( line ):
if blankParser.match( line ):
blanks = blanks + 1
else:
blanks = 0
if blanks < 2:
write( line.rstrip() + "\n" )
v = Version()
out.write( "/*\n" )
out.write( " * Catch v{0}\n".format( v.getVersionString() ) )
out.write( " * Generated: {0}\n".format( datetime.datetime.now() ) )
out.write( " * ----------------------------------------------------------\n" )
out.write( " * This file has been merged from multiple headers. Please don't edit it directly\n" )
out.write( " * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.\n" )
out.write( " *\n" )
out.write( " * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" )
out.write( " * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" )
out.write( " */\n" )
out.write( "#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
out.write( "#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
out.write( "/*\n" )
out.write( " * Catch v{0}\n".format( v.getVersionString() ) )
out.write( " * Generated: {0}\n".format( datetime.datetime.now() ) )
out.write( " * ----------------------------------------------------------\n" )
out.write( " * This file has been merged from multiple headers. Please don't edit it directly\n" )
out.write( " * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.\n" )
out.write( " *\n" )
out.write( " * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" )
out.write( " * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" )
out.write( " */\n" )
out.write( "#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
out.write( "#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
parseFile( rootPath, 'catch.hpp' )
parseFile( rootPath, 'catch.hpp' )
out.write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
out.write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
out.close()
print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) )
print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) )
if __name__ == '__main__':
from releaseCommon import Version
generate(Version())

View File

@ -1,11 +1,10 @@
#!/usr/bin/env python
from __future__ import print_function
from releaseCommon import Version
import releaseCommon
v = Version()
v = releaseCommon.Version()
v.incrementMajorVersion()
v.updateVersionFile()
v.updateReadmeFile()
releaseCommon.performUpdates(v)
print( "Updated Version.hpp and README to v{0}".format( v.getVersionString() ) )
print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) )

View File

@ -1,11 +1,10 @@
#!/usr/bin/env python
from __future__ import print_function
from releaseCommon import Version
import releaseCommon
v = Version()
v = releaseCommon.Version()
v.incrementMinorVersion()
v.updateVersionFile()
v.updateReadmeFile()
releaseCommon.performUpdates(v)
print( "Updated Version.hpp and README to v{0}".format( v.getVersionString() ) )
print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) )

View File

@ -1,11 +1,10 @@
#!/usr/bin/env python
from __future__ import print_function
from releaseCommon import Version
import releaseCommon
v = Version()
v = releaseCommon.Version()
v.incrementPatchNumber()
v.updateVersionFile()
v.updateReadmeFile()
releaseCommon.performUpdates(v)
print( "Updated Version.hpp and README to v{0}".format( v.getVersionString() ) )
print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) )

View File

@ -6,11 +6,15 @@ import re
import string
from scriptCommon import catchPath
import generateSingleHeader
import updateWandbox
versionParser = re.compile( r'(\s*static\sVersion\sversion)\s*\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*\"(.*)\"\s*,\s*(.*)\s*\).*' )
rootPath = os.path.join( catchPath, 'include/' )
versionPath = os.path.join( rootPath, "internal/catch_version.hpp" )
readmePath = os.path.join( catchPath, "README.md" )
conanPath = os.path.join(catchPath, 'conanfile.py')
conanTestPath = os.path.join(catchPath, 'test_package', 'conanfile.py')
class Version:
def __init__(self):
@ -74,15 +78,61 @@ class Version:
for line in lines:
f.write( line + "\n" )
def updateReadmeFile(self):
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:
lines.append( line.rstrip() )
f.close()
f = open( readmePath, 'w' )
for line in lines:
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" )
def updateReadmeFile(version):
downloadParser = re.compile( r'<a href=\"https://github.com/philsquared/Catch/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
success, wandboxLink = updateWandbox.uploadFiles()
if not success:
print('Error when uploading to wandbox: {}'.format(wandboxLink))
exit(1)
f = open( readmePath, 'r' )
lines = []
for line in f:
lines.append( line.rstrip() )
f.close()
f = open( readmePath, 'w' )
for line in lines:
line = downloadParser.sub( r'<a href="https://github.com/philsquared/Catch/releases/download/v{0}/catch.hpp">'.format(version.getVersionString()) , line)
if '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]' in line:
line = '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]({0})'.format(wandboxLink)
f.write( line + "\n" )
def updateConanFile(version):
conanParser = re.compile( r' version = "\d+\.\d+\.\d+.*"')
f = open( conanPath, 'r' )
lines = []
for line in f:
m = conanParser.match( line )
if m:
lines.append( ' version = "{0}"'.format(format(version.getVersionString())) )
else:
lines.append( line.rstrip() )
f.close()
f = open( conanPath, 'w' )
for line in lines:
f.write( line + "\n" )
def updateConanTestFile(version):
conanParser = re.compile( r' requires = \"Catch\/\d+\.\d+\.\d+.*@%s\/%s\" % \(username, channel\)')
f = open( conanTestPath, 'r' )
lines = []
for line in f:
m = conanParser.match( line )
if m:
lines.append( ' requires = "Catch/{0}@%s/%s" % (username, channel)'.format(format(version.getVersionString())) )
else:
lines.append( line.rstrip() )
f.close()
f = open( conanTestPath, 'w' )
for line in lines:
f.write( line + "\n" )
def performUpdates(version):
# First update version file, so we can regenerate single header and
# have it ready for upload to wandbox, when updating readme
version.updateVersionFile()
# ToDo: Regenerate single header
generateSingleHeader.generate(version)
updateReadmeFile(version)
updateConanFile(version)
updateConanTestFile(version)

View File

@ -8,7 +8,7 @@ from releaseCommon import Version
print(catchPath)
default_path = '../vcpkg/ports/catch/'
default_path = '../vcpkg/ports/catch-classic/'
def adjusted_path(path):
return os.path.join(catchPath, path)
@ -57,24 +57,21 @@ def update_portfile(path, header_hash, licence_hash):
for line in f:
lines.append(line)
with open(portfile_path, 'w') as f:
# Two things we need to change/update
# 1) Link and hash of releaseCommon
# 2) Link and hash of licence
# There are three things we need to change/update
# 1) CATCH_VERSION cmake variable
# 2) Hash of header
# 3) Hash of licence
# We could assume licence never changes, but where is the fun in that?
first_hash = True
for line in lines:
# Check what we are updating
# Update the version
if 'set(CATCH_VERSION' in line:
line = 'set(CATCH_VERSION v{})\n'.format(v.getVersionString())
# Determine which file we are updating
if 'vcpkg_download_distfile' in line:
kind = line.split('(')[-1].strip()
print(kind)
# Deal with URLS
if 'URLS' in line and kind == 'HEADER':
line = ' URLS "https://github.com/philsquared/Catch/releases/download/v{}/catch.hpp"\n'.format(v.getVersionString())
if 'URLS' in line and kind == 'LICENSE':
line = ' URLS "https://raw.githubusercontent.com/philsquared/Catch/v{}/LICENSE.txt"\n'.format(v.getVersionString())
# Deal with hashes
# Update the hashes
if 'SHA512' in line and kind == 'HEADER':
line = ' SHA512 {}\n'.format(header_hash)
if 'SHA512' in line and kind == 'LICENSE':
@ -86,8 +83,6 @@ def git_push(path_to_repo):
v = Version()
ver_string = v.getVersionString()
# Move to the repo dir
old_path = os.getcwd()
os.chdir(path_to_repo)
# Work with git
@ -96,6 +91,7 @@ def git_push(path_to_repo):
# Update repo to current master, so we don't work off old version of the portsfile
subprocess.call('git pull Microsoft master', shell=True)
subprocess.call('git push', shell=True)
# Create a new branch for the update
subprocess.call('git checkout -b catch-{}'.format(ver_string), shell=True)

47
scripts/updateWandbox.py Normal file
View File

@ -0,0 +1,47 @@
#!/usr/bin/env python
import json
import os
import urllib2
from scriptCommon import catchPath
def upload(options):
request = urllib2.Request('http://melpon.org/wandbox/api/compile.json')
request.add_header('Content-Type', 'application/json')
response = urllib2.urlopen(request, json.dumps(options))
return json.loads(response.read())
main_file = '''
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"
unsigned int Factorial( unsigned int number ) {
return number <= 1 ? number : Factorial(number-1)*number;
}
TEST_CASE( "Factorials are computed", "[factorial]" ) {
REQUIRE( Factorial(1) == 1 );
REQUIRE( Factorial(2) == 2 );
REQUIRE( Factorial(3) == 6 );
REQUIRE( Factorial(10) == 3628800 );
}
'''
def uploadFiles():
response = upload({
'compiler': 'gcc-head',
'code': main_file,
'codes': [{
'file': 'catch.hpp',
'code': open(os.path.join(catchPath, 'single_include', 'catch.hpp')).read()
}],
'options': 'c++11,cpp-no-pedantic,boost-nothing',
'compiler-option-raw': '-DCATCH_CONFIG_FAST_COMPILE',
'save': True
})
if 'status' in response and not 'compiler_error' in response:
return True, response['url']
else:
return False, response

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.0)
project(CatchTest CXX)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
add_executable(${CMAKE_PROJECT_NAME} MainTest.cpp)

21
test_package/MainTest.cpp Normal file
View File

@ -0,0 +1,21 @@
/*
* Created by Phil on 22/10/2010.
* Copyright 2010 Two Blue Cubes Ltd
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
unsigned int Factorial( unsigned int number ) {
return number > 1 ? Factorial(number-1)*number : 1;
}
TEST_CASE( "Factorials are computed", "[factorial]" ) {
REQUIRE( Factorial(0) == 1 );
REQUIRE( Factorial(1) == 1 );
REQUIRE( Factorial(2) == 2 );
REQUIRE( Factorial(3) == 6 );
REQUIRE( Factorial(10) == 3628800 );
}

21
test_package/conanfile.py Normal file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env python
from os import getenv
from os import path
from conans import ConanFile
from conans import CMake
class CatchConanTest(ConanFile):
generators = "cmake"
settings = "os", "compiler", "arch", "build_type"
username = getenv("CONAN_USERNAME", "philsquared")
channel = getenv("CONAN_CHANNEL", "testing")
requires = "Catch/1.12.2@%s/%s" % (username, channel)
def build(self):
cmake = CMake(self)
cmake.configure(build_dir="./")
cmake.build()
def test(self):
self.run(path.join("bin", "CatchTest"))