1
0
mirror of https://github.com/catchorg/Catch2.git synced 2025-04-29 04:03:51 +00:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Martin Hořeňovský
b2a6523d85
Fix Clang-3.8 compilation of tests
As far as I know, the compilation error is a compiler bug, but I
do not want to just drop the support for something that is trivial
to work around.
2020-02-13 16:57:37 +01:00
Martin Hořeňovský
b009d190bf
Avoid detecting Clang as having MSVC's traditional preprocessor
Fixes #1806
2020-02-13 16:28:30 +01:00
ptc-tgamper
ac83087bc2
catch_debugger.h - implement break into debugger assembler instructions for iOS 2020-02-13 16:28:02 +01:00
ptc-tgamper
123b449f8d
catch_console_colour.cpp - adjust useColourOnPlatform for iOS 2020-02-13 16:27:56 +01:00
ptc-tgamper
6ad743a62b
catch_debugger.cpp - debugger detection is identical on Mac OS X and iOS 2020-02-13 16:27:46 +01:00
Martin Hořeňovský
0f47fe16bd
Provide const overload of ObjectStorage::stored_object()
Fixes #1820
2020-02-13 16:26:06 +01:00
Joe Burzinski
82baef62e2
Fix forwarding in SingleValueGenerator and generator creation
Fixes #1809
2020-02-13 16:19:50 +01:00
Joe Burzinski
0fbf4f3e15
Fix wrong namespacing of benchmarking constructor helpers 2020-02-13 16:15:50 +01:00
Martin Hořeňovský
ad3f50bbc1
Suppress using-namespace lint in GENERATE* macros
Closes #1799
2020-02-13 15:31:09 +01:00
Martin Hořeňovský
13e01d273a
Cherry pick v2.11.0 release notes and docs 2020-02-13 15:30:46 +01:00
Martin Hořeňovský
2788897051
Minor cleanup in the benchmarking tests 2020-02-13 15:12:57 +01:00
Martin Hořeňovský
2945b80f61
Add more constexpr to StringRef 2020-02-13 15:01:03 +01:00
Martin Hořeňovský
63b7d6f98e
Improve erasure of test numbers in TAP approvals 2020-02-13 14:22:18 +01:00
Martin Hořeňovský
c50ba09cde
Split [.foo] into [.][foo] when parsing test specs
b77cec05c0 fixed this problem for tagging tests, so that a test
case tagged with `[.foo]` would be parsed as tagged with `[.][foo]`.
This does the same for the test spec parsing.

Fixes #1798
2020-02-13 13:35:10 +01:00
Martin Hořeňovský
c165bd15c5
Forbid copying ReusableStringStream
Copying a `ReusableStringStream` would lead to "double free" of
the stream, and thus it could be used in multiple places at the
same time, breaking the output.
2020-02-12 19:21:15 +01:00
cericks0n
4f0de7bbad
Fix error when period of steady_clock is not nano
On systems where std::chrono::steady_clock::period is not std::nano, benchmark tests fail to compile due to trying to convert analysis.samples from a vector of duration<double, clock::period> to a vector of std::chrono::duration<double, std::nano>.
2020-02-12 19:20:41 +01:00
Martin Hořeňovský
21b24e8326
Remove catch_external_interfaces.h
Its intent was to show which headers are expected to be useable by
Catch2's users, and to enforce their inclusion in the single header
distribution at the right place.

Given the new library model, the second use case is not needed and
the first one is better served with documentation and physical file
layout.
2020-02-12 16:57:15 +01:00
31 changed files with 501 additions and 180 deletions

View File

@ -164,7 +164,7 @@ Note that it is not possible to simply use the same instance for different runs
and resetting it between each run since that would pollute the measurements with and resetting it between each run since that would pollute the measurements with
the resetting code. the resetting code.
It is also possible to just provide an argument name to the simple `BENCHMARK` macro to get It is also possible to just provide an argument name to the simple `BENCHMARK` macro to get
the same semantics as providing a callable to `meter.measure` with `int` argument: the same semantics as providing a callable to `meter.measure` with `int` argument:
```c++ ```c++
@ -185,19 +185,17 @@ construct and destroy objects without dynamic allocation and in a way that lets
you measure construction and destruction separately. you measure construction and destruction separately.
```c++ ```c++
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
{
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs()); std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
meter.measure([&](int i) { storage[i].construct("thing"); }); meter.measure([&](int i) { storage[i].construct("thing"); });
}) };
BENCHMARK_ADVANCED("destroy", [](Catch::Benchmark::Chronometer meter) BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
{
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs()); std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
for(auto&& o : storage) for(auto&& o : storage)
o.construct("thing"); o.construct("thing");
meter.measure([&](int i) { storage[i].destruct(); }); meter.measure([&](int i) { storage[i].destruct(); });
}) };
``` ```
`Catch::Benchmark::storage_for<T>` objects are just pieces of raw storage suitable for `T` `Catch::Benchmark::storage_for<T>` objects are just pieces of raw storage suitable for `T`

View File

@ -78,7 +78,7 @@ type, making their usage much nicer. These are
> `from_range` has been introduced in Catch 2.10.0 > `from_range` has been introduced in Catch 2.10.0
> `range()` for floating point numbers has been introduced in Catch X.Y.Z > `range()` for floating point numbers has been introduced in Catch 2.11.0
And can be used as shown in the example below to create a generator And can be used as shown in the example below to create a generator
that returns 100 odd random number: that returns 100 odd random number:

View File

