|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* Catch v2.6.1 |
|
|
|
|
|
* Generated: 2019-02-12 19:52:52.262497 |
|
|
|
|
|
|
|
|
* Catch v2.7.0 |
|
|
|
|
|
* Generated: 2019-03-07 21:34:30.252164 |
|
|
* ---------------------------------------------------------- |
|
|
* ---------------------------------------------------------- |
|
|
* This file has been merged from multiple headers. Please don't edit it directly |
|
|
* This file has been merged from multiple headers. Please don't edit it directly |
|
|
* Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. |
|
|
* Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define CATCH_VERSION_MAJOR 2 |
|
|
#define CATCH_VERSION_MAJOR 2 |
|
|
#define CATCH_VERSION_MINOR 6 |
|
|
|
|
|
#define CATCH_VERSION_PATCH 1 |
|
|
|
|
|
|
|
|
#define CATCH_VERSION_MINOR 7 |
|
|
|
|
|
#define CATCH_VERSION_PATCH 0 |
|
|
|
|
|
|
|
|
#ifdef __clang__ |
|
|
#ifdef __clang__ |
|
|
# pragma clang system_header |
|
|
# pragma clang system_header |
|
|
|
|
|
|
|
|
#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ |
|
|
#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ |
|
|
#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ |
|
|
#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ |
|
|
#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF |
|
|
#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF |
|
|
|
|
|
#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) |
|
|
|
|
|
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
|
|
|
|
|
#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ |
|
|
|
|
|
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) |
|
|
|
|
|
#else |
|
|
|
|
|
// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF |
|
|
|
|
|
#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) |
|
|
|
|
|
#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ |
|
|
|
|
|
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) |
|
|
#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) |
|
|
#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)> |
|
|
|
|
|
|
|
|
#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) Catch::TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)> |
|
|
|
|
|
|
|
|
#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\ |
|
|
#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\ |
|
|
CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types)) |
|
|
CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <type_traits> |
|
|
#include <type_traits> |
|
|
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
template< typename... > |
|
|
template< typename... > |
|
|
struct TypeList{}; |
|
|
|
|
|
|
|
|
struct TypeList {}; |
|
|
|
|
|
|
|
|
template< typename... > |
|
|
template< typename... > |
|
|
struct append; |
|
|
struct append; |
|
|
|
|
|
|
|
|
template< template<typename...> class L1 |
|
|
template< template<typename...> class L1 |
|
|
, typename...E1 |
|
|
|
|
|
, template<typename...> class L2 |
|
|
|
|
|
, typename...E2 |
|
|
|
|
|
> |
|
|
|
|
|
struct append< L1<E1...>, L2<E2...> > |
|
|
|
|
|
{ |
|
|
|
|
|
using type = L1<E1..., E2...>; |
|
|
|
|
|
|
|
|
, typename...E1 |
|
|
|
|
|
, template<typename...> class L2 |
|
|
|
|
|
, typename...E2 |
|
|
|
|
|
> |
|
|
|
|
|
struct append< L1<E1...>, L2<E2...> > { |
|
|
|
|
|
using type = L1<E1..., E2...>; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
template< template<typename...> class L1 |
|
|
template< template<typename...> class L1 |
|
|
, typename...E1 |
|
|
|
|
|
, template<typename...> class L2 |
|
|
|
|
|
, typename...E2 |
|
|
|
|
|
, typename...Rest |
|
|
|
|
|
> |
|
|
|
|
|
struct append< L1<E1...>, L2<E2...>, Rest...> |
|
|
|
|
|
{ |
|
|
|
|
|
using type = typename append< L1<E1..., E2...>, Rest... >::type; |
|
|
|
|
|
|
|
|
, typename...E1 |
|
|
|
|
|
, template<typename...> class L2 |
|
|
|
|
|
, typename...E2 |
|
|
|
|
|
, typename...Rest |
|
|
|
|
|
> |
|
|
|
|
|
struct append< L1<E1...>, L2<E2...>, Rest...> { |
|
|
|
|
|
using type = typename append< L1<E1..., E2...>, Rest... >::type; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
template< template<typename...> class |
|
|
template< template<typename...> class |
|
|
, typename... |
|
|
|
|
|
> |
|
|
|
|
|
|
|
|
, typename... |
|
|
|
|
|
> |
|
|
struct rewrap; |
|
|
struct rewrap; |
|
|
|
|
|
|
|
|
template< template<typename...> class Container |
|
|
template< template<typename...> class Container |
|
|
, template<typename...> class List |
|
|
|
|
|
, typename...elems |
|
|
|
|
|
> |
|
|
|
|
|
struct rewrap<Container, List<elems...>> |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
, template<typename...> class List |
|
|
|
|
|
, typename...elems |
|
|
|
|
|
> |
|
|
|
|
|
struct rewrap<Container, List<elems...>> { |
|
|
using type = TypeList< Container< elems... > >; |
|
|
using type = TypeList< Container< elems... > >; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
template< template<typename...> class Container |
|
|
template< template<typename...> class Container |
|
|
, template<typename...> class List |
|
|
|
|
|
, class...Elems |
|
|
|
|
|
, typename...Elements> |
|
|
|
|
|
struct rewrap<Container, List<Elems...>, Elements...> |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
, template<typename...> class List |
|
|
|
|
|
, class...Elems |
|
|
|
|
|
, typename...Elements> |
|
|
|
|
|
struct rewrap<Container, List<Elems...>, Elements...> { |
|
|
using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type; |
|
|
using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
template< template<typename...> class...Containers > |
|
|
template< template<typename...> class...Containers > |
|
|
struct combine |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
struct combine { |
|
|
template< typename...Types > |
|
|
template< typename...Types > |
|
|
struct with_types |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
struct with_types { |
|
|
template< template <typename...> class Final > |
|
|
template< template <typename...> class Final > |
|
|
struct into |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
struct into { |
|
|
using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type; |
|
|
using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type; |
|
|
}; |
|
|
}; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
template<typename T> |
|
|
template<typename T> |
|
|
struct always_false : std::false_type {}; |
|
|
struct always_false : std::false_type {}; |
|
|
|
|
|
|
|
|
|
|
|
} // namespace Catch |
|
|
|
|
|
|
|
|
// end catch_meta.hpp |
|
|
// end catch_meta.hpp |
|
|
namespace Catch { |
|
|
namespace Catch { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \ |
|
|
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \ |
|
|
int index = 0; \ |
|
|
int index = 0; \ |
|
|
using expander = int[]; \ |
|
|
using expander = int[]; \ |
|
|
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \ |
|
|
|
|
|
|
|
|
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ |
|
|
|
|
|
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ |
|
|
|
|
|
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ |
|
|
|
|
|
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\ |
|
|
} \ |
|
|
} \ |
|
|
}; \ |
|
|
}; \ |
|
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ |
|
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ |
|
|
using TestInit = combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \ |
|
|
|
|
|
|
|
|
using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \ |
|
|
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \ |
|
|
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \ |
|
|
TestInit(); \ |
|
|
TestInit(); \ |
|
|
return 0; \ |
|
|
return 0; \ |
|
|
|
|
|
|
|
|
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\ |
|
|
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\ |
|
|
int index = 0;\ |
|
|
int index = 0;\ |
|
|
using expander = int[];\ |
|
|
using expander = int[];\ |
|
|
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \ |
|
|
|
|
|
|
|
|
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ |
|
|
|
|
|
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ |
|
|
|
|
|
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ |
|
|
|
|
|
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \ |
|
|
}\ |
|
|
}\ |
|
|
};\ |
|
|
};\ |
|
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
|
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
|
|
using TestInit = combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\ |
|
|
|
|
|
|
|
|
using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\ |
|
|
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\ |
|
|
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\ |
|
|
TestInit();\ |
|
|
TestInit();\ |
|
|
return 0;\ |
|
|
return 0;\ |
|
|
|
|
|
|
|
|
struct SectionInfo; |
|
|
struct SectionInfo; |
|
|
struct SectionEndInfo; |
|
|
struct SectionEndInfo; |
|
|
struct MessageInfo; |
|
|
struct MessageInfo; |
|
|
|
|
|
struct MessageBuilder; |
|
|
struct Counts; |
|
|
struct Counts; |
|
|
struct BenchmarkInfo; |
|
|
struct BenchmarkInfo; |
|
|
struct BenchmarkStats; |
|
|
struct BenchmarkStats; |
|
|
|
|
|
|
|
|
virtual void pushScopedMessage( MessageInfo const& message ) = 0; |
|
|
virtual void pushScopedMessage( MessageInfo const& message ) = 0; |
|
|
virtual void popScopedMessage( MessageInfo const& message ) = 0; |
|
|
virtual void popScopedMessage( MessageInfo const& message ) = 0; |
|
|
|
|
|
|
|
|
|
|
|
virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; |
|
|
|
|
|
|
|
|
virtual void handleFatalErrorCondition( StringRef message ) = 0; |
|
|
virtual void handleFatalErrorCondition( StringRef message ) = 0; |
|
|
|
|
|
|
|
|
virtual void handleExpr |
|
|
virtual void handleExpr |
|
|
|
|
|
|
|
|
class ScopedMessage { |
|
|
class ScopedMessage { |
|
|
public: |
|
|
public: |
|
|
explicit ScopedMessage( MessageBuilder const& builder ); |
|
|
explicit ScopedMessage( MessageBuilder const& builder ); |
|
|
|
|
|
ScopedMessage( ScopedMessage& duplicate ) = delete; |
|
|
|
|
|
ScopedMessage( ScopedMessage&& old ); |
|
|
~ScopedMessage(); |
|
|
~ScopedMessage(); |
|
|
|
|
|
|
|
|
MessageInfo m_info; |
|
|
MessageInfo m_info; |
|
|
|
|
|
bool m_moved; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
class Capturer { |
|
|
class Capturer { |
|
|
|
|
|
|
|
|
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ |
|
|
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ |
|
|
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ |
|
|
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ |
|
|
INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
|
|
INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
|
|
} while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look |
|
|
|
|
|
|
|
|
} while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look |
|
|
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. |
|
|
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. |
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
#define INTERNAL_CATCH_INFO( macroName, log ) \ |
|
|
#define INTERNAL_CATCH_INFO( macroName, log ) \ |
|
|
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); |
|
|
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); |
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ |
|
|
|
|
|
Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) |
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
// Although this is matcher-based, it can be used with just a string |
|
|
// Although this is matcher-based, it can be used with just a string |
|
|
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ |
|
|
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ |
|
|
|
|
|
|
|
|
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); |
|
|
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; |
|
|
|
|
|
|
|
|
|
|
|
template<typename L> |
|
|
|
|
|
// Note: The type after -> is weird, because VS2015 cannot parse |
|
|
|
|
|
// the expression used in the typedef inside, when it is in |
|
|
|
|
|
// return type. Yeah. |
|
|
|
|
|
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { |
|
|
|
|
|
using UnderlyingType = typename decltype(generatorExpression())::type; |
|
|
|
|
|
|
|
|
|
|
|
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); |
|
|
|
|
|
if (!tracker.hasGenerator()) { |
|
|
|
|
|
tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression())); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() ); |
|
|
|
|
|
return generator.get(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} // namespace Generators |
|
|
|
|
|
} // namespace Catch |
|
|
|
|
|
|
|
|
|
|
|
#define GENERATE( ... ) \ |
|
|
|
|
|
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) |
|
|
|
|
|
|
|
|
|
|
|
// end catch_generators.hpp |
|
|
|
|
|
// start catch_generators_generic.hpp |
|
|
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
|
namespace Generators { |
|
|
|
|
|
|
|
|
template <typename T> |
|
|
template <typename T> |
|
|
class TakeGenerator : public IGenerator<T> { |
|
|
class TakeGenerator : public IGenerator<T> { |
|
|
GeneratorWrapper<T> m_generator; |
|
|
GeneratorWrapper<T> m_generator; |
|
|
|
|
|
|
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; |
|
|
|
|
|
|
|
|
|
|
|
template<typename L> |
|
|
|
|
|
// Note: The type after -> is weird, because VS2015 cannot parse |
|
|
|
|
|
// the expression used in the typedef inside, when it is in |
|
|
|
|
|
// return type. Yeah, ¯\_(ツ)_/¯ |
|
|
|
|
|
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { |
|
|
|
|
|
using UnderlyingType = typename decltype(generatorExpression())::type; |
|
|
|
|
|
|
|
|
|
|
|
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); |
|
|
|
|
|
if (!tracker.hasGenerator()) { |
|
|
|
|
|
tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression())); |
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
|
class ChunkGenerator final : public IGenerator<std::vector<T>> { |
|
|
|
|
|
std::vector<T> m_chunk; |
|
|
|
|
|
size_t m_chunk_size; |
|
|
|
|
|
GeneratorWrapper<T> m_generator; |
|
|
|
|
|
bool m_used_up = false; |
|
|
|
|
|
public: |
|
|
|
|
|
ChunkGenerator(size_t size, GeneratorWrapper<T> generator) : |
|
|
|
|
|
m_chunk_size(size), m_generator(std::move(generator)) |
|
|
|
|
|
{ |
|
|
|
|
|
m_chunk.reserve(m_chunk_size); |
|
|
|
|
|
m_chunk.push_back(m_generator.get()); |
|
|
|
|
|
for (size_t i = 1; i < m_chunk_size; ++i) { |
|
|
|
|
|
if (!m_generator.next()) { |
|
|
|
|
|
Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk")); |
|
|
|
|
|
} |
|
|
|
|
|
m_chunk.push_back(m_generator.get()); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
std::vector<T> const& get() const override { |
|
|
|
|
|
return m_chunk; |
|
|
|
|
|
} |
|
|
|
|
|
bool next() override { |
|
|
|
|
|
m_chunk.clear(); |
|
|
|
|
|
for (size_t idx = 0; idx < m_chunk_size; ++idx) { |
|
|
|
|
|
if (!m_generator.next()) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
m_chunk.push_back(m_generator.get()); |
|
|
|
|
|
} |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() ); |
|
|
|
|
|
return generator.get(); |
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
|
GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) { |
|
|
|
|
|
return GeneratorWrapper<std::vector<T>>( |
|
|
|
|
|
pf::make_unique<ChunkGenerator<T>>(size, std::move(generator)) |
|
|
|
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} // namespace Generators |
|
|
} // namespace Generators |
|
|
} // namespace Catch |
|
|
} // namespace Catch |
|
|
|
|
|
|
|
|
#define GENERATE( ... ) \ |
|
|
|
|
|
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) |
|
|
|
|
|
|
|
|
// end catch_generators_generic.hpp |
|
|
|
|
|
// start catch_generators_specific.hpp |
|
|
|
|
|
|
|
|
// end catch_generators.hpp |
|
|
|
|
|
|
|
|
// start catch_context.h |
|
|
|
|
|
|
|
|
|
|
|
#include <memory> |
|
|
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
|
|
|
|
|
|
|
struct IResultCapture; |
|
|
|
|
|
struct IRunner; |
|
|
|
|
|
struct IConfig; |
|
|
|
|
|
struct IMutableContext; |
|
|
|
|
|
|
|
|
|
|
|
using IConfigPtr = std::shared_ptr<IConfig const>; |
|
|
|
|
|
|
|
|
|
|
|
struct IContext |
|
|
|
|
|
{ |
|
|
|
|
|
virtual ~IContext(); |
|
|
|
|
|
|
|
|
|
|
|
virtual IResultCapture* getResultCapture() = 0; |
|
|
|
|
|
virtual IRunner* getRunner() = 0; |
|
|
|
|
|
virtual IConfigPtr const& getConfig() const = 0; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct IMutableContext : IContext |
|
|
|
|
|
{ |
|
|
|
|
|
virtual ~IMutableContext(); |
|
|
|
|
|
virtual void setResultCapture( IResultCapture* resultCapture ) = 0; |
|
|
|
|
|
virtual void setRunner( IRunner* runner ) = 0; |
|
|
|
|
|
virtual void setConfig( IConfigPtr const& config ) = 0; |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
static IMutableContext *currentContext; |
|
|
|
|
|
friend IMutableContext& getCurrentMutableContext(); |
|
|
|
|
|
friend void cleanUpContext(); |
|
|
|
|
|
static void createContext(); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
inline IMutableContext& getCurrentMutableContext() |
|
|
|
|
|
{ |
|
|
|
|
|
if( !IMutableContext::currentContext ) |
|
|
|
|
|
IMutableContext::createContext(); |
|
|
|
|
|
return *IMutableContext::currentContext; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
inline IContext& getCurrentContext() |
|
|
|
|
|
{ |
|
|
|
|
|
return getCurrentMutableContext(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void cleanUpContext(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// end catch_context.h |
|
|
|
|
|
// start catch_interfaces_config.h |
|
|
|
|
|
|
|
|
|
|
|
#include <iosfwd> |
|
|
|
|
|
#include <string> |
|
|
|
|
|
#include <vector> |
|
|
|
|
|
#include <memory> |
|
|
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
|
|
|
|
|
|
|
enum class Verbosity { |
|
|
|
|
|
Quiet = 0, |
|
|
|
|
|
Normal, |
|
|
|
|
|
High |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct WarnAbout { enum What { |
|
|
|
|
|
Nothing = 0x00, |
|
|
|
|
|
NoAssertions = 0x01, |
|
|
|
|
|
NoTests = 0x02 |
|
|
|
|
|
}; }; |
|
|
|
|
|
|
|
|
|
|
|
struct ShowDurations { enum OrNot { |
|
|
|
|
|
DefaultForReporter, |
|
|
|
|
|
Always, |
|
|
|
|
|
Never |
|
|
|
|
|
}; }; |
|
|
|
|
|
struct RunTests { enum InWhatOrder { |
|
|
|
|
|
InDeclarationOrder, |
|
|
|
|
|
InLexicographicalOrder, |
|
|
|
|
|
InRandomOrder |
|
|
|
|
|
}; }; |
|
|
|
|
|
struct UseColour { enum YesOrNo { |
|
|
|
|
|
Auto, |
|
|
|
|
|
Yes, |
|
|
|
|
|
No |
|
|
|
|
|
}; }; |
|
|
|
|
|
struct WaitForKeypress { enum When { |
|
|
|
|
|
Never, |
|
|
|
|
|
BeforeStart = 1, |
|
|
|
|
|
BeforeExit = 2, |
|
|
|
|
|
BeforeStartAndExit = BeforeStart | BeforeExit |
|
|
|
|
|
}; }; |
|
|
|
|
|
|
|
|
|
|
|
class TestSpec; |
|
|
|
|
|
|
|
|
|
|
|
struct IConfig : NonCopyable { |
|
|
|
|
|
|
|
|
|
|
|
virtual ~IConfig(); |
|
|
|
|
|
|
|
|
|
|
|
virtual bool allowThrows() const = 0; |
|
|
|
|
|
virtual std::ostream& stream() const = 0; |
|
|
|
|
|
virtual std::string name() const = 0; |
|
|
|
|
|
virtual bool includeSuccessfulResults() const = 0; |
|
|
|
|
|
virtual bool shouldDebugBreak() const = 0; |
|
|
|
|
|
virtual bool warnAboutMissingAssertions() const = 0; |
|
|
|
|
|
virtual bool warnAboutNoTests() const = 0; |
|
|
|
|
|
virtual int abortAfter() const = 0; |
|
|
|
|
|
virtual bool showInvisibles() const = 0; |
|
|
|
|
|
virtual ShowDurations::OrNot showDurations() const = 0; |
|
|
|
|
|
virtual TestSpec const& testSpec() const = 0; |
|
|
|
|
|
virtual bool hasTestFilters() const = 0; |
|
|
|
|
|
virtual RunTests::InWhatOrder runOrder() const = 0; |
|
|
|
|
|
virtual unsigned int rngSeed() const = 0; |
|
|
|
|
|
virtual int benchmarkResolutionMultiple() const = 0; |
|
|
|
|
|
virtual UseColour::YesOrNo useColour() const = 0; |
|
|
|
|
|
virtual std::vector<std::string> const& getSectionsToRun() const = 0; |
|
|
|
|
|
virtual Verbosity verbosity() const = 0; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
using IConfigPtr = std::shared_ptr<IConfig const>; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// end catch_interfaces_config.h |
|
|
|
|
|
#include <random> |
|
|
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
|
namespace Generators { |
|
|
|
|
|
|
|
|
|
|
|
template <typename Float> |
|
|
|
|
|
class RandomFloatingGenerator final : public IGenerator<Float> { |
|
|
|
|
|
// FIXME: What is the right seed? |
|
|
|
|
|
std::minstd_rand m_rand; |
|
|
|
|
|
std::uniform_real_distribution<Float> m_dist; |
|
|
|
|
|
Float m_current_number; |
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
|
|
RandomFloatingGenerator(Float a, Float b): |
|
|
|
|
|
m_rand(getCurrentContext().getConfig()->rngSeed()), |
|
|
|
|
|
m_dist(a, b) { |
|
|
|
|
|
static_cast<void>(next()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Float const& get() const override { |
|
|
|
|
|
return m_current_number; |
|
|
|
|
|
} |
|
|
|
|
|
bool next() override { |
|
|
|
|
|
m_current_number = m_dist(m_rand); |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
template <typename Integer> |
|
|
|
|
|
class RandomIntegerGenerator final : public IGenerator<Integer> { |
|
|
|
|
|
std::minstd_rand m_rand; |
|
|
|
|
|
std::uniform_int_distribution<Integer> m_dist; |
|
|
|
|
|
Integer m_current_number; |
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
|
|
RandomIntegerGenerator(Integer a, Integer b): |
|
|
|
|
|
m_rand(getCurrentContext().getConfig()->rngSeed()), |
|
|
|
|
|
m_dist(a, b) { |
|
|
|
|
|
static_cast<void>(next()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Integer const& get() const override { |
|
|
|
|
|
return m_current_number; |
|
|
|
|
|
} |
|
|
|
|
|
bool next() override { |
|
|
|
|
|
m_current_number = m_dist(m_rand); |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// TODO: Ideally this would be also constrained against the various char types, |
|
|
|
|
|
// but I don't expect users to run into that in practice. |
|
|
|
|
|
template <typename T> |
|
|
|
|
|
typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, |
|
|
|
|
|
GeneratorWrapper<T>>::type |
|
|
|
|
|
random(T a, T b) { |
|
|
|
|
|
return GeneratorWrapper<T>( |
|
|
|
|
|
pf::make_unique<RandomIntegerGenerator<T>>(a, b) |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
|
typename std::enable_if<std::is_floating_point<T>::value, |
|
|
|
|
|
GeneratorWrapper<T>>::type |
|
|
|
|
|
random(T a, T b) { |
|
|
|
|
|
return GeneratorWrapper<T>( |
|
|
|
|
|
pf::make_unique<RandomFloatingGenerator<T>>(a, b) |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
|
class RangeGenerator final : public IGenerator<T> { |
|
|
|
|
|
T m_current; |
|
|
|
|
|
T m_end; |
|
|
|
|
|
T m_step; |
|
|
|
|
|
bool m_positive; |
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
RangeGenerator(T const& start, T const& end, T const& step): |
|
|
|
|
|
m_current(start), |
|
|
|
|
|
m_end(end), |
|
|
|
|
|
m_step(step), |
|
|
|
|
|
m_positive(m_step > T(0)) |
|
|
|
|
|
{ |
|
|
|
|
|
assert(m_current != m_end && "Range start and end cannot be equal"); |
|
|
|
|
|
assert(m_step != T(0) && "Step size cannot be zero"); |
|
|
|
|
|
assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
RangeGenerator(T const& start, T const& end): |
|
|
|
|
|
RangeGenerator(start, end, (start < end) ? T(1) : T(-1)) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
T const& get() const override { |
|
|
|
|
|
return m_current; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool next() override { |
|
|
|
|
|
m_current += m_step; |
|
|
|
|
|
return (m_positive) ? (m_current < m_end) : (m_current > m_end); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
|
GeneratorWrapper<T> range(T const& start, T const& end, T const& step) { |
|
|
|
|
|
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer"); |
|
|
|
|
|
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
|
GeneratorWrapper<T> range(T const& start, T const& end) { |
|
|
|
|
|
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer"); |
|
|
|
|
|
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} // namespace Generators |
|
|
|
|
|
} // namespace Catch |
|
|
|
|
|
|
|
|
|
|
|
// end catch_generators_specific.hpp |
|
|
|
|
|
|
|
|
// These files are included here so the single_include script doesn't put them |
|
|
// These files are included here so the single_include script doesn't put them |
|
|
// in the conditionally compiled sections |
|
|
// in the conditionally compiled sections |
|
|
|
|
|
|
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
// end catch_test_spec_parser.h |
|
|
// end catch_test_spec_parser.h |
|
|
// start catch_interfaces_config.h |
|
|
|
|
|
|
|
|
|
|
|
#include <iosfwd> |
|
|
|
|
|
#include <string> |
|
|
|
|
|
#include <vector> |
|
|
|
|
|
#include <memory> |
|
|
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
|
|
|
|
|
|
|
enum class Verbosity { |
|
|
|
|
|
Quiet = 0, |
|
|
|
|
|
Normal, |
|
|
|
|
|
High |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct WarnAbout { enum What { |
|
|
|
|
|
Nothing = 0x00, |
|
|
|
|
|
NoAssertions = 0x01, |
|
|
|
|
|
NoTests = 0x02 |
|
|
|
|
|
}; }; |
|
|
|
|
|
|
|
|
|
|
|
struct ShowDurations { enum OrNot { |
|
|
|
|
|
DefaultForReporter, |
|
|
|
|
|
Always, |
|
|
|
|
|
Never |
|
|
|
|
|
}; }; |
|
|
|
|
|
struct RunTests { enum InWhatOrder { |
|
|
|
|
|
InDeclarationOrder, |
|
|
|
|
|
InLexicographicalOrder, |
|
|
|
|
|
InRandomOrder |
|
|
|
|
|
}; }; |
|
|
|
|
|
struct UseColour { enum YesOrNo { |
|
|
|
|
|
Auto, |
|
|
|
|
|
Yes, |
|
|
|
|
|
No |
|
|
|
|
|
}; }; |
|
|
|
|
|
struct WaitForKeypress { enum When { |
|
|
|
|
|
Never, |
|
|
|
|
|
BeforeStart = 1, |
|
|
|
|
|
BeforeExit = 2, |
|
|
|
|
|
BeforeStartAndExit = BeforeStart | BeforeExit |
|
|
|
|
|
}; }; |
|
|
|
|
|
|
|
|
|
|
|
class TestSpec; |
|
|
|
|
|
|
|
|
|
|
|
struct IConfig : NonCopyable { |
|
|
|
|
|
|
|
|
|
|
|
virtual ~IConfig(); |
|
|
|
|
|
|
|
|
|
|
|
virtual bool allowThrows() const = 0; |
|
|
|
|
|
virtual std::ostream& stream() const = 0; |
|
|
|
|
|
virtual std::string name() const = 0; |
|
|
|
|
|
virtual bool includeSuccessfulResults() const = 0; |
|
|
|
|
|
virtual bool shouldDebugBreak() const = 0; |
|
|
|
|
|
virtual bool warnAboutMissingAssertions() const = 0; |
|
|
|
|
|
virtual bool warnAboutNoTests() const = 0; |
|
|
|
|
|
virtual int abortAfter() const = 0; |
|
|
|
|
|
virtual bool showInvisibles() const = 0; |
|
|
|
|
|
virtual ShowDurations::OrNot showDurations() const = 0; |
|
|
|
|
|
virtual TestSpec const& testSpec() const = 0; |
|
|
|
|
|
virtual bool hasTestFilters() const = 0; |
|
|
|
|
|
virtual RunTests::InWhatOrder runOrder() const = 0; |
|
|
|
|
|
virtual unsigned int rngSeed() const = 0; |
|
|
|
|
|
virtual int benchmarkResolutionMultiple() const = 0; |
|
|
|
|
|
virtual UseColour::YesOrNo useColour() const = 0; |
|
|
|
|
|
virtual std::vector<std::string> const& getSectionsToRun() const = 0; |
|
|
|
|
|
virtual Verbosity verbosity() const = 0; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
using IConfigPtr = std::shared_ptr<IConfig const>; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// end catch_interfaces_config.h |
|
|
|
|
|
// Libstdc++ doesn't like incomplete classes for unique_ptr |
|
|
// Libstdc++ doesn't like incomplete classes for unique_ptr |
|
|
|
|
|
|
|
|
#include <memory> |
|
|
#include <memory> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AssertionStats( AssertionStats const& ) = default; |
|
|
AssertionStats( AssertionStats const& ) = default; |
|
|
AssertionStats( AssertionStats && ) = default; |
|
|
AssertionStats( AssertionStats && ) = default; |
|
|
AssertionStats& operator = ( AssertionStats const& ) = default; |
|
|
|
|
|
AssertionStats& operator = ( AssertionStats && ) = default; |
|
|
|
|
|
|
|
|
AssertionStats& operator = ( AssertionStats const& ) = delete; |
|
|
|
|
|
AssertionStats& operator = ( AssertionStats && ) = delete; |
|
|
virtual ~AssertionStats(); |
|
|
virtual ~AssertionStats(); |
|
|
|
|
|
|
|
|
AssertionResult assertionResult; |
|
|
AssertionResult assertionResult; |
|
|
|
|
|
|
|
|
// end catch_approx.cpp |
|
|
// end catch_approx.cpp |
|
|
// start catch_assertionhandler.cpp |
|
|
// start catch_assertionhandler.cpp |
|
|
|
|
|
|
|
|
// start catch_context.h |
|
|
|
|
|
|
|
|
|
|
|
#include <memory> |
|
|
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
|
|
|
|
|
|
|
struct IResultCapture; |
|
|
|
|
|
struct IRunner; |
|
|
|
|
|
struct IConfig; |
|
|
|
|
|
struct IMutableContext; |
|
|
|
|
|
|
|
|
|
|
|
using IConfigPtr = std::shared_ptr<IConfig const>; |
|
|
|
|
|
|
|
|
|
|
|
struct IContext |
|
|
|
|
|
{ |
|
|
|
|
|
virtual ~IContext(); |
|
|
|
|
|
|
|
|
|
|
|
virtual IResultCapture* getResultCapture() = 0; |
|
|
|
|
|
virtual IRunner* getRunner() = 0; |
|
|
|
|
|
virtual IConfigPtr const& getConfig() const = 0; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct IMutableContext : IContext |
|
|
|
|
|
{ |
|
|
|
|
|
virtual ~IMutableContext(); |
|
|
|
|
|
virtual void setResultCapture( IResultCapture* resultCapture ) = 0; |
|
|
|
|
|
virtual void setRunner( IRunner* runner ) = 0; |
|
|
|
|
|
virtual void setConfig( IConfigPtr const& config ) = 0; |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
static IMutableContext *currentContext; |
|
|
|
|
|
friend IMutableContext& getCurrentMutableContext(); |
|
|
|
|
|
friend void cleanUpContext(); |
|
|
|
|
|
static void createContext(); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
inline IMutableContext& getCurrentMutableContext() |
|
|
|
|
|
{ |
|
|
|
|
|
if( !IMutableContext::currentContext ) |
|
|
|
|
|
IMutableContext::createContext(); |
|
|
|
|
|
return *IMutableContext::currentContext; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
inline IContext& getCurrentContext() |
|
|
|
|
|
{ |
|
|
|
|
|
return getCurrentMutableContext(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void cleanUpContext(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// end catch_context.h |
|
|
|
|
|
// start catch_debugger.h |
|
|
// start catch_debugger.h |
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
namespace Catch { |
|
|
|
|
|
|
|
|
void pushScopedMessage( MessageInfo const& message ) override; |
|
|
void pushScopedMessage( MessageInfo const& message ) override; |
|
|
void popScopedMessage( MessageInfo const& message ) override; |
|
|
void popScopedMessage( MessageInfo const& message ) override; |
|
|
|
|
|
|
|
|
|
|
|
void emplaceUnscopedMessage( MessageBuilder const& builder ) override; |
|
|
|
|
|
|
|
|
std::string getCurrentTestName() const override; |
|
|
std::string getCurrentTestName() const override; |
|
|
|
|
|
|
|
|
const AssertionResult* getLastResult() const override; |
|
|
const AssertionResult* getLastResult() const override; |
|
|
|
|
|
|
|
|
Totals m_totals; |
|
|
Totals m_totals; |
|
|
IStreamingReporterPtr m_reporter; |
|
|
IStreamingReporterPtr m_reporter; |
|
|
std::vector<MessageInfo> m_messages; |
|
|
std::vector<MessageInfo> m_messages; |
|
|
|
|
|
std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */ |
|
|
AssertionInfo m_lastAssertionInfo; |
|
|
AssertionInfo m_lastAssertionInfo; |
|
|
std::vector<SectionEndInfo> m_unfinishedSections; |
|
|
std::vector<SectionEndInfo> m_unfinishedSections; |
|
|
std::vector<ITracker*> m_activeSections; |
|
|
std::vector<ITracker*> m_activeSections; |
|
|
|
|
|
|
|
|
// ----------- end of #include from clara_textflow.hpp ----------- |
|
|
// ----------- end of #include from clara_textflow.hpp ----------- |
|
|
// ........... back in clara.hpp |
|
|
// ........... back in clara.hpp |
|
|
|
|
|
|
|
|
|
|
|
#include <cctype> |
|
|
#include <string> |
|
|
#include <string> |
|
|
#include <memory> |
|
|
#include <memory> |
|
|
#include <set> |
|
|
#include <set> |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { |
|
|
inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { |
|
|
std::string srcLC = source; |
|
|
std::string srcLC = source; |
|
|
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } ); |
|
|
|
|
|
|
|
|
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } ); |
|
|
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") |
|
|
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") |
|
|
target = true; |
|
|
target = true; |
|
|
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") |
|
|
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") |
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////// |
|
|
//////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
ScopedMessage::ScopedMessage( MessageBuilder const& builder ) |
|
|
ScopedMessage::ScopedMessage( MessageBuilder const& builder ) |
|
|
: m_info( builder.m_info ) |
|
|
|
|
|
|
|
|
: m_info( builder.m_info ), m_moved() |
|
|
{ |
|
|
{ |
|
|
m_info.message = builder.m_stream.str(); |
|
|
m_info.message = builder.m_stream.str(); |
|
|
getResultCapture().pushScopedMessage( m_info ); |
|
|
getResultCapture().pushScopedMessage( m_info ); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ScopedMessage::ScopedMessage( ScopedMessage&& old ) |
|
|
|
|
|
: m_info( old.m_info ), m_moved() |
|
|
|
|
|
{ |
|
|
|
|
|
old.m_moved = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
ScopedMessage::~ScopedMessage() { |
|
|
ScopedMessage::~ScopedMessage() { |
|
|
if ( !uncaught_exceptions() ){ |
|
|
|
|
|
|
|
|
if ( !uncaught_exceptions() && !m_moved ){ |
|
|
getResultCapture().popScopedMessage(m_info); |
|
|
getResultCapture().popScopedMessage(m_info); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
auto str() const -> std::string; |
|
|
auto str() const -> std::string; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
class RedirectedStreams { |
|
|
|
|
|
public: |
|
|
|
|
|
RedirectedStreams(RedirectedStreams const&) = delete; |
|
|
|
|
|
RedirectedStreams& operator=(RedirectedStreams const&) = delete; |
|
|
|
|
|
RedirectedStreams(RedirectedStreams&&) = delete; |
|
|
|
|
|
RedirectedStreams& operator=(RedirectedStreams&&) = delete; |
|
|
|
|
|
|
|
|
|
|
|
RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr); |
|
|
|
|
|
~RedirectedStreams(); |
|
|
|
|
|
private: |
|
|
|
|
|
std::string& m_redirectedCout; |
|
|
|
|
|
std::string& m_redirectedCerr; |
|
|
|
|
|
RedirectedStdOut m_redirectedStdOut; |
|
|
|
|
|
RedirectedStdErr m_redirectedStdErr; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
#if defined(CATCH_CONFIG_NEW_CAPTURE) |
|
|
#if defined(CATCH_CONFIG_NEW_CAPTURE) |
|
|
|
|
|
|
|
|
// Windows's implementation of std::tmpfile is terrible (it tries |
|
|
// Windows's implementation of std::tmpfile is terrible (it tries |
|
|
|
|
|
|
|
|
{} |
|
|
{} |
|
|
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } |
|
|
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } |
|
|
|
|
|
|
|
|
|
|
|
RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr) |
|
|
|
|
|
: m_redirectedCout(redirectedCout), |
|
|
|
|
|
m_redirectedCerr(redirectedCerr) |
|
|
|
|
|
{} |
|
|
|
|
|
|
|
|
|
|
|
RedirectedStreams::~RedirectedStreams() { |
|
|
|
|
|
m_redirectedCout += m_redirectedStdOut.str(); |
|
|
|
|
|
m_redirectedCerr += m_redirectedStdErr.str(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
#if defined(CATCH_CONFIG_NEW_CAPTURE) |
|
|
#if defined(CATCH_CONFIG_NEW_CAPTURE) |
|
|
|
|
|
|
|
|
#if defined(_MSC_VER) |
|
|
#if defined(_MSC_VER) |
|
|
|
|
|
|
|
|
// and should be let to clear themselves out. |
|
|
// and should be let to clear themselves out. |
|
|
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); |
|
|
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); |
|
|
|
|
|
|
|
|
|
|
|
if (result.getResultType() != ResultWas::Warning) |
|
|
|
|
|
m_messageScopes.clear(); |
|
|
|
|
|
|
|
|
// Reset working state |
|
|
// Reset working state |
|
|
resetAssertionInfo(); |
|
|
resetAssertionInfo(); |
|
|
m_lastResult = result; |
|
|
m_lastResult = result; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); |
|
|
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); |
|
|
m_messages.clear(); |
|
|
m_messages.clear(); |
|
|
|
|
|
m_messageScopes.clear(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { |
|
|
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { |
|
|
|
|
|
|
|
|
m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); |
|
|
m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { |
|
|
|
|
|
m_messageScopes.emplace_back( builder ); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
std::string RunContext::getCurrentTestName() const { |
|
|
std::string RunContext::getCurrentTestName() const { |
|
|
return m_activeTestCase |
|
|
return m_activeTestCase |
|
|
? m_activeTestCase->getTestCaseInfo().name |
|
|
? m_activeTestCase->getTestCaseInfo().name |
|
|
|
|
|
|
|
|
m_lastAssertionPassed = true; |
|
|
m_lastAssertionPassed = true; |
|
|
++m_totals.assertions.passed; |
|
|
++m_totals.assertions.passed; |
|
|
resetAssertionInfo(); |
|
|
resetAssertionInfo(); |
|
|
|
|
|
m_messageScopes.clear(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool RunContext::aborting() const { |
|
|
bool RunContext::aborting() const { |
|
|
|
|
|
|
|
|
CATCH_TRY { |
|
|
CATCH_TRY { |
|
|
if (m_reporter->getPreferences().shouldRedirectStdOut) { |
|
|
if (m_reporter->getPreferences().shouldRedirectStdOut) { |
|
|
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) |
|
|
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) |
|
|
RedirectedStdOut redirectedStdOut; |
|
|
|
|
|
RedirectedStdErr redirectedStdErr; |
|
|
|
|
|
|
|
|
RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); |
|
|
|
|
|
|
|
|
timer.start(); |
|
|
timer.start(); |
|
|
invokeActiveTestCase(); |
|
|
invokeActiveTestCase(); |
|
|
redirectedCout += redirectedStdOut.str(); |
|
|
|
|
|
redirectedCerr += redirectedStdErr.str(); |
|
|
|
|
|
#else |
|
|
#else |
|
|
OutputRedirect r(redirectedCout, redirectedCerr); |
|
|
OutputRedirect r(redirectedCout, redirectedCerr); |
|
|
timer.start(); |
|
|
timer.start(); |
|
|
|
|
|
|
|
|
m_testCaseTracker->close(); |
|
|
m_testCaseTracker->close(); |
|
|
handleUnfinishedSections(); |
|
|
handleUnfinishedSections(); |
|
|
m_messages.clear(); |
|
|
m_messages.clear(); |
|
|
|
|
|
m_messageScopes.clear(); |
|
|
|
|
|
|
|
|
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); |
|
|
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); |
|
|
m_reporter->sectionEnded(testCaseSectionStats); |
|
|
m_reporter->sectionEnded(testCaseSectionStats); |
|
|
|
|
|
|
|
|
return 1; |
|
|
return 1; |
|
|
|
|
|
|
|
|
auto result = m_cli.parse( clara::Args( argc, argv ) ); |
|
|
auto result = m_cli.parse( clara::Args( argc, argv ) ); |
|
|
config(); |
|
|
|
|
|
getCurrentMutableContext().setConfig( m_config ); |
|
|
|
|
|
if( !result ) { |
|
|
if( !result ) { |
|
|
|
|
|
config(); |
|
|
|
|
|
getCurrentMutableContext().setConfig(m_config); |
|
|
Catch::cerr() |
|
|
Catch::cerr() |
|
|
<< Colour( Colour::Red ) |
|
|
<< Colour( Colour::Red ) |
|
|
<< "\nError(s) in input:\n" |
|
|
<< "\nError(s) in input:\n" |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Version const& libraryVersion() { |
|
|
Version const& libraryVersion() { |
|
|
static Version version( 2, 6, 1, "", 0 ); |
|
|
|
|
|
|
|
|
static Version version( 2, 7, 0, "", 0 ); |
|
|
return version; |
|
|
return version; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _MSC_VER |
|
|
#ifdef _MSC_VER |
|
|
sprintf_s(buffer, "%.3f", duration); |
|
|
sprintf_s(buffer, "%.3f", duration); |
|
|
#else |
|
|
#else |
|
|
sprintf(buffer, "%.3f", duration); |
|
|
|
|
|
|
|
|
std::sprintf(buffer, "%.3f", duration); |
|
|
#endif |
|
|
#endif |
|
|
return std::string(buffer); |
|
|
return std::string(buffer); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
case Unit::Nanoseconds: |
|
|
case Unit::Nanoseconds: |
|
|
return "ns"; |
|
|
return "ns"; |
|
|
case Unit::Microseconds: |
|
|
case Unit::Microseconds: |
|
|
return "µs"; |
|
|
|
|
|
|
|
|
return "us"; |
|
|
case Unit::Milliseconds: |
|
|
case Unit::Milliseconds: |
|
|
return "ms"; |
|
|
return "ms"; |
|
|
case Unit::Seconds: |
|
|
case Unit::Seconds: |
|
|
|
|
|
|
|
|
#endif // CATCH_CONFIG_DISABLE_MATCHERS |
|
|
#endif // CATCH_CONFIG_DISABLE_MATCHERS |
|
|
|
|
|
|
|
|
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) |
|
|
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) |
|
|
|
|
|
#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg ) |
|
|
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) |
|
|
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) |
|
|
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) |
|
|
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) |
|
|
|
|
|
|