Compare commits

...

27 Commits

Author SHA1 Message Date
Martin Hořeňovský
62dae592c3 v2.1.1 2018-01-26 16:06:07 +01:00
Martin Hořeňovský
9a5705411a Add % to codecov coverage decrease threshold
Maybe now it will work?
2018-01-26 15:45:31 +01:00
Martin Hořeňovský
a1aefce6e4 Guard against CLR exceptions when translating exceptions
Partially fixes #1138, need to decide what to do about structured
exceptions.
2018-01-24 12:11:29 +01:00
Phil Nash
d5959907f5 Added Catch::clara namespace to doc for adding Opt
- Thanks to sakamoto-poteko in #1159 for point out its ommission
2018-01-23 07:44:09 +00:00
Phil Nash
31e6499e64 Embed Clara v1.1.1 2018-01-22 15:08:28 +00:00
David Seifert
b0f4f16ee0 Namespace Catch CMake options 2018-01-18 23:20:26 +01:00
David Seifert
1e3ddbb496 Specify VERSION in modern CMake 2018-01-18 23:20:26 +01:00
Martin Hořeňovský
15ad95c8db Make generateSingleHeader compatible with Python 2.7 2018-01-18 16:28:19 +01:00
Martin Hořeňovský
00a10d5a5e Return fixed codecov settings 2018-01-18 13:51:32 +01:00
David Seifert
0d687a15d3 Change CMake project name to 'Catch2' 2018-01-18 13:13:39 +01:00
David Seifert
bdf431c400 Install documentation 2018-01-18 13:13:39 +01:00
David Seifert
a0359980f0 Use CTest to control test suite via BUILD_TESTING 2018-01-18 13:13:39 +01:00
David Seifert
8d4074aad9 Use GNUInstallDirs module
* `GNUInstallDirs` is a standardised way to
  change paths, which makes systems integration
  easier and allows for a more consistent user
  experience.
