--- 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
7 changed files with 167 additions and 66 deletions

View File

@@ -1,6 +1,6 @@
/*
* Catch v2.11.3
* Generated: 2020-03-19 13:44:21.042491
* Catch v2.12.0
* Generated: 2020-04-21 16:27:54.138031
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved.
@@ -14,8 +14,8 @@
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 11
#define CATCH_VERSION_PATCH 3
#define CATCH_VERSION_MINOR 12
#define CATCH_VERSION_PATCH 0
#ifdef __clang__
# pragma clang system_header
@@ -132,7 +132,7 @@ namespace Catch {
#endif
#if defined(CATCH_CPP17_OR_GREATER)
#if defined(__cpp_lib_uncaught_exceptions)
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
@@ -151,7 +151,20 @@ namespace Catch {
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
# 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 \
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
@@ -2356,6 +2369,14 @@ namespace Catch {
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>
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& ) -> BinaryExpr<LhsT, RhsT const&> const {
@@ -3000,6 +3021,9 @@ namespace Catch {
{}
std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
return "";
#else
try {
if( it == itEnd )
std::rethrow_exception(std::current_exception());
@@ -3009,6 +3033,7 @@ namespace Catch {
catch( T& ex ) {
return m_translateFunction( ex );
}
#endif
}
protected:
@@ -3571,12 +3596,12 @@ namespace Catch {
namespace Matchers {
namespace Vector {
template<typename T>
struct ContainsElementMatcher : MatcherBase<std::vector<T>> {
template<typename T, typename Alloc>
struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> {
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) {
if (el == m_comparator) {
return true;
@@ -3592,12 +3617,12 @@ namespace Matchers {
T const& m_comparator;
};
template<typename T>
struct ContainsMatcher : MatcherBase<std::vector<T>> {
template<typename T, typename AllocComp, typename AllocMatch>
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
if (m_comparator.size() > v.size())
return false;
@@ -3619,18 +3644,18 @@ namespace Matchers {
return "Contains: " + ::Catch::Detail::stringify( m_comparator );
}
std::vector<T> const& m_comparator;
std::vector<T, AllocComp> const& m_comparator;
};
template<typename T>
struct EqualsMatcher : MatcherBase<std::vector<T>> {
template<typename T, typename AllocComp, typename AllocMatch>
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 !=
// - 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
if (m_comparator.size() != v.size())
return false;
@@ -3642,15 +3667,15 @@ namespace Matchers {
std::string describe() const override {
return "Equals: " + ::Catch::Detail::stringify( m_comparator );
}
std::vector<T> const& m_comparator;
std::vector<T, AllocComp> const& m_comparator;
};
template<typename T>
struct ApproxMatcher : MatcherBase<std::vector<T>> {
template<typename T, typename AllocComp, typename AllocMatch>
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())
return false;
for (std::size_t i = 0; i < v.size(); ++i)
@@ -3677,14 +3702,14 @@ namespace Matchers {
return *this;
}
std::vector<T> const& m_comparator;
std::vector<T, AllocComp> const& m_comparator;
mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();
};
template<typename T>
struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> {
UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
bool match(std::vector<T> const& vec) const override {
template<typename T, typename AllocComp, typename AllocMatch>
struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}
bool match(std::vector<T, AllocMatch> const& vec) const override {
// Note: This is a reimplementation of std::is_permutation,
// because I don't want to include <algorithm> inside the common path
if (m_target.size() != vec.size()) {
@@ -3697,7 +3722,7 @@ namespace Matchers {
return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
}
private:
std::vector<T> const& m_target;
std::vector<T, AllocComp> const& m_target;
};
} // namespace Vector
@@ -3705,29 +3730,29 @@ namespace Matchers {
// The following functions create the actual matcher objects.
// This allows the types to be inferred
template<typename T>
Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
return Vector::ContainsMatcher<T>( comparator );
template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );
}
template<typename T>
Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
return Vector::ContainsElementMatcher<T>( comparator );
template<typename T, typename Alloc = std::allocator<T>>
Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
return Vector::ContainsElementMatcher<T, Alloc>( comparator );
}
template<typename T>
Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
return Vector::EqualsMatcher<T>( comparator );
template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );
}
template<typename T>
Vector::ApproxMatcher<T> Approx( std::vector<T> const& comparator ) {
return Vector::ApproxMatcher<T>( comparator );
template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );
}
template<typename T>
Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) {
return Vector::UnorderedEqualsMatcher<T>(target);
template<typename T, typename AllocComp, typename AllocMatch = AllocComp>
Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );
}
} // namespace Matchers
@@ -10319,8 +10344,7 @@ namespace Catch {
#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
# include <assert.h>
# include <stdbool.h>
# include <cassert>
# include <sys/types.h>
# include <unistd.h>
# include <cstddef>
@@ -13977,27 +14001,77 @@ namespace Catch {
// end catch_test_case_info.cpp
// start catch_test_case_registry_impl.cpp
#include <algorithm>
#include <sstream>
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> sorted = unsortedTestCases;
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:
// already in declaration order
break;
case RunTests::InLexicographicalOrder: {
std::vector<TestCase> sorted = unsortedTestCases;
std::sort( sorted.begin(), sorted.end() );
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 sorted;
return unsortedTestCases;
}
bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
@@ -14591,6 +14665,7 @@ namespace Catch {
m_pos = m_arg.size();
m_substring.clear();
m_patternName.clear();
m_realPatternPos = 0;
return false;
}
endMode();
@@ -14609,6 +14684,7 @@ namespace Catch {
}
m_patternName.clear();
m_realPatternPos = 0;
return token;
}
@@ -15079,7 +15155,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 11, 3, "", 0 );
static Version version( 2, 12, 0, "", 0 );
return version;
}
@@ -16142,7 +16218,7 @@ ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
else
{
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 },
{ "iterations low mean low std dev", 14, ColumnInfo::Right },
{ "estimated high mean high std dev", 14, ColumnInfo::Right }