--- Improvements ---
* Running tests in random order (`--order rand`) has been reworked significantly (#1908)
  * Given same seed, all platforms now produce the same order
  * Given same seed, the relative order of tests does not change if you select only a subset of them
* Vector matchers support custom allocators (#1909)
* `|` and `&` (bitwise or and bitwise and) are now supported in `CHECK` and `REQUIRE`
  * The resulting type must be convertible to `bool`

--- Fixes ---
* Fixed computation of benchmarking column widths in ConsoleReporter (#1885, #1886)
* Suppressed clang-tidy's `cppcoreguidelines-pro-type-vararg` in assertions (#1901)
  * It was a false positive trigered by the new warning support workaround
* Fixed bug in test specification parser handling of OR'd patterns using escaping (#1905)

--- Miscellaneous ---
* Worked around IBM XL's codegen bug (#1907)
  * It would emit code for _destructors_ of temporaries in an unevaluated context
* Improved detection of stdlib's support for `std::uncaught_exceptions` (#1911)
This commit is contained in:
Martin Hořeňovský 2020-04-21 16:33:15 +02:00
parent e59fc2c3b3
commit cfb6956698
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
7 changed files with 167 additions and 66 deletions

View File

@ -14,7 +14,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif() endif()
project(Catch2 LANGUAGES CXX VERSION 2.11.3) project(Catch2 LANGUAGES CXX VERSION 2.12.0)
# Provide path for scripts # Provide path for scripts
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")

View File

@ -5,11 +5,11 @@
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2) [![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) [![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) [![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/p9Pcgple8QWwgNR0) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/oT7SOoJ9ua6JsdEB)
[![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD) [![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
<a href="https://github.com/catchorg/Catch2/releases/download/v2.11.3/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.12.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released! ## Catch2 is released!

View File

@ -260,6 +260,8 @@ Randomly sorted. The order is dependent on Catch2's random seed (see
is that as long as the random seed is fixed, running only some tests is that as long as the random seed is fixed, running only some tests
(e.g. via tag) does not change their relative order. (e.g. via tag) does not change their relative order.
> The subset stability was introduced in Catch2 v2.12.0
<a id="rng-seed"></a> <a id="rng-seed"></a>
## Specify a seed for the Random Number Generator ## Specify a seed for the Random Number Generator

View File

@ -2,6 +2,7 @@
# Release notes # Release notes
**Contents**<br> **Contents**<br>
[2.12.0](#2120)<br>
[2.11.3](#2113)<br> [2.11.3](#2113)<br>
[2.11.2](#2112)<br> [2.11.2](#2112)<br>
[2.11.1](#2111)<br> [2.11.1](#2111)<br>
@ -34,6 +35,28 @@
[Older versions](#older-versions)<br> [Older versions](#older-versions)<br>
[Even Older versions](#even-older-versions)<br> [Even Older versions](#even-older-versions)<br>
## 2.12.0
### Improvements
* Running tests in random order (`--order rand`) has been reworked significantly (#1908)
* Given same seed, all platforms now produce the same order
* Given same seed, the relative order of tests does not change if you select only a subset of them
* Vector matchers support custom allocators (#1909)
* `|` and `&` (bitwise or and bitwise and) are now supported in `CHECK` and `REQUIRE`
* The resulting type must be convertible to `bool`
### Fixes
* Fixed computation of benchmarking column widths in ConsoleReporter (#1885, #1886)
* Suppressed clang-tidy's `cppcoreguidelines-pro-type-vararg` in assertions (#1901)
* It was a false positive trigered by the new warning support workaround
* Fixed bug in test specification parser handling of OR'd patterns using escaping (#1905)
### Miscellaneous
* Worked around IBM XL's codegen bug (#1907)
* It would emit code for _destructors_ of temporaries in an unevaluated context
* Improved detection of stdlib's support for `std::uncaught_exceptions` (#1911)
## 2.11.3 ## 2.11.3
### Fixes ### Fixes

View File

@ -10,8 +10,8 @@
#define TWOBLUECUBES_CATCH_HPP_INCLUDED #define TWOBLUECUBES_CATCH_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 11 #define CATCH_VERSION_MINOR 12
#define CATCH_VERSION_PATCH 3 #define CATCH_VERSION_PATCH 0
#ifdef __clang__ #ifdef __clang__
# pragma clang system_header # pragma clang system_header

View File

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

View File

@ -1,6 +1,6 @@
/* /*
* Catch v2.11.3 * Catch v2.12.0
* Generated: 2020-03-19 13:44:21.042491 * Generated: 2020-04-21 16:27:54.138031
* ---------------------------------------------------------- * ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly * This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved.
@ -14,8 +14,8 @@
#define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 11 #define CATCH_VERSION_MINOR 12
#define CATCH_VERSION_PATCH 3 #define CATCH_VERSION_PATCH 0
#ifdef __clang__ #ifdef __clang__
# pragma clang system_header # pragma clang system_header
@ -132,7 +132,7 @@ namespace Catch {
#endif #endif
#if defined(CATCH_CPP17_OR_GREATER) #if defined(__cpp_lib_uncaught_exceptions)
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif #endif
@ -151,7 +151,20 @@ namespace Catch {
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) // As of this writing, IBM XL's implementation of __builtin_constant_p has a bug
// which results in calls to destructors being emitted for each temporary,
// without a matching initialization. In practice, this can result in something
// like `std::string::~string` being called on an uninitialized value.
//
// For example, this code will likely segfault under IBM XL:
// ```
// REQUIRE(std::string("12") + "34" == "1234")
// ```
//
// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
# if !defined(__ibmxl__)
# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg) */
# endif
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
@ -2356,6 +2369,14 @@ namespace Catch {
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { static_cast<bool>(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 { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs };
}
template <typename RhsT>
auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs };
}
template<typename RhsT> template<typename RhsT>
auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
@ -3000,6 +3021,9 @@ namespace Catch {
{} {}
std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
return "";
#else
try { try {
if( it == itEnd ) if( it == itEnd )
std::rethrow_exception(std::current_exception()); std::rethrow_exception(std::current_exception());
@ -3009,6 +3033,7 @@ namespace Catch {
catch( T& ex ) { catch( T& ex ) {
return m_translateFunction( ex ); return m_translateFunction( ex );
} }
#endif
} }
protected: protected:
@ -3571,12 +3596,12 @@ namespace Catch {
namespace Matchers { namespace Matchers {
namespace Vector { namespace Vector {
template<typename T> template<typename T, typename Alloc>
struct ContainsElementMatcher : MatcherBase<std::vector<T>> { struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> {
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
bool match(std::vector<T> const &v) const override { bool match(std::vector<T, Alloc> const &v) const override {
for (auto const& el : v) { for (auto const& el : v) {
if (el == m_comparator) { if (el == m_comparator) {
return true; return true;
@ -3592,12 +3617,12 @@ namespace Matchers {
T const& m_comparator; T const& m_comparator;
}; };
template<typename T> template<typename T, typename AllocComp, typename AllocMatch>
struct ContainsMatcher : MatcherBase<std::vector<T>> { struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> const &v) const override { bool match(std::vector<T, AllocMatch> const &v) const override {
// !TBD: see note in EqualsMatcher // !TBD: see note in EqualsMatcher
if (m_comparator.size() > v.size()) if (m_comparator.size() > v.size())
return false; return false;
@ -3619,18 +3644,18 @@ namespace Matchers {
return "Contains: " + ::Catch::Detail::stringify( m_comparator ); return "Contains: " + ::Catch::Detail::stringify( m_comparator );
} }
std::vector<T> const& m_comparator; std::vector<T, AllocComp> const& m_comparator;
}; };
template<typename T> template<typename T, typename AllocComp, typename AllocMatch>
struct EqualsMatcher : MatcherBase<std::vector<T>> { struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> const &v) const override { bool match(std::vector<T, AllocMatch> const &v) const override {
// !TBD: This currently works if all elements can be compared using != // !TBD: This currently works if all elements can be compared using !=
// - a more general approach would be via a compare template that defaults // - a more general approach would be via a compare template that defaults
// to using !=. but could be specialised for, e.g. std::vector<T> etc // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc
// - then just call that directly // - then just call that directly
if (m_comparator.size() != v.size()) if (m_comparator.size() != v.size())
return false; return false;
@ -3642,15 +3667,15 @@ namespace Matchers {
std::string describe() const override { std::string describe() const override {
return "Equals: " + ::Catch::Detail::stringify( m_comparator ); return "Equals: " + ::Catch::Detail::stringify( m_comparator );
} }
std::vector<T> const& m_comparator; std::vector<T, AllocComp> const& m_comparator;
}; };
template<typename T> template<typename T, typename AllocComp, typename AllocMatch>
struct ApproxMatcher : MatcherBase<std::vector<T>> { struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> {
ApproxMatcher(std::vector<T> const& comparator) : m_comparator( comparator ) {} ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {}
bool match(std::vector<T> const &v) const override { bool match(std::vector<T, AllocMatch> const &v) const override {
if (m_comparator.size() != v.size()) if (m_comparator.size() != v.size())
return false; return false;
for (std::size_t i = 0; i < v.size(); ++i) for (std::size_t i = 0; i < v.size(); ++i)
@ -3677,14 +3702,14 @@ namespace Matchers {
return *this; return *this;
} }
std::vector<T> const& m_comparator; std::vector<T, AllocComp> const& m_comparator;
mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();
}; };
template<typename T> template<typename T, typename AllocComp, typename AllocMatch>
struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> { struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {} UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}
bool match(std::vector<T> const& vec) const override { bool match(std::vector<T, AllocMatch> const& vec) const override {
// Note: This is a reimplementation of std::is_permutation, // Note: This is a reimplementation of std::is_permutation,
// because I don't want to include <algorithm> inside the common path // because I don't want to include <algorithm> inside the common path
if (m_target.size() != vec.size()) { if (m_target.size() != vec.size()) {
@ -3697,7 +3722,7 @@ namespace Matchers {
return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
} }
private: private:
std::vector<T> const& m_target; std::vector<T, AllocComp> const& m_target;
}; };
} // namespace Vector } // namespace Vector
@ -3705,29 +3730,29 @@ namespace Matchers {
// The following functions create the actual matcher objects. // The following functions create the actual matcher objects.
// This allows the types to be inferred // This allows the types to be inferred
template<typename T> template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
return Vector::ContainsMatcher<T>( comparator ); return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );
} }
template<typename T> template<typename T, typename Alloc = std::allocator<T>>
Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
return Vector::ContainsElementMatcher<T>( comparator ); return Vector::ContainsElementMatcher<T, Alloc>( comparator );
} }
template<typename T> template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
return Vector::EqualsMatcher<T>( comparator ); return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );
} }
template<typename T> template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
Vector::ApproxMatcher<T> Approx( std::vector<T> const& comparator ) { Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
return Vector::ApproxMatcher<T>( comparator ); return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );
} }
template<typename T> template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) { Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
return Vector::UnorderedEqualsMatcher<T>(target); return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );
} }
} // namespace Matchers } // namespace Matchers
@ -10319,8 +10344,7 @@ namespace Catch {
#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
# include <assert.h> # include <cassert>
# include <stdbool.h>
# include <sys/types.h> # include <sys/types.h>
# include <unistd.h> # include <unistd.h>
# include <cstddef> # include <cstddef>
@ -13977,29 +14001,79 @@ namespace Catch {
// end catch_test_case_info.cpp // end catch_test_case_info.cpp
// start catch_test_case_registry_impl.cpp // start catch_test_case_registry_impl.cpp
#include <algorithm>
#include <sstream> #include <sstream>
namespace Catch { namespace Catch {
namespace {
struct TestHasher {
explicit TestHasher(Catch::SimplePcg32& rng) {
basis = rng();
basis <<= 32;
basis |= rng();
}
uint64_t basis;
uint64_t operator()(TestCase const& t) const {
// Modified FNV-1a hash
static constexpr uint64_t prime = 1099511628211;
uint64_t hash = basis;
for (const char c : t.name) {
hash ^= c;
hash *= prime;
}
return hash;
}
};
} // end unnamed namespace
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
std::vector<TestCase> sorted = unsortedTestCases;
switch( config.runOrder() ) { switch( config.runOrder() ) {
case RunTests::InLexicographicalOrder:
std::sort( sorted.begin(), sorted.end() );
break;
case RunTests::InRandomOrder:
seedRng( config );
std::shuffle( sorted.begin(), sorted.end(), rng() );
break;
case RunTests::InDeclarationOrder: case RunTests::InDeclarationOrder:
// already in declaration order // already in declaration order
break; break;
}
case RunTests::InLexicographicalOrder: {
std::vector<TestCase> sorted = unsortedTestCases;
std::sort( sorted.begin(), sorted.end() );
return sorted; return sorted;
} }
case RunTests::InRandomOrder: {
seedRng( config );
TestHasher h( rng() );
using hashedTest = std::pair<uint64_t, TestCase const*>;
std::vector<hashedTest> indexed_tests;
indexed_tests.reserve( unsortedTestCases.size() );
for (auto const& testCase : unsortedTestCases) {
indexed_tests.emplace_back(h(testCase), &testCase);
}
std::sort(indexed_tests.begin(), indexed_tests.end(),
[](hashedTest const& lhs, hashedTest const& rhs) {
if (lhs.first == rhs.first) {
return lhs.second->name < rhs.second->name;
}
return lhs.first < rhs.first;
});
std::vector<TestCase> sorted;
sorted.reserve( indexed_tests.size() );
for (auto const& hashed : indexed_tests) {
sorted.emplace_back(*hashed.second);
}
return sorted;
}
}
return unsortedTestCases;
}
bool isThrowSafe( TestCase const& testCase, IConfig const& config ) { bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
return !testCase.throws() || config.allowThrows(); return !testCase.throws() || config.allowThrows();
} }
@ -14591,6 +14665,7 @@ namespace Catch {
m_pos = m_arg.size(); m_pos = m_arg.size();
m_substring.clear(); m_substring.clear();
m_patternName.clear(); m_patternName.clear();
m_realPatternPos = 0;
return false; return false;
} }
endMode(); endMode();
@ -14609,6 +14684,7 @@ namespace Catch {
} }
m_patternName.clear(); m_patternName.clear();
m_realPatternPos = 0;
return token; return token;
} }
@ -15079,7 +15155,7 @@ namespace Catch {
} }
Version const& libraryVersion() { Version const& libraryVersion() {
static Version version( 2, 11, 3, "", 0 ); static Version version( 2, 12, 0, "", 0 );
return version; return version;
} }
@ -16142,7 +16218,7 @@ ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
else else
{ {
return{ return{
{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
{ "samples mean std dev", 14, ColumnInfo::Right }, { "samples mean std dev", 14, ColumnInfo::Right },
{ "iterations low mean low std dev", 14, ColumnInfo::Right }, { "iterations low mean low std dev", 14, ColumnInfo::Right },
{ "estimated high mean high std dev", 14, ColumnInfo::Right } { "estimated high mean high std dev", 14, ColumnInfo::Right }