2018-01-18 13:13:39 +01:00
Martin Hořeňovský
f0f40a0dbf Ensure that the single header is kept with LFs 2018-01-18 12:44:59 +01:00
Martin Hořeňovský
fa4fd7f296 Modify codecov.yml again 2018-01-15 13:59:48 +01:00
Martin Hořeňovský
07c84adfba Allow disabling -Werror in CMake
Related to #1152
2018-01-14 18:14:11 +01:00
Martin Hořeňovský
8d854c689b Provide useful and unambigous stringification for static arrays 2018-01-14 18:06:43 +01:00
Martin Hořeňovský
f0909dfe02 Add yet another expansion of INF macro
Closes #1151
2018-01-14 17:04:36 +01:00
Martin Hořeňovský
de36b2ada6 Fix compilation for types where relops don't return bool
Closes #1147
2018-01-12 15:49:56 +01:00
Martin Hořeňovský
9700ee4fc0 Update CTest autodiscovery documentation 2018-01-12 12:28:14 +01:00
Martin Hořeňovský
bbda8cd77c Update reporter docs with their new location 2018-01-12 12:20:52 +01:00
Martin Hořeňovský
4575594bbf Comment why the return code is clamped 2018-01-12 11:49:48 +01:00
Martin Hořeňovský
c053dca26e Update path to vcpkg's portfile 2018-01-12 11:09:46 +01:00
garethsb-sony
3d7104c124 Catch `catch_discover_tests`
Copied from [Dynamic Catch test discovery in CMake](https://gist.github.com/garethsb/a01ed0dbd4977d439c16200640549935), which was inspired by [Dynamic Google Test Discovery in CMake 3.10](https://blog.kitware.com/dynamic-google-test-discovery-in-cmake-3-10/).

Original source code:

- Adapted by [Gareth Sylvester-Bradley](https://github.com/garethsb) from [GoogleTest ``gtest_discover_tests``](https://gitlab.kitware.com/cmake/cmake/merge_requests/1056).
- BSD 3-clause "New" or "Revised" License.
- Copyright 2000-2017 Kitware, Inc. and Contributors. All rights reserved.
2018-01-11 21:17:12 +01:00
Martin Hořeňovský
6441c20a2c Modify codecov behaviour 2018-01-11 21:13:52 +01:00
Martin Hořeňovský
5774c4f9c2 Update release process with the need to release reporters 2018-01-11 21:06:35 +01:00
Martin Hořeňovský
2bc33dd04d Fix script responsible for updating release link in the readme 2018-01-10 14:02:15 +01:00
37 changed files with 911 additions and 265 deletions

6
.gitattributes vendored
View File

@@ -8,4 +8,8 @@
*.hpp text
# Windows specific files should retain windows line-endings
*.sln text eol=crlf
*.sln text eol=crlf
# Keep the single include header with LFs to make sure it is uploaded,
# hashed etc with LF
single_include/*.hpp eol=lf

View File

@@ -204,7 +204,7 @@ before_script:
- |
# Use Debug builds for running Valgrind and building examples
cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_VALGRIND=${VALGRIND} -DBUILD_EXAMPLES=ON -DENABLE_COVERAGE=ON
cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_COVERAGE=ON
# Don't bother with release build for coverage build
cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}

View File

@@ -1,10 +1,19 @@
cmake_minimum_required(VERSION 3.0)
project(CatchSelfTest)
# detect if Catch is being bundled,
# disable testsuite in that case
if(NOT DEFINED PROJECT_NAME)
set(NOT_SUBPROJECT ON)
endif()
option(USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
option(BUILD_EXAMPLES "Build documentation examples" OFF)
option(ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
project(Catch2 LANGUAGES CXX VERSION 2.1.1)
include(GNUInstallDirs)
option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
option(CATCH_BUILD_EXAMPLES "Build documentation examples" OFF)
option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@@ -13,7 +22,6 @@ set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
set(HEADER_DIR ${CATCH_DIR}/include)
set(CATCH_VERSION_NUMBER 2.1.0)
if(USE_WMAIN)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
@@ -284,7 +292,19 @@ SOURCE_GROUP("Surrogates" FILES ${SURROGATE_SOURCES})
# Projects consuming Catch via ExternalProject_Add might want to use install step
# without building all of our selftests.
if (NOT NO_SELFTEST)
if(DEFINED NO_SELFTEST)
message(DEPRECATION "*** CMake option NO_SELFTEST is deprecated; use BUILD_TESTING instead")
if (NO_SELFTEST)
set(BUILD_TESTING OFF CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
else()
set(BUILD_TESTING ON CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
endif()
endif()
include(CTest)
if (BUILD_TESTING AND NOT_SUBPROJECT)
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS})
target_include_directories(SelfTest PRIVATE ${HEADER_DIR})
@@ -299,7 +319,8 @@ if (NOT NO_SELFTEST)
set_property(TARGET SelfTest PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET SelfTest PROPERTY CXX_EXTENSIONS OFF)
if (ENABLE_COVERAGE)
if (CATCH_ENABLE_COVERAGE)
set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
find_package(codecov)
add_coverage(SelfTest)
@@ -309,7 +330,10 @@ if (NOT NO_SELFTEST)
# Add desired warnings
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code -Werror )
target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code )
if (CATCH_ENABLE_WERROR)
target_compile_options( SelfTest PRIVATE -Werror)
endif()
endif()
# Clang specific warning go here
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
@@ -318,7 +342,10 @@ if (NOT NO_SELFTEST)
endif()
if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
STRING(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # override default warning level
target_compile_options( SelfTest PRIVATE /w44265 /WX /w44061 /w44062 )
target_compile_options( SelfTest PRIVATE /w44265 /w44061 /w44062 )
if (CATCH_ENABLE_WERROR)
target_compile_options( SelfTest PRIVATE /WX)
endif()
endif()
@@ -344,7 +371,7 @@ if (NOT NO_SELFTEST)
add_test(NAME ApprovalTests COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
if (USE_VALGRIND)
if (CATCH_USE_VALGRIND)
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
set_tests_properties(ValgrindListTests PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks")
@@ -355,18 +382,20 @@ if (NOT NO_SELFTEST)
endif() # !NO_SELFTEST
if(BUILD_EXAMPLES)
if(CATCH_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
install(DIRECTORY "single_include/" DESTINATION "include/catch")
install(DIRECTORY "single_include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/catch")
install(DIRECTORY docs/ DESTINATION "${CMAKE_INSTALL_DOCDIR}")
## Provide some pkg-config integration
# Don't bother on Windows
if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
set(PKGCONFIG_INSTALL_DIR
"${CMAKE_INSTALL_PREFIX}/share/pkgconfig"
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
CACHE PATH "Path where catch.pc is installed"
)

View File

@@ -5,9 +5,9 @@
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
[![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/nerce2MiN6sVmfCi)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TpIcJaLaH4WrKlhS)
<a href="https://github.com/catchorg/Catch2/releases/download/v2.0.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
<a href="https://github.com/catchorg/Catch2/releases/download/v2.1.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!

View File

@@ -54,7 +54,7 @@ before_build:
# build with MSBuild
build:
project: Build\CatchSelfTest.sln # path to Visual Studio solution or project
project: Build\Catch2.sln # path to Visual Studio solution or project
parallel: true # enable MSBuild parallel builds
verbosity: normal # MSBuild verbosity level {quiet|minimal|normal|detailed}

View File

@@ -1,9 +1,6 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: Catch
Description: Testing library for C++
Requires:
Version: @CATCH_VERSION_NUMBER@
Libs:
Cflags: -I${prefix}/@INCLUDE_INSTALL_DIR@/include
Version: @Catch2_VERSION@
Cflags: -I${includedir}

View File

@@ -1,6 +1,18 @@
coverage:
precision: 2
round: nearest
range: "60...90"
status:
project:
default:
threshold: 2%
codecov:
branch: master
comment:
layout: "diff"
coverage:
ignore:
- "projects/SelfTest"

View File

@@ -4,7 +4,7 @@ from conans import ConanFile
class CatchConan(ConanFile):
name = "Catch"
version = "2.1.0"
version = "2.1.1"
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
author = "philsquared"
generators = "cmake"

175
contrib/Catch.cmake Normal file
View File

@@ -0,0 +1,175 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
Catch
-----
This module defines a function to help use the Catch test framework.
The :command:`catch_discover_tests` discovers tests by asking the compiled test
executable to enumerate its tests. This does not require CMake to be re-run
when tests change. However, it may not work in a cross-compiling environment,
and setting test properties is less convenient.
This command is intended to replace use of :command:`add_test` to register
tests, and will create a separate CTest test for each Catch test case. Note
that this is in some cases less efficient, as common set-up and tear-down logic
cannot be shared by multiple test cases executing in the same instance.
However, it provides more fine-grained pass/fail information to CTest, which is
usually considered as more beneficial. By default, the CTest test name is the
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
.. command:: catch_discover_tests
Automatically add tests with CTest by querying the compiled test executable
for available tests::
catch_discover_tests(target
[TEST_SPEC arg1...]
[EXTRA_ARGS arg1...]
[WORKING_DIRECTORY dir]
[TEST_PREFIX prefix]
[TEST_SUFFIX suffix]
[PROPERTIES name1 value1...]
[TEST_LIST var]
)
``catch_discover_tests`` sets up a post-build command on the test executable
that generates the list of tests by parsing the output from running the test
with the ``--list-test-names-only`` argument. This ensures that the full
list of tests is obtained. Since test discovery occurs at build time, it is
not necessary to re-run CMake when the list of tests changes.
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
in order to function in a cross-compiling environment.
Additionally, setting properties on tests is somewhat less convenient, since
the tests are not available at CMake time. Additional test properties may be
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
more fine-grained test control is needed, custom content may be provided
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
directory property. The set of discovered tests is made accessible to such a
script via the ``<target>_TESTS`` variable.
The options are:
``target``
Specifies the Catch executable, which must be a known CMake executable
target. CMake will substitute the location of the built executable when
running the test.
``TEST_SPEC arg1...``
Specifies test cases, wildcarded test cases, tags and tag expressions to
pass to the Catch executable with the ``--list-test-names-only`` argument.
``EXTRA_ARGS arg1...``
Any extra arguments to pass on the command line to each test case.
``WORKING_DIRECTORY dir``
Specifies the directory in which to run the discovered test cases. If this
option is not provided, the current binary directory is used.
``TEST_PREFIX prefix``
Specifies a ``prefix`` to be prepended to the name of each discovered test
case. This can be useful when the same test executable is being used in
multiple calls to ``catch_discover_tests()`` but with different
``TEST_SPEC`` or ``EXTRA_ARGS``.
``TEST_SUFFIX suffix``
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
be specified.
``PROPERTIES name1 value1...``
Specifies additional properties to be set on all tests discovered by this
invocation of ``catch_discover_tests``.
``TEST_LIST var``
Make the list of tests available in the variable ``var``, rather than the
default ``<target>_TESTS``. This can be useful when the same test
executable is being used in multiple calls to ``catch_discover_tests()``.
Note that this variable is only available in CTest.
#]=======================================================================]
#------------------------------------------------------------------------------
function(catch_discover_tests TARGET)
cmake_parse_arguments(
""
""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
${ARGN}
)
if(NOT _WORKING_DIRECTORY)
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT _TEST_LIST)
set(_TEST_LIST ${TARGET}_TESTS)
endif()
## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
get_property(crosscompiling_emulator
TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR
)
add_custom_command(
TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${ctest_tests_file}"
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "CTEST_FILE=${ctest_tests_file}"
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
VERBATIM
)
file(WRITE "${ctest_include_file}"
"if(EXISTS \"${ctest_tests_file}\")\n"
" include(\"${ctest_tests_file}\")\n"
"else()\n"
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
"endif()\n"
)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
# Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
)
else()
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
if (NOT ${test_include_file_set})
set_property(DIRECTORY
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
)
else()
message(FATAL_ERROR
"Cannot set more than one TEST_INCLUDE_FILE"
)
endif()
endif()
endfunction()
###############################################################################
set(_CATCH_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
)

View File

@@ -0,0 +1,77 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
set(prefix "${TEST_PREFIX}")
set(suffix "${TEST_SUFFIX}")
set(spec ${TEST_SPEC})
set(extra_args ${TEST_EXTRA_ARGS})
set(properties ${TEST_PROPERTIES})
set(script)
set(suite)
set(tests)
function(add_command NAME)
set(_args "")
foreach(_arg ${ARGN})
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
# Run test executable to get list of available tests
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
)
endif()
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
OUTPUT_VARIABLE output
RESULT_VARIABLE result
)
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
if(${result} EQUAL 0)
message(WARNING
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
)
elseif(${result} LESS 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${result}\n"
" Output: ${output}\n"
)
endif()
string(REPLACE "\n" ";" output "${output}")
# Parse output
foreach(line ${output})
# Test name; strip spaces to get just the name...
string(REGEX REPLACE " +" "" test "${line}")
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
"${test}"
${extra_args}
)
add_command(set_tests_properties
"${prefix}${test}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
${properties}
)
list(APPEND tests "${prefix}${test}${suffix}")
endforeach()
# Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests
add_command(set ${TEST_LIST} ${tests})
# Write CTest script
file(WRITE "${CTEST_FILE}" "${script}")

View File

@@ -28,9 +28,14 @@ The advantage of this format is that the JUnit Ant schema is widely understood b
The disadvantage is that this schema was designed to correspond to how JUnit works - and there is a significant mismatch with how Catch works. Additionally the format is not streamable (because opening elements hold counts of failed and passing tests as attributes) - so the whole test run must complete before it can be written.
## Other reporters
Other reporters are not part of the single-header distribution and need to be downloaded and included separately. All reporters are stored in `include/reporters` directory in the git repository, and are named `catch_reporter_*.hpp`. For example, to use the TeamCity reporter you need to download `include/reporters/catch_reporter_teamcity.hpp` and include it after Catch itself.
Other reporters are not part of the single-header distribution and need
to be downloaded and included separately. All reporters are stored in
`single_include` directory in the git repository, and are named
`catch_reporter_*.hpp`. For example, to use the TeamCity reporter you
need to download `single_include/catch_reporter_teamcity.hpp` and include
it after Catch itself.
```
```cpp
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "catch_reporter_teamcity.hpp"
@@ -124,7 +129,15 @@ The advantage of this approach is that you can always automatically update Catch
### Automatic test registration
If you are also using ctest, `contrib/ParseAndAddCatchTests.cmake` is a CMake script that attempts to parse your test files and automatically register all test cases, using tags as labels. This means that these
We provide 2 CMake scripts that can automatically register Catch-based
tests with CTest,
* `contrib/ParseAndAddCatchTests.cmake`
* `contrib/CatchAddTests.cmake`
The first is based on parsing the test implementation files, and attempts
to register all `TEST_CASE`s using their tags as labels. This means that
these:
```cpp
TEST_CASE("Test1", "[unit]") {
int a = 1;
@@ -144,7 +157,14 @@ TEST_CASE("Test3", "[a][b][c]") {
REQUIRE(a == b);
}
```
would be registered as 3 tests, `Test1`, `Test2` and `Test3`, and 4 ctest labels would be created, `a`, `b`, `c` and `unit`.
would be registered as 3 tests, `Test1`, `Test2` and `Test3`,
and 4 CTest labels would be created, `a`, `b`, `c` and `unit`.
The second is based on parsing the output of a Catch binary given
`--list-test-names-only`. This means that it deals with inactive
(e.g. commented-out) tests better, but requires CMake 3.10 for full
functionality.
### CodeCoverage module (GCOV, LCOV...)

View File

@@ -81,6 +81,7 @@ int main( int argc, char* argv[] )
int height = 0; // Some user variable you want to be able to set
// Build a new parser on top of Catch's
using namespace Catch::clara;
auto cli
= session.cli() // Get Catch's composite command line parser
| Opt( height, "height" ) // bind variable to a new option, with a hint string

View File

@@ -1,5 +1,27 @@
<a id="top"></a>
# 2.1.1
## Improvements
* Static arrays are now properly stringified like ranges across MSVC/GCC/Clang
* Embedded newer version of Clara -- v1.1.1
* This should fix some warnings dragged in from Clara
* MSVC's CLR exceptions are supported
## Fixes
* Fixed compilation when comparison operators do not return bool (#1147)
* Fixed CLR exceptions blowing up the executable during translation (#1138)
## Other changes
* Many CMake changes
* `NO_SELFTEST` option is deprecated, use `BUILD_TESTING` instead.
* Catch specific CMake options were prefixed with `CATCH_` for namespacing purposes
* Other changes to simplify Catch2's packaging
# 2.1.0
## Improvements

View File

@@ -21,10 +21,8 @@ Catch uses a variant of [semantic versioning](http://semver.org/), with breaking
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`.
This will take care of generating the single include header, updating
version numbers everywhere and pushing the new version to Wandbox.
### Release notes
@@ -39,11 +37,19 @@ After version number is incremented, single-include header is regenerated and re
### 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.
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. All non-bundled reporters (Automake,
TAP, TeamCity) should also be attached as binaries, as they are dependent
on a specific version of the single-include header.
## 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.
The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they *should* happen, but they can happen the next day without losing anything significant.
### vcpkg update
@@ -57,8 +63,3 @@ GitHub
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

@@ -1,7 +1,7 @@
#
# Build examples.
#
# Requires BUILD_EXAMPLES to be defined 'true', see ../CMakeLists.txt.
# Requires CATCH_BUILD_EXAMPLES to be defined 'true', see ../CMakeLists.txt.
#
cmake_minimum_required( VERSION 3.0 )

View File

@@ -1,5 +1,11 @@
// v1.0-develop.2
// See https://github.com/philsquared/Clara
// 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)
//
// See https://github.com/philsquared/Clara for more details
// Clara v1.1.1
#ifndef CATCH_CLARA_HPP_INCLUDED
#define CATCH_CLARA_HPP_INCLUDED
@@ -370,7 +376,7 @@ namespace detail {
template<typename ClassT, typename ReturnT, typename ArgT>
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
static const bool isValid = true;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
using ReturnType = ReturnT;
};
@@ -535,7 +541,7 @@ namespace detail {
return *this;
}
~ResultValueBase() {
~ResultValueBase() override {
if( m_type == Ok )
m_value.~T();
}
@@ -573,7 +579,7 @@ namespace detail {
auto errorMessage() const -> std::string { return m_errorMessage; }
protected:
virtual void enforceOk() const {
void enforceOk() const override {
// !TBD: If no exceptions, std::terminate here or something
switch( m_type ) {
case ResultBase::LogicError:
@@ -653,46 +659,30 @@ namespace detail {
return ParserResult::ok( ParseResultType::Matched );
}
struct BoundRefBase {
BoundRefBase() = default;
BoundRefBase( BoundRefBase const & ) = delete;
BoundRefBase( BoundRefBase && ) = delete;
BoundRefBase &operator=( BoundRefBase const & ) = delete;
BoundRefBase &operator=( BoundRefBase && ) = delete;
struct NonCopyable {
NonCopyable() = default;
NonCopyable( NonCopyable const & ) = delete;
NonCopyable( NonCopyable && ) = delete;
NonCopyable &operator=( NonCopyable const & ) = delete;
NonCopyable &operator=( NonCopyable && ) = delete;
};
virtual ~BoundRefBase() = default;
virtual auto isFlag() const -> bool = 0;
struct BoundRef : NonCopyable {
virtual ~BoundRef() = default;
virtual auto isContainer() const -> bool { return false; }
};
struct BoundValueRefBase : BoundRef {
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
};
struct BoundFlagRefBase : BoundRef {
virtual auto setFlag( bool flag ) -> ParserResult = 0;
};
struct BoundValueRefBase : BoundRefBase {
auto isFlag() const -> bool override { return false; }
auto setFlag( bool ) -> ParserResult override {
return ParserResult::logicError( "Flags can only be set on boolean fields" );
}
};
struct BoundFlagRefBase : BoundRefBase {
auto isFlag() const -> bool override { return true; }
auto setValue( std::string const &arg ) -> ParserResult override {
bool flag;
auto result = convertInto( arg, flag );
if( result )
setFlag( flag );
return result;
}
};
template<typename T>
struct BoundRef : BoundValueRefBase {
struct BoundValueRef : BoundValueRefBase {
T &m_ref;
explicit BoundRef( T &ref ) : m_ref( ref ) {}
explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
auto setValue( std::string const &arg ) -> ParserResult override {
return convertInto( arg, m_ref );
@@ -700,10 +690,10 @@ namespace detail {
};
template<typename T>
struct BoundRef<std::vector<T>> : BoundValueRefBase {
struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
std::vector<T> &m_ref;
explicit BoundRef( std::vector<T> &ref ) : m_ref( ref ) {}
explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
auto isContainer() const -> bool override { return true; }
@@ -748,12 +738,12 @@ namespace detail {
template<typename ArgType, typename L>
inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
ArgType temp;
ArgType temp{};
auto result = convertInto( arg, temp );
return !result
? result
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
};
}
template<typename L>
@@ -803,6 +793,9 @@ namespace detail {
public:
template<typename T>
auto operator|( T const &other ) const -> Parser;
template<typename T>
auto operator+( T const &other ) const -> Parser;
};
// Common code and state for Args and Opts
@@ -810,16 +803,16 @@ namespace detail {
class ParserRefImpl : public ComposableParserImpl<DerivedT> {
protected:
Optionality m_optionality = Optionality::Optional;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundRef> m_ref;
std::string m_hint;
std::string m_description;
explicit ParserRefImpl( std::shared_ptr<BoundRefBase> const &ref ) : m_ref( ref ) {}
explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
public:
template<typename T>
ParserRefImpl( T &ref, std::string const &hint )
: m_ref( std::make_shared<BoundRef<T>>( ref ) ),
: m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
m_hint( hint )
{}
@@ -860,10 +853,10 @@ namespace detail {
class ExeName : public ComposableParserImpl<ExeName> {
std::shared_ptr<std::string> m_name;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundValueRefBase> m_ref;
template<typename LambdaT>
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundRefBase> {
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
}
@@ -871,7 +864,7 @@ namespace detail {
ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
explicit ExeName( std::string &ref ) : ExeName() {
m_ref = std::make_shared<BoundRef<std::string>>( ref );
m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
}
template<typename LambdaT>
@@ -914,7 +907,10 @@ namespace detail {
if( token.type != TokenType::Argument )
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
auto result = m_ref->setValue( remainingTokens->token );
assert( dynamic_cast<detail::BoundValueRefBase*>( m_ref.get() ) );
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
auto result = valueRef->setValue( remainingTokens->token );
if( !result )
return InternalParseResult( result );
else
@@ -987,20 +983,22 @@ namespace detail {
if( remainingTokens && remainingTokens->type == TokenType::Option ) {
auto const &token = *remainingTokens;
if( isMatch(token.token ) ) {
if( m_ref->isFlag() ) {
auto result = m_ref->setFlag( true );
if( auto flagRef = dynamic_cast<detail::BoundFlagRefBase*>( m_ref.get() ) ) {
auto result = flagRef->setFlag( true );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
} else {
assert( dynamic_cast<detail::BoundValueRefBase*>( m_ref.get() ) );
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
++remainingTokens;
if( !remainingTokens )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto const &argToken = *remainingTokens;
if( argToken.type != TokenType::Argument )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto result = m_ref->setValue( argToken.token );
auto result = valueRef->setValue( argToken.token );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
@@ -1077,6 +1075,12 @@ namespace detail {
return Parser( *this ) |= other;
}
// Forward deprecated interface with '+' instead of '|'
template<typename T>
auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
template<typename T>
auto operator+( T const &other ) const -> Parser { return operator|( other ); }
auto getHelpColumns() const -> std::vector<HelpColumns> {
std::vector<HelpColumns> cols;
for (auto const &o : m_options) {
@@ -1116,6 +1120,8 @@ namespace detail {
for( auto const &cols : rows )
optWidth = (std::max)(optWidth, cols.left.size() + 2);
optWidth = (std::min)(optWidth, consoleWidth/2);
for( auto const &cols : rows ) {
auto row =
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +

View File

@@ -82,7 +82,7 @@ namespace Catch {
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
template<typename LhsT, typename RhsT>
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; };
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); };
template<typename T>
auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
template<typename T>
@@ -93,7 +93,7 @@ namespace Catch {
auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
template<typename LhsT, typename RhsT>
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; };
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); };
template<typename T>
auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
template<typename T>
@@ -128,19 +128,19 @@ namespace Catch {
template<typename RhsT>
auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs > rhs, m_lhs, ">", rhs };
return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };
}
template<typename RhsT>
auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs < rhs, m_lhs, "<", rhs };
return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };
}
template<typename RhsT>
auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs >= rhs, m_lhs, ">=", rhs };
return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };
}
template<typename RhsT>
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs <= rhs, m_lhs, "<=", rhs };
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
}
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {

View File

@@ -33,6 +33,17 @@ namespace Catch {
return Catch::Detail::stringify( [exception description] );
}
#else
// Compiling a mixed mode project with MSVC means that CLR
// exceptions will be caught in (...) as well. However, these
// do not fill-in std::current_exception and thus lead to crash
// when attempting rethrow.
// /EHa switch also causes structured exceptions to be caught
// here, but they fill-in current_exception properly, so
// at worst the output should be a little weird, instead of
// causing a crash.
if (std::current_exception() == nullptr) {
return "Non C++ exception. Possibly a CLR exception.";
}
return tryTranslators();
#endif
}

View File

@@ -259,6 +259,9 @@ namespace Catch {
if( Option<std::size_t> listed = list( config() ) )
return static_cast<int>( *listed );
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
return (std::min)( MaxExitCode, static_cast<int>( runTests( m_config ).assertions.failed ) );
}
catch( std::exception& ex ) {

View File

@@ -136,18 +136,6 @@ namespace Catch {
static std::string convert(wchar_t * str);
};
template<typename T>
struct is_string_array : std::false_type {};
template<std::size_t N>
struct is_string_array<char[N]> : std::true_type {};
template<std::size_t N>
struct is_string_array<signed char[N]> : std::true_type {};
template<std::size_t N>
struct is_string_array<unsigned char[N]> : std::true_type {};
template<int SZ>
struct StringMaker<char[SZ]> {
static std::string convert(const char* str) {
@@ -399,12 +387,20 @@ namespace Catch {
}
template<typename R>
struct StringMaker<R, typename std::enable_if<is_range<R>::value && !is_string_array<R>::value>::type> {
struct StringMaker<R, typename std::enable_if<is_range<R>::value && !std::is_array<R>::value>::type> {
static std::string convert( R const& range ) {
return rangeToString( range );
}
};
template <typename T, int SZ>
struct StringMaker<T[SZ]> {
static std::string convert(T const(&arr)[SZ]) {
return rangeToString(arr);
}
};
} // namespace Catch
// Separate std::chrono::duration specialization

View File

@@ -37,7 +37,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 1, 0, "", 0 );
static Version version( 2, 1, 1, "", 0 );
return version;
}

View File

@@ -6,7 +6,7 @@ if "%CONFIGURATION%"=="Debug" (
python scripts\generateSingleHeader.py
cmake -Hmisc -Bbuild-misc -A%PLATFORM%
cmake --build build-misc
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DBUILD_EXAMPLES=ON -DMEMORYCHECK_COMMAND=build-misc\Debug\CoverageHelper.exe -DMEMORYCHECK_COMMAND_OPTIONS=--sep-- -DMEMORYCHECK_TYPE=Valgrind
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DCATCH_BUILD_EXAMPLES=ON -DMEMORYCHECK_COMMAND=build-misc\Debug\CoverageHelper.exe -DMEMORYCHECK_COMMAND_OPTIONS=--sep-- -DMEMORYCHECK_TYPE=Valgrind
)
if "%CONFIGURATION%"=="Release" (
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%

View File

@@ -3,6 +3,12 @@ Decomposition.tests.cpp:<line number>: passed: fptr == 0 for: 0 == 0
Decomposition.tests.cpp:<line number>: passed: fptr == 0l for: 0 == 0
Compilation.tests.cpp:<line number>: passed: y.v == 0 for: 0 == 0
Compilation.tests.cpp:<line number>: passed: 0 == y.v for: 0 == 0
Compilation.tests.cpp:<line number>: passed: t1 == t2 for: {?} == {?}
Compilation.tests.cpp:<line number>: passed: t1 != t2 for: {?} != {?}
Compilation.tests.cpp:<line number>: passed: t1 < t2 for: {?} < {?}
Compilation.tests.cpp:<line number>: passed: t1 > t2 for: {?} > {?}
Compilation.tests.cpp:<line number>: passed: t1 <= t2 for: {?} <= {?}
Compilation.tests.cpp:<line number>: passed: t1 >= t2 for: {?} >= {?}
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception'
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
@@ -592,6 +598,11 @@ Message from section one
Message from section two
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), StartsWith("This String") for: "this string contains 'abc' as a substring" starts with: "This String"
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), StartsWith("string", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" starts with: "string" (case insensitive)
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify(singular) == "{ 1 }" for: "{ 1 }" == "{ 1 }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify(arr) == "{ 3, 2, 1 }" for: "{ 3, 2, 1 }" == "{ 3, 2, 1 }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })" for: "{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
==
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Contains("string") for: "this string contains 'abc' as a substring" contains: "string"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Contains("string", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "string" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Contains("abc") for: "this string contains 'abc' as a substring" contains: "abc"

View File

@@ -1064,6 +1064,6 @@ with expansion:
"first" == "second"
===============================================================================
test cases: 195 | 144 passed | 47 failed | 4 failed as expected
assertions: 983 | 857 passed | 105 failed | 21 failed as expected
test cases: 197 | 146 passed | 47 failed | 4 failed as expected
assertions: 992 | 866 passed | 105 failed | 21 failed as expected

View File

@@ -51,6 +51,48 @@ PASSED:
with expansion:
0 == 0
-------------------------------------------------------------------------------
#1147
-------------------------------------------------------------------------------
Compilation.tests.cpp:<line number>
...............................................................................
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 == t2 )
with expansion:
{?} == {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 != t2 )
with expansion:
{?} != {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 < t2 )
with expansion:
{?} < {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 > t2 )
with expansion:
{?} > {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 <= t2 )
with expansion:
{?} <= {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 >= t2 )
with expansion:
{?} >= {?}
-------------------------------------------------------------------------------
#748 - captures with unexpected exceptions
outside assertions
@@ -4707,6 +4749,47 @@ with expansion:
"this string contains 'abc' as a substring" starts with: "string" (case
insensitive)
-------------------------------------------------------------------------------
Static arrays are convertible to string
Single item
-------------------------------------------------------------------------------
ToStringGeneral.tests.cpp:<line number>
...............................................................................
ToStringGeneral.tests.cpp:<line number>:
PASSED:
REQUIRE( Catch::Detail::stringify(singular) == "{ 1 }" )
with expansion:
"{ 1 }" == "{ 1 }"
-------------------------------------------------------------------------------
Static arrays are convertible to string
Multiple
-------------------------------------------------------------------------------
ToStringGeneral.tests.cpp:<line number>
...............................................................................
ToStringGeneral.tests.cpp:<line number>:
PASSED:
REQUIRE( Catch::Detail::stringify(arr) == "{ 3, 2, 1 }" )
with expansion:
"{ 3, 2, 1 }" == "{ 3, 2, 1 }"
-------------------------------------------------------------------------------
Static arrays are convertible to string
Non-trivial inner items
-------------------------------------------------------------------------------
ToStringGeneral.tests.cpp:<line number>
...............................................................................
ToStringGeneral.tests.cpp:<line number>:
PASSED:
REQUIRE( Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })" )
with expansion:
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
==
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
-------------------------------------------------------------------------------
String matchers
-------------------------------------------------------------------------------
@@ -8246,6 +8329,6 @@ Misc.tests.cpp:<line number>:
PASSED:
===============================================================================
test cases: 195 | 142 passed | 49 failed | 4 failed as expected
assertions: 982 | 853 passed | 108 failed | 21 failed as expected
test cases: 197 | 144 passed | 49 failed | 4 failed as expected
assertions: 991 | 862 passed | 108 failed | 21 failed as expected

View File

@@ -51,6 +51,48 @@ PASSED:
with expansion:
0 == 0
-------------------------------------------------------------------------------
#1147
-------------------------------------------------------------------------------
Compilation.tests.cpp:<line number>
...............................................................................
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 == t2 )
with expansion:
{?} == {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 != t2 )
with expansion:
{?} != {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 < t2 )
with expansion:
{?} < {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 > t2 )
with expansion:
{?} > {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 <= t2 )
with expansion:
{?} <= {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 >= t2 )
with expansion:
{?} >= {?}
-------------------------------------------------------------------------------
#748 - captures with unexpected exceptions
outside assertions
@@ -257,6 +299,6 @@ with expansion:
!true
===============================================================================
test cases: 10 | 7 passed | 1 failed | 2 failed as expected
assertions: 28 | 21 passed | 4 failed | 3 failed as expected
test cases: 11 | 8 passed | 1 failed | 2 failed as expected
assertions: 34 | 27 passed | 4 failed | 3 failed as expected

View File

@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="15" failures="94" tests="983" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="15" failures="94" tests="992" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1147" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}">
<error type="TEST_CASE">
expected exception
@@ -537,6 +538,9 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Single item" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Multiple" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Non-trivial inner items" time="{duration}"/>
<testcase classname="<exe-name>.global" name="String matchers" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Empty string" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/From string literal" time="{duration}"/>

View File

@@ -42,6 +42,57 @@
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="#1147" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 == t2
</Original>
<Expanded>
{?} == {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 != t2
</Original>
<Expanded>
{?} != {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 &lt; t2
</Original>
<Expanded>
{?} &lt; {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 > t2
</Original>
<Expanded>
{?} > {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 &lt;= t2
</Original>
<Expanded>
{?} &lt;= {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 >= t2
</Original>
<Expanded>
{?} >= {?}
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="#748 - captures with unexpected exceptions" tags="[!shouldfail][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Section name="outside assertions" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Info>
@@ -5426,6 +5477,44 @@ Message from section two
</Expression>
<OverallResult success="false"/>
</TestCase>
<TestCase name="Static arrays are convertible to string" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Section name="Single item" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Original>
Catch::Detail::stringify(singular) == "{ 1 }"
</Original>
<Expanded>
"{ 1 }" == "{ 1 }"
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Multiple" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Original>
Catch::Detail::stringify(arr) == "{ 3, 2, 1 }"
</Original>
<Expanded>
"{ 3, 2, 1 }" == "{ 3, 2, 1 }"
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Non-trivial inner items" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Original>
Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })"
</Original>
<Expanded>
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
==
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="String matchers" tags="[matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
@@ -9168,7 +9257,7 @@ loose text artifact
</Section>
<OverallResult success="true"/>
</TestCase>
<OverallResults successes="853" failures="109" expectedFailures="21"/>
<OverallResults successes="862" failures="109" expectedFailures="21"/>
</Group>
<OverallResults successes="853" failures="108" expectedFailures="21"/>
<OverallResults successes="862" failures="108" expectedFailures="21"/>
</Catch>

View File

@@ -12,6 +12,19 @@ namespace { namespace CompilationTests {
#ifndef COMPILATION_TEST_HELPERS_INCLUDED // Don't compile this more than once per TU
#define COMPILATION_TEST_HELPERS_INCLUDED
// Comparison operators can return non-booleans.
// This is unusual, but should be supported.
struct logic_t {
logic_t operator< (logic_t) const { return {}; }
logic_t operator<=(logic_t) const { return {}; }
logic_t operator> (logic_t) const { return {}; }
logic_t operator>=(logic_t) const { return {}; }
logic_t operator==(logic_t) const { return {}; }
logic_t operator!=(logic_t) const { return {}; }
explicit operator bool() const { return true; }
};
// This is a minimal example for an issue we have found in 1.7.0
struct foo {
int i;
@@ -109,4 +122,16 @@ namespace { namespace CompilationTests {
REQUIRE(0 == y.v);
}
// Comparison operators can return non-booleans.
// This is unusual, but should be supported.
TEST_CASE("#1147") {
logic_t t1, t2;
REQUIRE(t1 == t2);
REQUIRE(t1 != t2);
REQUIRE(t1 < t2);
REQUIRE(t1 > t2);
REQUIRE(t1 <= t2);
REQUIRE(t1 >= t2);
}
}} // namespace CompilationTests

View File

@@ -100,3 +100,18 @@ TEST_CASE( "std::set is convertible string", "[toString]" ) {
REQUIRE( Catch::Detail::stringify( set ) == "{ \"abc\", \"def\", \"ghi\" }" );
}
}
TEST_CASE("Static arrays are convertible to string", "[toString]") {
SECTION("Single item") {
int singular[1] = { 1 };
REQUIRE(Catch::Detail::stringify(singular) == "{ 1 }");
}
SECTION("Multiple") {
int arr[3] = { 3, 2, 1 };
REQUIRE(Catch::Detail::stringify(arr) == "{ 3, 2, 1 }");
}
SECTION("Non-trivial inner items") {
std::vector<std::string> arr[2] = { {"1:1", "1:2", "1:3"}, {"2:1", "2:2"} };
REQUIRE(Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })");
}
}

View File

@@ -50,6 +50,8 @@ infParser = re.compile(r'''
|
\(__builtin_inff\(\)\) # Linux (ubuntu) INFINITY macro
|
\(__builtin_inff\ \(\)\) # Fedora INFINITY macro
|
__builtin_huge_valf\(\) # OSX macro
''', re.VERBOSE)
nanParser = re.compile(r'''

View File

@@ -3,6 +3,7 @@
from __future__ import print_function
import os
import io
import sys
import re
import datetime
@@ -46,11 +47,11 @@ def generate(v):
outDir = os.path.dirname(outputPath)
if not os.path.exists(outDir):
os.makedirs(outDir)
out = open( outputPath, 'w' )
out = io.open( outputPath, 'w', newline='\n')
def write( line ):
if globals['includeImpl'] or globals['implIfDefs'] == -1:
out.write( line )
out.write( line.decode('utf-8') )
def insertCpps():
dirs = [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters']]
@@ -104,22 +105,22 @@ def generate(v):
write( '// end {}\n'.format(filename) )
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) {} Two Blue Cubes Ltd. All rights reserved.\n".format( datetime.date.today().year ) )
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" )
write( "/*\n" )
write( " * Catch v{0}\n".format( v.getVersionString() ) )
write( " * Generated: {0}\n".format( datetime.datetime.now() ) )
write( " * ----------------------------------------------------------\n" )
write( " * This file has been merged from multiple headers. Please don't edit it directly\n" )
write( " * Copyright (c) {} Two Blue Cubes Ltd. All rights reserved.\n".format( datetime.date.today().year ) )
write( " *\n" )
write( " * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" )
write( " * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" )
write( " */\n" )
write( "#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
write( "#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
parseFile( rootPath, 'catch.hpp' )
out.write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
out.close()
print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) )

View File

@@ -80,7 +80,7 @@ class Version:
def updateReadmeFile(version):
import updateWandbox
downloadParser = re.compile( r'<a href=\"https://github.com/philsquared/Catch/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
downloadParser = re.compile( r'<a href=\"https://github.com/catchorg/Catch2/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
success, wandboxLink = updateWandbox.uploadFiles()
if not success:
print('Error when uploading to wandbox: {}'.format(wandboxLink))
@@ -92,7 +92,7 @@ def updateReadmeFile(version):
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)
line = downloadParser.sub( r'<a href="https://github.com/catchorg/Catch2/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" )
@@ -128,13 +128,12 @@ def updateConanTestFile(version):
f.write( line + "\n" )
def updateCmakeFile(version):
cmakeParser = re.compile(r'set(CATCH_VERSION_NUMBER \d+\.\d+\.\d+)')
with open(cmakePath, 'r') as file:
lines = file.readlines()
with open(cmakePath, 'w') as file:
for line in lines:
if 'set(CATCH_VERSION_NUMBER ' in line:
file.write('set(CATCH_VERSION_NUMBER {0})\n'.format(version.getVersionString()))
if 'project(Catch2 LANGUAGES CXX VERSION ' in line:
file.write('project(Catch2 LANGUAGES CXX VERSION {0})\n'.format(version.getVersionString()))
else:
file.write(line)

View File

@@ -8,7 +8,7 @@ from releaseCommon import Version
print(catchPath)
default_path = '../vcpkg/ports/catch/'
default_path = '../vcpkg/ports/catch2/'
def adjusted_path(path):
return os.path.join(catchPath, path)

View File

@@ -1,6 +1,6 @@
/*
* Catch v2.1.0
* Generated: 2018-01-10 13:51:15.378034
* Catch v2.1.1
* Generated: 2018-01-26 16:04:07.190063
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved.
@@ -807,18 +807,6 @@ namespace Catch {
static std::string convert(wchar_t * str);
};
template<typename T>
struct is_string_array : std::false_type {};
template<std::size_t N>
struct is_string_array<char[N]> : std::true_type {};
template<std::size_t N>
struct is_string_array<signed char[N]> : std::true_type {};
template<std::size_t N>
struct is_string_array<unsigned char[N]> : std::true_type {};
template<int SZ>
struct StringMaker<char[SZ]> {
static std::string convert(const char* str) {
@@ -1069,12 +1057,19 @@ namespace Catch {
}
template<typename R>
struct StringMaker<R, typename std::enable_if<is_range<R>::value && !is_string_array<R>::value>::type> {
struct StringMaker<R, typename std::enable_if<is_range<R>::value && !std::is_array<R>::value>::type> {
static std::string convert( R const& range ) {
return rangeToString( range );
}
};
template <typename T, int SZ>
struct StringMaker<T[SZ]> {
static std::string convert(T const(&arr)[SZ]) {
return rangeToString(arr);
}
};
} // namespace Catch
// Separate std::chrono::duration specialization
@@ -1269,7 +1264,7 @@ namespace Catch {
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
template<typename LhsT, typename RhsT>
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; };
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); };
template<typename T>
auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
template<typename T>
@@ -1280,7 +1275,7 @@ namespace Catch {
auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
template<typename LhsT, typename RhsT>
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; };
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); };
template<typename T>
auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
template<typename T>
@@ -1314,19 +1309,19 @@ namespace Catch {
template<typename RhsT>
auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs > rhs, m_lhs, ">", rhs };
return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };
}
template<typename RhsT>
auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs < rhs, m_lhs, "<", rhs };
return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };
}
template<typename RhsT>
auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs >= rhs, m_lhs, ">=", rhs };
return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };
}
template<typename RhsT>
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs <= rhs, m_lhs, "<=", rhs };
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
}
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
@@ -5093,8 +5088,14 @@ namespace Catch {
#endif
// start clara.hpp
// v1.0-develop.2
// See https://github.com/philsquared/Clara
// 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)
//
// See https://github.com/philsquared/Clara for more details
// Clara v1.1.1
#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH
@@ -5457,7 +5458,7 @@ namespace detail {
template<typename ClassT, typename ReturnT, typename ArgT>
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
static const bool isValid = true;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
using ReturnType = ReturnT;
};
@@ -5621,7 +5622,7 @@ namespace detail {
return *this;
}
~ResultValueBase() {
~ResultValueBase() override {
if( m_type == Ok )
m_value.~T();
}
@@ -5659,7 +5660,7 @@ namespace detail {
auto errorMessage() const -> std::string { return m_errorMessage; }
protected:
virtual void enforceOk() const {
void enforceOk() const override {
// !TBD: If no exceptions, std::terminate here or something
switch( m_type ) {
case ResultBase::LogicError:
@@ -5739,46 +5740,30 @@ namespace detail {
return ParserResult::ok( ParseResultType::Matched );
}
struct BoundRefBase {
BoundRefBase() = default;
BoundRefBase( BoundRefBase const & ) = delete;
BoundRefBase( BoundRefBase && ) = delete;
BoundRefBase &operator=( BoundRefBase const & ) = delete;
BoundRefBase &operator=( BoundRefBase && ) = delete;
struct NonCopyable {
NonCopyable() = default;
NonCopyable( NonCopyable const & ) = delete;
NonCopyable( NonCopyable && ) = delete;
NonCopyable &operator=( NonCopyable const & ) = delete;
NonCopyable &operator=( NonCopyable && ) = delete;
};
virtual ~BoundRefBase() = default;
virtual auto isFlag() const -> bool = 0;
struct BoundRef : NonCopyable {
virtual ~BoundRef() = default;
virtual auto isContainer() const -> bool { return false; }
};
struct BoundValueRefBase : BoundRef {
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
};
struct BoundFlagRefBase : BoundRef {
virtual auto setFlag( bool flag ) -> ParserResult = 0;
};
struct BoundValueRefBase : BoundRefBase {
auto isFlag() const -> bool override { return false; }
auto setFlag( bool ) -> ParserResult override {
return ParserResult::logicError( "Flags can only be set on boolean fields" );
}
};
struct BoundFlagRefBase : BoundRefBase {
auto isFlag() const -> bool override { return true; }
auto setValue( std::string const &arg ) -> ParserResult override {
bool flag;
auto result = convertInto( arg, flag );
if( result )
setFlag( flag );
return result;
}
};
template<typename T>
struct BoundRef : BoundValueRefBase {
struct BoundValueRef : BoundValueRefBase {
T &m_ref;
explicit BoundRef( T &ref ) : m_ref( ref ) {}
explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
auto setValue( std::string const &arg ) -> ParserResult override {
return convertInto( arg, m_ref );
@@ -5786,10 +5771,10 @@ namespace detail {
};
template<typename T>
struct BoundRef<std::vector<T>> : BoundValueRefBase {
struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
std::vector<T> &m_ref;
explicit BoundRef( std::vector<T> &ref ) : m_ref( ref ) {}
explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
auto isContainer() const -> bool override { return true; }
@@ -5834,12 +5819,12 @@ namespace detail {
template<typename ArgType, typename L>
inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
ArgType temp;
ArgType temp{};
auto result = convertInto( arg, temp );
return !result
? result
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
};
}
template<typename L>
struct BoundLambda : BoundValueRefBase {
@@ -5888,6 +5873,9 @@ namespace detail {
public:
template<typename T>
auto operator|( T const &other ) const -> Parser;
template<typename T>
auto operator+( T const &other ) const -> Parser;
};
// Common code and state for Args and Opts
@@ -5895,16 +5883,16 @@ namespace detail {
class ParserRefImpl : public ComposableParserImpl<DerivedT> {
protected:
Optionality m_optionality = Optionality::Optional;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundRef> m_ref;
std::string m_hint;
std::string m_description;
explicit ParserRefImpl( std::shared_ptr<BoundRefBase> const &ref ) : m_ref( ref ) {}
explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
public:
template<typename T>
ParserRefImpl( T &ref, std::string const &hint )
: m_ref( std::make_shared<BoundRef<T>>( ref ) ),
: m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
m_hint( hint )
{}
@@ -5945,10 +5933,10 @@ namespace detail {
class ExeName : public ComposableParserImpl<ExeName> {
std::shared_ptr<std::string> m_name;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundValueRefBase> m_ref;
template<typename LambdaT>
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundRefBase> {
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
}
@@ -5956,7 +5944,7 @@ namespace detail {
ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
explicit ExeName( std::string &ref ) : ExeName() {
m_ref = std::make_shared<BoundRef<std::string>>( ref );
m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
}
template<typename LambdaT>
@@ -5999,7 +5987,10 @@ namespace detail {
if( token.type != TokenType::Argument )
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
auto result = m_ref->setValue( remainingTokens->token );
assert( dynamic_cast<detail::BoundValueRefBase*>( m_ref.get() ) );
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
auto result = valueRef->setValue( remainingTokens->token );
if( !result )
return InternalParseResult( result );
else
@@ -6072,20 +6063,22 @@ namespace detail {
if( remainingTokens && remainingTokens->type == TokenType::Option ) {
auto const &token = *remainingTokens;
if( isMatch(token.token ) ) {
if( m_ref->isFlag() ) {
auto result = m_ref->setFlag( true );
if( auto flagRef = dynamic_cast<detail::BoundFlagRefBase*>( m_ref.get() ) ) {
auto result = flagRef->setFlag( true );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
} else {
assert( dynamic_cast<detail::BoundValueRefBase*>( m_ref.get() ) );
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
++remainingTokens;
if( !remainingTokens )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto const &argToken = *remainingTokens;
if( argToken.type != TokenType::Argument )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto result = m_ref->setValue( argToken.token );
auto result = valueRef->setValue( argToken.token );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
@@ -6161,6 +6154,12 @@ namespace detail {
return Parser( *this ) |= other;
}
// Forward deprecated interface with '+' instead of '|'
template<typename T>
auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
template<typename T>
auto operator+( T const &other ) const -> Parser { return operator|( other ); }
auto getHelpColumns() const -> std::vector<HelpColumns> {
std::vector<HelpColumns> cols;
for (auto const &o : m_options) {
@@ -6200,6 +6199,8 @@ namespace detail {
for( auto const &cols : rows )
optWidth = (std::max)(optWidth, cols.left.size() + 2);
optWidth = (std::min)(optWidth, consoleWidth/2);
for( auto const &cols : rows ) {
auto row =
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
@@ -7086,6 +7087,17 @@ namespace Catch {
return Catch::Detail::stringify( [exception description] );
}
#else
// Compiling a mixed mode project with MSVC means that CLR
// exceptions will be caught in (...) as well. However, these
// do not fill-in std::current_exception and thus lead to crash
// when attempting rethrow.
// /EHa switch also causes structured exceptions to be caught
// here, but they fill-in current_exception properly, so
// at worst the output should be a little weird, instead of
// causing a crash.
if (std::current_exception() == nullptr) {
return "Non C++ exception. Possibly a CLR exception.";
}
return tryTranslators();
#endif
}
@@ -9148,6 +9160,9 @@ namespace Catch {
if( Option<std::size_t> listed = list( config() ) )
return static_cast<int>( *listed );
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
return (std::min)( MaxExitCode, static_cast<int>( runTests( m_config ).assertions.failed ) );
}
catch( std::exception& ex ) {
@@ -10689,7 +10704,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 1, 0, "", 0 );
static Version version( 2, 1, 1, "", 0 );
return version;
}

View File

@@ -10,7 +10,7 @@ class CatchConanTest(ConanFile):
settings = "os", "compiler", "arch", "build_type"
username = getenv("CONAN_USERNAME", "philsquared")
channel = getenv("CONAN_CHANNEL", "testing")
requires = "Catch/2.1.0@%s/%s" % (username, channel)
requires = "Catch/2.1.1@%s/%s" % (username, channel)
def build(self):
cmake = CMake(self)

106
third_party/clara.hpp vendored
View File

@@ -1,5 +1,11 @@
// v1.0-develop.2
// See https://github.com/philsquared/Clara
// 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)
//
// See https://github.com/philsquared/Clara for more details
// Clara v1.1.1
#ifndef CLARA_HPP_INCLUDED
#define CLARA_HPP_INCLUDED
@@ -370,7 +376,7 @@ namespace detail {
template<typename ClassT, typename ReturnT, typename ArgT>
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
static const bool isValid = true;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
using ReturnType = ReturnT;
};
@@ -535,7 +541,7 @@ namespace detail {
return *this;
}
~ResultValueBase() {
~ResultValueBase() override {
if( m_type == Ok )
m_value.~T();
}
@@ -573,7 +579,7 @@ namespace detail {
auto errorMessage() const -> std::string { return m_errorMessage; }
protected:
virtual void enforceOk() const {
void enforceOk() const override {
// !TBD: If no exceptions, std::terminate here or something
switch( m_type ) {
case ResultBase::LogicError:
@@ -653,46 +659,30 @@ namespace detail {
return ParserResult::ok( ParseResultType::Matched );
}
struct BoundRefBase {
BoundRefBase() = default;
BoundRefBase( BoundRefBase const & ) = delete;
BoundRefBase( BoundRefBase && ) = delete;
BoundRefBase &operator=( BoundRefBase const & ) = delete;
BoundRefBase &operator=( BoundRefBase && ) = delete;
struct NonCopyable {
NonCopyable() = default;
NonCopyable( NonCopyable const & ) = delete;
NonCopyable( NonCopyable && ) = delete;
NonCopyable &operator=( NonCopyable const & ) = delete;
NonCopyable &operator=( NonCopyable && ) = delete;
};
virtual ~BoundRefBase() = default;
virtual auto isFlag() const -> bool = 0;
struct BoundRef : NonCopyable {
virtual ~BoundRef() = default;
virtual auto isContainer() const -> bool { return false; }
};
struct BoundValueRefBase : BoundRef {
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
};
struct BoundFlagRefBase : BoundRef {
virtual auto setFlag( bool flag ) -> ParserResult = 0;
};
struct BoundValueRefBase : BoundRefBase {
auto isFlag() const -> bool override { return false; }
auto setFlag( bool ) -> ParserResult override {
return ParserResult::logicError( "Flags can only be set on boolean fields" );
}
};
struct BoundFlagRefBase : BoundRefBase {
auto isFlag() const -> bool override { return true; }
auto setValue( std::string const &arg ) -> ParserResult override {
bool flag;
auto result = convertInto( arg, flag );
if( result )
setFlag( flag );
return result;
}
};
template<typename T>
struct BoundRef : BoundValueRefBase {
struct BoundValueRef : BoundValueRefBase {
T &m_ref;
explicit BoundRef( T &ref ) : m_ref( ref ) {}
explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
auto setValue( std::string const &arg ) -> ParserResult override {
return convertInto( arg, m_ref );
@@ -700,10 +690,10 @@ namespace detail {
};
template<typename T>
struct BoundRef<std::vector<T>> : BoundValueRefBase {
struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
std::vector<T> &m_ref;
explicit BoundRef( std::vector<T> &ref ) : m_ref( ref ) {}
explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
auto isContainer() const -> bool override { return true; }
@@ -748,12 +738,12 @@ namespace detail {
template<typename ArgType, typename L>
inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
ArgType temp;
ArgType temp{};
auto result = convertInto( arg, temp );
return !result
? result
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
};
}
template<typename L>
@@ -803,6 +793,9 @@ namespace detail {
public:
template<typename T>
auto operator|( T const &other ) const -> Parser;
template<typename T>
auto operator+( T const &other ) const -> Parser;
};
// Common code and state for Args and Opts
@@ -810,16 +803,16 @@ namespace detail {
class ParserRefImpl : public ComposableParserImpl<DerivedT> {
protected:
Optionality m_optionality = Optionality::Optional;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundRef> m_ref;
std::string m_hint;
std::string m_description;
explicit ParserRefImpl( std::shared_ptr<BoundRefBase> const &ref ) : m_ref( ref ) {}
explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
public:
template<typename T>
ParserRefImpl( T &ref, std::string const &hint )
: m_ref( std::make_shared<BoundRef<T>>( ref ) ),
: m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
m_hint( hint )
{}
@@ -860,10 +853,10 @@ namespace detail {
class ExeName : public ComposableParserImpl<ExeName> {
std::shared_ptr<std::string> m_name;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundValueRefBase> m_ref;
template<typename LambdaT>
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundRefBase> {
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
}
@@ -871,7 +864,7 @@ namespace detail {
ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
explicit ExeName( std::string &ref ) : ExeName() {
m_ref = std::make_shared<BoundRef<std::string>>( ref );
m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
}
template<typename LambdaT>
@@ -914,7 +907,10 @@ namespace detail {
if( token.type != TokenType::Argument )
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
auto result = m_ref->setValue( remainingTokens->token );
assert( dynamic_cast<detail::BoundValueRefBase*>( m_ref.get() ) );
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
auto result = valueRef->setValue( remainingTokens->token );
if( !result )
return InternalParseResult( result );
else
@@ -987,20 +983,22 @@ namespace detail {
if( remainingTokens && remainingTokens->type == TokenType::Option ) {
auto const &token = *remainingTokens;
if( isMatch(token.token ) ) {
if( m_ref->isFlag() ) {
auto result = m_ref->setFlag( true );
if( auto flagRef = dynamic_cast<detail::BoundFlagRefBase*>( m_ref.get() ) ) {
auto result = flagRef->setFlag( true );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
} else {
assert( dynamic_cast<detail::BoundValueRefBase*>( m_ref.get() ) );
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
++remainingTokens;
if( !remainingTokens )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto const &argToken = *remainingTokens;
if( argToken.type != TokenType::Argument )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto result = m_ref->setValue( argToken.token );
auto result = valueRef->setValue( argToken.token );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
@@ -1077,6 +1075,12 @@ namespace detail {
return Parser( *this ) |= other;
}
// Forward deprecated interface with '+' instead of '|'
template<typename T>
auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
template<typename T>
auto operator+( T const &other ) const -> Parser { return operator|( other ); }
auto getHelpColumns() const -> std::vector<HelpColumns> {
std::vector<HelpColumns> cols;
for (auto const &o : m_options) {
@@ -1116,6 +1120,8 @@ namespace detail {
for( auto const &cols : rows )
optWidth = (std::max)(optWidth, cols.left.size() + 2);
optWidth = (std::min)(optWidth, consoleWidth/2);
for( auto const &cols : rows ) {
auto row =
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +