Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMartin Hořeňovský2018-01-10 13:53:04 +0100
committerMartin Hořeňovský2018-01-10 13:53:04 +0100
commitcd76f5730c9a3afa19f3b9c83608d9c7ab325a19 (patch)
treeb189f1e5399737491266204879bbd185669f799a
parentf5910f38ef38ac2cca9f3830804abf6d9a8d40bf (diff)
downloadcatch3-2.1.0.tar.gz
v2.1.0v2.1.0
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md4
-rw-r--r--conanfile.py2
-rw-r--r--docs/release-notes.md41
-rw-r--r--include/internal/catch_version.cpp2
-rw-r--r--single_include/catch.hpp5208
-rw-r--r--single_include/catch_reporter_automake.hpp62
-rw-r--r--single_include/catch_reporter_tap.hpp255
-rw-r--r--single_include/catch_reporter_teamcity.hpp220
-rw-r--r--test_package/conanfile.py2
10 files changed, 3549 insertions, 2249 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 97a11485..0fa91501 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,7 +13,7 @@ set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
set(HEADER_DIR ${CATCH_DIR}/include)
-set(CATCH_VERSION_NUMBER 2.0.1)
+set(CATCH_VERSION_NUMBER 2.1.0)
if(USE_WMAIN)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
diff --git a/README.md b/README.md
index 6d50ed5c..207ba30e 100644
--- a/README.md
+++ b/README.md
@@ -5,13 +5,13 @@
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
[![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
-[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/tB8z0G3kMAIZkIca)
+[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/nerce2MiN6sVmfCi)
<a href="https://github.com/catchorg/Catch2/releases/download/v2.0.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!
-If you've been using an earlier version of Catch, please see the
+If you've been using an earlier version of Catch, please see the
Breaking Changes section of [the release notes](https://github.com/catchorg/Catch2/releases/tag/v2.0.1)
before moving to Catch2. You might also like to read [this blog post](http://www.levelofindirection.com/journal/2017/11/3/catch2-released.html) for more details.
diff --git a/conanfile.py b/conanfile.py
index b4993b71..354f68a4 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -4,7 +4,7 @@ from conans import ConanFile
class CatchConan(ConanFile):
name = "Catch"
- version = "2.0.1"
+ version = "2.1.0"
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
author = "philsquared"
generators = "cmake"
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 1a762dbd..5c02f6bf 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -1,4 +1,45 @@
<a id="top"></a>
+
+# 2.1.0
+
+## Improvements
+* Various performance improvements
+ * On top of the performance regression fixes
+* Experimental support for PCH was added (#1061)
+* `CATCH_CONFIG_EXTERNAL_INTERFACES` now brings in declarations of Console, Compact, XML and JUnit reporters
+* `MatcherBase` no longer has a pointless second template argument
+* Reduced the number of warning suppressions that leak into user's code
+ * Bugs in g++ 4.x and 5.x mean that some of them have to be left in
+
+
+## Fixes
+* Fixed performance regression from Catch classic
+ * One of the performance improvement patches for Catch classic was not applied to Catch2
+* Fixed platform detection for iOS (#1084)
+* Fixed compilation when `g++` is used together with `libc++` (#1110)
+* Fixed TeamCity reporter compilation with the single header version
+ * To fix the underlying issue we will be versioning reporters in single_include folder per release
+* The XML reporter will now report `WARN` messages even when not used with `-s`
+* Fixed compilation when `VectorContains` matcher was combined using `&&` (#1092)
+* Fixed test duration overflowing after 10 seconds (#1125, #1129)
+* Fixed `std::uncaught_exception` deprecation warning (#1124)
+
+
+## New features
+* New Matchers
+ * Regex matcher for strings, `Matches`.
+ * Set-equal matcher for vectors, `UnorderedEquals`
+ * Floating point matchers, `WithinAbs` and `WithinULP`.
+* Stringification now attempts to decompose all containers (#606)
+ * Containers are objects that respond to ADL `begin(T)` and `end(T)`.
+
+
+## Other changes
+* Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version
+
+
+
+
# 2.0.1
## Breaking changes
diff --git a/include/internal/catch_version.cpp b/include/internal/catch_version.cpp
index a9dc64e6..8b50ace0 100644
--- a/include/internal/catch_version.cpp
+++ b/include/internal/catch_version.cpp
@@ -37,7 +37,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 2, 0, 1, "", 0 );
+ static Version version( 2, 1, 0, "", 0 );
return version;
}
diff --git a/single_include/catch.hpp b/single_include/catch.hpp
index 362f8693..ef720908 100644
--- a/single_include/catch.hpp
+++ b/single_include/catch.hpp
@@ -1,9 +1,9 @@
/*
- * Catch v2.0.1
- * Generated: 2017-11-03 11:53:39.642003
+ * Catch v2.1.0
+ * Generated: 2018-01-10 13:51:15.378034
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
- * Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved.
+ * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -26,9 +26,6 @@
# pragma warning(push)
# pragma warning(disable: 161 1682)
# else // __ICC
-# pragma clang diagnostic ignored "-Wglobal-constructors"
-# pragma clang diagnostic ignored "-Wvariadic-macros"
-# pragma clang diagnostic ignored "-Wc99-extensions"
# pragma clang diagnostic ignored "-Wunused-variable"
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wpadded"
@@ -36,27 +33,33 @@
# pragma clang diagnostic ignored "-Wcovered-switch-default"
# endif
#elif defined __GNUC__
-# pragma GCC diagnostic ignored "-Wvariadic-macros"
# pragma GCC diagnostic ignored "-Wunused-variable"
# pragma GCC diagnostic ignored "-Wparentheses"
-
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wpadded"
#endif
// end catch_suppress_warnings.h
#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
# define CATCH_IMPL
+# define CATCH_CONFIG_ALL_PARTS
+#endif
+
+// In the impl file, we want to have access to all parts of the headers
+// Can also be used to sanely support PCHs
+#if defined(CATCH_CONFIG_ALL_PARTS)
# define CATCH_CONFIG_EXTERNAL_INTERFACES
# if defined(CATCH_CONFIG_DISABLE_MATCHERS)
# undef CATCH_CONFIG_DISABLE_MATCHERS
# endif
+# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
#endif
+#if !defined(CATCH_CONFIG_IMPL_ONLY)
// start catch_platform.h
#ifdef __APPLE__
# include <TargetConditionals.h>
-# if TARGET_OS_MAC == 1
+# if TARGET_OS_OSX == 1
# define CATCH_PLATFORM_MAC
# elif TARGET_OS_IPHONE == 1
# define CATCH_PLATFORM_IPHONE
@@ -70,6 +73,7 @@
#endif
// end catch_platform.h
+
#ifdef CATCH_IMPL
# ifndef CLARA_CONFIG_MAIN
# define CLARA_CONFIG_MAIN_NOT_DEFINED
@@ -77,6 +81,13 @@
# endif
#endif
+// start catch_user_interfaces.h
+
+namespace Catch {
+ unsigned int rngSeed();
+}
+
+// end catch_user_interfaces.h
// start catch_tag_alias_autoregistrar.h
// start catch_common.h
@@ -228,7 +239,10 @@ namespace Catch {
struct SourceLineInfo {
SourceLineInfo() = delete;
- SourceLineInfo( char const* _file, std::size_t _line ) noexcept;
+ SourceLineInfo( char const* _file, std::size_t _line ) noexcept
+ : file( _file ),
+ line( _line )
+ {}
SourceLineInfo( SourceLineInfo const& other ) = default;
SourceLineInfo( SourceLineInfo && ) = default;
@@ -245,11 +259,6 @@ namespace Catch {
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
- // This is just here to avoid compiler warnings with macro constants and boolean literals
- bool isTrue( bool value );
- bool alwaysTrue();
- bool alwaysFalse();
-
// Use this in variadic streaming macros to allow
// >> +StreamEndStop
// as well as
@@ -275,7 +284,10 @@ namespace Catch {
} // end namespace Catch
-#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
+ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
// end catch_tag_alias_autoregistrar.h
// start catch_test_registry.h
@@ -330,10 +342,12 @@ namespace Catch {
/// visible - but it does mean (substring) StringRefs should not be shared between
/// threads.
class StringRef {
- friend struct StringRefTestAccess;
-
+ public:
using size_type = std::size_t;
+ private:
+ friend struct StringRefTestAccess;
+
char const* m_start;
size_type m_size;
@@ -341,16 +355,50 @@ namespace Catch {
void takeOwnership();
+ static constexpr char const* const s_empty = "";
+
public: // construction/ assignment
- StringRef() noexcept;
- StringRef( StringRef const& other ) noexcept;
- StringRef( StringRef&& other ) noexcept;
+ StringRef() noexcept
+ : StringRef( s_empty, 0 )
+ {}
+
+ StringRef( StringRef const& other ) noexcept
+ : m_start( other.m_start ),
+ m_size( other.m_size )
+ {}
+
+ StringRef( StringRef&& other ) noexcept
+ : m_start( other.m_start ),
+ m_size( other.m_size ),
+ m_data( other.m_data )
+ {
+ other.m_data = nullptr;
+ }
+
StringRef( char const* rawChars ) noexcept;
- StringRef( char const* rawChars, size_type size ) noexcept;
- StringRef( std::string const& stdString ) noexcept;
- ~StringRef() noexcept;
- auto operator = ( StringRef other ) noexcept -> StringRef&;
+ StringRef( char const* rawChars, size_type size ) noexcept
+ : m_start( rawChars ),
+ m_size( size )
+ {}
+
+ StringRef( std::string const& stdString ) noexcept
+ : m_start( stdString.c_str() ),
+ m_size( stdString.size() )
+ {}
+
+ ~StringRef() noexcept {
+ delete[] m_data;
+ }
+
+ auto operator = ( StringRef const &other ) noexcept -> StringRef& {
+ delete[] m_data;
+ m_data = nullptr;
+ m_start = other.m_start;
+ m_size = other.m_size;
+ return *this;
+ }
+
operator std::string() const;
void swap( StringRef& other ) noexcept;
@@ -362,8 +410,13 @@ namespace Catch {
auto operator[] ( size_type index ) const noexcept -> char;
public: // named queries
- auto empty() const noexcept -> bool;
- auto size() const noexcept -> size_type;
+ auto empty() const noexcept -> bool {
+ return m_size == 0;
+ }
+ auto size() const noexcept -> size_type {
+ return m_size;
+ }
+
auto numberOfCharacters() const noexcept -> size_type;
auto c_str() const -> char const*;
@@ -382,6 +435,10 @@ namespace Catch {
auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
+ inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
+ return StringRef( rawChars, size );
+ }
+
} // namespace Catch
// end catch_stringref.h
@@ -407,7 +464,7 @@ auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {
}
struct NameAndTags {
- NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept;
+ NameAndTags( StringRef name_ = StringRef(), StringRef tags_ = StringRef() ) noexcept;
StringRef name;
StringRef tags;
};
@@ -473,15 +530,121 @@ struct AutoReg : NonCopyable {
// start catch_assertionhandler.h
+// start catch_assertioninfo.h
+
+// start catch_result_type.h
+
+namespace Catch {
+
+ // ResultWas::OfType enum
+ struct ResultWas { enum OfType {
+ Unknown = -1,
+ Ok = 0,
+ Info = 1,
+ Warning = 2,
+
+ FailureBit = 0x10,
+
+ ExpressionFailed = FailureBit | 1,
+ ExplicitFailure = FailureBit | 2,
+
+ Exception = 0x100 | FailureBit,
+
+ ThrewException = Exception | 1,
+ DidntThrowException = Exception | 2,
+
+ FatalErrorCondition = 0x200 | FailureBit
+
+ }; };
+
+ bool isOk( ResultWas::OfType resultType );
+ bool isJustInfo( int flags );
+
+ // ResultDisposition::Flags enum
+ struct ResultDisposition { enum Flags {
+ Normal = 0x01,
+
+ ContinueOnFailure = 0x02, // Failures fail test, but execution continues
+ FalseTest = 0x04, // Prefix expression with !
+ SuppressFail = 0x08 // Failures are reported but do not fail the test
+ }; };
+
+ ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );
+
+ bool shouldContinueOnFailure( int flags );
+ inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
+ bool shouldSuppressFailure( int flags );
+
+} // end namespace Catch
+
+// end catch_result_type.h
+namespace Catch {
+
+ struct AssertionInfo
+ {
+ StringRef macroName;
+ SourceLineInfo lineInfo;
+ StringRef capturedExpression;
+ ResultDisposition::Flags resultDisposition;
+
+ // We want to delete this constructor but a compiler bug in 4.8 means
+ // the struct is then treated as non-aggregate
+ //AssertionInfo() = delete;
+ };
+
+} // end namespace Catch
+
+// end catch_assertioninfo.h
// start catch_decomposer.h
// start catch_tostring.h
-#include <sstream>
#include <vector>
#include <cstddef>
#include <type_traits>
#include <string>
+// start catch_stream.h
+
+#include <iosfwd>
+#include <cstddef>
+#include <ostream>
+
+namespace Catch {
+
+ std::ostream& cout();
+ std::ostream& cerr();
+ std::ostream& clog();
+
+ class StringRef;
+
+ struct IStream {
+ virtual ~IStream();
+ virtual std::ostream& stream() const = 0;
+ };
+
+ auto makeStream( StringRef const &filename ) -> IStream const*;
+
+ class ReusableStringStream {
+ std::size_t m_index;
+ std::ostream* m_oss;
+ public:
+ ReusableStringStream();
+ ~ReusableStringStream();
+
+ auto str() const -> std::string;
+
+ template<typename T>
+ auto operator << ( T const& value ) -> ReusableStringStream& {
+ *m_oss << value;
+ return *this;
+ }
+ auto get() -> std::ostream& { return *m_oss; }
+
+ static void cleanup();
+ };
+}
+
+// end catch_stream.h
#ifdef __OBJC__
// start catch_objc_arc.hpp
@@ -535,7 +698,7 @@ inline id performOptionalSelector( id obj, SEL sel ) {
#endif
// We need a dummy global operator<< so we can bring it into Catch namespace later
-struct Catch_global_namespace_dummy;
+struct Catch_global_namespace_dummy {};
std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
namespace Catch {
@@ -566,25 +729,37 @@ namespace Catch {
static const bool value = decltype(test<std::ostream, const T&>(0))::value;
};
+ template<typename E>
+ std::string convertUnknownEnumToString( E e );
+
+ template<typename T>
+ typename std::enable_if<!std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& ) {
+ return Detail::unprintableString;
+ };
+ template<typename T>
+ typename std::enable_if<std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& value ) {
+ return convertUnknownEnumToString( value );
+ };
+
} // namespace Detail
// If we decide for C++14, change these to enable_if_ts
- template <typename T>
+ template <typename T, typename = void>
struct StringMaker {
template <typename Fake = T>
static
typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
- convert(const Fake& t) {
- std::ostringstream sstr;
- sstr << t;
- return sstr.str();
+ convert(const Fake& value) {
+ ReusableStringStream rss;
+ rss << value;
+ return rss.str();
}
template <typename Fake = T>
static
typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
- convert(const Fake&) {
- return Detail::unprintableString;
+ convert( const Fake& value ) {
+ return Detail::convertUnstreamable( value );
}
};
@@ -597,6 +772,11 @@ namespace Catch {
return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e);
}
+ template<typename E>
+ std::string convertUnknownEnumToString( E e ) {
+ return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e));
+ }
+
} // namespace Detail
// Some predefined specializations
@@ -627,6 +807,18 @@ namespace Catch {
static std::string convert(wchar_t * str);
};
+ template<typename T>
+ struct is_string_array : std::false_type {};
+
+ template<std::size_t N>
+ struct is_string_array<char[N]> : std::true_type {};
+
+ template<std::size_t N>
+ struct is_string_array<signed char[N]> : std::true_type {};
+
+ template<std::size_t N>
+ struct is_string_array<unsigned char[N]> : std::true_type {};
+
template<int SZ>
struct StringMaker<char[SZ]> {
static std::string convert(const char* str) {
@@ -729,32 +921,18 @@ namespace Catch {
namespace Detail {
template<typename InputIterator>
std::string rangeToString(InputIterator first, InputIterator last) {
- std::ostringstream oss;
- oss << "{ ";
+ ReusableStringStream rss;
+ rss << "{ ";
if (first != last) {
- oss << ::Catch::Detail::stringify(*first);
+ rss << ::Catch::Detail::stringify(*first);
for (++first; first != last; ++first)
- oss << ", " << ::Catch::Detail::stringify(*first);
+ rss << ", " << ::Catch::Detail::stringify(*first);
}
- oss << " }";
- return oss.str();
+ rss << " }";
+ return rss.str();
}
}
- template<typename T, typename Allocator>
- struct StringMaker<std::vector<T, Allocator> > {
- static std::string convert( std::vector<T,Allocator> const& v ) {
- return ::Catch::Detail::rangeToString( v.begin(), v.end() );
- }
- };
-
- template<typename T>
- struct EnumStringMaker {
- static std::string convert(const T& t) {
- return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<T>::type>(t));
- }
- };
-
#ifdef __OBJC__
template<>
struct StringMaker<NSString*> {
@@ -798,13 +976,13 @@ namespace Catch {
template<typename T1, typename T2>
struct StringMaker<std::pair<T1, T2> > {
static std::string convert(const std::pair<T1, T2>& pair) {
- std::ostringstream oss;
- oss << "{ "
+ ReusableStringStream rss;
+ rss << "{ "
<< ::Catch::Detail::stringify(pair.first)
<< ", "
<< ::Catch::Detail::stringify(pair.second)
<< " }";
- return oss.str();
+ return rss.str();
}
};
}
@@ -841,22 +1019,72 @@ namespace Catch {
template<typename ...Types>
struct StringMaker<std::tuple<Types...>> {
static std::string convert(const std::tuple<Types...>& tuple) {
- std::ostringstream os;
- os << '{';
- Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, os);
- os << " }";
- return os.str();
+ ReusableStringStream rss;
+ rss << '{';
+ Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
+ rss << " }";
+ return rss.str();
}
};
}
#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
+namespace Catch {
+ struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
+
+ // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
+ using std::begin;
+ using std::end;
+
+ not_this_one begin( ... );
+ not_this_one end( ... );
+
+ template <typename T>
+ struct is_range {
+ static const bool value =
+ !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
+ !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
+ };
+
+ template<typename Range>
+ std::string rangeToString( Range const& range ) {
+ return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
+ }
+
+ // Handle vector<bool> specially
+ template<typename Allocator>
+ std::string rangeToString( std::vector<bool, Allocator> const& v ) {
+ ReusableStringStream rss;
+ rss << "{ ";
+ bool first = true;
+ for( bool b : v ) {
+ if( first )
+ first = false;
+ else
+ rss << ", ";
+ rss << ::Catch::Detail::stringify( b );
+ }
+ rss << " }";
+ return rss.str();
+ }
+
+ template<typename R>
+ struct StringMaker<R, typename std::enable_if<is_range<R>::value && !is_string_array<R>::value>::type> {
+ static std::string convert( R const& range ) {
+ return rangeToString( range );
+ }
+ };
+
+} // namespace Catch
+
// Separate std::chrono::duration specialization
#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
#include <ctime>
#include <ratio>
#include <chrono>
+namespace Catch {
+
template <class Ratio>
struct ratio_string {
static std::string symbol();
@@ -864,69 +1092,68 @@ struct ratio_string {
template <class Ratio>
std::string ratio_string<Ratio>::symbol() {
- std::ostringstream oss;
- oss << '[' << Ratio::num << '/'
+ Catch::ReusableStringStream rss;
+ rss << '[' << Ratio::num << '/'
<< Ratio::den << ']';
- return oss.str();
+ return rss.str();
}
template <>
struct ratio_string<std::atto> {
- static std::string symbol() { return "a"; }
+ static std::string symbol();
};
template <>
struct ratio_string<std::femto> {
- static std::string symbol() { return "f"; }
+ static std::string symbol();
};
template <>
struct ratio_string<std::pico> {
- static std::string symbol() { return "p"; }
+ static std::string symbol();
};
template <>
struct ratio_string<std::nano> {
- static std::string symbol() { return "n"; }
+ static std::string symbol();
};
template <>
struct ratio_string<std::micro> {
- static std::string symbol() { return "u"; }
+ static std::string symbol();
};
template <>
struct ratio_string<std::milli> {
- static std::string symbol() { return "m"; }
+ static std::string symbol();
};
-namespace Catch {
////////////
// std::chrono::duration specializations
template<typename Value, typename Ratio>
struct StringMaker<std::chrono::duration<Value, Ratio>> {
static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
- std::ostringstream oss;
- oss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
- return oss.str();
+ ReusableStringStream rss;
+ rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
+ return rss.str();
}
};
template<typename Value>
struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
- std::ostringstream oss;
- oss << duration.count() << " s";
- return oss.str();
+ ReusableStringStream rss;
+ rss << duration.count() << " s";
+ return rss.str();
}
};
template<typename Value>
struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
- std::ostringstream oss;
- oss << duration.count() << " m";
- return oss.str();
+ ReusableStringStream rss;
+ rss << duration.count() << " m";
+ return rss.str();
}
};
template<typename Value>
struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
- std::ostringstream oss;
- oss << duration.count() << " h";
- return oss.str();
+ ReusableStringStream rss;
+ rss << duration.count() << " h";
+ return rss.str();
}
};
@@ -972,7 +1199,7 @@ namespace Catch {
#endif
// end catch_tostring.h
-#include <ostream>
+#include <iosfwd>
#ifdef _MSC_VER
#pragma warning(push)
@@ -985,27 +1212,32 @@ namespace Catch {
namespace Catch {
struct ITransientExpression {
- virtual auto isBinaryExpression() const -> bool = 0;
- virtual auto getResult() const -> bool = 0;
+ auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
+ auto getResult() const -> bool { return m_result; }
virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
- // We don't actually need a virtual destructore, but many static analysers
+ ITransientExpression( bool isBinaryExpression, bool result )
+ : m_isBinaryExpression( isBinaryExpression ),
+ m_result( result )
+ {}
+
+ // We don't actually need a virtual destructor, but many static analysers
// complain if it's not here :-(
virtual ~ITransientExpression();
+
+ bool m_isBinaryExpression;
+ bool m_result;
+
};
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
template<typename LhsT, typename RhsT>
class BinaryExpr : public ITransientExpression {
- bool m_result;
LhsT m_lhs;
StringRef m_op;
RhsT m_rhs;
- auto isBinaryExpression() const -> bool override { return true; }
- auto getResult() const -> bool override { return m_result; }
-
void streamReconstructedExpression( std::ostream &os ) const override {
formatReconstructedExpression
( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
@@ -1013,7 +1245,7 @@ namespace Catch {
public:
BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
- : m_result( comparisonResult ),
+ : ITransientExpression{ true, comparisonResult },
m_lhs( lhs ),
m_op( op ),
m_rhs( rhs )
@@ -1024,15 +1256,15 @@ namespace Catch {
class UnaryExpr : public ITransientExpression {
LhsT m_lhs;
- auto isBinaryExpression() const -> bool override { return false; }
- auto getResult() const -> bool override { return m_lhs ? true : false; }
-
void streamReconstructedExpression( std::ostream &os ) const override {
os << Catch::Detail::stringify( m_lhs );
}
public:
- UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {}
+ explicit UnaryExpr( LhsT lhs )
+ : ITransientExpression{ false, lhs ? true : false },
+ m_lhs( lhs )
+ {}
};
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
@@ -1062,43 +1294,43 @@ namespace Catch {
class ExprLhs {
LhsT m_lhs;
public:
- ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
+ explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
template<typename RhsT>
auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
- return BinaryExpr<LhsT, RhsT const&>( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs );
+ return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs };
}
auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
- return BinaryExpr<LhsT, bool>( m_lhs == rhs, m_lhs, "==", rhs );
+ return { m_lhs == rhs, m_lhs, "==", rhs };
}
template<typename RhsT>
auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
- return BinaryExpr<LhsT, RhsT const&>( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs );
+ return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs };
}
auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
- return BinaryExpr<LhsT, bool>( m_lhs != rhs, m_lhs, "!=", rhs );
+ return { m_lhs != rhs, m_lhs, "!=", rhs };
}
template<typename RhsT>
auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
- return BinaryExpr<LhsT, RhsT const&>( m_lhs > rhs, m_lhs, ">", rhs );
+ return { m_lhs > rhs, m_lhs, ">", rhs };
}
template<typename RhsT>
auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
- return BinaryExpr<LhsT, RhsT const&>( m_lhs < rhs, m_lhs, "<", rhs );
+ return { m_lhs < rhs, m_lhs, "<", rhs };
}
template<typename RhsT>
auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
- return BinaryExpr<LhsT, RhsT const&>( m_lhs >= rhs, m_lhs, ">=", rhs );
+ return { m_lhs >= rhs, m_lhs, ">=", rhs };
}
template<typename RhsT>
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
- return BinaryExpr<LhsT, RhsT const&>( m_lhs <= rhs, m_lhs, "<=", rhs );
+ return { m_lhs <= rhs, m_lhs, "<=", rhs };
}
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
- return UnaryExpr<LhsT>( m_lhs );
+ return UnaryExpr<LhsT>{