@ -2,6 +2,7 @@
# Release notes # Release notes
**Contents**<br> **Contents**<br>
[2.11.0](#2110)<br>
[2.10.2](#2102)<br> [2.10.2](#2102)<br>
[2.10.1](#2101)<br> [2.10.1](#2101)<br>
[2.10.0](#2100)<br> [2.10.0](#2100)<br>
@ -62,6 +63,23 @@
* `CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER` no longer exists. * `CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER` no longer exists.
* `StringMaker` specializations for <chrono> are always provided * `StringMaker` specializations for <chrono> are always provided
## 2.11.0
### Improvements
* JUnit reporter output now contains more details in case of failure (#1347, #1719)
* Added SonarQube Test Data reporter (#1738)
* It is in a separate header, just like the TAP, Automake, and TeamCity reporters
* `range` generator now allows floating point numbers (#1776)
* Reworked part of internals to increase throughput
### Fixes
* The single header version should contain full benchmarking support (#1800)
* `[.foo]` is now properly parsed as `[.][foo]` when used on the command line (#1798)
* Fixed compilation of benchmarking on platforms where `steady_clock::period` is not `std::nano` (#1794)
## 2.10.2 ## 2.10.2
### Improvements ### Improvements

View File

@ -55,7 +55,6 @@ set(INTERNAL_HEADERS
${SOURCES_DIR}/catch_enum_values_registry.h ${SOURCES_DIR}/catch_enum_values_registry.h
${SOURCES_DIR}/catch_errno_guard.h ${SOURCES_DIR}/catch_errno_guard.h
${SOURCES_DIR}/catch_exception_translator_registry.h ${SOURCES_DIR}/catch_exception_translator_registry.h
${SOURCES_DIR}/catch_external_interfaces.h
${SOURCES_DIR}/catch_fatal_condition.h ${SOURCES_DIR}/catch_fatal_condition.h
${SOURCES_DIR}/catch_generators.hpp ${SOURCES_DIR}/catch_generators.hpp
${SOURCES_DIR}/catch_generators_generic.hpp ${SOURCES_DIR}/catch_generators_generic.hpp

View File

@ -79,7 +79,7 @@ namespace Catch {
}); });
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
BenchmarkStats<std::chrono::duration<double, std::nano>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
getResultCapture().benchmarkEnded(stats); getResultCapture().benchmarkEnded(stats);
} CATCH_CATCH_ALL{ } CATCH_CATCH_ALL{

View File

@ -14,60 +14,66 @@
#include <type_traits> #include <type_traits>
namespace Catch { namespace Catch {
namespace Detail { namespace Benchmark {
template <typename T, bool Destruct> namespace Detail {
struct ObjectStorage template <typename T, bool Destruct>
{ struct ObjectStorage
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
ObjectStorage() : data() {}
ObjectStorage(const ObjectStorage& other)
{ {
new(&data) T(other.stored_object()); using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
}
ObjectStorage(ObjectStorage&& other) ObjectStorage() : data() {}
{
new(&data) T(std::move(other.stored_object()));
}
~ObjectStorage() { destruct_on_exit<T>(); } ObjectStorage(const ObjectStorage& other)
{
new(&data) T(other.stored_object());
}
template <typename... Args> ObjectStorage(ObjectStorage&& other)
void construct(Args&&... args) {
{ new(&data) T(std::move(other.stored_object()));
new (&data) T(std::forward<Args>(args)...); }
}
template <bool AllowManualDestruction = !Destruct> ~ObjectStorage() { destruct_on_exit<T>(); }
typename std::enable_if<AllowManualDestruction>::type destruct()
{
stored_object().~T();
}
private: template <typename... Args>
// If this is a constructor benchmark, destruct the underlying object void construct(Args&&... args)
template <typename U> {
void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); } new (&data) T(std::forward<Args>(args)...);
// Otherwise, don't }
template <typename U>
void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
T& stored_object() template <bool AllowManualDestruction = !Destruct>
{ typename std::enable_if<AllowManualDestruction>::type destruct()
return *static_cast<T*>(static_cast<void*>(&data)); {
} stored_object().~T();
}
TStorage data; private:
}; // If this is a constructor benchmark, destruct the underlying object
} template <typename U>
void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
// Otherwise, don't
template <typename U>
void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
template <typename T> T& stored_object() {
using storage_for = Detail::ObjectStorage<T, true>; return *static_cast<T*>(static_cast<void*>(&data));
}
template <typename T> T const& stored_object() const {
using destructable_object = Detail::ObjectStorage<T, false>; return *static_cast<T*>(static_cast<void*>(&data));
} }
TStorage data;
};
} // namespace Detail
template <typename T>
using storage_for = Detail::ObjectStorage<T, true>;
template <typename T>
using destructable_object = Detail::ObjectStorage<T, false>;
} // namespace Benchmark
} // namespace Catch
#endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED

View File

@ -40,8 +40,6 @@
#include <catch2/catch_objc.hpp> #include <catch2/catch_objc.hpp>
#endif #endif
#include <catch2/catch_external_interfaces.h>
#endif // ! CATCH_CONFIG_IMPL_ONLY #endif // ! CATCH_CONFIG_IMPL_ONLY
#if !defined(CATCH_CONFIG_IMPL_ONLY) #if !defined(CATCH_CONFIG_IMPL_ONLY)

View File

@ -149,9 +149,12 @@
// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // MSVC traditional preprocessor needs some workaround for __VA_ARGS__
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 0 means new conformant preprocessor
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) # if !defined(__clang__) // Handle Clang masquerading for msvc
# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
# endif # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
# endif // MSVC_TRADITIONAL
# endif // __clang__
#endif // _MSC_VER #endif // _MSC_VER
#if defined(_REENTRANT) || defined(_MSC_VER) #if defined(_REENTRANT) || defined(_MSC_VER)

View File

@ -167,7 +167,7 @@ namespace {
bool useColourOnPlatform() { bool useColourOnPlatform() {
return return
#ifdef CATCH_PLATFORM_MAC #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
!isDebuggerActive() && !isDebuggerActive() &&
#endif #endif
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))

View File

@ -12,7 +12,7 @@
#include <catch2/catch_stream.h> #include <catch2/catch_stream.h>
#include <catch2/catch_platform.h> #include <catch2/catch_platform.h>
#ifdef CATCH_PLATFORM_MAC #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
# include <assert.h> # include <assert.h>
# include <stdbool.h> # include <stdbool.h>

View File

@ -19,6 +19,17 @@ namespace Catch {
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
#elif defined(CATCH_PLATFORM_IPHONE)
// use inline assembler
#if defined(__i386__) || defined(__x86_64__)
#define CATCH_TRAP() __asm__("int $3")
#elif defined(__aarch64__)
#define CATCH_TRAP() __asm__(".inst 0xd4200000")
#elif defined(__arm__)
#define CATCH_TRAP() __asm__(".inst 0xe7f001f0")
#endif
#elif defined(CATCH_PLATFORM_LINUX) #elif defined(CATCH_PLATFORM_LINUX)
// If we can use inline assembler, do it because this allows us to break // If we can use inline assembler, do it because this allows us to break
// directly at the location of the failing check instead of breaking inside // directly at the location of the failing check instead of breaking inside

View File

@ -1,20 +0,0 @@
/*
* Created by Martin on 17/08/2017.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H_INCLUDED
#define TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H_INCLUDED
#include <catch2/reporters/catch_reporter_bases.hpp>
#include <catch2/catch_console_colour.h>
#include <catch2/catch_reporter_registrars.hpp>
// Allow users to base their work off existing reporters
#include <catch2/reporters/catch_reporter_compact.h>
#include <catch2/reporters/catch_reporter_console.h>
#include <catch2/reporters/catch_reporter_junit.h>
#include <catch2/reporters/catch_reporter_xml.h>
#endif // TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H_INCLUDED

View File

@ -49,7 +49,6 @@ namespace Generators {
class SingleValueGenerator final : public IGenerator<T> { class SingleValueGenerator final : public IGenerator<T> {
T m_value; T m_value;
public: public:
SingleValueGenerator(T const& value) : m_value( value ) {}
SingleValueGenerator(T&& value) : m_value(std::move(value)) {} SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
T const& get() const override { T const& get() const override {
@ -112,21 +111,21 @@ namespace Generators {
m_generators.emplace_back(std::move(generator)); m_generators.emplace_back(std::move(generator));
} }
void populate(T&& val) { void populate(T&& val) {
m_generators.emplace_back(value(std::move(val))); m_generators.emplace_back(value(std::forward<T>(val)));
} }
template<typename U> template<typename U>
void populate(U&& val) { void populate(U&& val) {
populate(T(std::move(val))); populate(T(std::forward<U>(val)));
} }
template<typename U, typename... Gs> template<typename U, typename... Gs>
void populate(U&& valueOrGenerator, Gs... moreGenerators) { void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {
populate(std::forward<U>(valueOrGenerator)); populate(std::forward<U>(valueOrGenerator));
populate(std::forward<Gs>(moreGenerators)...); populate(std::forward<Gs>(moreGenerators)...);
} }
public: public:
template <typename... Gs> template <typename... Gs>
Generators(Gs... moreGenerators) { Generators(Gs &&... moreGenerators) {
m_generators.reserve(sizeof...(Gs)); m_generators.reserve(sizeof...(Gs));
populate(std::forward<Gs>(moreGenerators)...); populate(std::forward<Gs>(moreGenerators)...);
} }
@ -158,7 +157,7 @@ namespace Generators {
struct as {}; struct as {};
template<typename T, typename... Gs> template<typename T, typename... Gs>
auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> { auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...); return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
} }
template<typename T> template<typename T>
@ -166,11 +165,11 @@ namespace Generators {
return Generators<T>(std::move(generator)); return Generators<T>(std::move(generator));
} }
template<typename T, typename... Gs> template<typename T, typename... Gs>
auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> { auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> {
return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... ); return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
} }
template<typename T, typename U, typename... Gs> template<typename T, typename U, typename... Gs>
auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> { auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
} }
@ -196,10 +195,10 @@ namespace Generators {
} // namespace Catch } // namespace Catch
#define GENERATE( ... ) \ #define GENERATE( ... ) \
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_COPY( ... ) \ #define GENERATE_COPY( ... ) \
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_REF( ... ) \ #define GENERATE_REF( ... ) \
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED

View File

@ -9,6 +9,8 @@
#ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED #ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#include "catch_common.h"
#include <iosfwd> #include <iosfwd>
#include <cstddef> #include <cstddef>
#include <ostream> #include <ostream>
@ -28,7 +30,7 @@ namespace Catch {
auto makeStream( StringRef const &filename ) -> IStream const*; auto makeStream( StringRef const &filename ) -> IStream const*;
class ReusableStringStream { class ReusableStringStream : NonCopyable {
std::size_t m_index; std::size_t m_index;
std::ostream* m_oss; std::ostream* m_oss;
public: public:

View File

@ -22,17 +22,7 @@ namespace Catch {
CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance"); CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance");
return m_start; return m_start;
} }
auto StringRef::data() const noexcept -> char const* {
return m_start;
}
auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
if (start < m_size) {
return StringRef(m_start + start, (std::min)(m_size - start, size));
} else {
return StringRef();
}
}
auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
return m_size == other.m_size return m_size == other.m_size
&& (std::memcmp( m_start, other.m_start, m_size ) == 0); && (std::memcmp( m_start, other.m_start, m_size ) == 0);

View File

@ -74,12 +74,21 @@ namespace Catch {
public: // substrings and searches public: // substrings and searches
// Returns a substring of [start, start + length). // Returns a substring of [start, start + length).
// If start + length > size(), then the substring is [start, size()). // If start + length > size(), then the substring is [start, start + size()).
// If start > size(), then the substring is empty. // If start > size(), then the substring is empty.
auto substr( size_type start, size_type length ) const noexcept -> StringRef; constexpr StringRef substr(size_type start, size_type length) const noexcept {
if (start < m_size) {
const auto shortened_size = m_size - start;
return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length);
} else {
return StringRef();
}
}
// Returns the current start pointer. May not be null-terminated. // Returns the current start pointer. May not be null-terminated.
auto data() const noexcept -> char const*; constexpr char const* data() const noexcept {
return m_start;
}
constexpr auto isNullTerminated() const noexcept -> bool { constexpr auto isNullTerminated() const noexcept -> bool {
return m_start[m_size] == '\0'; return m_start[m_size] == '\0';

View File

@ -113,9 +113,9 @@ namespace Catch {
switch( m_mode ) { switch( m_mode ) {
case Name: case Name:
case QuotedName: case QuotedName:
return addPattern<TestSpec::NamePattern>(); return addNamePattern();
case Tag: case Tag:
return addPattern<TestSpec::TagPattern>(); return addTagPattern();
case EscapedName: case EscapedName:
revertBackToLastMode(); revertBackToLastMode();
return; return;
@ -175,6 +175,63 @@ namespace Catch {
return true; //success return true; //success
} }
std::string TestSpecParser::preprocessPattern() {
std::string token = m_patternName;
for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
m_escapeChars.clear();
if (startsWith(token, "exclude:")) {
m_exclusion = true;
token = token.substr(8);
}
m_patternName.clear();
return token;
}
void TestSpecParser::addNamePattern() {
auto token = preprocessPattern();
if (!token.empty()) {
if (m_exclusion) {
m_currentFilter.m_forbidden.emplace_back(std::make_unique<TestSpec::NamePattern>(token, m_substring));
} else {
m_currentFilter.m_required.emplace_back(std::make_unique<TestSpec::NamePattern>(token, m_substring));
}
}
m_substring.clear();
m_exclusion = false;
m_mode = None;
}
void TestSpecParser::addTagPattern() {
auto token = preprocessPattern();
if (!token.empty()) {
// If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
// we have to create a separate hide tag and shorten the real one
if (token.size() > 1 && token[0] == '.') {
token.erase(token.begin());
if (m_exclusion) {
m_currentFilter.m_forbidden.emplace_back(std::make_unique<TestSpec::TagPattern>(".", m_substring));
m_currentFilter.m_forbidden.emplace_back(std::make_unique<TestSpec::TagPattern>(token, m_substring));
} else {
m_currentFilter.m_required.emplace_back(std::make_unique<TestSpec::TagPattern>(".", m_substring));
m_currentFilter.m_required.emplace_back(std::make_unique<TestSpec::TagPattern>(token, m_substring));
}
}
if (m_exclusion) {
m_currentFilter.m_forbidden.emplace_back(std::make_unique<TestSpec::TagPattern>(token, m_substring));
} else {
m_currentFilter.m_required.emplace_back(std::make_unique<TestSpec::TagPattern>(token, m_substring));
}
}
m_substring.clear();
m_exclusion = false;
m_mode = None;
}
TestSpec parseTestSpec( std::string const& arg ) { TestSpec parseTestSpec( std::string const& arg ) {
return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
} }

View File

@ -54,28 +54,12 @@ namespace Catch {
void addFilter(); void addFilter();
bool separate(); bool separate();
template<typename T> // Handles common preprocessing of the pattern for name/tag patterns
void addPattern() { std::string preprocessPattern();
std::string token = m_patternName; // Adds the current pattern as a test name
for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) void addNamePattern();
token = token.substr( 0, m_escapeChars[i] - i ) + token.substr( m_escapeChars[i] -i +1 ); // Adds the current pattern as a tag
m_escapeChars.clear(); void addTagPattern();
if( startsWith( token, "exclude:" ) ) {
m_exclusion = true;
token = token.substr( 8 );
}
if( !token.empty() ) {
if (m_exclusion) {
m_currentFilter.m_forbidden.emplace_back(std::make_unique<T>(token, m_substring));
} else {
m_currentFilter.m_required.emplace_back(std::make_unique<T>(token, m_substring));
}
}
m_substring.clear();
m_patternName.clear();
m_exclusion = false;
m_mode = None;
}
inline void addCharToPattern(char c) { inline void addCharToPattern(char c) {
m_substring += c; m_substring += c;

View File

@ -28,14 +28,6 @@ TEST_CASE("Benchmark factorial", "[benchmark]") {
BENCHMARK("factorial 14") { BENCHMARK("factorial 14") {
return factorial(14); return factorial(14);
}; };
//
// BENCHMARK("factorial 20") {
// return factorial(20);
// };
//
// BENCHMARK("factorial 35") {
// return factorial(35);
// };
} }
TEST_CASE("Benchmark containers", "[.][benchmark]") { TEST_CASE("Benchmark containers", "[.][benchmark]") {

View File

@ -1028,6 +1028,12 @@ CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( " aardvar
CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( " aardvark " ) ) for: true CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( " aardvark " ) ) for: true
CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( "aardvark " ) ) for: true CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( "aardvark " ) ) for: true
CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( "aardvark" ) ) for: true CmdLine.tests.cpp:<line number>: passed: spec.matches( *fakeTestCase( "aardvark" ) ) for: true
CmdLine.tests.cpp:<line number>: passed: spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")) for: true
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(*fakeTestCase("only foo", "[foo]"))) for: !false
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]"))) for: !false
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(*fakeTestCase("only foo", "[foo]"))) for: !false
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(*fakeTestCase("only hidden", "[.]"))) for: !false
CmdLine.tests.cpp:<line number>: passed: spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")) for: true
Condition.tests.cpp:<line number>: passed: p == 0 for: 0 == 0 Condition.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
Condition.tests.cpp:<line number>: passed: p == pNULL for: 0 == 0 Condition.tests.cpp:<line number>: passed: p == pNULL for: 0 == 0
Condition.tests.cpp:<line number>: passed: p != 0 for: 0x<hex digits> != 0 Condition.tests.cpp:<line number>: passed: p != 0 for: 0x<hex digits> != 0
@ -1187,6 +1193,7 @@ String.tests.cpp:<line number>: passed: s.data() == s2.data() for: "hello world!
String.tests.cpp:<line number>: passed: s.data() == ss.data() for: "hello world!" == "hello world!" String.tests.cpp:<line number>: passed: s.data() == ss.data() for: "hello world!" == "hello world!"
String.tests.cpp:<line number>: passed: s.substr(s.size() + 1, 123).empty() for: true String.tests.cpp:<line number>: passed: s.substr(s.size() + 1, 123).empty() for: true
String.tests.cpp:<line number>: passed: std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0 String.tests.cpp:<line number>: passed: std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0
String.tests.cpp:<line number>: passed: s.substr(1'000'000, 1).empty() for: true
String.tests.cpp:<line number>: passed: (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello" String.tests.cpp:<line number>: passed: (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello"
String.tests.cpp:<line number>: passed: left == right for: Hello == Hello String.tests.cpp:<line number>: passed: left == right for: Hello == Hello
String.tests.cpp:<line number>: passed: left != left.substr(0, 3) for: Hello != Hel String.tests.cpp:<line number>: passed: left != left.substr(0, 3) for: Hello != Hel
@ -1200,11 +1207,20 @@ String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringre
String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11 String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11
String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringref" == "a stringref" String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringref" == "a stringref"
String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11 String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{}.size() == 0' String.tests.cpp:<line number>: passed: with 1 message: 'empty.size() == 0'
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 3 }.size() == 3' String.tests.cpp:<line number>: passed: with 1 message: 'empty.begin() == empty.end()'
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 3 }.isNullTerminated()' String.tests.cpp:<line number>: passed: with 1 message: 'stringref.size() == 3'
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 2 }.size() == 2' String.tests.cpp:<line number>: passed: with 1 message: 'stringref.isNullTerminated()'
String.tests.cpp:<line number>: passed: with 1 message: '!(StringRef{ "abc", 2 }.isNullTerminated())' String.tests.cpp:<line number>: passed: with 1 message: 'stringref.data() == abc'
String.tests.cpp:<line number>: passed: with 1 message: 'stringref.begin() == abc'
String.tests.cpp:<line number>: passed: with 1 message: 'stringref.begin() != stringref.end()'
String.tests.cpp:<line number>: passed: with 1 message: 'stringref.substr(10, 0).empty()'
String.tests.cpp:<line number>: passed: with 1 message: 'stringref.substr(2, 1).data() == abc + 2'
String.tests.cpp:<line number>: passed: with 1 message: 'shortened.size() == 2'
String.tests.cpp:<line number>: passed: with 1 message: 'shortened.data() == abc'
String.tests.cpp:<line number>: passed: with 1 message: 'shortened.begin() != shortened.end()'
String.tests.cpp:<line number>: passed: with 1 message: '!(shortened.isNullTerminated())'
String.tests.cpp:<line number>: passed: with 1 message: '!(shortened.substr(1, 3).isNullTerminated())'
String.tests.cpp:<line number>: passed: with 1 message: '!(sr1.empty())' String.tests.cpp:<line number>: passed: with 1 message: '!(sr1.empty())'
String.tests.cpp:<line number>: passed: with 1 message: 'sr1.size() == 3' String.tests.cpp:<line number>: passed: with 1 message: 'sr1.size() == 3'
String.tests.cpp:<line number>: passed: with 1 message: 'sr1.isNullTerminated()' String.tests.cpp:<line number>: passed: with 1 message: 'sr1.isNullTerminated()'

View File

@ -1381,5 +1381,5 @@ due to unexpected exception with message:
=============================================================================== ===============================================================================
test cases: 320 | 246 passed | 70 failed | 4 failed as expected test cases: 320 | 246 passed | 70 failed | 4 failed as expected
assertions: 1776 | 1624 passed | 131 failed | 21 failed as expected assertions: 1792 | 1640 passed | 131 failed | 21 failed as expected

View File

@ -7370,6 +7370,50 @@ CmdLine.tests.cpp:<line number>: PASSED:
with expansion: with expansion:
true true
-------------------------------------------------------------------------------
Parse test names and tags
Shortened hide tags are split apart when parsing
-------------------------------------------------------------------------------
CmdLine.tests.cpp:<line number>
...............................................................................
CmdLine.tests.cpp:<line number>: PASSED:
CHECK( spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")) )
with expansion:
true
CmdLine.tests.cpp:<line number>: PASSED:
CHECK_FALSE( spec.matches(*fakeTestCase("only foo", "[foo]")) )
with expansion:
!false
-------------------------------------------------------------------------------
Parse test names and tags
Shortened hide tags also properly handle exclusion
-------------------------------------------------------------------------------
CmdLine.tests.cpp:<line number>
...............................................................................
CmdLine.tests.cpp:<line number>: PASSED:
CHECK_FALSE( spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")) )
with expansion:
!false
CmdLine.tests.cpp:<line number>: PASSED:
CHECK_FALSE( spec.matches(*fakeTestCase("only foo", "[foo]")) )
with expansion:
!false
CmdLine.tests.cpp:<line number>: PASSED:
CHECK_FALSE( spec.matches(*fakeTestCase("only hidden", "[.]")) )
with expansion:
!false
CmdLine.tests.cpp:<line number>: PASSED:
CHECK( spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")) )
with expansion:
true
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Pointers can be compared to null Pointers can be compared to null
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -8671,6 +8715,19 @@ String.tests.cpp:<line number>: PASSED:
with expansion: with expansion:
0 == 0 0 == 0
-------------------------------------------------------------------------------
StringRef
Substrings
substring start after the end is empty
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>: PASSED:
REQUIRE( s.substr(1'000'000, 1).empty() )
with expansion:
true
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
StringRef StringRef
Comparisons are deep Comparisons are deep
@ -8792,23 +8849,59 @@ String.tests.cpp:<line number>
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
StringRef{}.size() == 0 empty.size() == 0
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
StringRef{ "abc", 3 }.size() == 3 empty.begin() == empty.end()
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
StringRef{ "abc", 3 }.isNullTerminated() stringref.size() == 3
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
StringRef{ "abc", 2 }.size() == 2 stringref.isNullTerminated()
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
!(StringRef{ "abc", 2 }.isNullTerminated()) stringref.data() == abc
String.tests.cpp:<line number>: PASSED:
with message:
stringref.begin() == abc
String.tests.cpp:<line number>: PASSED:
with message:
stringref.begin() != stringref.end()
String.tests.cpp:<line number>: PASSED:
with message:
stringref.substr(10, 0).empty()
String.tests.cpp:<line number>: PASSED:
with message:
stringref.substr(2, 1).data() == abc + 2
String.tests.cpp:<line number>: PASSED:
with message:
shortened.size() == 2
String.tests.cpp:<line number>: PASSED:
with message:
shortened.data() == abc
String.tests.cpp:<line number>: PASSED:
with message:
shortened.begin() != shortened.end()
String.tests.cpp:<line number>: PASSED:
with message:
!(shortened.isNullTerminated())
String.tests.cpp:<line number>: PASSED:
with message:
!(shortened.substr(1, 3).isNullTerminated())
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
StringRef at compilation time StringRef at compilation time
@ -13961,5 +14054,5 @@ Misc.tests.cpp:<line number>: PASSED:
=============================================================================== ===============================================================================
test cases: 320 | 230 passed | 86 failed | 4 failed as expected test cases: 320 | 230 passed | 86 failed | 4 failed as expected
assertions: 1793 | 1624 passed | 148 failed | 21 failed as expected assertions: 1809 | 1640 passed | 148 failed | 21 failed as expected

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact <testsuitesloose text artifact
> >
<testsuite name="<exe-name>" errors="17" failures="132" tests="1794" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}"> <testsuite name="<exe-name>" errors="17" failures="132" tests="1810" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties> <properties>
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals] *"/> <property name="filters" value="~[!nonportable]~[!benchmark]~[approvals] *"/>
<property name="random-seed" value="1"/> <property name="random-seed" value="1"/>
@ -983,6 +983,8 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Parse test names and tags/quoted string followed by tag exclusion" time="{duration}"/> <testcase classname="<exe-name>.global" name="Parse test names and tags/quoted string followed by tag exclusion" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test spec" time="{duration}"/> <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test spec" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test name" time="{duration}"/> <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test name" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags are split apart when parsing" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags also properly handle exclusion" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Pointers can be compared to null" time="{duration}"/> <testcase classname="<exe-name>.global" name="Pointers can be compared to null" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Floats" time="{duration}"/> <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Floats" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Double" time="{duration}"/> <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Double" time="{duration}"/>
@ -1112,6 +1114,7 @@ Matchers.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of substring refs should also match" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of substring refs should also match" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/Past the end substring" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/Substrings/Past the end substring" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/Substring off the end are trimmed" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/Substrings/Substring off the end are trimmed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/substring start after the end is empty" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Comparisons are deep" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/Comparisons are deep" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/from std::string/implicitly constructed" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/from std::string/implicitly constructed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/from std::string/explicitly constructed" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/from std::string/explicitly constructed" time="{duration}"/>

View File

@ -35,6 +35,8 @@
<testCase name="Parse test names and tags/quoted string followed by tag exclusion" duration="{duration}"/> <testCase name="Parse test names and tags/quoted string followed by tag exclusion" duration="{duration}"/>
<testCase name="Parse test names and tags/Leading and trailing spaces in test spec" duration="{duration}"/> <testCase name="Parse test names and tags/Leading and trailing spaces in test spec" duration="{duration}"/>
<testCase name="Parse test names and tags/Leading and trailing spaces in test name" duration="{duration}"/> <testCase name="Parse test names and tags/Leading and trailing spaces in test name" duration="{duration}"/>
<testCase name="Parse test names and tags/Shortened hide tags are split apart when parsing" duration="{duration}"/>
<testCase name="Parse test names and tags/Shortened hide tags also properly handle exclusion" duration="{duration}"/>
<testCase name="Process can be configured on command line/empty args don't cause a crash" duration="{duration}"/> <testCase name="Process can be configured on command line/empty args don't cause a crash" duration="{duration}"/>
<testCase name="Process can be configured on command line/default - no arguments" duration="{duration}"/> <testCase name="Process can be configured on command line/default - no arguments" duration="{duration}"/>
<testCase name="Process can be configured on command line/test lists/Specify one test case using" duration="{duration}"/> <testCase name="Process can be configured on command line/test lists/Specify one test case using" duration="{duration}"/>
@ -140,6 +142,7 @@
<testCase name="StringRef/Substrings/Pointer values of substring refs should also match" duration="{duration}"/> <testCase name="StringRef/Substrings/Pointer values of substring refs should also match" duration="{duration}"/>
<testCase name="StringRef/Substrings/Past the end substring" duration="{duration}"/> <testCase name="StringRef/Substrings/Past the end substring" duration="{duration}"/>
<testCase name="StringRef/Substrings/Substring off the end are trimmed" duration="{duration}"/> <testCase name="StringRef/Substrings/Substring off the end are trimmed" duration="{duration}"/>
<testCase name="StringRef/Substrings/substring start after the end is empty" duration="{duration}"/>
<testCase name="StringRef/Comparisons are deep" duration="{duration}"/> <testCase name="StringRef/Comparisons are deep" duration="{duration}"/>
<testCase name="StringRef/from std::string/implicitly constructed" duration="{duration}"/> <testCase name="StringRef/from std::string/implicitly constructed" duration="{duration}"/>
<testCase name="StringRef/from std::string/explicitly constructed" duration="{duration}"/> <testCase name="StringRef/from std::string/explicitly constructed" duration="{duration}"/>

View File

@ -37,7 +37,7 @@ ok {test-number} -
# #1403 # #1403
ok {test-number} - h1 == h2 for: [1403 helper] == [1403 helper] ok {test-number} - h1 == h2 for: [1403 helper] == [1403 helper]
# #1455 - INFO and WARN can start with a linebreak # #1455 - INFO and WARN can start with a linebreak
warning 20 - ' warning {test-number} - '
This info message starts with a linebreak' with 1 message: ' This info message starts with a linebreak' with 1 message: '
This warning message starts with a linebreak' This warning message starts with a linebreak'
This would not be caught previously This would not be caught previously
@ -795,7 +795,7 @@ not ok {test-number} - explicitly
# FAIL_CHECK does not abort the test # FAIL_CHECK does not abort the test
not ok {test-number} - explicitly with 1 message: 'This is a failure' not ok {test-number} - explicitly with 1 message: 'This is a failure'
# FAIL_CHECK does not abort the test # FAIL_CHECK does not abort the test
warning 397 - 'This message appears in the output' warning {test-number} - 'This message appears in the output'
# Factorials are computed # Factorials are computed
ok {test-number} - Factorial(0) == 1 for: 1 == 1 ok {test-number} - Factorial(0) == 1 for: 1 == 1
# Factorials are computed # Factorials are computed
@ -1443,7 +1443,7 @@ ok {test-number} - !(d >= Approx( 1.24 )) for: !(1.23 >= Approx( 1.24 ))
# Greater-than inequalities with different epsilons # Greater-than inequalities with different epsilons
ok {test-number} - d >= Approx( 1.24 ).epsilon(0.1) for: 1.23 >= Approx( 1.24 ) ok {test-number} - d >= Approx( 1.24 ).epsilon(0.1) for: 1.23 >= Approx( 1.24 )
# INFO and WARN do not abort tests # INFO and WARN do not abort tests
warning 721 - 'this is a message' with 1 message: 'this is a warning' warning {test-number} - 'this is a message' with 1 message: 'this is a warning'
# INFO gets logged on failure # INFO gets logged on failure
not ok {test-number} - a == 1 for: 2 == 1 with 2 messages: 'this message should be logged' and 'so should this' not ok {test-number} - a == 1 for: 2 == 1 with 2 messages: 'this message should be logged' and 'so should this'
# INFO gets logged on failure, even if captured before successful assertions # INFO gets logged on failure, even if captured before successful assertions
@ -1569,7 +1569,7 @@ ok {test-number} - values > -6 for: 98 > -6
# Nested generators and captured variables # Nested generators and captured variables
ok {test-number} - values > -6 for: 99 > -6 ok {test-number} - values > -6 for: 99 > -6
# Nice descriptive name # Nice descriptive name
warning 784 - 'This one ran' warning {test-number} - 'This one ran'
# Non-std exceptions can be translated # Non-std exceptions can be translated
not ok {test-number} - unexpected exception with message: 'custom exception' not ok {test-number} - unexpected exception with message: 'custom exception'
# Objects that evaluated in boolean contexts can be checked # Objects that evaluated in boolean contexts can be checked
@ -1978,6 +1978,18 @@ ok {test-number} - spec.matches( *fakeTestCase( " aardvark " ) ) for: true
ok {test-number} - spec.matches( *fakeTestCase( "aardvark " ) ) for: true ok {test-number} - spec.matches( *fakeTestCase( "aardvark " ) ) for: true
# Parse test names and tags # Parse test names and tags
ok {test-number} - spec.matches( *fakeTestCase( "aardvark" ) ) for: true ok {test-number} - spec.matches( *fakeTestCase( "aardvark" ) ) for: true
# Parse test names and tags
ok {test-number} - spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")) for: true
# Parse test names and tags
ok {test-number} - !(spec.matches(*fakeTestCase("only foo", "[foo]"))) for: !false
# Parse test names and tags
ok {test-number} - !(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]"))) for: !false
# Parse test names and tags
ok {test-number} - !(spec.matches(*fakeTestCase("only foo", "[foo]"))) for: !false
# Parse test names and tags
ok {test-number} - !(spec.matches(*fakeTestCase("only hidden", "[.]"))) for: !false
# Parse test names and tags
ok {test-number} - spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")) for: true
# Pointers can be compared to null # Pointers can be compared to null
ok {test-number} - p == 0 for: 0 == 0 ok {test-number} - p == 0 for: 0 == 0
# Pointers can be compared to null # Pointers can be compared to null
@ -2288,6 +2300,8 @@ ok {test-number} - s.substr(s.size() + 1, 123).empty() for: true
# StringRef # StringRef
ok {test-number} - std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0 ok {test-number} - std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0
# StringRef # StringRef
ok {test-number} - s.substr(1'000'000, 1).empty() for: true
# StringRef
ok {test-number} - (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello" ok {test-number} - (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello"
# StringRef # StringRef
ok {test-number} - left == right for: Hello == Hello ok {test-number} - left == right for: Hello == Hello
@ -2314,15 +2328,33 @@ ok {test-number} - stdStr == "a stringref" for: "a stringref" == "a stringref"
# StringRef # StringRef
ok {test-number} - stdStr.size() == sr.size() for: 11 == 11 ok {test-number} - stdStr.size() == sr.size() for: 11 == 11
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: 'StringRef{}.size() == 0' ok {test-number} - with 1 message: 'empty.size() == 0'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: 'StringRef{ "abc", 3 }.size() == 3' ok {test-number} - with 1 message: 'empty.begin() == empty.end()'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: 'StringRef{ "abc", 3 }.isNullTerminated()' ok {test-number} - with 1 message: 'stringref.size() == 3'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: 'StringRef{ "abc", 2 }.size() == 2' ok {test-number} - with 1 message: 'stringref.isNullTerminated()'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: '!(StringRef{ "abc", 2 }.isNullTerminated())' ok {test-number} - with 1 message: 'stringref.data() == abc'
# StringRef at compilation time
ok {test-number} - with 1 message: 'stringref.begin() == abc'
# StringRef at compilation time
ok {test-number} - with 1 message: 'stringref.begin() != stringref.end()'
# StringRef at compilation time
ok {test-number} - with 1 message: 'stringref.substr(10, 0).empty()'
# StringRef at compilation time
ok {test-number} - with 1 message: 'stringref.substr(2, 1).data() == abc + 2'
# StringRef at compilation time
ok {test-number} - with 1 message: 'shortened.size() == 2'
# StringRef at compilation time
ok {test-number} - with 1 message: 'shortened.data() == abc'
# StringRef at compilation time
ok {test-number} - with 1 message: 'shortened.begin() != shortened.end()'
# StringRef at compilation time
ok {test-number} - with 1 message: '!(shortened.isNullTerminated())'
# StringRef at compilation time
ok {test-number} - with 1 message: '!(shortened.substr(1, 3).isNullTerminated())'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: '!(sr1.empty())' ok {test-number} - with 1 message: '!(sr1.empty())'
# StringRef at compilation time # StringRef at compilation time
@ -2928,9 +2960,9 @@ not ok {test-number} - unexpected exception with message: 'expected exception';
# When unchecked exceptions are thrown from sections they are always failures # When unchecked exceptions are thrown from sections they are always failures
not ok {test-number} - unexpected exception with message: 'unexpected exception' not ok {test-number} - unexpected exception with message: 'unexpected exception'
# Where the LHS is not a simple value # Where the LHS is not a simple value
warning 1461 - 'Uncomment the code in this test to check that it gives a sensible compiler error' warning {test-number} - 'Uncomment the code in this test to check that it gives a sensible compiler error'
# Where there is more to the expression after the RHS # Where there is more to the expression after the RHS
warning 1462 - 'Uncomment the code in this test to check that it gives a sensible compiler error' warning {test-number} - 'Uncomment the code in this test to check that it gives a sensible compiler error'
# X/level/0/a # X/level/0/a
ok {test-number} - ok {test-number} -
# X/level/0/b # X/level/0/b
@ -3197,9 +3229,9 @@ ok {test-number} - s.result == 17 for: 17 == 17
# measure # measure
ok {test-number} - s.iterations == 1 for: 1 == 1 ok {test-number} - s.iterations == 1 for: 1 == 1
# mix info, unscoped info and warning # mix info, unscoped info and warning
warning 1595 - 'info' with 2 messages: 'unscoped info' and 'and warn may mix' warning {test-number} - 'info' with 2 messages: 'unscoped info' and 'and warn may mix'
# mix info, unscoped info and warning # mix info, unscoped info and warning
warning 1596 - 'info' with 2 messages: 'unscoped info' and 'they are not cleared after warnings' warning {test-number} - 'info' with 2 messages: 'unscoped info' and 'they are not cleared after warnings'
# more nested SECTION tests # more nested SECTION tests
not ok {test-number} - a == b for: 1 == 2 not ok {test-number} - a == b for: 1 == 2
# more nested SECTION tests # more nested SECTION tests
@ -3578,5 +3610,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
ok {test-number} - ok {test-number} -
# xmlentitycheck # xmlentitycheck
ok {test-number} - ok {test-number} -
1..1785 1..1801

View File

@ -8025,7 +8025,7 @@ Nor would this
</Section> </Section>
<OverallResult success="false"/> <OverallResult success="false"/>
</TestCase> </TestCase>
<TestCase name="Parse test names and tags" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > <TestCase name="Parse test names and tags" tags="[command-line][test-spec]" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Section name="Empty test spec should have no filters" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > <Section name="Empty test spec should have no filters" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > <Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original> <Original>
@ -9285,6 +9285,60 @@ Nor would this
</Expression> </Expression>
<OverallResults successes="5" failures="0" expectedFailures="0"/> <OverallResults successes="5" failures="0" expectedFailures="0"/>
</Section> </Section>
<Section name="Shortened hide tags are split apart when parsing" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
spec.matches(*fakeTestCase("hidden and foo", "[.][foo]"))
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="CHECK_FALSE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
!(spec.matches(*fakeTestCase("only foo", "[foo]")))
</Original>
<Expanded>
!false
</Expanded>
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
<Section name="Shortened hide tags also properly handle exclusion" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Expression success="true" type="CHECK_FALSE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
!(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")))
</Original>
<Expanded>
!false
</Expanded>
</Expression>
<Expression success="true" type="CHECK_FALSE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
!(spec.matches(*fakeTestCase("only foo", "[foo]")))
</Original>
<Expanded>
!false
</Expanded>
</Expression>
<Expression success="true" type="CHECK_FALSE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
!(spec.matches(*fakeTestCase("only hidden", "[.]")))
</Original>
<Expanded>
!false
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]"))
</Original>
<Expanded>
true
</Expanded>
</Expression>
<OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/> <OverallResult success="true"/>
</TestCase> </TestCase>
<TestCase name="Pointers can be compared to null" filename="tests/<exe-name>/UsageTests/Condition.tests.cpp" > <TestCase name="Pointers can be compared to null" filename="tests/<exe-name>/UsageTests/Condition.tests.cpp" >
@ -10852,6 +10906,20 @@ Message from section two
</Section> </Section>
<OverallResults successes="1" failures="0" expectedFailures="0"/> <OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section> </Section>
<Section name="Substrings" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Section name="substring start after the end is empty" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
s.substr(1'000'000, 1).empty()
</Original>
<Expanded>
true
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Comparisons are deep" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <Section name="Comparisons are deep" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original> <Original>
@ -10993,7 +11061,7 @@ Message from section two
</TestCase> </TestCase>
<TestCase name="StringRef at compilation time" tags="[constexpr][StringRef][Strings]" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <TestCase name="StringRef at compilation time" tags="[constexpr][StringRef][Strings]" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Section name="Simple constructors" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <Section name="Simple constructors" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<OverallResults successes="5" failures="0" expectedFailures="0"/> <OverallResults successes="14" failures="0" expectedFailures="0"/>
</Section> </Section>
<Section name="UDL construction" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <Section name="UDL construction" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<OverallResults successes="6" failures="0" expectedFailures="0"/> <OverallResults successes="6" failures="0" expectedFailures="0"/>
@ -16841,7 +16909,7 @@ loose text artifact
</Section> </Section>
<OverallResult success="true"/> <OverallResult success="true"/>
</TestCase> </TestCase>
<OverallResults successes="1624" failures="149" expectedFailures="21"/> <OverallResults successes="1640" failures="149" expectedFailures="21"/>
</Group> </Group>
<OverallResults successes="1624" failures="148" expectedFailures="21"/> <OverallResults successes="1640" failures="148" expectedFailures="21"/>
</Catch> </Catch>

View File

@ -19,7 +19,7 @@ namespace {
auto fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCaseInfo("", { name, desc }, CATCH_INTERNAL_LINEINFO); } auto fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCaseInfo("", { name, desc }, CATCH_INTERNAL_LINEINFO); }
} }
TEST_CASE( "Parse test names and tags" ) { TEST_CASE( "Parse test names and tags", "[command-line][test-spec]" ) {
using Catch::parseTestSpec; using Catch::parseTestSpec;
using Catch::TestSpec; using Catch::TestSpec;
@ -280,7 +280,18 @@ TEST_CASE( "Parse test names and tags" ) {
CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) ); CHECK( spec.matches( *fakeTestCase( " aardvark " ) ) );
CHECK( spec.matches( *fakeTestCase( "aardvark " ) ) ); CHECK( spec.matches( *fakeTestCase( "aardvark " ) ) );
CHECK( spec.matches( *fakeTestCase( "aardvark" ) ) ); CHECK( spec.matches( *fakeTestCase( "aardvark" ) ) );
}
SECTION("Shortened hide tags are split apart when parsing") {
TestSpec spec = parseTestSpec("[.foo]");
CHECK(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")));
CHECK_FALSE(spec.matches(*fakeTestCase("only foo", "[foo]")));
}
SECTION("Shortened hide tags also properly handle exclusion") {
TestSpec spec = parseTestSpec("~[.foo]");
CHECK_FALSE(spec.matches(*fakeTestCase("hidden and foo", "[.][foo]")));
CHECK_FALSE(spec.matches(*fakeTestCase("only foo", "[foo]")));
CHECK_FALSE(spec.matches(*fakeTestCase("only hidden", "[.]")));
CHECK(spec.matches(*fakeTestCase("neither foo nor hidden", "[bar]")));
} }
} }

View File

@ -315,6 +315,21 @@ TEST_CASE("GENERATE capture macros", "[generators][internals][approvals]") {
REQUIRE(value == value2); REQUIRE(value == value2);
} }
TEST_CASE("#1809 - GENERATE_COPY and SingleValueGenerator does not compile", "[generators][compilation][approvals]") {
// Verify Issue #1809 fix, only needs to compile.
auto a = GENERATE_COPY(1, 2);
(void)a;
auto b = GENERATE_COPY(as<long>{}, 1, 2);
(void)b;
int i = 1;
int j = 2;
auto c = GENERATE_COPY(i, j);
(void)c;
auto d = GENERATE_COPY(as<long>{}, i, j);
(void)d;
SUCCEED();
}
TEST_CASE("Multiple random generators in one test case output different values", "[generators][internals][approvals]") { TEST_CASE("Multiple random generators in one test case output different values", "[generators][internals][approvals]") {
SECTION("Integer") { SECTION("Integer") {
auto random1 = Catch::Generators::random(0, 1000); auto random1 = Catch::Generators::random(0, 1000);

View File

@ -72,7 +72,9 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
ss = s.substr(6, 123); ss = s.substr(6, 123);
REQUIRE(std::strcmp(ss.c_str(), "world!") == 0); REQUIRE(std::strcmp(ss.c_str(), "world!") == 0);
} }
// TODO: substring into string + size is longer than end SECTION("substring start after the end is empty") {
REQUIRE(s.substr(1'000'000, 1).empty());
}
} }
SECTION( "Comparisons are deep" ) { SECTION( "Comparisons are deep" ) {
@ -124,15 +126,32 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
} }
TEST_CASE("StringRef at compilation time", "[Strings][StringRef][constexpr]") { TEST_CASE("StringRef at compilation time", "[Strings][StringRef][constexpr]") {
//TODO:
// * substr
using Catch::StringRef; using Catch::StringRef;
SECTION("Simple constructors") { SECTION("Simple constructors") {
STATIC_REQUIRE(StringRef{}.size() == 0); constexpr StringRef empty{};
STATIC_REQUIRE(empty.size() == 0);
STATIC_REQUIRE(empty.begin() == empty.end());
STATIC_REQUIRE(StringRef{ "abc", 3 }.size() == 3); constexpr char const* const abc = "abc";
STATIC_REQUIRE(StringRef{ "abc", 3 }.isNullTerminated());
STATIC_REQUIRE(StringRef{ "abc", 2 }.size() == 2); constexpr StringRef stringref(abc, 3);
STATIC_REQUIRE_FALSE(StringRef{ "abc", 2 }.isNullTerminated()); STATIC_REQUIRE(stringref.size() == 3);
STATIC_REQUIRE(stringref.isNullTerminated());
STATIC_REQUIRE(stringref.data() == abc);
STATIC_REQUIRE(stringref.begin() == abc);
STATIC_REQUIRE(stringref.begin() != stringref.end());
STATIC_REQUIRE(stringref.substr(10, 0).empty());
STATIC_REQUIRE(stringref.substr(2, 1).data() == abc + 2);
constexpr StringRef shortened(abc, 2);
STATIC_REQUIRE(shortened.size() == 2);
STATIC_REQUIRE(shortened.data() == abc);
STATIC_REQUIRE(shortened.begin() != shortened.end());
STATIC_REQUIRE_FALSE(shortened.isNullTerminated());
STATIC_REQUIRE_FALSE(shortened.substr(1, 3).isNullTerminated());
} }
SECTION("UDL construction") { SECTION("UDL construction") {
constexpr auto sr1 = "abc"_catch_sr; constexpr auto sr1 = "abc"_catch_sr;

View File

@ -1,5 +1,6 @@
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include <catch2/benchmark/catch_benchmark.hpp> #include <catch2/benchmark/catch_benchmark.hpp>
#include <catch2/benchmark/catch_constructor.hpp>
#include <catch2/catch_generators_specific.hpp> #include <catch2/catch_generators_specific.hpp>
#include <map> #include <map>
@ -127,4 +128,18 @@ TEST_CASE("Benchmark containers", "[!benchmark]") {
REQUIRE(v[i] == generated); REQUIRE(v[i] == generated);
} }
} }
SECTION("construct and destroy example") {
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
meter.measure([&](int i) { storage[i].construct("thing"); });
};
BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
for(auto&& o : storage)
o.construct("thing");
meter.measure([&](int i) { storage[i].destruct(); });
};
}
} }

View File

@ -71,7 +71,7 @@ nanParser = re.compile(r'''
''', re.VERBOSE) ''', re.VERBOSE)
# The weird OR is there to always have at least empty string for group 1 # The weird OR is there to always have at least empty string for group 1
tapTestNumParser = re.compile(r'^(not |)?ok (\d+) -') tapTestNumParser = re.compile(r'^((?:not ok)|(?:ok)|(?:warning)|(?:info)) (\d+) -')
if len(sys.argv) == 2: if len(sys.argv) == 2:
cmdPath = sys.argv[1] cmdPath = sys.argv[1]
@ -128,7 +128,7 @@ def filterLine(line, isCompact):
line = line.replace(': PASSED', ': passed') line = line.replace(': PASSED', ': passed')
# strip out the test order number in TAP to avoid massive diffs for every change # strip out the test order number in TAP to avoid massive diffs for every change
line = tapTestNumParser.sub("\g<1>ok {test-number} -", line) line = tapTestNumParser.sub("\g<1> {test-number} -", line)
# strip Catch version number # strip Catch version number
line = versionParser.sub("<version>", line) line = versionParser.sub("<version>", line)