From: Michael Altizer (mialtize) Date: Tue, 17 Oct 2017 23:21:10 +0000 (-0400) Subject: Merge pull request #1044 in SNORT/snort3 from catch-update to master X-Git-Tag: 3.0.0-240~11 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ccfa1626d8e65c4350104cd2415bc5c336f69427;p=thirdparty%2Fsnort3.git Merge pull request #1044 in SNORT/snort3 from catch-update to master Squashed commit of the following: commit bea7c6f4b881ee359e4b6ec3723da079fd85fe2b Author: Michael Altizer Date: Mon Oct 16 21:41:37 2017 -0400 catch: Clean up some more test REQUIREs commit 391feec2e8da530dda0df8d107595d0e28c8f3c3 Author: Michael Altizer Date: Mon Oct 16 21:07:16 2017 -0400 lua: Add missing REQUIREs in LuaStack Catch tests commit 695b07072bc7c5651632d31bb58107613e113f88 Author: Michael Altizer Date: Mon Oct 16 21:03:10 2017 -0400 framework: Add default initializers to Range This silences some Clang analyzer uninitialized memory warnings. commit 1c692642f05d55cc2d6e222b31b646e31103d99e Author: Michael Altizer Date: Mon Oct 16 21:00:04 2017 -0400 build: Emit compile_commands.json in CMake builds for clang-tidy commit fe3c96d92ee52b8b501b6b18e001510e8eedc50d Author: Michael Altizer Date: Mon Oct 16 20:14:09 2017 -0400 appid: Reorganize AppIdHttpSession to minimize padding commit a7795211e32e43cf3b549df5f2285c8eabe17cbc Author: Michael Altizer Date: Mon Oct 16 20:06:17 2017 -0400 main: Fix potential memory leak when queuing Analyzer Commands commit 3e3ced83ca69936b0c839a1004aa305634cfc552 Author: Michael Altizer Date: Mon Oct 16 15:17:47 2017 -0400 flow: Use an empty SfIp for the fixed ICMP router address commit bd8e9ba61b6c17f451edf9a8cdb843655bc648c2 Author: Michael Altizer Date: Mon Oct 16 13:48:07 2017 -0400 build: Include clang diagnostics and analyzer in clang-tidy config commit e4cffedfaa87295373969582dbc8448b8f7e5b03 Author: Michael Altizer Date: Mon Oct 16 13:47:47 2017 -0400 build: clang-tidy pass against extras commit 1731e7832aa86862e3a9dff03b79809f728c866b Author: Michael Altizer Date: Mon Oct 16 13:33:10 2017 -0400 build: Fix 'make dist' in extras commit 8599d95c1f769dfa58079b7776eda26d7d95564c Author: Michael Altizer Date: Mon Oct 16 13:18:14 2017 -0400 build: Another pass to clean up some more clang-tidy warnings commit d2882ff72e02c581da8748e0e1ed6529a0bfd22d Author: Michael Altizer Date: Sat Oct 14 13:26:24 2017 -0400 u2spewfoo: Fix build on FreeBSD commit 9f5cc9882c61d782d7a4948d67bb4828f6832ad5 Author: Michael Altizer Date: Sat Oct 14 13:25:21 2017 -0400 catch: Update to Catch v1.10.0 --- diff --git a/.clang-tidy b/.clang-tidy index a10592dcf..e6a983a27 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1 +1 @@ -Checks: '-*,readability-redundant-*,readability-non-const-parameter,readability-container-size-empty,misc-string-compare,misc-macro-parentheses,bugprone-*,performance-*,modernize-use-equals-default,modernize-use-bool-literals,modernize-redundant-void-arg,modernize-make-shared,modernize-deprecated-headers,modernize-use-override,modernize-use-nullptr' +Checks: '-*,clang-diagnostic-*,clang-analyzer-*,readability-redundant-*,readability-non-const-parameter,readability-container-size-empty,misc-string-compare,misc-macro-parentheses,bugprone-*,performance-*,modernize-use-equals-default,modernize-use-bool-literals,modernize-redundant-void-arg,modernize-make-shared,modernize-deprecated-headers,modernize-use-override,modernize-use-nullptr' diff --git a/configure_cmake.sh b/configure_cmake.sh index a9d0cfb88..a5f455fa1 100755 --- a/configure_cmake.sh +++ b/configure_cmake.sh @@ -393,6 +393,7 @@ gen="" cmake $gen \ -DCMAKE_CXX_FLAGS:STRING="$CXXFLAGS $CPPFLAGS" \ -DCMAKE_C_FLAGS:STRING="$CFLAGS $CPPFLAGS" \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ $CMakeCacheEntries $sourcedir echo "# This is the command used to configure this build" > config.status diff --git a/extra/Makefile.am b/extra/Makefile.am index 68c3522ac..09ec3c4ba 100644 --- a/extra/Makefile.am +++ b/extra/Makefile.am @@ -1,20 +1,3 @@ ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 -# the below files are implicitly included in EXTRA_DIST if present -# but autoreconf -isvf won't install them here because it finds them -# in the parent dir. this means they must be explicitly copied from -# the parent to this source dir after the autoreconf step when doing -# distcheck. this situation also necessitates adding DISTCLEANFILES -# to keep distcheck happy even w/o EXTRA_DIST. - -EXTRA_DIST = \ -config.guess \ -config.sub \ -install-sh \ -ltmain.sh \ -missing \ -depcomp - -DISTCLEANFILES = $(EXTRA_DIST) - SUBDIRS = src diff --git a/extra/configure_cmake.sh b/extra/configure_cmake.sh index 9e6fed565..882d2ed39 100755 --- a/extra/configure_cmake.sh +++ b/extra/configure_cmake.sh @@ -92,6 +92,7 @@ gen="" cmake $gen \ -DCMAKE_CXX_FLAGS:STRING="$CXXFLAGS $CPPFLAGS" \ -DCMAKE_C_FLAGS:STRING="$CFLAGS $CPPFLAGS" \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ $CMakeCacheEntries $sourcedir echo "# This is the command used to configure this build" > config.status diff --git a/extra/src/codecs/cd_eapol/cd_eapol.cc b/extra/src/codecs/cd_eapol/cd_eapol.cc index 6f6451b26..6541252e0 100644 --- a/extra/src/codecs/cd_eapol/cd_eapol.cc +++ b/extra/src/codecs/cd_eapol/cd_eapol.cc @@ -47,7 +47,6 @@ class EapolCodec : public Codec { public: EapolCodec() : Codec(CD_EAPOL_NAME) { } - ~EapolCodec() { } bool decode(const RawData&, CodecData&, DecodeData&) override; void get_protocol_ids(std::vector&) override; diff --git a/extra/src/codecs/cd_linux_sll/cd_linux_sll.cc b/extra/src/codecs/cd_linux_sll/cd_linux_sll.cc index 415e12faf..ac91172e6 100644 --- a/extra/src/codecs/cd_linux_sll/cd_linux_sll.cc +++ b/extra/src/codecs/cd_linux_sll/cd_linux_sll.cc @@ -32,7 +32,6 @@ class LinuxSllCodec : public Codec { public: LinuxSllCodec() : Codec(CD_LINUX_SLL_NAME) { } - ~LinuxSllCodec() { } void get_data_link_type(std::vector&) override; bool decode(const RawData&, CodecData&, DecodeData&) override; diff --git a/extra/src/codecs/cd_null/cd_null.cc b/extra/src/codecs/cd_null/cd_null.cc index 369d4990c..4e0e7881e 100644 --- a/extra/src/codecs/cd_null/cd_null.cc +++ b/extra/src/codecs/cd_null/cd_null.cc @@ -31,7 +31,6 @@ class NullCodec : public Codec { public: NullCodec() : Codec(CD_NULL_NAME) { } - ~NullCodec() { } bool decode(const RawData&, CodecData&, DecodeData&) override; void get_data_link_type(std::vector&) override; diff --git a/extra/src/codecs/cd_pflog/cd_pflog.cc b/extra/src/codecs/cd_pflog/cd_pflog.cc index 91ae328bf..caf370a44 100644 --- a/extra/src/codecs/cd_pflog/cd_pflog.cc +++ b/extra/src/codecs/cd_pflog/cd_pflog.cc @@ -50,7 +50,6 @@ class PflogCodec : public Codec { public: PflogCodec() : Codec(PFLOG_NAME) { } - ~PflogCodec() { } bool decode(const RawData&, CodecData&, DecodeData&) override; void get_data_link_type(std::vector&) override; @@ -156,7 +155,7 @@ bool PflogCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) return false; /* lay the pf header structure over the packet data */ - switch (*((uint8_t*)raw.data)) + switch (*((const uint8_t*)raw.data)) { case PFLOG2_HDRMIN: { diff --git a/extra/src/codecs/cd_pim/cd_pim.cc b/extra/src/codecs/cd_pim/cd_pim.cc index 74d96a30b..450c8b8ce 100644 --- a/extra/src/codecs/cd_pim/cd_pim.cc +++ b/extra/src/codecs/cd_pim/cd_pim.cc @@ -33,7 +33,6 @@ class PimCodec : public Codec { public: PimCodec() : Codec(CD_PIM_NAME) { } - ~PimCodec() { } void get_protocol_ids(std::vector&) override; bool decode(const RawData&, CodecData&, DecodeData&) override; diff --git a/extra/src/codecs/cd_ppp/cd_ppp.cc b/extra/src/codecs/cd_ppp/cd_ppp.cc index 7f82a5e6c..09b2d7481 100644 --- a/extra/src/codecs/cd_ppp/cd_ppp.cc +++ b/extra/src/codecs/cd_ppp/cd_ppp.cc @@ -31,7 +31,6 @@ class PPPCodec : public Codec { public: PPPCodec() : Codec(PPP_NAME) { } - ~PPPCodec() { } bool decode(const RawData&, CodecData&, DecodeData&) override; void get_data_link_type(std::vector&) override; diff --git a/extra/src/codecs/cd_raw4/cd_raw4.cc b/extra/src/codecs/cd_raw4/cd_raw4.cc index 967f0b92b..322e64792 100644 --- a/extra/src/codecs/cd_raw4/cd_raw4.cc +++ b/extra/src/codecs/cd_raw4/cd_raw4.cc @@ -31,7 +31,6 @@ class Raw4Codec : public Codec { public: Raw4Codec() : Codec(CD_RAW4_NAME) { } - ~Raw4Codec() { } bool decode(const RawData&, CodecData&, DecodeData&) override; void get_data_link_type(std::vector&) override; diff --git a/extra/src/codecs/cd_raw6/cd_raw6.cc b/extra/src/codecs/cd_raw6/cd_raw6.cc index 08d04df26..4e6c9e822 100644 --- a/extra/src/codecs/cd_raw6/cd_raw6.cc +++ b/extra/src/codecs/cd_raw6/cd_raw6.cc @@ -31,7 +31,6 @@ class Raw6Codec : public Codec { public: Raw6Codec() : Codec(CD_RAW6_NAME) { } - ~Raw6Codec() { } bool decode(const RawData&, CodecData&, DecodeData&) override; void get_data_link_type(std::vector&) override; diff --git a/extra/src/codecs/cd_slip/cd_slip.cc b/extra/src/codecs/cd_slip/cd_slip.cc index d965db132..5e547bc14 100644 --- a/extra/src/codecs/cd_slip/cd_slip.cc +++ b/extra/src/codecs/cd_slip/cd_slip.cc @@ -33,7 +33,6 @@ class SlipCodec : public Codec { public: SlipCodec() : Codec(CD_SLIP_NAME) { } - ~SlipCodec() { } bool decode(const RawData&, CodecData&, DecodeData&) override; void get_data_link_type(std::vector&) override; diff --git a/extra/src/codecs/cd_token_ring/cd_token_ring.cc b/extra/src/codecs/cd_token_ring/cd_token_ring.cc index 6140bbc07..6775d35da 100644 --- a/extra/src/codecs/cd_token_ring/cd_token_ring.cc +++ b/extra/src/codecs/cd_token_ring/cd_token_ring.cc @@ -52,7 +52,6 @@ class TrCodec : public Codec { public: TrCodec() : Codec(TR_NAME) { } - ~TrCodec() { } void get_data_link_type(std::vector&) override; bool decode(const RawData&, CodecData&, DecodeData&) override; diff --git a/extra/src/codecs/cd_wlan/cd_wlan.cc b/extra/src/codecs/cd_wlan/cd_wlan.cc index b1b877b0f..6b564774b 100644 --- a/extra/src/codecs/cd_wlan/cd_wlan.cc +++ b/extra/src/codecs/cd_wlan/cd_wlan.cc @@ -43,7 +43,7 @@ class WlanCodecModule : public CodecModule public: WlanCodecModule() : CodecModule(CD_WLAN_NAME, CD_WLAN_HELP) { } - const RuleMap* get_rules() const + const RuleMap* get_rules() const override { return wlan_rules; } }; @@ -51,7 +51,6 @@ class WlanCodec : public Codec { public: WlanCodec() : Codec(CD_WLAN_NAME) { } - ~WlanCodec() { } bool decode(const RawData&, CodecData&, DecodeData&) override; void get_data_link_type(std::vector&) override; diff --git a/extra/src/daqs/daq_regtest/daq_regtest.c b/extra/src/daqs/daq_regtest/daq_regtest.c index bc6bce904..3f8f58824 100644 --- a/extra/src/daqs/daq_regtest/daq_regtest.c +++ b/extra/src/daqs/daq_regtest/daq_regtest.c @@ -423,7 +423,7 @@ static int daq_regtest_modify_flow(void *handle, const DAQ_PktHdr_t *hdr, const if (modify->length != sizeof(DAQ_ModFlowPktTrace_t)) return DAQ_ERROR_INVAL; - DAQ_ModFlowPktTrace_t* mod_tr = (DAQ_ModFlowPktTrace_t *) modify->value; + const DAQ_ModFlowPktTrace_t* mod_tr = (const DAQ_ModFlowPktTrace_t *) modify->value; printf("DAQ_REGTEST_PKT_TRACE (%d)\n%s\n", mod_tr->pkt_trace_data_len, mod_tr->pkt_trace_data); } diff --git a/extra/src/inspectors/data_log/data_log.cc b/extra/src/inspectors/data_log/data_log.cc index 978d3b14b..bda1c504b 100644 --- a/extra/src/inspectors/data_log/data_log.cc +++ b/extra/src/inspectors/data_log/data_log.cc @@ -17,7 +17,7 @@ //-------------------------------------------------------------------------- // data_log.cc author Russ Combs -#include +#include #include "flow/flow.h" #include "framework/data_bus.h" @@ -44,7 +44,7 @@ public: LogHandler(const std::string& s) { key = s; } - void handle(DataEvent& e, Flow*); + void handle(DataEvent& e, Flow*) override; private: void log(const uint8_t*, int32_t); diff --git a/extra/src/inspectors/reg_test/reg_test.cc b/extra/src/inspectors/reg_test/reg_test.cc index 4ccb0f981..2f7058ebe 100644 --- a/extra/src/inspectors/reg_test/reg_test.cc +++ b/extra/src/inspectors/reg_test/reg_test.cc @@ -17,7 +17,7 @@ //-------------------------------------------------------------------------- // rti_service.cc author davis mcpherson -#include +#include #include "flow/flow.h" #include "framework/data_bus.h" diff --git a/extra/src/ips_options/ips_pkt_num/ips_pkt_num.cc b/extra/src/ips_options/ips_pkt_num/ips_pkt_num.cc index 53f565537..1b89adfd5 100644 --- a/extra/src/ips_options/ips_pkt_num/ips_pkt_num.cc +++ b/extra/src/ips_options/ips_pkt_num/ips_pkt_num.cc @@ -69,7 +69,7 @@ bool PktNumOption::operator==(const IpsOption& ips) const if ( strcmp(s_name, ips.get_name()) ) return false; - PktNumOption& rhs = (PktNumOption&)ips; + const PktNumOption& rhs = (const PktNumOption&)ips; return ( config == rhs.config ); } diff --git a/extra/src/ips_options/ips_urg/ips_urg.cc b/extra/src/ips_options/ips_urg/ips_urg.cc index 1e155c116..0f344c7ae 100644 --- a/extra/src/ips_options/ips_urg/ips_urg.cc +++ b/extra/src/ips_options/ips_urg/ips_urg.cc @@ -70,7 +70,7 @@ bool TcpUrgOption::operator==(const IpsOption& ips) const if ( strcmp(s_name, ips.get_name()) ) return false; - TcpUrgOption& rhs = (TcpUrgOption&)ips; + const TcpUrgOption& rhs = (const TcpUrgOption&)ips; return ( config == rhs.config ); } diff --git a/extra/src/loggers/alert_unixsock/alert_unixsock.cc b/extra/src/loggers/alert_unixsock/alert_unixsock.cc index eb596a07d..db6000b85 100644 --- a/extra/src/loggers/alert_unixsock/alert_unixsock.cc +++ b/extra/src/loggers/alert_unixsock/alert_unixsock.cc @@ -151,29 +151,29 @@ static void get_alert_pkt( if (p->proto_bits & PROTO_BIT__ETH) { const eth::EtherHdr* eh = layer::get_eth_layer(p); - us.alert.dlthdr=(char*)eh-(char*)p->pkt; + us.alert.dlthdr=(const char*)eh-(const char*)p->pkt; } /* we don't log any headers besides eth yet */ if (p->ptrs.ip_api.is_ip4() && p->pkt) { - us.alert.nethdr=(char*)p->ptrs.ip_api.get_ip4h()-(char*)p->pkt; + us.alert.nethdr=(const char*)p->ptrs.ip_api.get_ip4h()-(const char*)p->pkt; switch (p->type()) { case PktType::TCP: if (p->ptrs.tcph) - us.alert.transhdr=(char*)p->ptrs.tcph-(char*)p->pkt; + us.alert.transhdr=(const char*)p->ptrs.tcph-(const char*)p->pkt; break; case PktType::UDP: if (p->ptrs.udph) - us.alert.transhdr=(char*)p->ptrs.udph-(char*)p->pkt; + us.alert.transhdr=(const char*)p->ptrs.udph-(const char*)p->pkt; break; case PktType::ICMP: if (p->ptrs.icmph) - us.alert.transhdr=(char*)p->ptrs.icmph-(char*)p->pkt; + us.alert.transhdr=(const char*)p->ptrs.icmph-(const char*)p->pkt; break; default: @@ -221,7 +221,7 @@ static void OpenAlertSock() class UnixSockLogger : public Logger { public: - UnixSockLogger() { } + UnixSockLogger() = default; void open() override; void close() override; diff --git a/extra/src/loggers/log_null/log_null.cc b/extra/src/loggers/log_null/log_null.cc index e3996f88f..8fcde5fa7 100644 --- a/extra/src/loggers/log_null/log_null.cc +++ b/extra/src/loggers/log_null/log_null.cc @@ -36,7 +36,7 @@ class NullLogger : public Logger { public: - NullLogger() { } + NullLogger() = default; }; static Logger* null_ctor(SnortConfig*, Module*) diff --git a/extra/src/search_engines/lowmem/lowmem.cc b/extra/src/search_engines/lowmem/lowmem.cc index 2b09da4c5..c583f36f9 100644 --- a/extra/src/search_engines/lowmem/lowmem.cc +++ b/extra/src/search_engines/lowmem/lowmem.cc @@ -47,7 +47,7 @@ public: : Mpse("lowmem") { obj = KTrieNew(0, agent); } - ~LowmemMpse() + ~LowmemMpse() override { KTrieDelete(obj); } int add_pattern( diff --git a/extra/src/search_engines/lowmem/sfksearch.h b/extra/src/search_engines/lowmem/sfksearch.h index 6eb3a933a..9ae361278 100644 --- a/extra/src/search_engines/lowmem/sfksearch.h +++ b/extra/src/search_engines/lowmem/sfksearch.h @@ -23,7 +23,7 @@ // ksearch.h - Trie based multi-pattern matcher -#include +#include #include "search_engines/search_common.h" struct KTRIEPATTERN diff --git a/extra/src/so_rules/sid_18758/sid_18758.cc b/extra/src/so_rules/sid_18758/sid_18758.cc index 36e53e4b2..7ec4261ae 100644 --- a/extra/src/so_rules/sid_18758/sid_18758.cc +++ b/extra/src/so_rules/sid_18758/sid_18758.cc @@ -57,7 +57,7 @@ static const SoApi so_api = nullptr, nullptr }, - (uint8_t*)rule_18758, + (const uint8_t*)rule_18758, rule_18758_len, nullptr, // pinit nullptr, // pterm diff --git a/src/catch/catch.hpp b/src/catch/catch.hpp index 7f1bed520..4d1fc334a 100644 --- a/src/catch/catch.hpp +++ b/src/catch/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v1.5.6 - * Generated: 2016-06-09 19:20:41.460328 + * Catch v1.10.0 + * Generated: 2017-08-26 15:16:46.676990 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -13,9 +13,7 @@ #define TWOBLUECUBES_CATCH_HPP_INCLUDED -#ifdef __ICC -# pragma system_header -#elif __clang__ +#ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ # pragma GCC system_header @@ -23,23 +21,27 @@ // #included from: internal/catch_suppress_warnings.h -#ifdef __ICC -# pragma warning(push) -# pragma warning(disable: 161 1682) -#elif __clang__ -# 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" -# pragma clang diagnostic ignored "-Wc++98-compat" -# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" -# pragma clang diagnostic ignored "-Wswitch-enum" -# pragma clang diagnostic ignored "-Wcovered-switch-default" +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# 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" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# 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 @@ -60,21 +62,6 @@ // #included from: catch_common.h #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr -#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) - -#include -#include -#include - // #included from: catch_compiler_capabilities.h #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED @@ -89,11 +76,15 @@ // CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? // CATCH_CONFIG_CPP11_OVERRIDE : is override supported? // CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) +// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported? +// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too @@ -129,11 +120,46 @@ # endif # if defined(CATCH_CPP11_OR_GREATER) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic pop" ) # endif #endif // __clang__ +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) + +# if !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# endif + +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE + +#endif // __CYGWIN__ + //////////////////////////////////////////////////////////////////////////////// // Borland #ifdef __BORLANDC__ @@ -160,10 +186,6 @@ # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif -# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_CPP11_OR_GREATER) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) -# endif - // - otherwise more recent versions define __cplusplus >= 201103L // and will get picked up below @@ -173,6 +195,8 @@ // Visual C++ #ifdef _MSC_VER +#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH + #if (_MSC_VER >= 1600) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR @@ -181,6 +205,8 @@ #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) #define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT #define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE +#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS #endif #endif // _MSC_VER @@ -199,7 +225,7 @@ // Use __COUNTER__ if the compiler supports it #if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ - ( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \ + ( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \ ( defined __clang__ && __clang_major__ >= 3 ) #define CATCH_INTERNAL_CONFIG_COUNTER @@ -246,6 +272,12 @@ # if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR # endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) +# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) +# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS +# endif #endif // __cplusplus >= 201103L @@ -268,21 +300,42 @@ #if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) # define CATCH_CONFIG_VARIADIC_MACROS #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_LONG_LONG #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_OVERRIDE #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for +// analytics) because, at time of writing, __COUNTER__ is not properly handled by it. +// This does not affect compilation +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__) # define CATCH_CONFIG_COUNTER #endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_SHUFFLE +#endif +# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TYPE_TRAITS +# endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #endif // noexcept support: @@ -315,6 +368,20 @@ # define CATCH_AUTO_PTR( T ) std::auto_ptr #endif +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include + namespace Catch { struct IConfig; @@ -352,14 +419,14 @@ namespace Catch { }; template - inline void deleteAll( ContainerT& container ) { + void deleteAll( ContainerT& container ) { typename ContainerT::const_iterator it = container.begin(); typename ContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete *it; } template - inline void deleteAllValues( AssociativeContainerT& container ) { + void deleteAllValues( AssociativeContainerT& container ) { typename AssociativeContainerT::const_iterator it = container.begin(); typename AssociativeContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) @@ -367,7 +434,9 @@ namespace Catch { } bool startsWith( std::string const& s, std::string const& prefix ); + bool startsWith( std::string const& s, char prefix ); bool endsWith( std::string const& s, std::string const& suffix ); + bool endsWith( std::string const& s, char suffix ); bool contains( std::string const& s, std::string const& infix ); void toLowerInPlace( std::string& s ); std::string toLower( std::string const& s ); @@ -387,8 +456,8 @@ namespace Catch { SourceLineInfo(); SourceLineInfo( char const* _file, std::size_t _line ); - SourceLineInfo( SourceLineInfo const& other ); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo(SourceLineInfo const& other) = default; SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; @@ -397,7 +466,7 @@ namespace Catch { bool operator == ( SourceLineInfo const& other ) const; bool operator < ( SourceLineInfo const& other ) const; - std::string file; + char const* file; std::size_t line; }; @@ -431,15 +500,12 @@ namespace Catch { #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); -#include - namespace Catch { class NotImplementedException : public std::exception { public: NotImplementedException( SourceLineInfo const& lineInfo ); - NotImplementedException( NotImplementedException const& ) {} virtual ~NotImplementedException() CATCH_NOEXCEPT {} @@ -565,10 +631,6 @@ namespace Catch { #pragma clang diagnostic pop #endif -#include -#include -#include - namespace Catch { class TestCase; @@ -712,59 +774,76 @@ void registerTestCaseFunction /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ \ struct TestName : ClassName{ \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ } \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ - Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \ static void TestName(); \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\ + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ namespace{ \ struct TestCaseName : ClassName{ \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ } \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestCaseName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ - Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); + CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS + #endif // #included from: internal/catch_capture.hpp @@ -832,27 +911,83 @@ namespace Catch { namespace Catch { + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct DecomposedExpression + { + virtual ~DecomposedExpression() {} + virtual bool isBinaryExpression() const { + return false; + } + virtual void reconstructExpression( std::string& dest ) const = 0; + + // Only simple binary comparisons can be decomposed. + // If more complex check is required then wrap sub-expressions in parentheses. + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); + + private: + DecomposedExpression& operator = (DecomposedExpression const&); + }; + struct AssertionInfo { - AssertionInfo() {} - AssertionInfo( std::string const& _macroName, + AssertionInfo(); + AssertionInfo( char const * _macroName, SourceLineInfo const& _lineInfo, - std::string const& _capturedExpression, - ResultDisposition::Flags _resultDisposition ); + char const * _capturedExpression, + ResultDisposition::Flags _resultDisposition, + char const * _secondArg = ""); - std::string macroName; + char const * macroName; SourceLineInfo lineInfo; - std::string capturedExpression; + char const * capturedExpression; ResultDisposition::Flags resultDisposition; + char const * secondArg; }; struct AssertionResultData { - AssertionResultData() : resultType( ResultWas::Unknown ) {} + AssertionResultData() : decomposedExpression( CATCH_NULL ) + , resultType( ResultWas::Unknown ) + , negated( false ) + , parenthesized( false ) {} + + void negate( bool parenthesize ) { + negated = !negated; + parenthesized = parenthesize; + if( resultType == ResultWas::Ok ) + resultType = ResultWas::ExpressionFailed; + else if( resultType == ResultWas::ExpressionFailed ) + resultType = ResultWas::Ok; + } + + std::string const& reconstructExpression() const { + if( decomposedExpression != CATCH_NULL ) { + decomposedExpression->reconstructExpression( reconstructedExpression ); + if( parenthesized ) { + reconstructedExpression.insert( 0, 1, '(' ); + reconstructedExpression.append( 1, ')' ); + } + if( negated ) { + reconstructedExpression.insert( 0, 1, '!' ); + } + decomposedExpression = CATCH_NULL; + } + return reconstructedExpression; + } - std::string reconstructedExpression; + mutable DecomposedExpression const* decomposedExpression; + mutable std::string reconstructedExpression; std::string message; ResultWas::OfType resultType; + bool negated; + bool parenthesized; }; class AssertionResult { @@ -879,6 +1014,8 @@ namespace Catch { std::string getMessage() const; SourceLineInfo getSourceInfo() const; std::string getTestMacroName() const; + void discardDecomposedExpression() const; + void expandDecomposedExpression() const; protected: AssertionInfo m_info; @@ -894,313 +1031,161 @@ namespace Catch { namespace Matchers { namespace Impl { - namespace Generic { - template class AllOf; - template class AnyOf; - template class Not; - } - - template - struct Matcher : SharedImpl - { - typedef ExpressionT ExpressionType; - - virtual ~Matcher() {} - virtual Ptr clone() const = 0; - virtual bool match( ExpressionT const& expr ) const = 0; - virtual std::string toString() const = 0; - - Generic::AllOf operator && ( Matcher const& other ) const; - Generic::AnyOf operator || ( Matcher const& other ) const; - Generic::Not operator ! () const; - }; - - template - struct MatcherImpl : Matcher { + template struct MatchAllOf; + template struct MatchAnyOf; + template struct MatchNotOf; - virtual Ptr > clone() const { - return Ptr >( new DerivedT( static_cast( *this ) ) ); - } - }; - - namespace Generic { - template - class Not : public MatcherImpl, ExpressionT> { + class MatcherUntypedBase { public: - explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} - Not( Not const& other ) : m_matcher( other.m_matcher ) {} - - virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { - return !m_matcher->match( expr ); + std::string toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = describe(); + return m_cachedToString; } - virtual std::string toString() const CATCH_OVERRIDE { - return "not " + m_matcher->toString(); - } + protected: + virtual ~MatcherUntypedBase(); + virtual std::string describe() const = 0; + mutable std::string m_cachedToString; private: - Ptr< Matcher > m_matcher; + MatcherUntypedBase& operator = ( MatcherUntypedBase const& ); }; - template - class AllOf : public MatcherImpl, ExpressionT> { - public: + template + struct MatcherMethod { + virtual bool match( ObjectT const& arg ) const = 0; + }; + template + struct MatcherMethod { + virtual bool match( PtrT* arg ) const = 0; + }; - AllOf() {} - AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + template + struct MatcherBase : MatcherUntypedBase, MatcherMethod { - AllOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( !m_matchers[i]->match( expr ) ) + MatchAllOf operator && ( MatcherBase const& other ) const; + MatchAnyOf operator || ( MatcherBase const& other ) const; + MatchNotOf operator ! () const; + }; + + template + struct MatchAllOf : MatcherBase { + virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if (!m_matchers[i]->match(arg)) return false; + } return true; } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; + virtual std::string describe() const CATCH_OVERRIDE { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) - oss << " and "; - oss << m_matchers[i]->toString(); + description += " and "; + description += m_matchers[i]->toString(); } - oss << " )"; - return oss.str(); + description += " )"; + return description; } - AllOf operator && ( Matcher const& other ) const { - AllOf allOfExpr( *this ); - allOfExpr.add( other ); - return allOfExpr; + MatchAllOf& operator && ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; } - private: - std::vector > > m_matchers; + std::vector const*> m_matchers; }; + template + struct MatchAnyOf : MatcherBase { - template - class AnyOf : public MatcherImpl, ExpressionT> { - public: - - AnyOf() {} - AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} - - AnyOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( m_matchers[i]->match( expr ) ) + virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if (m_matchers[i]->match(arg)) return true; + } return false; } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; + virtual std::string describe() const CATCH_OVERRIDE { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) - oss << " or "; - oss << m_matchers[i]->toString(); + description += " or "; + description += m_matchers[i]->toString(); } - oss << " )"; - return oss.str(); - } - - AnyOf operator || ( Matcher const& other ) const { - AnyOf anyOfExpr( *this ); - anyOfExpr.add( other ); - return anyOfExpr; - } - - private: - std::vector > > m_matchers; - }; - - } // namespace Generic - - template - Generic::AllOf Matcher::operator && ( Matcher const& other ) const { - Generic::AllOf allOfExpr; - allOfExpr.add( *this ); - allOfExpr.add( other ); - return allOfExpr; - } - - template - Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { - Generic::AnyOf anyOfExpr; - anyOfExpr.add( *this ); - anyOfExpr.add( other ); - return anyOfExpr; - } - - template - Generic::Not Matcher::operator ! () const { - return Generic::Not( *this ); - } - - namespace StdString { - - inline std::string makeString( std::string const& str ) { return str; } - inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } - - struct CasedString - { - CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_str( adjustString( str ) ) - {} - std::string adjustString( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No - ? toLower( str ) - : str; - + description += " )"; + return description; } - std::string toStringSuffix() const - { - return m_caseSensitivity == CaseSensitive::No - ? " (case insensitive)" - : ""; - } - CaseSensitive::Choice m_caseSensitivity; - std::string m_str; - }; - - struct Equals : MatcherImpl { - Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) - : m_data( str, caseSensitivity ) - {} - Equals( Equals const& other ) : m_data( other.m_data ){} - - virtual ~Equals(); - virtual bool match( std::string const& expr ) const { - return m_data.m_str == m_data.adjustString( expr );; - } - virtual std::string toString() const { - return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + MatchAnyOf& operator || ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; } - CasedString m_data; + std::vector const*> m_matchers; }; - struct Contains : MatcherImpl { - Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) - : m_data( substr, caseSensitivity ){} - Contains( Contains const& other ) : m_data( other.m_data ){} + template + struct MatchNotOf : MatcherBase { - virtual ~Contains(); + MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} - virtual bool match( std::string const& expr ) const { - return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; - } - virtual std::string toString() const { - return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { + return !m_underlyingMatcher.match( arg ); } - CasedString m_data; - }; - - struct StartsWith : MatcherImpl { - StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) - : m_data( substr, caseSensitivity ){} - - StartsWith( StartsWith const& other ) : m_data( other.m_data ){} - - virtual ~StartsWith(); - - virtual bool match( std::string const& expr ) const { - return startsWith( m_data.adjustString( expr ), m_data.m_str ); + virtual std::string describe() const CATCH_OVERRIDE { + return "not " + m_underlyingMatcher.toString(); } - virtual std::string toString() const { - return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); - } - - CasedString m_data; + MatcherBase const& m_underlyingMatcher; }; - struct EndsWith : MatcherImpl { - EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) - : m_data( substr, caseSensitivity ){} - EndsWith( EndsWith const& other ) : m_data( other.m_data ){} - - virtual ~EndsWith(); - - virtual bool match( std::string const& expr ) const { - return endsWith( m_data.adjustString( expr ), m_data.m_str ); - } - virtual std::string toString() const { - return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); - } + template + MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { + return MatchAllOf() && *this && other; + } + template + MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { + return MatchAnyOf() || *this || other; + } + template + MatchNotOf MatcherBase::operator ! () const { + return MatchNotOf( *this ); + } - CasedString m_data; - }; - } // namespace StdString } // namespace Impl // The following functions create the actual matcher objects. // This allows the types to be inferred - template - inline Impl::Generic::Not Not( Impl::Matcher const& m ) { - return Impl::Generic::Not( m ); - } - - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); - } - - inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { - return Impl::StdString::Equals( str, caseSensitivity ); - } - inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); - } - inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { - return Impl::StdString::Contains( substr, caseSensitivity ); - } - inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + // - deprecated: prefer ||, && and ! + template + Impl::MatchNotOf Not( Impl::MatcherBase const& underlyingMatcher ) { + return Impl::MatchNotOf( underlyingMatcher ); } - inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { - return Impl::StdString::StartsWith( substr ); + template + Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { + return Impl::MatchAllOf() && m1 && m2; } - inline Impl::StdString::StartsWith StartsWith( const char* substr ) { - return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + template + Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { + return Impl::MatchAllOf() && m1 && m2 && m3; } - inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { - return Impl::StdString::EndsWith( substr ); + template + Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { + return Impl::MatchAnyOf() || m1 || m2; } - inline Impl::StdString::EndsWith EndsWith( const char* substr ) { - return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + template + Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { + return Impl::MatchAnyOf() || m1 || m2 || m3; } } // namespace Matchers using namespace Matchers; +using Matchers::Impl::MatcherBase; } // namespace Catch @@ -1210,28 +1195,27 @@ namespace Catch { template class ExpressionLhs; - struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; - struct CopyableStream { CopyableStream() {} CopyableStream( CopyableStream const& other ) { oss << other.oss.str(); } CopyableStream& operator=( CopyableStream const& other ) { - oss.str(""); + oss.str(std::string()); oss << other.oss.str(); return *this; } std::ostringstream oss; }; - class ResultBuilder { + class ResultBuilder : public DecomposedExpression { public: ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition, char const* secondArg = "" ); + ~ResultBuilder(); template ExpressionLhs operator <= ( T const& operand ); @@ -1239,46 +1223,60 @@ namespace Catch { template ResultBuilder& operator << ( T const& value ) { - m_stream.oss << value; + stream().oss << value; return *this; } - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); - ResultBuilder& setResultType( ResultWas::OfType result ); ResultBuilder& setResultType( bool result ); - ResultBuilder& setLhs( std::string const& lhs ); - ResultBuilder& setRhs( std::string const& rhs ); - ResultBuilder& setOp( std::string const& op ); - void endExpression(); + void endExpression( DecomposedExpression const& expr ); + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE; - std::string reconstructExpression() const; AssertionResult build() const; + AssertionResult build( DecomposedExpression const& expr ) const; void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void captureResult( ResultWas::OfType resultType ); void captureExpression(); void captureExpectedException( std::string const& expectedMessage ); - void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void captureExpectedException( Matchers::Impl::MatcherBase const& matcher ); void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; bool allowThrows() const; + template + void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); + + void setExceptionGuard(); + void unsetExceptionGuard(); + private: AssertionInfo m_assertionInfo; AssertionResultData m_data; - struct ExprComponents { - ExprComponents() : testFalse( false ) {} - bool testFalse; - std::string lhs, rhs, op; - } m_exprComponents; - CopyableStream m_stream; + + CopyableStream &stream() + { + if(!m_usedStream) + { + m_usedStream = true; + m_stream().oss.str(""); + } + return m_stream(); + } + + static CopyableStream &m_stream() + { + static CopyableStream s; + return s; + } bool m_shouldDebugBreak; bool m_shouldThrow; + bool m_guardException; + bool m_usedStream; }; } // namespace Catch @@ -1293,6 +1291,8 @@ namespace Catch { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#pragma warning(disable:4018) // more "signed/unsigned mismatch" +#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) #endif #include @@ -1318,176 +1318,103 @@ namespace Internal { template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; template - inline T& opCast(T const& t) { return const_cast(t); } - -// nullptr_t support based on pull request #154 from Konstantin Baumann + T& removeConst(T const &t) { return const_cast(t); } #ifdef CATCH_CONFIG_CPP11_NULLPTR - inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } -#endif // CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t removeConst(std::nullptr_t) { return nullptr; } +#endif // So the compare overloads can be operator agnostic we convey the operator as a template // enum, which is used to specialise an Evaluator for doing the comparison. template - class Evaluator{}; + struct Evaluator{}; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs) { - return bool( opCast( lhs ) == opCast( rhs ) ); + return bool(removeConst(lhs) == removeConst(rhs) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) != opCast( rhs ) ); + return bool(removeConst(lhs) != removeConst(rhs) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) < opCast( rhs ) ); + return bool(removeConst(lhs) < removeConst(rhs) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) > opCast( rhs ) ); + return bool(removeConst(lhs) > removeConst(rhs) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) >= opCast( rhs ) ); + return bool(removeConst(lhs) >= removeConst(rhs) ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) <= opCast( rhs ) ); + return bool(removeConst(lhs) <= removeConst(rhs) ); } }; - template - bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { - return Evaluator::evaluate( lhs, rhs ); - } - - // This level of indirection allows us to specialise for integer types - // to avoid signed/ unsigned warnings - - // "base" overload - template - bool compare( T1 const& lhs, T2 const& rhs ) { - return Evaluator::evaluate( lhs, rhs ); - } - - // unsigned X to int - template bool compare( unsigned int lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned long lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned char lhs, int rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - - // unsigned X to long - template bool compare( unsigned int lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned long lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - template bool compare( unsigned char lhs, long rhs ) { - return applyEvaluator( lhs, static_cast( rhs ) ); - } - - // int to unsigned X - template bool compare( int lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( int lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( int lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // long to unsigned X - template bool compare( long lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // pointer to long (when comparing against NULL) - template bool compare( long lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, long rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } - - // pointer to int (when comparing against NULL) - template bool compare( int lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, int rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } - -#ifdef CATCH_CONFIG_CPP11_LONG_LONG - // long long to unsigned X - template bool compare( long long lhs, unsigned int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long long lhs, unsigned long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long long lhs, unsigned long long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( long long lhs, unsigned char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // unsigned long long to X - template bool compare( unsigned long long lhs, int rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( unsigned long long lhs, long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( unsigned long long lhs, long long rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - template bool compare( unsigned long long lhs, char rhs ) { - return applyEvaluator( static_cast( lhs ), rhs ); - } - - // pointer to long long (when comparing against NULL) - template bool compare( long long lhs, T* rhs ) { - return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); - } - template bool compare( T* lhs, long long rhs ) { - return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); - } -#endif // CATCH_CONFIG_CPP11_LONG_LONG + // Special case for comparing a pointer to an int (deduced for p==0) + template + struct Evaluator { + static bool evaluate( int lhs, T* rhs) { + return reinterpret_cast( lhs ) == rhs; + } + }; + template + struct Evaluator { + static bool evaluate( T* lhs, int rhs) { + return lhs == reinterpret_cast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( int lhs, T* rhs) { + return reinterpret_cast( lhs ) != rhs; + } + }; + template + struct Evaluator { + static bool evaluate( T* lhs, int rhs) { + return lhs != reinterpret_cast( rhs ); + } + }; -#ifdef CATCH_CONFIG_CPP11_NULLPTR - // pointer to nullptr_t (when comparing against nullptr) - template bool compare( std::nullptr_t, T* rhs ) { - return Evaluator::evaluate( nullptr, rhs ); - } - template bool compare( T* lhs, std::nullptr_t ) { - return Evaluator::evaluate( lhs, nullptr ); - } -#endif // CATCH_CONFIG_CPP11_NULLPTR + template + struct Evaluator { + static bool evaluate( long lhs, T* rhs) { + return reinterpret_cast( lhs ) == rhs; + } + }; + template + struct Evaluator { + static bool evaluate( T* lhs, long rhs) { + return lhs == reinterpret_cast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( long lhs, T* rhs) { + return reinterpret_cast( lhs ) != rhs; + } + }; + template + struct Evaluator { + static bool evaluate( T* lhs, long rhs) { + return lhs != reinterpret_cast( rhs ); + } + }; } // end of namespace Internal } // end of namespace Catch @@ -1594,7 +1521,7 @@ std::string toString( std::nullptr_t ); #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ); - std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG & nsstring ); std::string toString( NSObject* const& nsObject ); #endif @@ -1602,6 +1529,7 @@ namespace Detail { extern const std::string unprintableString; + #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK) struct BorgType { template BorgType( T const& ); }; @@ -1620,6 +1548,20 @@ namespace Detail { static T const&t; enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; }; +#else + template + class IsStreamInsertable { + template + static auto test(int) + -> decltype( std::declval() << std::declval(), std::true_type() ); + + template + static auto test(...) -> std::false_type; + + public: + static const bool value = decltype(test(0))::value; + }; +#endif #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template - inline std::string rawMemoryToString( const T& object ) { + std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } @@ -1796,90 +1738,159 @@ std::string toString( T const& value ) { namespace Catch { -// Wraps the LHS of an expression and captures the operator and RHS (if any) - -// wrapping them all in a ResultBuilder object -template -class ExpressionLhs { - ExpressionLhs& operator = ( ExpressionLhs const& ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - ExpressionLhs& operator = ( ExpressionLhs && ) = delete; -# endif +template +class BinaryExpression; +template +class MatchExpression; + +// Wraps the LHS of an expression and overloads comparison operators +// for also capturing those and RHS (if any) +template +class ExpressionLhs : public DecomposedExpression { public: - ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - ExpressionLhs( ExpressionLhs const& ) = default; - ExpressionLhs( ExpressionLhs && ) = default; -# endif + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} + + ExpressionLhs& operator = ( const ExpressionLhs& ); template - ResultBuilder& operator == ( RhsT const& rhs ) { + BinaryExpression + operator == ( RhsT const& rhs ) { return captureExpression( rhs ); } template - ResultBuilder& operator != ( RhsT const& rhs ) { + BinaryExpression + operator != ( RhsT const& rhs ) { return captureExpression( rhs ); } template - ResultBuilder& operator < ( RhsT const& rhs ) { + BinaryExpression + operator < ( RhsT const& rhs ) { return captureExpression( rhs ); } template - ResultBuilder& operator > ( RhsT const& rhs ) { + BinaryExpression + operator > ( RhsT const& rhs ) { return captureExpression( rhs ); } template - ResultBuilder& operator <= ( RhsT const& rhs ) { + BinaryExpression + operator <= ( RhsT const& rhs ) { return captureExpression( rhs ); } template - ResultBuilder& operator >= ( RhsT const& rhs ) { + BinaryExpression + operator >= ( RhsT const& rhs ) { return captureExpression( rhs ); } - ResultBuilder& operator == ( bool rhs ) { + BinaryExpression operator == ( bool rhs ) { return captureExpression( rhs ); } - ResultBuilder& operator != ( bool rhs ) { + BinaryExpression operator != ( bool rhs ) { return captureExpression( rhs ); } void endExpression() { - bool value = m_lhs ? true : false; + m_truthy = m_lhs ? true : false; m_rb - .setLhs( Catch::toString( value ) ) - .setResultType( value ) - .endExpression(); + .setResultType( m_truthy ) + .endExpression( *this ); } - // Only simple binary expressions are allowed on the LHS. - // If more complex compositions are required then place the sub expression in parentheses - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { + dest = Catch::toString( m_lhs ); + } private: template - ResultBuilder& captureExpression( RhsT const& rhs ) { - return m_rb - .setResultType( Internal::compare( m_lhs, rhs ) ) - .setLhs( Catch::toString( m_lhs ) ) - .setRhs( Catch::toString( rhs ) ) - .setOp( Internal::OperatorTraits::getName() ); + BinaryExpression captureExpression( RhsT& rhs ) const { + return BinaryExpression( m_rb, m_lhs, rhs ); + } + + template + BinaryExpression captureExpression( bool rhs ) const { + return BinaryExpression( m_rb, m_lhs, rhs ); } private: ResultBuilder& m_rb; T m_lhs; + bool m_truthy; +}; + +template +class BinaryExpression : public DecomposedExpression { +public: + BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) + : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} + + BinaryExpression& operator = ( BinaryExpression& ); + + void endExpression() const { + m_rb + .setResultType( Internal::Evaluator::evaluate( m_lhs, m_rhs ) ) + .endExpression( *this ); + } + + virtual bool isBinaryExpression() const CATCH_OVERRIDE { + return true; + } + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { + std::string lhs = Catch::toString( m_lhs ); + std::string rhs = Catch::toString( m_rhs ); + char delim = lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ? ' ' : '\n'; + dest.reserve( 7 + lhs.size() + rhs.size() ); + // 2 for spaces around operator + // 2 for operator + // 2 for parentheses (conditionally added later) + // 1 for negation (conditionally added later) + dest = lhs; + dest += delim; + dest += Internal::OperatorTraits::getName(); + dest += delim; + dest += rhs; + } + +private: + ResultBuilder& m_rb; + LhsT m_lhs; + RhsT m_rhs; +}; + +template +class MatchExpression : public DecomposedExpression { +public: + MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) + : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} + + virtual bool isBinaryExpression() const CATCH_OVERRIDE { + return true; + } + + virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { + std::string matcherAsString = m_matcher.toString(); + dest = Catch::toString( m_arg ); + dest += ' '; + if( matcherAsString == Detail::unprintableString ) + dest += m_matcherString; + else + dest += matcherAsString; + } + +private: + ArgT m_arg; + MatcherT m_matcher; + char const* m_matcherString; }; } // end namespace Catch @@ -1888,7 +1899,7 @@ private: namespace Catch { template - inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { return ExpressionLhs( *this, operand ); } @@ -1896,6 +1907,14 @@ namespace Catch { return ExpressionLhs( *this, value ); } + template + void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, + char const* matcherString ) { + MatchExpression expr( arg, matcher, matcherString ); + setResultType( matcher.match( arg ) ); + endExpression( expr ); + } + } // namespace Catch // #included from: catch_message.h @@ -1985,7 +2004,13 @@ namespace Catch { virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; + virtual void exceptionEarlyReported() = 0; + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + + virtual bool lastAssertionPassed() = 0; + virtual void assertionPassed() = 0; + virtual void assertionRun() = 0; }; IResultCapture& getResultCapture(); @@ -1998,11 +2023,19 @@ namespace Catch { #define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) -#define CATCH_PLATFORM_MAC +# define CATCH_PLATFORM_MAC #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) -#define CATCH_PLATFORM_IPHONE +# define CATCH_PLATFORM_IPHONE +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) -#define CATCH_PLATFORM_WINDOWS +# define CATCH_PLATFORM_WINDOWS +# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINES_NOMINMAX +# endif +# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN +# endif #endif #include @@ -2017,27 +2050,36 @@ namespace Catch{ // The following code snippet based on: // http://cocoawithlove.com/2008/03/break-into-debugger.html - #ifdef DEBUG - #if defined(__ppc64__) || defined(__ppc__) - #define CATCH_BREAK_INTO_DEBUGGER() \ - if( Catch::isDebuggerActive() ) { \ - __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ - : : : "memory","r0","r3","r4" ); \ - } - #else - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} - #endif + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_TRAP() \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ) /* NOLINT */ + #else + #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ ) #endif +#elif defined(CATCH_PLATFORM_LINUX) + // 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 + // raise() called from it, i.e. one stack frame below. + #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) + #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ + #else // Fall back to the generic way. + #include + + #define CATCH_TRAP() raise(SIGTRAP) + #endif #elif defined(_MSC_VER) - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } + #define CATCH_TRAP() __debugbreak() #elif defined(__MINGW32__) extern "C" __declspec(dllimport) void __stdcall DebugBreak(); - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } + #define CATCH_TRAP() DebugBreak() #endif -#ifndef CATCH_BREAK_INTO_DEBUGGER -#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } +#else + #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); #endif // #included from: catch_interfaces_runner.h @@ -2052,6 +2094,47 @@ namespace Catch { }; } +#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) +# define CATCH_INTERNAL_STRINGIFY(expr) #expr +#else +# define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" +#endif + +#if defined(CATCH_CONFIG_FAST_COMPILE) +/////////////////////////////////////////////////////////////////////////////// +// We can speedup compilation significantly by breaking into debugger lower in +// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER +// macro in each assertion +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +// Another way to speed-up compilation is to omit local try-catch for REQUIRE* +// macros. +// This can potentially cause false negative, if the test code catches +// the exception before it propagates back up to the runner. +#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \ + __catchResult.setExceptionGuard(); \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + ( __catchResult <= expr ).endExpression(); \ + CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + __catchResult.unsetExceptionGuard(); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr 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 &&. + +#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + __catchResult.setExceptionGuard(); \ + __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \ + __catchResult.unsetExceptionGuard(); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +#else /////////////////////////////////////////////////////////////////////////////// // In the event of a failure works out if the debugger needs to be invoked // and/or an exception thrown and takes appropriate action. @@ -2060,37 +2143,40 @@ namespace Catch { #define INTERNAL_CATCH_REACT( resultBuilder ) \ if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ resultBuilder.react(); +#endif /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ +#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \ try { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ ( __catchResult <= expr ).endExpression(); \ + CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } \ catch( ... ) { \ - __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + __catchResult.useActiveException( resultDisposition ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + } while( Catch::isTrue( false && static_cast( !!(expr) ) ) ) // expr 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 &&. /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ - INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ - if( Catch::getResultCapture().getLastResult()->succeeded() ) +#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ + if( Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ - INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ - if( !Catch::getResultCapture().getLastResult()->succeeded() ) +#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ + if( !Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ +#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \ try { \ - expr; \ + static_cast(expr); \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ @@ -2100,12 +2186,12 @@ namespace Catch { } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ +#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \ if( __catchResult.allowThrows() ) \ try { \ - expr; \ + static_cast(expr); \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ @@ -2117,12 +2203,12 @@ namespace Catch { } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ +#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ if( __catchResult.allowThrows() ) \ try { \ - expr; \ + static_cast(expr); \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( exceptionType ) { \ @@ -2138,7 +2224,7 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #ifdef CATCH_CONFIG_VARIADIC_MACROS - #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ @@ -2146,7 +2232,7 @@ namespace Catch { INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #else - #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << log + ::Catch::StreamEndStop(); \ @@ -2156,21 +2242,15 @@ namespace Catch { #endif /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_INFO( log, macroName ) \ +#define INTERNAL_CATCH_INFO( macroName, log ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ +#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ try { \ - std::string matcherAsString = (matcher).toString(); \ - __catchResult \ - .setLhs( Catch::toString( arg ) ) \ - .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ - .setOp( "matches" ) \ - .setResultType( (matcher).match( arg ) ); \ - __catchResult.captureExpression(); \ + __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ } \ @@ -2253,6 +2333,8 @@ namespace Catch { }; } +#include + namespace Catch { struct SectionInfo { @@ -2281,14 +2363,19 @@ namespace Catch { // #included from: catch_timer.h #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED -#ifdef CATCH_PLATFORM_WINDOWS -typedef unsigned long long uint64_t; +#ifdef _MSC_VER + +namespace Catch { + typedef unsigned long long UInt64; +} #else #include +namespace Catch { + typedef uint64_t UInt64; +} #endif namespace Catch { - class Timer { public: Timer() : m_ticks( 0 ) {} @@ -2298,7 +2385,7 @@ namespace Catch { double getElapsedSeconds() const; private: - uint64_t m_ticks; + UInt64 m_ticks; }; } // namespace Catch @@ -2337,7 +2424,6 @@ namespace Catch { // #included from: internal/catch_generators.hpp #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED -#include #include #include #include @@ -2451,7 +2537,7 @@ public: private: void move( CompositeGenerator& other ) { - std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() ); m_totalSize += other.m_totalSize; other.m_composed.clear(); } @@ -2533,12 +2619,15 @@ namespace Catch { struct IExceptionTranslator; struct IReporterRegistry; struct IReporterFactory; + struct ITagAliasRegistry; struct IRegistryHub { virtual ~IRegistryHub(); virtual IReporterRegistry const& getReporterRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; }; @@ -2548,6 +2637,7 @@ namespace Catch { virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; }; IRegistryHub& getRegistryHub(); @@ -2623,6 +2713,10 @@ namespace Catch { #include #include +#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) +#include +#endif + namespace Catch { namespace Detail { @@ -2630,30 +2724,111 @@ namespace Detail { public: explicit Approx ( double value ) : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_margin( 0.0 ), m_scale( 1.0 ), m_value( value ) {} - Approx( Approx const& other ) - : m_epsilon( other.m_epsilon ), - m_scale( other.m_scale ), - m_value( other.m_value ) - {} - static Approx custom() { return Approx( 0 ); } +#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) + + template ::value>::type> + Approx operator()( T value ) { + Approx approx( static_cast(value) ); + approx.epsilon( m_epsilon ); + approx.margin( m_margin ); + approx.scale( m_scale ); + return approx; + } + + template ::value>::type> + explicit Approx( T value ): Approx(static_cast(value)) + {} + + template ::value>::type> + friend bool operator == ( const T& lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + auto lhs_v = double(lhs); + bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value))); + if (relativeOK) { + return true; + } + return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin; + } + + template ::value>::type> + friend bool operator == ( Approx const& lhs, const T& rhs ) { + return operator==( rhs, lhs ); + } + + template ::value>::type> + friend bool operator != ( T lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + template ::value>::type> + friend bool operator != ( Approx const& lhs, T rhs ) { + return !operator==( rhs, lhs ); + } + + template ::value>::type> + friend bool operator <= ( T lhs, Approx const& rhs ) { + return double(lhs) < rhs.m_value || lhs == rhs; + } + + template ::value>::type> + friend bool operator <= ( Approx const& lhs, T rhs ) { + return lhs.m_value < double(rhs) || lhs == rhs; + } + + template ::value>::type> + friend bool operator >= ( T lhs, Approx const& rhs ) { + return double(lhs) > rhs.m_value || lhs == rhs; + } + + template ::value>::type> + friend bool operator >= ( Approx const& lhs, T rhs ) { + return lhs.m_value > double(rhs) || lhs == rhs; + } + + template ::value>::type> + Approx& epsilon( T newEpsilon ) { + m_epsilon = double(newEpsilon); + return *this; + } + + template ::value>::type> + Approx& margin( T newMargin ) { + m_margin = double(newMargin); + return *this; + } + + template ::value>::type> + Approx& scale( T newScale ) { + m_scale = double(newScale); + return *this; + } + +#else + Approx operator()( double value ) { Approx approx( value ); approx.epsilon( m_epsilon ); + approx.margin( m_margin ); approx.scale( m_scale ); return approx; } friend bool operator == ( double lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula - return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); + if (relativeOK) { + return true; + } + return std::fabs(lhs - rhs.m_value) < rhs.m_margin; } friend bool operator == ( Approx const& lhs, double rhs ) { @@ -2668,15 +2843,37 @@ namespace Detail { return !operator==( rhs, lhs ); } + friend bool operator <= ( double lhs, Approx const& rhs ) { + return lhs < rhs.m_value || lhs == rhs; + } + + friend bool operator <= ( Approx const& lhs, double rhs ) { + return lhs.m_value < rhs || lhs == rhs; + } + + friend bool operator >= ( double lhs, Approx const& rhs ) { + return lhs > rhs.m_value || lhs == rhs; + } + + friend bool operator >= ( Approx const& lhs, double rhs ) { + return lhs.m_value > rhs || lhs == rhs; + } + Approx& epsilon( double newEpsilon ) { m_epsilon = newEpsilon; return *this; } + Approx& margin( double newMargin ) { + m_margin = newMargin; + return *this; + } + Approx& scale( double newScale ) { m_scale = newScale; return *this; } +#endif std::string toString() const { std::ostringstream oss; @@ -2686,6 +2883,7 @@ namespace Detail { private: double m_epsilon; + double m_margin; double m_scale; double m_value; }; @@ -2698,6 +2896,153 @@ inline std::string toString( Detail::Approx const& value ) { } // end namespace Catch +// #included from: internal/catch_matchers_string.h +#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED + +namespace Catch { +namespace Matchers { + + namespace StdString { + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); + std::string adjustString( std::string const& str ) const; + std::string caseSensitivitySuffix() const; + + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct StringMatcherBase : MatcherBase { + StringMatcherBase( std::string const& operation, CasedString const& comparator ); + virtual std::string describe() const CATCH_OVERRIDE; + + CasedString m_comparator; + std::string m_operation; + }; + + struct EqualsMatcher : StringMatcherBase { + EqualsMatcher( CasedString const& comparator ); + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + }; + struct ContainsMatcher : StringMatcherBase { + ContainsMatcher( CasedString const& comparator ); + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + }; + struct StartsWithMatcher : StringMatcherBase { + StartsWithMatcher( CasedString const& comparator ); + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + }; + struct EndsWithMatcher : StringMatcherBase { + EndsWithMatcher( CasedString const& comparator ); + virtual bool match( std::string const& source ) const CATCH_OVERRIDE; + }; + + } // namespace StdString + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + +} // namespace Matchers +} // namespace Catch + +// #included from: internal/catch_matchers_vector.h +#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED + +namespace Catch { +namespace Matchers { + + namespace Vector { + + template + struct ContainsElementMatcher : MatcherBase, T> { + + ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} + + bool match(std::vector const &v) const CATCH_OVERRIDE { + return std::find(v.begin(), v.end(), m_comparator) != v.end(); + } + + virtual std::string describe() const CATCH_OVERRIDE { + return "Contains: " + Catch::toString( m_comparator ); + } + + T const& m_comparator; + }; + + template + struct ContainsMatcher : MatcherBase, std::vector > { + + ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} + + bool match(std::vector const &v) const CATCH_OVERRIDE { + // !TBD: see note in EqualsMatcher + if (m_comparator.size() > v.size()) + return false; + for (size_t i = 0; i < m_comparator.size(); ++i) + if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end()) + return false; + return true; + } + virtual std::string describe() const CATCH_OVERRIDE { + return "Contains: " + Catch::toString( m_comparator ); + } + + std::vector const& m_comparator; + }; + + template + struct EqualsMatcher : MatcherBase, std::vector > { + + EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} + + bool match(std::vector const &v) const CATCH_OVERRIDE { + // !TBD: This currently works if all elements can be compared using != + // - a more general approach would be via a compare template that defaults + // to using !=. but could be specialised for, e.g. std::vector etc + // - then just call that directly + if (m_comparator.size() != v.size()) + return false; + for (size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != v[i]) + return false; + return true; + } + virtual std::string describe() const CATCH_OVERRIDE { + return "Equals: " + Catch::toString( m_comparator ); + } + std::vector const& m_comparator; + }; + + } // namespace Vector + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + + template + Vector::ContainsMatcher Contains( std::vector const& comparator ) { + return Vector::ContainsMatcher( comparator ); + } + + template + Vector::ContainsElementMatcher VectorContains( T const& comparator ) { + return Vector::ContainsElementMatcher( comparator ); + } + + template + Vector::EqualsMatcher Equals( std::vector const& comparator ) { + return Vector::EqualsMatcher( comparator ); + } + +} // namespace Matchers +} // namespace Catch + // #included from: internal/catch_interfaces_tag_alias_registry.h #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED @@ -2709,7 +3054,7 @@ inline std::string toString( Detail::Approx const& value ) { namespace Catch { struct TagAlias { - TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} std::string tag; SourceLineInfo lineInfo; @@ -2781,8 +3126,18 @@ namespace Catch { } private: - T* nullableValue; - char storage[sizeof(T)]; + T *nullableValue; + union { + char storage[sizeof(T)]; + + // These are here to force alignment for the storage + long double dummy1; + void (*dummy2)(); + long double dummy3; +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + long long dummy4; +#endif + }; }; } // end namespace Catch @@ -2822,7 +3177,8 @@ namespace Catch { IsHidden = 1 << 1, ShouldFail = 1 << 2, MayFail = 1 << 3, - Throws = 1 << 4 + Throws = 1 << 4, + NonPortable = 1 << 5 }; TestCaseInfo( std::string const& _name, @@ -2980,64 +3336,67 @@ namespace Catch { namespace Impl { namespace NSStringMatchers { - template - struct StringHolder : MatcherImpl{ + struct StringHolder : MatcherBase{ StringHolder( NSString* substr ) : m_substr( [substr copy] ){} StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} StringHolder() { arcSafeRelease( m_substr ); } + virtual bool match( NSString* arg ) const CATCH_OVERRIDE { + return false; + } + NSString* m_substr; }; - struct Equals : StringHolder { + struct Equals : StringHolder { Equals( NSString* substr ) : StringHolder( substr ){} - virtual bool match( ExpressionType const& str ) const { + virtual bool match( NSString* str ) const CATCH_OVERRIDE { return (str != nil || m_substr == nil ) && [str isEqualToString:m_substr]; } - virtual std::string toString() const { + virtual std::string describe() const CATCH_OVERRIDE { return "equals string: " + Catch::toString( m_substr ); } }; - struct Contains : StringHolder { + struct Contains : StringHolder { Contains( NSString* substr ) : StringHolder( substr ){} - virtual bool match( ExpressionType const& str ) const { + virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location != NSNotFound; } - virtual std::string toString() const { + virtual std::string describe() const CATCH_OVERRIDE { return "contains string: " + Catch::toString( m_substr ); } }; - struct StartsWith : StringHolder { + struct StartsWith : StringHolder { StartsWith( NSString* substr ) : StringHolder( substr ){} - virtual bool match( ExpressionType const& str ) const { + virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == 0; } - virtual std::string toString() const { + virtual std::string describe() const CATCH_OVERRIDE { return "starts with: " + Catch::toString( m_substr ); } }; - struct EndsWith : StringHolder { + struct EndsWith : StringHolder { EndsWith( NSString* substr ) : StringHolder( substr ){} - virtual bool match( ExpressionType const& str ) const { + virtual bool match( NSString* str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } - virtual std::string toString() const { + virtual std::string describe() const CATCH_OVERRIDE { return "ends with: " + Catch::toString( m_substr ); } }; @@ -3078,6 +3437,29 @@ return @ desc; \ #endif #ifdef CATCH_IMPL + +// !TBD: Move the leak detector code into a separate header +#ifdef CATCH_CONFIG_WINDOWS_CRTDBG +#include +class LeakDetector { +public: + LeakDetector() { + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF; + flag |= _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + // Change this to leaking allocation's number to break there + _CrtSetBreakAlloc(-1); + } +}; +#else +class LeakDetector {}; +#endif + +LeakDetector leakDetector; + // #included from: internal/catch_impl.hpp #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED @@ -3117,6 +3499,8 @@ return @ desc; \ // #included from: catch_wildcard_pattern.hpp #define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED +#include + namespace Catch { class WildcardPattern { @@ -3134,11 +3518,11 @@ namespace Catch m_wildcard( NoWildcard ), m_pattern( adjustCase( pattern ) ) { - if( startsWith( m_pattern, "*" ) ) { + if( startsWith( m_pattern, '*' ) ) { m_pattern = m_pattern.substr( 1 ); m_wildcard = WildcardAtStart; } - if( endsWith( m_pattern, "*" ) ) { + if( endsWith( m_pattern, '*' ) ) { m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); } @@ -3223,10 +3607,11 @@ namespace Catch { bool matches( TestCaseInfo const& testCase ) const { // All patterns in a filter must match for the filter to be a match - for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { if( !(*it)->matches( testCase ) ) return false; - return true; + } + return true; } }; @@ -3256,23 +3641,25 @@ namespace Catch { namespace Catch { class TestSpecParser { - enum Mode{ None, Name, QuotedName, Tag }; + enum Mode{ None, Name, QuotedName, Tag, EscapedName }; Mode m_mode; bool m_exclusion; std::size_t m_start, m_pos; std::string m_arg; + std::vector m_escapeChars; TestSpec::Filter m_currentFilter; TestSpec m_testSpec; ITagAliasRegistry const* m_tagAliases; public: - TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {} TestSpecParser& parse( std::string const& arg ) { m_mode = None; m_exclusion = false; m_start = std::string::npos; m_arg = m_tagAliases->expandAliases( arg ); + m_escapeChars.clear(); for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) visitChar( m_arg[m_pos] ); if( m_mode == Name ) @@ -3291,6 +3678,7 @@ namespace Catch { case '~': m_exclusion = true; return; case '[': return startNewMode( Tag, ++m_pos ); case '"': return startNewMode( QuotedName, ++m_pos ); + case '\\': return escape(); default: startNewMode( Name, m_pos ); break; } } @@ -3306,7 +3694,11 @@ namespace Catch { addPattern(); startNewMode( Tag, ++m_pos ); } + else if( c == '\\' ) + escape(); } + else if( m_mode == EscapedName ) + m_mode = Name; else if( m_mode == QuotedName && c == '"' ) addPattern(); else if( m_mode == Tag && c == ']' ) @@ -3316,10 +3708,19 @@ namespace Catch { m_mode = mode; m_start = start; } + void escape() { + if( m_mode == None ) + m_start = m_pos; + m_mode = EscapedName; + m_escapeChars.push_back( m_pos ); + } std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } template void addPattern() { std::string token = subString(); + for( size_t i = 0; i < m_escapeChars.size(); ++i ) + token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); + m_escapeChars.clear(); if( startsWith( token, "exclude:" ) ) { m_exclusion = true; token = token.substr( 8 ); @@ -3353,7 +3754,7 @@ namespace Catch { // #included from: catch_interfaces_config.h #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED -#include +#include #include #include @@ -3385,6 +3786,12 @@ namespace Catch { Yes, No }; }; + struct WaitForKeypress { enum When { + Never, + BeforeStart = 1, + BeforeExit = 2, + BeforeStartAndExit = BeforeStart | BeforeExit + }; }; class TestSpec; @@ -3405,6 +3812,8 @@ namespace Catch { virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; virtual UseColour::YesOrNo useColour() const = 0; + virtual std::vector const& getSectionsToRun() const = 0; + }; } @@ -3427,11 +3836,13 @@ namespace Catch { #include #include #include +#include namespace Catch { std::ostream& cout(); std::ostream& cerr(); + std::ostream& clog(); struct IStream { virtual ~IStream() CATCH_NOEXCEPT; @@ -3472,8 +3883,7 @@ namespace Catch { #include #include #include -#include -#include +#include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 @@ -3488,25 +3898,29 @@ namespace Catch { listTags( false ), listReporters( false ), listTestNamesOnly( false ), + listExtraInfo( false ), showSuccessfulTests( false ), shouldDebugBreak( false ), noThrow( false ), showHelp( false ), showInvisibles( false ), filenamesAsTags( false ), + libIdentify( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), warnings( WarnAbout::Nothing ), showDurations( ShowDurations::DefaultForReporter ), runOrder( RunTests::InDeclarationOrder ), - useColour( UseColour::Auto ) + useColour( UseColour::Auto ), + waitForKeypress( WaitForKeypress::Never ) {} bool listTests; bool listTags; bool listReporters; bool listTestNamesOnly; + bool listExtraInfo; bool showSuccessfulTests; bool shouldDebugBreak; @@ -3514,6 +3928,7 @@ namespace Catch { bool showHelp; bool showInvisibles; bool filenamesAsTags; + bool libIdentify; int abortAfter; unsigned int rngSeed; @@ -3523,6 +3938,7 @@ namespace Catch { ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; UseColour::YesOrNo useColour; + WaitForKeypress::When waitForKeypress; std::string outputFilename; std::string name; @@ -3530,6 +3946,7 @@ namespace Catch { std::vector reporterNames; std::vector testsOrTags; + std::vector sectionsToRun; }; class Config : public SharedImpl { @@ -3554,8 +3971,7 @@ namespace Catch { } } - virtual ~Config() { - } + virtual ~Config() {} std::string const& getFilename() const { return m_data.outputFilename ; @@ -3565,30 +3981,30 @@ namespace Catch { bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } bool listTags() const { return m_data.listTags; } bool listReporters() const { return m_data.listReporters; } + bool listExtraInfo() const { return m_data.listExtraInfo; } std::string getProcessName() const { return m_data.processName; } - bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + std::vector const& getReporterNames() const { return m_data.reporterNames; } + std::vector const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; } - std::vector getReporterNames() const { return m_data.reporterNames; } - - int abortAfter() const { return m_data.abortAfter; } - - TestSpec const& testSpec() const { return m_testSpec; } + virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; } bool showHelp() const { return m_data.showHelp; } - bool showInvisibles() const { return m_data.showInvisibles; } // IConfig interface - virtual bool allowThrows() const { return !m_data.noThrow; } - virtual std::ostream& stream() const { return m_stream->stream(); } - virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } - virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } - virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } - virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } - virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } - virtual unsigned int rngSeed() const { return m_data.rngSeed; } - virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } + virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; } + virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); } + virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; } + virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; } + virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; } + virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; } + virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; } + virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; } private: @@ -3653,6 +4069,7 @@ namespace Catch { #include #include #include +#include // Use optional outer namespace #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE @@ -3762,7 +4179,7 @@ namespace Tbc { return oss.str(); } - inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) @@ -3994,9 +4411,12 @@ namespace Clara { inline void convertInto( std::string const& _source, std::string& _dest ) { _dest = _source; } + char toLowerCh(char c) { + return static_cast( std::tolower( c ) ); + } inline void convertInto( std::string const& _source, bool& _dest ) { std::string sourceLC = _source; - std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh ); if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) _dest = true; else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) @@ -4152,6 +4572,7 @@ namespace Clara { inQuotes = !inQuotes; mode = handleMode( i, c, arg, tokens ); } + mode = handleMode( arg.size(), '\0', arg, tokens ); } Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { switch( mode ) { @@ -4184,6 +4605,7 @@ namespace Clara { default: from = i; return ShortOpt; } } + Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector& tokens ) { if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) return mode; @@ -4515,7 +4937,7 @@ namespace Clara { } std::vector parseInto( std::vector const& args, ConfigT& config ) const { - std::string processName = args[0]; + std::string processName = args.empty() ? std::string() : args[0]; std::size_t lastSlash = processName.find_last_of( "/\\" ); if( lastSlash != std::string::npos ) processName = processName.substr( lastSlash+1 ); @@ -4647,6 +5069,7 @@ STITCH_CLARA_CLOSE_NAMESPACE #endif #include +#include namespace Catch { @@ -4657,13 +5080,14 @@ namespace Catch { config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); } inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); else - throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' ); } inline void setOrder( ConfigData& config, std::string const& order ) { if( startsWith( "declared", order ) ) @@ -4673,7 +5097,7 @@ namespace Catch { else if( startsWith( "random", order ) ) config.runOrder = RunTests::InRandomOrder; else - throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' ); } inline void setRngSeed( ConfigData& config, std::string const& seed ) { if( seed == "time" ) { @@ -4684,7 +5108,7 @@ namespace Catch { ss << seed; ss >> config.rngSeed; if( ss.fail() ) - throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" ); } } inline void setVerbosity( ConfigData& config, int level ) { @@ -4708,6 +5132,18 @@ namespace Catch { else throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); } + inline void setWaitForKeypress( ConfigData& config, std::string const& keypress ) { + std::string keypressLc = toLower( keypress ); + if( keypressLc == "start" ) + config.waitForKeypress = WaitForKeypress::BeforeStart; + else if( keypressLc == "exit" ) + config.waitForKeypress = WaitForKeypress::BeforeExit; + else if( keypressLc == "both" ) + config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; + else + throw std::runtime_error( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); + }; + inline void forceColour( ConfigData& config ) { config.useColour = UseColour::Yes; } @@ -4719,8 +5155,11 @@ namespace Catch { std::string line; while( std::getline( f, line ) ) { line = trim(line); - if( !line.empty() && !startsWith( line, "#" ) ) - addTestOrTags( config, "\"" + line + "\"," ); + if( !line.empty() && !startsWith( line, '#' ) ) { + if( !startsWith( line, '"' ) ) + line = '"' + line + '"'; + addTestOrTags( config, line + ',' ); + } } } @@ -4807,11 +5246,19 @@ namespace Catch { .describe( "adds a tag for the filename" ) .bind( &ConfigData::filenamesAsTags ); + cli["-c"]["--section"] + .describe( "specify section to run" ) + .bind( &addSectionToRun, "section name" ); + // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) .bind( &ConfigData::listTestNamesOnly ); + cli["--list-extra-info"] + .describe( "list all/matching test cases with more info" ) + .bind( &ConfigData::listExtraInfo ); + cli["--list-reporters"] .describe( "list all reporters" ) .bind( &ConfigData::listReporters ); @@ -4832,6 +5279,18 @@ namespace Catch { .describe( "should output be colourised" ) .bind( &setUseColour, "yes|no" ); + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); + + cli["--libidentify"] + .describe( "report name and version according to libidentify standard" ) + .bind( &ConfigData::libIdentify ); + + cli["--wait-for-keypress"] + .describe( "waits for a keypress before exiting" ) + .bind( &setWaitForKeypress, "start|exit|both" ); + return cli; } @@ -4879,82 +5338,93 @@ namespace Tbc { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), - width( consoleWidth-1 ), - tabChar( '\t' ) + width( consoleWidth-1 ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap - char tabChar; // If this char is seen the indent is changed to current pos }; class Text { public: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) - { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; - - while( !remainder.empty() ) { - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } - - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; + { + const std::string wrappableBeforeChars = "[({<\t"; + const std::string wrappableAfterChars = "])}>-,./|\\"; + const std::string wrappableInsteadOfChars = " \n\r"; + std::string indent = _attr.initialIndent != std::string::npos + ? std::string( _attr.initialIndent, ' ' ) + : std::string( _attr.indent, ' ' ); + + typedef std::string::const_iterator iterator; + iterator it = _str.begin(); + const iterator strEnd = _str.end(); + + while( it != strEnd ) { + + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); + + std::string suffix; + std::size_t width = (std::min)( static_cast( strEnd-it ), _attr.width-static_cast( indent.size() ) ); + iterator itEnd = it+width; + iterator itNext = _str.end(); + + iterator itNewLine = std::find( it, itEnd, '\n' ); + if( itNewLine != itEnd ) + itEnd = itNewLine; + + if( itEnd != strEnd ) { + bool foundWrapPoint = false; + iterator findIt = itEnd; + do { + if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) { + itEnd = findIt+1; + itNext = findIt+1; + foundWrapPoint = true; + } + else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) { + itEnd = findIt; + itNext = findIt; + foundWrapPoint = true; + } + else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) { + itNext = findIt+1; + itEnd = findIt; + foundWrapPoint = true; + } + if( findIt == it ) + break; + else + --findIt; + } + while( !foundWrapPoint ); + + if( !foundWrapPoint ) { + // No good wrap char, so we'll break mid word and add a hyphen + --itEnd; + itNext = itEnd; + suffix = "-"; } else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; + while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos ) + --itEnd; } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; } - } - } + lines.push_back( indent + std::string( it, itEnd ) + suffix ); - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); + if( indent.size() != _attr.indent ) + indent = std::string( _attr.indent, ' ' ); + it = itNext; + } } typedef std::vector::const_iterator const_iterator; @@ -5063,7 +5533,6 @@ namespace Catch { #include #include #include -#include namespace Catch { @@ -5330,8 +5799,9 @@ namespace Catch { } std::size_t matchedTests = 0; - TextAttributes nameAttr, tagsAttr; + TextAttributes nameAttr, descAttr, tagsAttr; nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + descAttr.setIndent( 4 ); tagsAttr.setIndent( 6 ); std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); @@ -5346,14 +5816,21 @@ namespace Catch { Colour colourGuard( colour ); Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( config.listExtraInfo() ) { + Catch::cout() << " " << testCaseInfo.lineInfo << std::endl; + std::string description = testCaseInfo.description; + if( description.empty() ) + description = "(NO DESCRIPTION)"; + Catch::cout() << Text( description, descAttr ) << std::endl; + } if( !testCaseInfo.tags.empty() ) Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; } if( !config.testSpec().hasFilters() ) - Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl; else - Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl; return matchedTests; } @@ -5368,7 +5845,13 @@ namespace Catch { ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Catch::cout() << testCaseInfo.name << std::endl; + if( startsWith( testCaseInfo.name, '#' ) ) + Catch::cout() << '"' << testCaseInfo.name << '"'; + else + Catch::cout() << testCaseInfo.name; + if ( config.listExtraInfo() ) + Catch::cout() << "\t@" << testCaseInfo.lineInfo; + Catch::cout() << std::endl; } return matchedTests; } @@ -5429,9 +5912,9 @@ namespace Catch { .setInitialIndent( 0 ) .setIndent( oss.str().size() ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); - Catch::cout() << oss.str() << wrapper << "\n"; + Catch::cout() << oss.str() << wrapper << '\n'; } - Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; return tagCounts.size(); } @@ -5450,9 +5933,9 @@ namespace Catch { .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); Catch::cout() << " " << it->first - << ":" + << ':' << std::string( maxNameLen - it->first.size() + 2, ' ' ) - << wrapper << "\n"; + << wrapper << '\n'; } Catch::cout() << std::endl; return factories.size(); @@ -5460,7 +5943,7 @@ namespace Catch { inline Option list( Config const& config ) { Option listedCount; - if( config.listTests() ) + if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) ) listedCount = listedCount.valueOr(0) + listTests( config ); if( config.listTestNamesOnly() ) listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); @@ -5479,19 +5962,32 @@ namespace Catch { // #included from: catch_test_case_tracker.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED -#include +#include #include #include #include +#include + +CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS namespace Catch { namespace TestCaseTracking { + struct NameAndLocation { + std::string name; + SourceLineInfo location; + + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) + : name( _name ), + location( _location ) + {} + }; + struct ITracker : SharedImpl<> { virtual ~ITracker(); // static queries - virtual std::string name() const = 0; + virtual NameAndLocation const& nameAndLocation() const = 0; // dynamic queries virtual bool isComplete() const = 0; // Successfully completed or failed @@ -5507,7 +6003,7 @@ namespace TestCaseTracking { virtual void markAsNeedingAnotherRun() = 0; virtual void addChild( Ptr const& child ) = 0; - virtual ITracker* findChild( std::string const& name ) = 0; + virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0; virtual void openChild() = 0; // Debug/ checking @@ -5515,7 +6011,7 @@ namespace TestCaseTracking { virtual bool isIndexTracker() const = 0; }; - class TrackerContext { + class TrackerContext { enum RunState { NotStarted, @@ -5577,30 +6073,32 @@ namespace TestCaseTracking { Failed }; class TrackerHasName { - std::string m_name; + NameAndLocation m_nameAndLocation; public: - TrackerHasName( std::string const& name ) : m_name( name ) {} + TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} bool operator ()( Ptr const& tracker ) { - return tracker->name() == m_name; + return + tracker->nameAndLocation().name == m_nameAndLocation.name && + tracker->nameAndLocation().location == m_nameAndLocation.location; } }; typedef std::vector > Children; - std::string m_name; + NameAndLocation m_nameAndLocation; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; CycleState m_runState; public: - TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) - : m_name( name ), + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : m_nameAndLocation( nameAndLocation ), m_ctx( ctx ), m_parent( parent ), m_runState( NotStarted ) {} virtual ~TrackerBase(); - virtual std::string name() const CATCH_OVERRIDE { - return m_name; + virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE { + return m_nameAndLocation; } virtual bool isComplete() const CATCH_OVERRIDE { return m_runState == CompletedSuccessfully || m_runState == Failed; @@ -5619,8 +6117,8 @@ namespace TestCaseTracking { m_children.push_back( child ); } - virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { - Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); return( it != m_children.end() ) ? it->get() : CATCH_NULL; @@ -5698,32 +6196,56 @@ namespace TestCaseTracking { }; class SectionTracker : public TrackerBase { + std::vector m_filters; public: - SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( name, ctx, parent ) - {} + SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ) + { + if( parent ) { + while( !parent->isSectionTracker() ) + parent = &parent->parent(); + + SectionTracker& parentSection = static_cast( *parent ); + addNextFilters( parentSection.m_filters ); + } + } virtual ~SectionTracker(); virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } - static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { SectionTracker* section = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); - if( ITracker* childTracker = currentTracker.findChild( name ) ) { + if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isSectionTracker() ); section = static_cast( childTracker ); } else { - section = new SectionTracker( name, ctx, ¤tTracker ); + section = new SectionTracker( nameAndLocation, ctx, ¤tTracker ); currentTracker.addChild( section ); } - if( !ctx.completedCycle() && !section->isComplete() ) { + if( !ctx.completedCycle() ) + section->tryOpen(); + return *section; + } + + void tryOpen() { + if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) + open(); + } - section->open(); + void addInitialFilters( std::vector const& filters ) { + if( !filters.empty() ) { + m_filters.push_back(""); // Root - should never be consulted + m_filters.push_back(""); // Test Case - not a section filter + m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); } - return *section; + } + void addNextFilters( std::vector const& filters ) { + if( filters.size() > 1 ) + m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); } }; @@ -5731,8 +6253,8 @@ namespace TestCaseTracking { int m_size; int m_index; public: - IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) - : TrackerBase( name, ctx, parent ), + IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( nameAndLocation, ctx, parent ), m_size( size ), m_index( -1 ) {} @@ -5740,17 +6262,17 @@ namespace TestCaseTracking { virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } - static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { IndexTracker* tracker = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); - if( ITracker* childTracker = currentTracker.findChild( name ) ) { + if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isIndexTracker() ); tracker = static_cast( childTracker ); } else { - tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size ); currentTracker.addChild( tracker ); } @@ -5778,7 +6300,7 @@ namespace TestCaseTracking { }; inline ITracker& TrackerContext::startRun() { - m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL ); m_currentTracker = CATCH_NULL; m_runState = Executing; return *m_rootTracker; @@ -5793,40 +6315,144 @@ using TestCaseTracking::IndexTracker; } // namespace Catch +CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS + // #included from: catch_fatal_condition.hpp #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED namespace Catch { - // Report the error condition then exit the process - inline void fatal( std::string const& message, int exitCode ) { + // Report the error condition + inline void reportFatal( std::string const& message ) { IContext& context = Catch::getCurrentContext(); IResultCapture* resultCapture = context.getResultCapture(); resultCapture->handleFatalErrorCondition( message ); - - if( Catch::alwaysTrue() ) // avoids "no return" warnings - exit( exitCode ); } } // namespace Catch #if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// +// #included from: catch_windows_h_proxy.h + +#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED + +#ifdef CATCH_DEFINES_NOMINMAX +# define NOMINMAX +#endif +#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +#ifdef CATCH_DEFINES_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + + +# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + struct FatalConditionHandler { + void reset() {} + }; +} + +# else // CATCH_CONFIG_WINDOWS_SEH is defined namespace Catch { + struct SignalDefs { DWORD id; const char* name; }; + extern SignalDefs signalDefs[]; + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + SignalDefs signalDefs[] = { + { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, + { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, + { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, + { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, + }; + struct FatalConditionHandler { - void reset() {} - }; + + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { + reportFatal(signalDefs[i].name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + FatalConditionHandler() { + isSet = true; + // 32k seems enough for Catch to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + exceptionHandlerHandle = CATCH_NULL; + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } + + static void reset() { + if (isSet) { + // Unregister handler and restore the old guarantee + RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetThreadStackGuarantee(&guaranteeSize); + exceptionHandlerHandle = CATCH_NULL; + isSet = false; + } + } + + ~FatalConditionHandler() { + reset(); + } + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; + + bool FatalConditionHandler::isSet = false; + ULONG FatalConditionHandler::guaranteeSize = 0; + PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL; } // namespace Catch +# endif // CATCH_CONFIG_WINDOWS_SEH + #else // Not Windows - assumed to be POSIX compatible ////////////////////////// +# if !defined(CATCH_CONFIG_POSIX_SIGNALS) + +namespace Catch { + struct FatalConditionHandler { + void reset() {} + }; +} + +# else // CATCH_CONFIG_POSIX_SIGNALS is defined + #include namespace Catch { - struct SignalDefs { int id; const char* name; }; + struct SignalDefs { + int id; + const char* name; + }; extern SignalDefs signalDefs[]; SignalDefs signalDefs[] = { { SIGINT, "SIGINT - Terminal interrupt signal" }, @@ -5835,37 +6461,70 @@ namespace Catch { { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, { SIGTERM, "SIGTERM - Termination request signal" }, { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } - }; + }; struct FatalConditionHandler { + static bool isSet; + static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)]; + static stack_t oldSigStack; + static char altStackMem[SIGSTKSZ]; + static void handleSignal( int sig ) { - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) - if( sig == signalDefs[i].id ) - fatal( signalDefs[i].name, -sig ); - fatal( "", -sig ); + std::string name = ""; + for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + SignalDefs &def = signalDefs[i]; + if (sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise( sig ); } - FatalConditionHandler() : m_isSet( true ) { - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) - signal( signalDefs[i].id, handleSignal ); + FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = SIGSTKSZ; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { 0 }; + + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } } + ~FatalConditionHandler() { reset(); } - void reset() { - if( m_isSet ) { - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) - signal( signalDefs[i].id, SIG_DFL ); - m_isSet = false; + static void reset() { + if( isSet ) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { + sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL); + } + // Return the old stack + sigaltstack(&oldSigStack, CATCH_NULL); + isSet = false; } } - - bool m_isSet; }; + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; + } // namespace Catch +# endif // CATCH_CONFIG_POSIX_SIGNALS + #endif // not Windows #include @@ -5896,6 +6555,29 @@ namespace Catch { std::string& m_targetString; }; + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes and cannot use StreamRedirect on its own + class StdErrRedirect { + public: + StdErrRedirect(std::string& targetString) + :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()), + m_targetString(targetString){ + cerr().rdbuf(m_oss.rdbuf()); + clog().rdbuf(m_oss.rdbuf()); + } + ~StdErrRedirect() { + m_targetString += m_oss.str(); + cerr().rdbuf(m_cerrBuf); + clog().rdbuf(m_clogBuf); + } + private: + std::streambuf* m_cerrBuf; + std::streambuf* m_clogBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { @@ -5910,7 +6592,8 @@ namespace Catch { m_context( getCurrentMutableContext() ), m_activeTestCase( CATCH_NULL ), m_config( _config ), - m_reporter( reporter ) + m_reporter( reporter ), + m_shouldReportUnexpected ( true ) { m_context.setRunner( this ); m_context.setConfig( m_config ); @@ -5942,10 +6625,12 @@ namespace Catch { m_activeTestCase = &testCase; do { - m_trackerContext.startRun(); + ITracker& rootTracker = m_trackerContext.startRun(); + assert( rootTracker.isSectionTracker() ); + static_cast( rootTracker ).addInitialFilters( m_config->getSectionsToRun() ); do { m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) ); runCurrentTest( redirectedCout, redirectedCerr ); } while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); @@ -5983,26 +6668,44 @@ namespace Catch { m_totals.assertions.passed++; } else if( !result.isOk() ) { - m_totals.assertions.failed++; + if( m_activeTestCase->getTestCaseInfo().okToFail() ) + m_totals.assertions.failedButOk++; + else + m_totals.assertions.failed++; } - if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) - m_messages.clear(); + // We have no use for the return value (whether messages should be cleared), because messages were made scoped + // and should be let to clear themselves out. + static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); // Reset working state m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); m_lastResult = result; } + virtual bool lastAssertionPassed() + { + return m_totals.assertions.passed == (m_prevPassed + 1); + } + + virtual void assertionPassed() + { + m_totals.assertions.passed++; + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; + m_lastAssertionInfo.macroName = ""; + } + + virtual void assertionRun() + { + m_prevPassed = m_totals.assertions.passed; + } + virtual bool sectionStarted ( SectionInfo const& sectionInfo, Counts& assertions ) { - std::ostringstream oss; - oss << sectionInfo.name << "@" << sectionInfo.lineInfo; - - ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) ); if( !sectionTracker.isOpen() ) return false; m_activeSections.push_back( §ionTracker ); @@ -6061,18 +6764,26 @@ namespace Catch { virtual std::string getCurrentTestName() const { return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name - : ""; + : std::string(); } virtual const AssertionResult* getLastResult() const { return &m_lastResult; } + virtual void exceptionEarlyReported() { + m_shouldReportUnexpected = false; + } + virtual void handleFatalErrorCondition( std::string const& message ) { - ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); - resultBuilder.setResultType( ResultWas::FatalErrorCondition ); - resultBuilder << message; - resultBuilder.captureExpression(); + // Don't rebuild the result -- the stringification itself can cause more fatal errors + // Instead, fake a result data. + AssertionResultData tempResult; + tempResult.resultType = ResultWas::FatalErrorCondition; + tempResult.message = message; + AssertionResult result(m_lastAssertionInfo, tempResult); + + getResultCapture().assertionEnded(result); handleUnfinishedSections(); @@ -6089,13 +6800,14 @@ namespace Catch { Totals deltaTotals; deltaTotals.testCases.failed = 1; + deltaTotals.assertions.failed = 1; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, - "", - "", + std::string(), + std::string(), false ) ); m_totals.testCases.failed++; - testGroupEnded( "", m_totals, 1, 1 ); + testGroupEnded( std::string(), m_totals, 1, 1 ); m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); } @@ -6113,6 +6825,7 @@ namespace Catch { m_reporter->sectionStarting( testCaseSection ); Counts prevAssertions = m_totals.assertions; double duration = 0; + m_shouldReportUnexpected = true; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); @@ -6122,7 +6835,7 @@ namespace Catch { timer.start(); if( m_reporter->getPreferences().shouldRedirectStdOut ) { StreamRedirect coutRedir( Catch::cout(), redirectedCout ); - StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + StdErrRedirect errRedir( redirectedCerr ); invokeActiveTestCase(); } else { @@ -6134,7 +6847,11 @@ namespace Catch { // This just means the test was aborted due to failure } catch(...) { - makeUnexpectedResultBuilder().useActiveException(); + // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions + // are reported without translation at the point of origin. + if (m_shouldReportUnexpected) { + makeUnexpectedResultBuilder().useActiveException(); + } } m_testCaseTracker->close(); handleUnfinishedSections(); @@ -6143,12 +6860,6 @@ namespace Catch { Counts assertions = m_totals.assertions - prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); - if( testCaseInfo.okToFail() ) { - std::swap( assertions.failedButOk, assertions.failed ); - m_totals.assertions.failed -= assertions.failedButOk; - m_totals.assertions.failedButOk += assertions.failedButOk; - } - SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); m_reporter->sectionEnded( testCaseSectionStats ); } @@ -6162,9 +6873,9 @@ namespace Catch { private: ResultBuilder makeUnexpectedResultBuilder() const { - return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + return ResultBuilder( m_lastAssertionInfo.macroName, m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.capturedExpression, m_lastAssertionInfo.resultDisposition ); } @@ -6194,6 +6905,8 @@ namespace Catch { std::vector m_unfinishedSections; std::vector m_activeSections; TrackerContext m_trackerContext; + size_t m_prevPassed; + bool m_shouldReportUnexpected; }; IResultCapture& getResultCapture() { @@ -6215,7 +6928,7 @@ namespace Catch { Version( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, - std::string const& _branchName, + char const * const _branchName, unsigned int _buildNumber ); unsigned int const majorVersion; @@ -6223,7 +6936,7 @@ namespace Catch { unsigned int const patchNumber; // buildNumber is only used if branchName is not null - std::string const branchName; + char const * const branchName; unsigned int const buildNumber; friend std::ostream& operator << ( std::ostream& os, Version const& version ); @@ -6232,7 +6945,7 @@ namespace Catch { void operator=( Version const& ); }; - extern Version libraryVersion; + inline Version libraryVersion(); } #include @@ -6251,10 +6964,14 @@ namespace Catch { return reporter; } +#if !defined(CATCH_CONFIG_DEFAULT_REPORTER) +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif + Ptr makeReporter( Ptr const& config ) { std::vector reporters = config->getReporterNames(); if( reporters.empty() ) - reporters.push_back( "console" ); + reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER ); Ptr reporter; for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); @@ -6314,11 +7031,11 @@ namespace Catch { if( lastSlash != std::string::npos ) filename = filename.substr( lastSlash+1 ); - std::string::size_type lastDot = filename.find_last_of( "." ); + std::string::size_type lastDot = filename.find_last_of( '.' ); if( lastDot != std::string::npos ) filename = filename.substr( 0, lastDot ); - tags.insert( "#" + filename ); + tags.insert( '#' + filename ); setTags( test, tags ); } } @@ -6344,11 +7061,18 @@ namespace Catch { } void showHelp( std::string const& processName ) { - Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + Catch::cout() << "\nCatch v" << libraryVersion() << "\n"; m_cli.usage( Catch::cout(), processName ); Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } + void libIdentify() { + Catch::cout() + << std::left << std::setw(16) << "description: " << "A Catch test executable\n" + << std::left << std::setw(16) << "category: " << "testframework\n" + << std::left << std::setw(16) << "framework: " << "Catch Test\n" + << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; + } int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { @@ -6356,6 +7080,8 @@ namespace Catch { m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); if( m_configData.showHelp ) showHelp( m_configData.processName ); + if( m_configData.libIdentify ) + libIdentify(); m_config.reset(); } catch( std::exception& ex ) { @@ -6385,29 +7111,43 @@ namespace Catch { return returnCode; } - int run() { - if( m_configData.showHelp ) - return 0; + #if defined(WIN32) && defined(UNICODE) + int run( int argc, wchar_t const* const* const argv ) { - try - { - config(); // Force config to be constructed + char **utf8Argv = new char *[ argc ]; - seedRng( *m_config ); + for ( int i = 0; i < argc; ++i ) { + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); - if( m_configData.filenamesAsTags ) - applyFilenamesAsTags( *m_config ); + utf8Argv[ i ] = new char[ bufSize ]; - // Handle list request - if( Option listed = list( config() ) ) - return static_cast( *listed ); + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); + } - return static_cast( runTests( m_config ).assertions.failed ); + int returnCode = applyCommandLine( argc, utf8Argv ); + if( returnCode == 0 ) + returnCode = run(); + + for ( int i = 0; i < argc; ++i ) + delete [] utf8Argv[ i ]; + + delete [] utf8Argv; + + return returnCode; + } + #endif + + int run() { + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before starting" << std::endl; + static_cast(std::getchar()); } - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return (std::numeric_limits::max)(); + int exitCode = runInternal(); + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; + static_cast(std::getchar()); } + return exitCode; } Clara::CommandLine const& cli() const { @@ -6425,6 +7165,32 @@ namespace Catch { return *m_config; } private: + + int runInternal() { + if( m_configData.showHelp || m_configData.libIdentify ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runTests( m_config ).assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + Clara::CommandLine m_cli; std::vector m_unusedTokens; ConfigData m_configData; @@ -6444,21 +7210,16 @@ namespace Catch { #include #include #include -#include #include -#ifdef CATCH_CPP14_OR_GREATER -#include -#endif - namespace Catch { struct RandomNumberGenerator { - typedef int result_type; + typedef std::ptrdiff_t result_type; result_type operator()( result_type n ) const { return std::rand() % n; } -#ifdef CATCH_CPP14_OR_GREATER +#ifdef CATCH_CONFIG_CPP11_SHUFFLE static constexpr result_type min() { return 0; } static constexpr result_type max() { return 1000000; } result_type operator()() const { return std::rand() % max(); } @@ -6466,7 +7227,7 @@ namespace Catch { template static void shuffle( V& vector ) { RandomNumberGenerator rng; -#ifdef CATCH_CPP14_OR_GREATER +#ifdef CATCH_CONFIG_CPP11_SHUFFLE std::shuffle( vector.begin(), vector.end(), rng ); #else std::random_shuffle( vector.begin(), vector.end(), rng ); @@ -6509,7 +7270,7 @@ namespace Catch { ss << Colour( Colour::Red ) << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n' << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; throw std::runtime_error(ss.str()); @@ -6541,7 +7302,7 @@ namespace Catch { virtual void registerTest( TestCase const& testCase ) { std::string name = testCase.getTestCaseInfo().name; - if( name == "" ) { + if( name.empty() ) { std::ostringstream oss; oss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( oss.str() ) ); @@ -6590,7 +7351,7 @@ namespace Catch { inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { std::string className = classOrQualifiedMethodName; - if( startsWith( className, "&" ) ) + if( startsWith( className, '&' ) ) { std::size_t lastColons = className.rfind( "::" ); std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); @@ -6737,6 +7498,26 @@ namespace Catch { }; } +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); + + private: + std::map m_registry; + }; + +} // end namespace Catch + namespace Catch { namespace { @@ -6758,6 +7539,9 @@ namespace Catch { virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { return m_exceptionTranslatorRegistry; } + virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE { + return m_tagAliasRegistry; + } public: // IMutableRegistryHub virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { @@ -6772,11 +7556,15 @@ namespace Catch { virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { m_exceptionTranslatorRegistry.registerTranslator( translator ); } + virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE { + m_tagAliasRegistry.add( alias, tag, lineInfo ); + } private: TestRegistry m_testCaseRegistry; ReporterRegistry m_reporterRegistry; ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + TagAliasRegistry m_tagAliasRegistry; }; // Single, global, instance @@ -6808,7 +7596,7 @@ namespace Catch { // #included from: catch_notimplemented_exception.hpp #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED -#include +#include namespace Catch { @@ -6880,7 +7668,7 @@ namespace Catch { m_ofs.open( filename.c_str() ); if( m_ofs.fail() ) { std::ostringstream oss; - oss << "Unable to open file: '" << filename << "'"; + oss << "Unable to open file: '" << filename << '\''; throw std::domain_error( oss.str() ); } } @@ -6922,6 +7710,9 @@ namespace Catch { std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { + return std::clog; + } #endif } @@ -6933,6 +7724,11 @@ namespace Catch { Context( Context const& ); void operator=( Context const& ); + public: + virtual ~Context() { + deleteAllValues( m_generatorsByTestName ); + } + public: // IContext virtual IResultCapture* getResultCapture() { return m_resultCapture; @@ -7016,6 +7812,23 @@ namespace Catch { // #included from: catch_console_colour_impl.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED +// #included from: catch_errno_guard.hpp +#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED + +#include + +namespace Catch { + + class ErrnoGuard { + public: + ErrnoGuard():m_oldErrno(errno){} + ~ErrnoGuard() { errno = m_oldErrno; } + private: + int m_oldErrno; + }; + +} + namespace Catch { namespace { @@ -7044,18 +7857,8 @@ namespace Catch { # endif #endif -#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#ifdef __AFXDLL -#include -#else -#include -#endif - +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + namespace Catch { namespace { @@ -7136,7 +7939,7 @@ namespace { case Colour::White: return setColour( "[0m" ); case Colour::Red: return setColour( "[0;31m" ); case Colour::Green: return setColour( "[0;32m" ); - case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Blue: return setColour( "[0;34m" ); case Colour::Cyan: return setColour( "[0;36m" ); case Colour::Yellow: return setColour( "[0;33m" ); case Colour::Grey: return setColour( "[1;30m" ); @@ -7161,6 +7964,7 @@ namespace { }; IColourImpl* platformColourInstance() { + ErrnoGuard guard; Ptr config = getCurrentContext().getConfig(); UseColour::YesOrNo colourMode = config ? config->useColour() @@ -7279,14 +8083,18 @@ namespace Catch { namespace Catch { - AssertionInfo::AssertionInfo( std::string const& _macroName, + AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){} + + AssertionInfo::AssertionInfo( char const * _macroName, SourceLineInfo const& _lineInfo, - std::string const& _capturedExpression, - ResultDisposition::Flags _resultDisposition ) + char const * _capturedExpression, + ResultDisposition::Flags _resultDisposition, + char const * _secondArg) : macroName( _macroName ), lineInfo( _lineInfo ), capturedExpression( _capturedExpression ), - resultDisposition( _resultDisposition ) + resultDisposition( _resultDisposition ), + secondArg( _secondArg ) {} AssertionResult::AssertionResult() {} @@ -7313,24 +8121,30 @@ namespace Catch { } bool AssertionResult::hasExpression() const { - return !m_info.capturedExpression.empty(); + return m_info.capturedExpression[0] != 0; } bool AssertionResult::hasMessage() const { return !m_resultData.message.empty(); } + std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) { + return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"') + ? capturedExpression + : std::string(capturedExpression) + ", " + secondArg; + } + std::string AssertionResult::getExpression() const { if( isFalseTest( m_info.resultDisposition ) ) - return "!" + m_info.capturedExpression; + return '!' + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); else - return m_info.capturedExpression; + return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); } std::string AssertionResult::getExpressionInMacro() const { - if( m_info.macroName.empty() ) - return m_info.capturedExpression; + if( m_info.macroName[0] == 0 ) + return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); else - return m_info.macroName + "( " + m_info.capturedExpression + " )"; + return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )"; } bool AssertionResult::hasExpandedExpression() const { @@ -7338,7 +8152,7 @@ namespace Catch { } std::string AssertionResult::getExpandedExpression() const { - return m_resultData.reconstructedExpression; + return m_resultData.reconstructExpression(); } std::string AssertionResult::getMessage() const { @@ -7352,15 +8166,25 @@ namespace Catch { return m_info.macroName; } + void AssertionResult::discardDecomposedExpression() const { + m_resultData.decomposedExpression = CATCH_NULL; + } + + void AssertionResult::expandDecomposedExpression() const { + m_resultData.reconstructExpression(); + } + } // end namespace Catch // #included from: catch_test_case_info.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED +#include + namespace Catch { inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, "." ) || + if( startsWith( tag, '.' ) || tag == "hide" || tag == "!hide" ) return TestCaseInfo::IsHidden; @@ -7370,25 +8194,23 @@ namespace Catch { return TestCaseInfo::ShouldFail; else if( tag == "!mayfail" ) return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; else return TestCaseInfo::None; } inline bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); } inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { if( isReservedTag( tag ) ) { - { - Colour colourGuard( Colour::Red ); - Catch::cerr() - << "Tag name [" << tag << "] not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n"; - } - { - Colour colourGuard( Colour::FileName ); - Catch::cerr() << _lineInfo << std::endl; - } - exit(1); + std::ostringstream ss; + ss << Colour(Colour::Red) + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n" + << Colour(Colour::FileName) + << _lineInfo << '\n'; + throw std::runtime_error(ss.str()); } } @@ -7444,7 +8266,7 @@ namespace Catch { std::ostringstream oss; for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { - oss << "[" << *it << "]"; + oss << '[' << *it << ']'; std::string lcaseTag = toLower( *it ); testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); testCaseInfo.lcaseTags.insert( lcaseTag ); @@ -7550,7 +8372,7 @@ namespace Catch { ( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, - std::string const& _branchName, + char const * const _branchName, unsigned int _buildNumber ) : majorVersion( _majorVersion ), minorVersion( _minorVersion ), @@ -7560,18 +8382,21 @@ namespace Catch { {} std::ostream& operator << ( std::ostream& os, Version const& version ) { - os << version.majorVersion << "." - << version.minorVersion << "." + os << version.majorVersion << '.' + << version.minorVersion << '.' << version.patchNumber; - - if( !version.branchName.empty() ) { - os << "-" << version.branchName - << "." << version.buildNumber; + // branchName is never null -> 0th char is \0 if it is empty + if (version.branchName[0]) { + os << '-' << version.branchName + << '.' << version.buildNumber; } return os; } - Version libraryVersion( 1, 5, 6, "", 0 ); + inline Version libraryVersion() { + static Version version( 1, 10, 0, "", 0 ); + return version; + } } @@ -7605,7 +8430,9 @@ namespace Catch { {} ScopedMessage::~ScopedMessage() { - getResultCapture().popScopedMessage( m_info ); + if ( !std::uncaught_exception() ){ + getResultCapture().popScopedMessage(m_info); + } } } // end namespace Catch @@ -7742,30 +8569,32 @@ namespace Catch #endif #ifdef CATCH_PLATFORM_WINDOWS -#include + #else + #include + #endif namespace Catch { namespace { #ifdef CATCH_PLATFORM_WINDOWS - uint64_t getCurrentTicks() { - static uint64_t hz=0, hzo=0; + UInt64 getCurrentTicks() { + static UInt64 hz=0, hzo=0; if (!hz) { QueryPerformanceFrequency( reinterpret_cast( &hz ) ); QueryPerformanceCounter( reinterpret_cast( &hzo ) ); } - uint64_t t; + UInt64 t; QueryPerformanceCounter( reinterpret_cast( &t ) ); return ((t-hzo)*1000000)/hz; } #else - uint64_t getCurrentTicks() { + UInt64 getCurrentTicks() { timeval t; gettimeofday(&t,CATCH_NULL); - return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif } @@ -7791,19 +8620,31 @@ namespace Catch { // #included from: catch_common.hpp #define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED +#include +#include + namespace Catch { bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); + } + bool startsWith( std::string const& s, char prefix ) { + return !s.empty() && s[0] == prefix; } bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); + } + bool endsWith( std::string const& s, char suffix ) { + return !s.empty() && s[s.size()-1] == suffix; } bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } + char toLowerCh(char c) { + return static_cast( std::tolower( c ) ); + } void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); } std::string toLower( std::string const& s ) { std::string lc = s; @@ -7815,7 +8656,7 @@ namespace Catch { std::string::size_type start = str.find_first_not_of( whitespaceChars ); std::string::size_type end = str.find_last_not_of( whitespaceChars ); - return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); } bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { @@ -7838,29 +8679,25 @@ namespace Catch { {} std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << " " << pluraliser.m_label; + os << pluraliser.m_count << ' ' << pluraliser.m_label; if( pluraliser.m_count != 1 ) - os << "s"; + os << 's'; return os; } - SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){} SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) : file( _file ), line( _line ) {} - SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) - : file( other.file ), - line( other.line ) - {} bool SourceLineInfo::empty() const { - return file.empty(); + return file[0] == '\0'; } bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { - return line == other.line && file == other.file; + return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); } bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { - return line < other.line || ( line == other.line && file < other.file ); + return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); } void seedRng( IConfig const& config ) { @@ -7873,16 +8710,16 @@ namespace Catch { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ - os << info.file << "(" << info.line << ")"; + os << info.file << '(' << info.line << ')'; #else - os << info.file << ":" << info.line; + os << info.file << ':' << info.line; #endif return os; } void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { std::ostringstream oss; - oss << locationInfo << ": Internal Catch error: '" << message << "'"; + oss << locationInfo << ": Internal Catch error: '" << message << '\''; if( alwaysTrue() ) throw std::logic_error( oss.str() ); } @@ -7909,6 +8746,10 @@ namespace Catch { m_timer.start(); } +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 +#endif Section::~Section() { if( m_sectionIncluded ) { SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); @@ -7918,6 +8759,9 @@ namespace Catch { getResultCapture().sectionEnded( endInfo ); } } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif // This indicates whether the section should be executed or not Section::operator bool() const { @@ -7929,8 +8773,6 @@ namespace Catch { // #included from: catch_debugger.hpp #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED -#include - #ifdef CATCH_PLATFORM_MAC #include @@ -7979,6 +8821,36 @@ namespace Catch { } } // namespace Catch +#elif defined(CATCH_PLATFORM_LINUX) + #include + #include + + namespace Catch{ + // The standard POSIX way of detecting a debugger is to attempt to + // ptrace() the process, but this needs to be done from a child and not + // this process itself to still allow attaching to this process later + // if wanted, so is rather heavy. Under Linux we have the PID of the + // "debugger" (which doesn't need to be gdb, of course, it could also + // be strace, for example) in /proc/$PID/status, so just get it from + // there instead. + bool isDebuggerActive(){ + // Libstdc++ has a bug, where std::ifstream sets errno to 0 + // This way our users can properly assert over errno values + ErrnoGuard guard; + std::ifstream in("/proc/self/status"); + for( std::string line; std::getline(in, line); ) { + static const int PREFIX_LEN = 11; + if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { + // We're traced if the PID is not 0 and no other PID starts + // with 0 digit, so it's enough to check for just a single + // character. + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } + + return false; + } + } // namespace Catch #elif defined(_MSC_VER) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { @@ -8000,7 +8872,7 @@ namespace Catch { #endif // Platform #ifdef CATCH_PLATFORM_WINDOWS - extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { void writeToDebugConsole( std::string const& text ) { ::OutputDebugStringA( text.c_str() ); @@ -8076,7 +8948,7 @@ std::string toString( std::string const& value ) { } } } - return "\"" + s + "\""; + return '"' + s + '"'; } std::string toString( std::wstring const& value ) { @@ -8097,19 +8969,19 @@ std::string toString( char* const value ) { std::string toString( const wchar_t* const value ) { - return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); } std::string toString( wchar_t* const value ) { - return Catch::toString( static_cast( value ) ); + return Catch::toString( static_cast( value ) ); } std::string toString( int value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ")"; + oss << " (0x" << std::hex << value << ')'; return oss.str(); } @@ -8117,7 +8989,7 @@ std::string toString( unsigned long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ")"; + oss << " (0x" << std::hex << value << ')'; return oss.str(); } @@ -8145,7 +9017,7 @@ std::string toString( const double value ) { return fpToString( value, 10 ); } std::string toString( const float value ) { - return fpToString( value, 5 ) + "f"; + return fpToString( value, 5 ) + 'f'; } std::string toString( bool value ) { @@ -8153,9 +9025,19 @@ std::string toString( bool value ) { } std::string toString( char value ) { - return value < ' ' - ? toString( static_cast( value ) ) - : Detail::makeString( value ); + if ( value == '\r' ) + return "'\\r'"; + if ( value == '\f' ) + return "'\\f'"; + if ( value == '\n' ) + return "'\\n'"; + if ( value == '\t' ) + return "'\\t'"; + if ( '\0' <= value && value < ' ' ) + return toString( static_cast( value ) ); + char chstr[] = "' '"; + chstr[1] = value; + return chstr; } std::string toString( signed char value ) { @@ -8171,14 +9053,14 @@ std::string toString( long long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ")"; + oss << " (0x" << std::hex << value << ')'; return oss.str(); } std::string toString( unsigned long long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ")"; + oss << " (0x" << std::hex << value << ')'; return oss.str(); } #endif @@ -8195,7 +9077,7 @@ std::string toString( std::nullptr_t ) { return "nil"; return "@" + toString([nsstring UTF8String]); } - std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + std::string toString( NSString * CATCH_ARC_STRONG & nsstring ) { if( !nsstring ) return "nil"; return "@" + toString([nsstring UTF8String]); @@ -8212,21 +9094,28 @@ std::string toString( std::nullptr_t ) { namespace Catch { - std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { - return secondArg.empty() || secondArg == "\"\"" - ? capturedExpression - : capturedExpression + ", " + secondArg; - } ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition, char const* secondArg ) - : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), + : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ), m_shouldDebugBreak( false ), - m_shouldThrow( false ) + m_shouldThrow( false ), + m_guardException( false ), + m_usedStream( false ) {} + ResultBuilder::~ResultBuilder() { +#if defined(CATCH_CONFIG_FAST_COMPILE) + if ( m_guardException ) { + stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + captureResult( ResultWas::ThrewException ); + getCurrentContext().getResultCapture()->exceptionEarlyReported(); + } +#endif + } + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { m_data.resultType = result; return *this; @@ -8235,27 +9124,27 @@ namespace Catch { m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; return *this; } - ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { - m_exprComponents.lhs = lhs; - return *this; - } - ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { - m_exprComponents.rhs = rhs; - return *this; - } - ResultBuilder& ResultBuilder::setOp( std::string const& op ) { - m_exprComponents.op = op; - return *this; - } - void ResultBuilder::endExpression() { - m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); - captureExpression(); + void ResultBuilder::endExpression( DecomposedExpression const& expr ) { + // Flip bool results if FalseTest flag is set + if( isFalseTest( m_assertionInfo.resultDisposition ) ) { + m_data.negate( expr.isBinaryExpression() ); + } + + getResultCapture().assertionRun(); + + if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok) + { + AssertionResult result = build( expr ); + handleResult( result ); + } + else + getResultCapture().assertionPassed(); } void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { m_assertionInfo.resultDisposition = resultDisposition; - m_stream.oss << Catch::translateActiveException(); + stream().oss << Catch::translateActiveException(); captureResult( ResultWas::ThrewException ); } @@ -8263,19 +9152,20 @@ namespace Catch { setResultType( resultType ); captureExpression(); } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { if( expectedMessage.empty() ) - captureExpectedException( Matchers::Impl::Generic::AllOf() ); + captureExpectedException( Matchers::Impl::MatchAllOf() ); else captureExpectedException( Matchers::Equals( expectedMessage ) ); } - void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase const& matcher ) { - assert( m_exprComponents.testFalse == false ); + assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); AssertionResultData data = m_data; data.resultType = ResultWas::Ok; - data.reconstructedExpression = m_assertionInfo.capturedExpression; + data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); std::string actualMessage = Catch::translateActiveException(); if( !matcher.match( actualMessage ) ) { @@ -8290,6 +9180,7 @@ namespace Catch { AssertionResult result = build(); handleResult( result ); } + void ResultBuilder::handleResult( AssertionResult const& result ) { getResultCapture().assertionEnded( result ); @@ -8301,7 +9192,17 @@ namespace Catch { m_shouldThrow = true; } } + void ResultBuilder::react() { +#if defined(CATCH_CONFIG_FAST_COMPILE) + if (m_shouldDebugBreak) { + /////////////////////////////////////////////////////////////////// + // To inspect the state during test, you need to go one level up the callstack + // To go back to the test and change execution, jump over the throw statement + /////////////////////////////////////////////////////////////////// + CATCH_BREAK_INTO_DEBUGGER(); + } +#endif if( m_shouldThrow ) throw Catch::TestFailureException(); } @@ -8311,43 +9212,35 @@ namespace Catch { AssertionResult ResultBuilder::build() const { - assert( m_data.resultType != ResultWas::Unknown ); + return build( *this ); + } + // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, + // a temporary DecomposedExpression, which in turn holds references to + // operands, possibly temporary as well. + // It should immediately be passed to handleResult; if the expression + // needs to be reported, its string expansion must be composed before + // the temporaries are destroyed. + AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const + { + assert( m_data.resultType != ResultWas::Unknown ); AssertionResultData data = m_data; - // Flip bool results if testFalse is set - if( m_exprComponents.testFalse ) { - if( data.resultType == ResultWas::Ok ) - data.resultType = ResultWas::ExpressionFailed; - else if( data.resultType == ResultWas::ExpressionFailed ) - data.resultType = ResultWas::Ok; - } - - data.message = m_stream.oss.str(); - data.reconstructedExpression = reconstructExpression(); - if( m_exprComponents.testFalse ) { - if( m_exprComponents.op == "" ) - data.reconstructedExpression = "!" + data.reconstructedExpression; - else - data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; - } + if(m_usedStream) + data.message = m_stream().oss.str(); + data.decomposedExpression = &expr; // for lazy reconstruction return AssertionResult( m_assertionInfo, data ); } - std::string ResultBuilder::reconstructExpression() const { - if( m_exprComponents.op == "" ) - return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; - else if( m_exprComponents.op == "matches" ) - return m_exprComponents.lhs + " " + m_exprComponents.rhs; - else if( m_exprComponents.op != "!" ) { - if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && - m_exprComponents.lhs.find("\n") == std::string::npos && - m_exprComponents.rhs.find("\n") == std::string::npos ) - return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; - else - return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; - } - else - return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + + void ResultBuilder::reconstructExpression( std::string& dest ) const { + dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); + } + + void ResultBuilder::setExceptionGuard() { + m_guardException = true; + } + void ResultBuilder::unsetExceptionGuard() { + m_guardException = false; } } // end namespace Catch @@ -8355,30 +9248,6 @@ namespace Catch { // #included from: catch_tag_alias_registry.hpp #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED -// #included from: catch_tag_alias_registry.h -#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED - -#include - -namespace Catch { - - class TagAliasRegistry : public ITagAliasRegistry { - public: - virtual ~TagAliasRegistry(); - virtual Option find( std::string const& alias ) const; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; - void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - static TagAliasRegistry& get(); - - private: - std::map m_registry; - }; - -} // end namespace Catch - -#include -#include - namespace Catch { TagAliasRegistry::~TagAliasRegistry() {} @@ -8406,44 +9275,120 @@ namespace Catch { return expandedTestSpec; } - void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { - if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) { std::ostringstream oss; - oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + oss << Colour( Colour::Red ) + << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" + << Colour( Colour::FileName ) + << lineInfo << '\n'; throw std::domain_error( oss.str().c_str() ); } if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { std::ostringstream oss; - oss << "error: tag alias, \"" << alias << "\" already registered.\n" - << "\tFirst seen at " << find(alias)->lineInfo << "\n" - << "\tRedefined at " << lineInfo; + oss << Colour( Colour::Red ) + << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " + << Colour( Colour::Red ) << find(alias)->lineInfo << '\n' + << Colour( Colour::Red ) << "\tRedefined at " + << Colour( Colour::FileName) << lineInfo << '\n'; throw std::domain_error( oss.str().c_str() ); } } - TagAliasRegistry& TagAliasRegistry::get() { - static TagAliasRegistry instance; - return instance; + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { + return getRegistryHub().getTagAliasRegistry(); } - ITagAliasRegistry::~ITagAliasRegistry() {} - ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } - RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { - try { - TagAliasRegistry::get().add( alias, tag, lineInfo ); - } - catch( std::exception& ex ) { - Colour colourGuard( Colour::Red ); - Catch::cerr() << ex.what() << std::endl; - exit(1); - } + getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo ); } } // end namespace Catch +// #included from: catch_matchers_string.hpp + +namespace Catch { +namespace Matchers { + + namespace StdString { + + CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string CasedString::adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + } + std::string CasedString::caseSensitivitySuffix() const { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : std::string(); + } + + StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) + : m_comparator( comparator ), + m_operation( operation ) { + } + + std::string StringMatcherBase::describe() const { + std::string description; + description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + + m_comparator.caseSensitivitySuffix().size()); + description += m_operation; + description += ": \""; + description += m_comparator.m_str; + description += "\""; + description += m_comparator.caseSensitivitySuffix(); + return description; + } + + EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} + + bool EqualsMatcher::match( std::string const& source ) const { + return m_comparator.adjustString( source ) == m_comparator.m_str; + } + + ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} + + bool ContainsMatcher::match( std::string const& source ) const { + return contains( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} + + bool StartsWithMatcher::match( std::string const& source ) const { + return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} + + bool EndsWithMatcher::match( std::string const& source ) const { + return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + } // namespace StdString + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + +} // namespace Matchers +} // namespace Catch // #included from: ../reporters/catch_reporter_multi.hpp #define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED @@ -8587,9 +9532,34 @@ Ptr addReporter( Ptr const& existingRepo #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED #include +#include +#include +#include namespace Catch { + namespace { + // Because formatting using c++ streams is stateful, drop down to C is required + // Alternatively we could use stringstream, but its performance is... not good. + std::string getFormattedDuration( double duration ) { + // Max exponent + 1 is required to represent the whole part + // + 1 for decimal point + // + 3 for the 3 decimal places + // + 1 for null terminator + const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; + char buffer[maxDoubleSize]; + + // Save previous errno, to prevent sprintf from overwriting it + ErrnoGuard guard; +#ifdef _MSC_VER + sprintf_s(buffer, "%.3f", duration); +#else + sprintf(buffer, "%.3f", duration); +#endif + return std::string(buffer); + } + } + struct StreamingReporterBase : SharedImpl { StreamingReporterBase( ReporterConfig const& _config ) @@ -8684,12 +9654,13 @@ namespace Catch { struct BySectionInfo { BySectionInfo( SectionInfo const& other ) : m_other( other ) {} - BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} bool operator() ( Ptr const& node ) const { - return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + return ((node->stats.sectionInfo.name == m_other.name) && + (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); } private: - void operator=( BySectionInfo const& ); + void operator=( BySectionInfo const& ); SectionInfo const& m_other; }; @@ -8745,6 +9716,12 @@ namespace Catch { assert( !m_sectionStack.empty() ); SectionNode& sectionNode = *m_sectionStack.back(); sectionNode.assertions.push_back( assertionStats ); + // AssertionResult holds a pointer to a temporary DecomposedExpression, + // which getExpandedExpression() calls to build the expression string. + // Our section stack copy of the assertionResult will likely outlive the + // temporary, so it must be expanded or discarded now to avoid calling + // a destroyed object later. + prepareExpandedExpression( sectionNode.assertions.back().assertionResult ); return true; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { @@ -8779,6 +9756,13 @@ namespace Catch { virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + virtual void prepareExpandedExpression( AssertionResult& result ) const { + if( result.isOk() ) + result.discardDecomposedExpression(); + else + result.expandDecomposedExpression(); + } + Ptr m_config; std::ostream& stream; std::vector m_assertions; @@ -8799,7 +9783,7 @@ namespace Catch { char const* getLineOfChars() { static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; if( !*line ) { - memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; } return line; @@ -8884,7 +9868,7 @@ namespace Catch { return new T( config ); } virtual std::string getDescription() const { - return ""; + return std::string(); } }; @@ -8902,9 +9886,13 @@ namespace Catch { #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +// Deprecated - use the form without INTERNAL_ #define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } +#define CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + // #included from: ../internal/catch_xmlwriter.hpp #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED @@ -8951,9 +9939,13 @@ namespace Catch { break; default: - // Escape control chars - based on contribution by @espenalb in PR #465 - if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) - os << "&#x" << std::uppercase << std::hex << static_cast( c ); + // Escape control chars - based on contribution by @espenalb in PR #465 and + // by @mrpi PR #588 + if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast( c ); + } else os << c; } @@ -9007,14 +9999,18 @@ namespace Catch { XmlWriter() : m_tagIsOpen( false ), m_needsNewline( false ), - m_os( &Catch::cout() ) - {} + m_os( Catch::cout() ) + { + writeDeclaration(); + } XmlWriter( std::ostream& os ) : m_tagIsOpen( false ), m_needsNewline( false ), - m_os( &os ) - {} + m_os( os ) + { + writeDeclaration(); + } ~XmlWriter() { while( !m_tags.empty() ) @@ -9024,7 +10020,7 @@ namespace Catch { XmlWriter& startElement( std::string const& name ) { ensureTagClosed(); newlineIfNecessary(); - stream() << m_indent << "<" << name; + m_os << m_indent << '<' << name; m_tags.push_back( name ); m_indent += " "; m_tagIsOpen = true; @@ -9041,24 +10037,25 @@ namespace Catch { newlineIfNecessary(); m_indent = m_indent.substr( 0, m_indent.size()-2 ); if( m_tagIsOpen ) { - stream() << "/>\n"; + m_os << "/>"; m_tagIsOpen = false; } else { - stream() << m_indent << "\n"; + m_os << m_indent << ""; } + m_os << std::endl; m_tags.pop_back(); return *this; } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { if( !name.empty() && !attribute.empty() ) - stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; return *this; } XmlWriter& writeAttribute( std::string const& name, bool attribute ) { - stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; return *this; } @@ -9074,8 +10071,8 @@ namespace Catch { bool tagWasOpen = m_tagIsOpen; ensureTagClosed(); if( tagWasOpen && indent ) - stream() << m_indent; - stream() << XmlEncode( text ); + m_os << m_indent; + m_os << XmlEncode( text ); m_needsNewline = true; } return *this; @@ -9083,39 +10080,39 @@ namespace Catch { XmlWriter& writeComment( std::string const& text ) { ensureTagClosed(); - stream() << m_indent << ""; + m_os << m_indent << ""; m_needsNewline = true; return *this; } + void writeStylesheetRef( std::string const& url ) { + m_os << "\n"; + } + XmlWriter& writeBlankLine() { ensureTagClosed(); - stream() << "\n"; + m_os << '\n'; return *this; } - void setStream( std::ostream& os ) { - m_os = &os; + void ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } } private: XmlWriter( XmlWriter const& ); void operator=( XmlWriter const& ); - std::ostream& stream() { - return *m_os; - } - - void ensureTagClosed() { - if( m_tagIsOpen ) { - stream() << ">\n"; - m_tagIsOpen = false; - } + void writeDeclaration() { + m_os << "\n"; } void newlineIfNecessary() { if( m_needsNewline ) { - stream() << "\n"; + m_os << std::endl; m_needsNewline = false; } } @@ -9124,28 +10121,17 @@ namespace Catch { bool m_needsNewline; std::vector m_tags; std::string m_indent; - std::ostream* m_os; + std::ostream& m_os; }; } -// #included from: catch_reenable_warnings.h - -#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED - -#ifdef __ICC -# pragma warning(pop) -#elif __clang__ -# pragma clang diagnostic pop -#elif defined __GNUC__ -# pragma GCC diagnostic pop -#endif - namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), + m_xml(_config.stream()), m_sectionDepth( 0 ) { m_reporterPrefs.shouldRedirectStdOut = true; @@ -9157,6 +10143,16 @@ namespace Catch { return "Reports test results as an XML document"; } + virtual std::string getStylesheetRef() const { + return std::string(); + } + + void writeSourceInfo( SourceLineInfo const& sourceInfo ) { + m_xml + .writeAttribute( "filename", sourceInfo.file ) + .writeAttribute( "line", sourceInfo.line ); + } + public: // StreamingReporterBase virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { @@ -9165,7 +10161,9 @@ namespace Catch { virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testRunStarting( testInfo ); - m_xml.setStream( stream ); + std::string stylesheetRef = getStylesheetRef(); + if( !stylesheetRef.empty() ) + m_xml.writeStylesheetRef( stylesheetRef ); m_xml.startElement( "Catch" ); if( !m_config->name().empty() ) m_xml.writeAttribute( "name", m_config->name() ); @@ -9179,10 +10177,16 @@ namespace Catch { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + m_xml.startElement( "TestCase" ) + .writeAttribute( "name", trim( testInfo.name ) ) + .writeAttribute( "description", testInfo.description ) + .writeAttribute( "tags", testInfo.tagsAsString ); + + writeSourceInfo( testInfo.lineInfo ); if ( m_config->showDurations() == ShowDurations::Always ) m_testCaseTimer.start(); + m_xml.ensureTagClosed(); } virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { @@ -9191,77 +10195,84 @@ namespace Catch { m_xml.startElement( "Section" ) .writeAttribute( "name", trim( sectionInfo.name ) ) .writeAttribute( "description", sectionInfo.description ); + writeSourceInfo( sectionInfo.lineInfo ); + m_xml.ensureTagClosed(); } } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { - const AssertionResult& assertionResult = assertionStats.assertionResult; - // Print any info messages in tags. - if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + AssertionResult const& result = assertionStats.assertionResult; + + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + + if( includeResults ) { + // Print any info messages in tags. for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); - it != itEnd; - ++it ) { + it != itEnd; + ++it ) { if( it->type == ResultWas::Info ) { m_xml.scopedElement( "Info" ) - .writeText( it->message ); + .writeText( it->message ); } else if ( it->type == ResultWas::Warning ) { m_xml.scopedElement( "Warning" ) - .writeText( it->message ); + .writeText( it->message ); } } } // Drop out if result was successful but we're not printing them. - if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + if( !includeResults && result.getResultType() != ResultWas::Warning ) return true; // Print the expression if there is one. - if( assertionResult.hasExpression() ) { + if( result.hasExpression() ) { m_xml.startElement( "Expression" ) - .writeAttribute( "success", assertionResult.succeeded() ) - .writeAttribute( "type", assertionResult.getTestMacroName() ) - .writeAttribute( "filename", assertionResult.getSourceInfo().file ) - .writeAttribute( "line", assertionResult.getSourceInfo().line ); + .writeAttribute( "success", result.succeeded() ) + .writeAttribute( "type", result.getTestMacroName() ); + + writeSourceInfo( result.getSourceInfo() ); m_xml.scopedElement( "Original" ) - .writeText( assertionResult.getExpression() ); + .writeText( result.getExpression() ); m_xml.scopedElement( "Expanded" ) - .writeText( assertionResult.getExpandedExpression() ); + .writeText( result.getExpandedExpression() ); } // And... Print a result applicable to each result type. - switch( assertionResult.getResultType() ) { + switch( result.getResultType() ) { case ResultWas::ThrewException: - m_xml.scopedElement( "Exception" ) - .writeAttribute( "filename", assertionResult.getSourceInfo().file ) - .writeAttribute( "line", assertionResult.getSourceInfo().line ) - .writeText( assertionResult.getMessage() ); + m_xml.startElement( "Exception" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); break; case ResultWas::FatalErrorCondition: - m_xml.scopedElement( "Fatal Error Condition" ) - .writeAttribute( "filename", assertionResult.getSourceInfo().file ) - .writeAttribute( "line", assertionResult.getSourceInfo().line ) - .writeText( assertionResult.getMessage() ); + m_xml.startElement( "FatalErrorCondition" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); break; case ResultWas::Info: m_xml.scopedElement( "Info" ) - .writeText( assertionResult.getMessage() ); + .writeText( result.getMessage() ); break; case ResultWas::Warning: // Warning will already have been written break; case ResultWas::ExplicitFailure: - m_xml.scopedElement( "Failure" ) - .writeText( assertionResult.getMessage() ); + m_xml.startElement( "Failure" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); break; default: break; } - if( assertionResult.hasExpression() ) + if( result.hasExpression() ) m_xml.endElement(); return true; @@ -9290,6 +10301,11 @@ namespace Catch { if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + if( !testCaseStats.stdOut.empty() ) + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); + if( !testCaseStats.stdErr.empty() ) + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + m_xml.endElement(); } @@ -9329,11 +10345,42 @@ namespace Catch { namespace Catch { + namespace { + std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z"); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &rawtime); +#else + std::tm* timeInfo; + timeInfo = std::gmtime(&rawtime); +#endif + + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + + } + class JunitReporter : public CumulativeReporterBase { public: JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), - xml( _config.stream() ) + xml( _config.stream() ), + unexpectedExceptions( 0 ), + m_okToFail( false ) { m_reporterPrefs.shouldRedirectStdOut = true; } @@ -9359,8 +10406,11 @@ namespace Catch { CumulativeReporterBase::testGroupStarting( groupInfo ); } + virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE { + m_okToFail = testCaseInfo.okToFail(); + } virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } @@ -9393,7 +10443,7 @@ namespace Catch { xml.writeAttribute( "time", "" ); else xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", "tbd" ); // !TBD + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); // Write test cases for( TestGroupNode::ChildNodes::const_iterator @@ -9428,7 +10478,7 @@ namespace Catch { SectionNode const& sectionNode ) { std::string name = trim( sectionNode.stats.sectionInfo.name ); if( !rootName.empty() ) - name = rootName + "/" + name; + name = rootName + '/' + name; if( !sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || @@ -9506,14 +10556,14 @@ namespace Catch { std::ostringstream oss; if( !result.getMessage().empty() ) - oss << result.getMessage() << "\n"; + oss << result.getMessage() << '\n'; for( std::vector::const_iterator it = stats.infoMessages.begin(), itEnd = stats.infoMessages.end(); it != itEnd; ++it ) if( it->type == ResultWas::Info ) - oss << it->message << "\n"; + oss << it->message << '\n'; oss << "at " << result.getSourceInfo(); xml.writeText( oss.str(), false ); @@ -9525,6 +10575,7 @@ namespace Catch { std::ostringstream stdOutForSuite; std::ostringstream stdErrForSuite; unsigned int unexpectedExceptions; + bool m_okToFail; }; INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) @@ -9534,6 +10585,9 @@ namespace Catch { // #included from: ../reporters/catch_reporter_console.hpp #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED +#include +#include + namespace Catch { struct ConsoleReporter : StreamingReporterBase { @@ -9548,7 +10602,7 @@ namespace Catch { } virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { - stream << "No test cases matched '" << spec << "'" << std::endl; + stream << "No test cases matched '" << spec << '\'' << std::endl; } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { @@ -9557,18 +10611,15 @@ namespace Catch { virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; - bool printInfoMessages = true; + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; - } + // Drop out if result was successful but we're not printing them. + if( !includeResults && result.getResultType() != ResultWas::Warning ) + return false; lazyPrint(); - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + AssertionPrinter printer( stream, _assertionStats, includeResults ); printer.print(); stream << std::endl; return true; @@ -9588,15 +10639,12 @@ namespace Catch { stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } + if( m_config->showDurations() == ShowDurations::Always ) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } if( m_headerPrinted ) { - if( m_config->showDurations() == ShowDurations::Always ) - stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; m_headerPrinted = false; } - else { - if( m_config->showDurations() == ShowDurations::Always ) - stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; - } StreamingReporterBase::sectionEnded( _sectionStats ); } @@ -9609,7 +10657,7 @@ namespace Catch { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; printTotals( _testGroupStats.totals ); - stream << "\n" << std::endl; + stream << '\n' << std::endl; } StreamingReporterBase::testGroupEnded( _testGroupStats ); } @@ -9661,7 +10709,11 @@ namespace Catch { case ResultWas::ThrewException: colour = Colour::Error; passOrFail = "FAILED"; - messageLabel = "due to unexpected exception with message"; + messageLabel = "due to unexpected exception with "; + if (_stats.infoMessages.size() == 1) + messageLabel += "message"; + if (_stats.infoMessages.size() > 1) + messageLabel += "messages"; break; case ResultWas::FatalErrorCondition: colour = Colour::Error; @@ -9701,13 +10753,13 @@ namespace Catch { printSourceInfo(); if( stats.totals.assertions.total() > 0 ) { if( result.isOk() ) - stream << "\n"; + stream << '\n'; printResultType(); printOriginalExpression(); printReconstructedExpression(); } else { - stream << "\n"; + stream << '\n'; } printMessage(); } @@ -9724,25 +10776,25 @@ namespace Catch { Colour colourGuard( Colour::OriginalExpression ); stream << " "; stream << result.getExpressionInMacro(); - stream << "\n"; + stream << '\n'; } } void printReconstructedExpression() const { if( result.hasExpandedExpression() ) { stream << "with expansion:\n"; Colour colourGuard( Colour::ReconstructedExpression ); - stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n'; } } void printMessage() const { if( !messageLabel.empty() ) - stream << messageLabel << ":" << "\n"; + stream << messageLabel << ':' << '\n'; for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); it != itEnd; ++it ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || it->type != ResultWas::Info ) - stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n'; } } void printSourceInfo() const { @@ -9774,10 +10826,10 @@ namespace Catch { } } void lazyPrintRunInfo() { - stream << "\n" << getLineOfChars<'~'>() << "\n"; + stream << '\n' << getLineOfChars<'~'>() << '\n'; Colour colour( Colour::SecondaryText ); stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion << " host application.\n" + << " is a Catch v" << libraryVersion() << " host application.\n" << "Run with -? for options\n\n"; if( m_config->rngSeed() != 0 ) @@ -9805,22 +10857,22 @@ namespace Catch { printHeaderString( it->name, 2 ); } - SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; if( !lineInfo.empty() ){ - stream << getLineOfChars<'-'>() << "\n"; + stream << getLineOfChars<'-'>() << '\n'; Colour colourGuard( Colour::FileName ); - stream << lineInfo << "\n"; + stream << lineInfo << '\n'; } - stream << getLineOfChars<'.'>() << "\n" << std::endl; + stream << getLineOfChars<'.'>() << '\n' << std::endl; } void printClosedHeader( std::string const& _name ) { printOpenHeader( _name ); - stream << getLineOfChars<'.'>() << "\n"; + stream << getLineOfChars<'.'>() << '\n'; } void printOpenHeader( std::string const& _name ) { - stream << getLineOfChars<'-'>() << "\n"; + stream << getLineOfChars<'-'>() << '\n'; { Colour colourGuard( Colour::Headers ); printHeaderString( _name ); @@ -9837,7 +10889,7 @@ namespace Catch { i = 0; stream << Text( _string, TextAttributes() .setIndent( indent+i) - .setInitialIndent( indent ) ) << "\n"; + .setInitialIndent( indent ) ) << '\n'; } struct SummaryColumn { @@ -9852,9 +10904,9 @@ namespace Catch { std::string row = oss.str(); for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { while( it->size() < row.size() ) - *it = " " + *it; + *it = ' ' + *it; while( it->size() > row.size() ) - row = " " + row; + row = ' ' + row; } rows.push_back( row ); return *this; @@ -9874,8 +10926,8 @@ namespace Catch { stream << Colour( Colour::ResultSuccess ) << "All tests passed"; stream << " (" << pluralise( totals.assertions.passed, "assertion" ) << " in " - << pluralise( totals.testCases.passed, "test case" ) << ")" - << "\n"; + << pluralise( totals.testCases.passed, "test case" ) << ')' + << '\n'; } else { @@ -9910,10 +10962,10 @@ namespace Catch { else if( value != "0" ) { stream << Colour( Colour::LightGrey ) << " | "; stream << Colour( it->colour ) - << value << " " << it->label; + << value << ' ' << it->label; } } - stream << "\n"; + stream << '\n'; } static std::size_t makeRatio( std::size_t number, std::size_t total ) { @@ -9949,10 +11001,10 @@ namespace Catch { else { stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); } - stream << "\n"; + stream << '\n'; } void printSummaryDivider() { - stream << getLineOfChars<'-'>() << "\n"; + stream << getLineOfChars<'-'>() << '\n'; } private: @@ -9987,11 +11039,10 @@ namespace Catch { } virtual void noMatchingTestCases( std::string const& spec ) { - stream << "No test cases matched '" << spec << "'" << std::endl; + stream << "No test cases matched '" << spec << '\'' << std::endl; } - virtual void assertionStarting( AssertionInfo const& ) { - } + virtual void assertionStarting( AssertionInfo const& ) {} virtual bool assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; @@ -10012,9 +11063,15 @@ namespace Catch { return true; } + virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE { + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) { printTotals( _testRunStats.totals ); - stream << "\n" << std::endl; + stream << '\n' << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } @@ -10114,26 +11171,26 @@ namespace Catch { void printSourceInfo() const { Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ":"; + stream << result.getSourceInfo() << ':'; } - void printResultType( Colour::Code colour, std::string passOrFail ) const { + void printResultType( Colour::Code colour, std::string const& passOrFail ) const { if( !passOrFail.empty() ) { { Colour colourGuard( colour ); - stream << " " << passOrFail; + stream << ' ' << passOrFail; } - stream << ":"; + stream << ':'; } } - void printIssue( std::string issue ) const { - stream << " " << issue; + void printIssue( std::string const& issue ) const { + stream << ' ' << issue; } void printExpressionWas() { if( result.hasExpression() ) { - stream << ";"; + stream << ';'; { Colour colour( dimColour() ); stream << " expression was:"; @@ -10144,7 +11201,7 @@ namespace Catch { void printOriginalExpression() const { if( result.hasExpression() ) { - stream << " " << result.getExpression(); + stream << ' ' << result.getExpression(); } } @@ -10160,7 +11217,7 @@ namespace Catch { void printMessage() { if ( itMessage != messages.end() ) { - stream << " '" << itMessage->message << "'"; + stream << " '" << itMessage->message << '\''; ++itMessage; } } @@ -10175,13 +11232,13 @@ namespace Catch { { Colour colourGuard( colour ); - stream << " with " << pluralise( N, "message" ) << ":"; + stream << " with " << pluralise( N, "message" ) << ':'; } for(; itMessage != itEnd; ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || itMessage->type != ResultWas::Info ) { - stream << " '" << itMessage->message << "'"; + stream << " '" << itMessage->message << '\''; if ( ++itMessage != itEnd ) { Colour colourGuard( dimColour() ); stream << " and"; @@ -10207,7 +11264,7 @@ namespace Catch { // - green: Passed [both/all] N tests cases with M assertions. std::string bothOrAll( std::size_t count ) const { - return count == 1 ? "" : count == 2 ? "both " : "all " ; + return count == 1 ? std::string() : count == 2 ? "both " : "all " ; } void printTotals( const Totals& totals ) const { @@ -10218,12 +11275,12 @@ namespace Catch { Colour colour( Colour::ResultError ); const std::string qualify_assertions_failed = totals.assertions.failed == totals.assertions.total() ? - bothOrAll( totals.assertions.failed ) : ""; + bothOrAll( totals.assertions.failed ) : std::string(); stream << "Failed " << bothOrAll( totals.testCases.failed ) << pluralise( totals.testCases.failed, "test case" ) << ", " "failed " << qualify_assertions_failed << - pluralise( totals.assertions.failed, "assertion" ) << "."; + pluralise( totals.assertions.failed, "assertion" ) << '.'; } else if( totals.assertions.total() == 0 ) { stream << @@ -10235,14 +11292,14 @@ namespace Catch { Colour colour( Colour::ResultError ); stream << "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; } else { Colour colour( Colour::ResultSuccess ); stream << "Passed " << bothOrAll( totals.testCases.passed ) << pluralise( totals.testCases.passed, "test case" ) << - " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; } } }; @@ -10298,11 +11355,7 @@ namespace Catch { TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} TestSpec::ExcludedPattern::~ExcludedPattern() {} - - Matchers::Impl::StdString::Equals::~Equals() {} - Matchers::Impl::StdString::Contains::~Contains() {} - Matchers::Impl::StdString::StartsWith::~StartsWith() {} - Matchers::Impl::StdString::EndsWith::~EndsWith() {} + Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {} void Config::dummy() {} @@ -10326,9 +11379,16 @@ namespace Catch { #ifndef __OBJC__ +#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +// Standard C/C++ Win32 Unicode wmain entry point +extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { +#else // Standard C/C++ main entry point int main (int argc, char * argv[]) { - return Catch::Session().run( argc, argv ); +#endif + + int result = Catch::Session().run( argc, argv ); + return ( result < 0xff ? result : 0xff ); } #else // __OBJC__ @@ -10346,7 +11406,7 @@ int main (int argc, char * const argv[]) { [pool drain]; #endif - return result; + return ( result < 0xff ? result : 0xff ); } #endif // __OBJC__ @@ -10362,33 +11422,43 @@ int main (int argc, char * const argv[]) { // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL -#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) -#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) +#if defined(CATCH_CONFIG_FAST_COMPILE) +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) +#else +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) +#endif + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) -#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) -#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) -#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) -#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) -#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) -#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) -#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) -#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) -#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) -#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) -#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) +#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) -#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) -#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) +#if defined(CATCH_CONFIG_FAST_COMPILE) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#else +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#endif -#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) -#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) -#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) -#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) -#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) #ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) @@ -10396,16 +11466,18 @@ int main (int argc, char * const argv[]) { #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) - #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) + #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #else #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) - #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) - #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) + #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) #endif #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) @@ -10431,50 +11503,63 @@ int main (int argc, char * const argv[]) { // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else -#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) -#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) +#if defined(CATCH_CONFIG_FAST_COMPILE) +#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) + +#else +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) +#endif + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) -#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) -#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) -#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) +#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) -#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) -#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) -#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) -#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) -#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) -#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) -#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) -#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) -#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) -#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) +#if defined(CATCH_CONFIG_FAST_COMPILE) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#else +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#endif -#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) -#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) -#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) -#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) -#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) #ifdef CATCH_CONFIG_VARIADIC_MACROS - #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) - #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) - #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) - #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) - #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) - #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) +#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) +#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #else - #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) +#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) - #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) - #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) + #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) #endif #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) @@ -10503,5 +11588,19 @@ int main (int argc, char * const argv[]) { using Catch::Detail::Approx; +// #included from: internal/catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED diff --git a/src/decompress/file_decomp.cc b/src/decompress/file_decomp.cc index 3e4ade1aa..29796a4da 100644 --- a/src/decompress/file_decomp.cc +++ b/src/decompress/file_decomp.cc @@ -429,8 +429,8 @@ TEST_CASE("File_Decomp_New", "[file_decomp]") REQUIRE(p_s->Total_Out == 0); REQUIRE(p_s->Avail_In == 0); REQUIRE(p_s->Avail_Out == 0); - REQUIRE(p_s->Next_In == NULL); - REQUIRE(p_s->Next_Out == NULL); + REQUIRE(p_s->Next_In == nullptr); + REQUIRE(p_s->Next_Out == nullptr); File_Decomp_Free(p_s); } diff --git a/src/decompress/file_decomp_pdf.cc b/src/decompress/file_decomp_pdf.cc index 5b2149993..218d551a9 100644 --- a/src/decompress/file_decomp_pdf.cc +++ b/src/decompress/file_decomp_pdf.cc @@ -73,7 +73,7 @@ #define CHR_SPACE ' ' #define CHR_NAME_SEP '/' -#define IS_WHITESPACE(c) ((strchr((const char*)WHITESPACE_STRING, (int)(c)) != NULL) || ((c) == 0)) +#define IS_WHITESPACE(c) ((strchr((const char*)WHITESPACE_STRING, (int)(c)) != nullptr) || ((c) == 0)) #define IS_EOL(c) (((c) == CHR_CR) || ((c) == CHR_LF)) /* Define the parser states */ diff --git a/src/detection/detect_trace.cc b/src/detection/detect_trace.cc index 22813b958..91e709827 100644 --- a/src/detection/detect_trace.cc +++ b/src/detection/detect_trace.cc @@ -24,18 +24,16 @@ #include "detect_trace.h" -#include -#include - #include "log/log.h" #include "main/snort_debug.h" #include "main/thread.h" +#include "protocols/packet.h" #include "utils/stats.h" #include "utils/util.h" -#include "packet_io/active.h" +#include "detection_options.h" #include "fp_create.h" -#include "treenodes.h" +#include "pattern_match_data.h" using namespace std; diff --git a/src/detection/detect_trace.h b/src/detection/detect_trace.h index e8c4cfec5..f90a0f4c4 100644 --- a/src/detection/detect_trace.h +++ b/src/detection/detect_trace.h @@ -26,8 +26,8 @@ #include "framework/cursor.h" #include "main/snort_types.h" -#include "detection_options.h" -#include "pattern_match_data.h" +struct detection_option_tree_node_t; +struct PatternMatchData; enum { diff --git a/src/detection/pattern_match_data.h b/src/detection/pattern_match_data.h index f9ba7069f..e0e995463 100644 --- a/src/detection/pattern_match_data.h +++ b/src/detection/pattern_match_data.h @@ -138,11 +138,5 @@ inline bool PatternMatchData::can_be_fp() const return true; } -// pmd related utilities -struct OptFpList; - -PatternMatchData* get_pmd(OptFpList*, int proto, RuleDirection); -bool is_fast_pattern_only(OptFpList*); - #endif diff --git a/src/filters/sfrf_test.cc b/src/filters/sfrf_test.cc index adfe42cb7..619554f1d 100644 --- a/src/filters/sfrf_test.cc +++ b/src/filters/sfrf_test.cc @@ -34,7 +34,7 @@ SNORT_CATCH_FORCED_INCLUSION_DEFINITION(sfrf_test); -#define IP_ANY NULL // used to get "unset" +#define IP_ANY nullptr // used to get "unset" #define IP4_SRC "1.2.3.4" #define IP4_DST "1.2.3.5" @@ -45,7 +45,6 @@ SNORT_CATCH_FORCED_INCLUSION_DEFINITION(sfrf_test); #define IP6_DST "1:2::9" #define IP6_NET "1:2::/32" #define IP6_EXT "2:2::8" -#define IP6_NONE NULL #define IP4_SET1 "[1.2.3.4,1.2.3.5]" #define IP4_SET2 "[1.2.0.0/16,![1.2.3.4,1.2.3.5]]" diff --git a/src/filters/sfthd_test.cc b/src/filters/sfthd_test.cc index 93a97dc24..09eed68b6 100644 --- a/src/filters/sfthd_test.cc +++ b/src/filters/sfthd_test.cc @@ -34,7 +34,7 @@ SNORT_CATCH_FORCED_INCLUSION_DEFINITION(sfthd_test); -#define IP_ANY NULL // used to get "unset" +#define IP_ANY nullptr // used to get "unset" #define IP4_SRC "1.2.3.4" #define IP4_DST "1.2.3.5" diff --git a/src/flow/flow_key.cc b/src/flow/flow_key.cc index 382ae682d..a04ac1e24 100644 --- a/src/flow/flow_key.cc +++ b/src/flow/flow_key.cc @@ -34,9 +34,11 @@ // icmp foo //------------------------------------------------------------------------- -static const ip::snort_in6_addr fixed_addr = { { { 0xFF, 0, 0, 0 } } }; +static const uint32_t empty_addr[4] = { 0, 0, 0, 0 }; +static const SfIp empty_ip4 = { (void*) &empty_addr, AF_INET }; +static const SfIp empty_ip6 = { (void*) &empty_addr, AF_INET6 }; -inline void FlowKey::update_icmp4(const SfIp*& srcIP, uint16_t& srcPort, +static inline void update_icmp4(const SfIp*& srcIP, uint16_t& srcPort, const SfIp*& dstIP, uint16_t& dstPort) { if (srcPort == ICMP_ECHOREPLY) @@ -49,18 +51,18 @@ inline void FlowKey::update_icmp4(const SfIp*& srcIP, uint16_t& srcPort, { dstPort = ICMP_ROUTER_SOLICIT; /* Treat ICMP router advertisement the same as solicitation */ srcPort = 0; - srcIP = (SfIp *)&fixed_addr; /* Matching src address to solicit dest address */ + srcIP = &empty_ip4; /* Matching src address to solicit dest address */ } else { /* otherwise, every ICMP type gets different key */ dstPort = 0; if (srcPort == ICMP_ROUTER_SOLICIT) - dstIP = (SfIp* )&fixed_addr; /* To get unique key, don't use multicast/broadcast addr (RFC 1256) */ + dstIP = &empty_ip4; /* To get unique key, don't use multicast/broadcast addr (RFC 1256) */ } } -inline void FlowKey::update_icmp6(const SfIp*& srcIP, uint16_t& srcPort, +static inline void update_icmp6(const SfIp*& srcIP, uint16_t& srcPort, const SfIp*& dstIP, uint16_t& dstPort) { if (srcPort == icmp::Icmp6Types::ECHO_REPLY) @@ -73,14 +75,14 @@ inline void FlowKey::update_icmp6(const SfIp*& srcIP, uint16_t& srcPort, { dstPort = icmp::Icmp6Types::ROUTER_SOLICITATION; /* Treat ICMPv6 router advertisement the same as solicitation */ srcPort = 0; - srcIP = (SfIp* )&fixed_addr; /* Matching src address to solicit dest address */ + srcIP = &empty_ip6; /* Matching src address to solicit dest address */ } else { /* otherwise, every ICMP type gets different key */ dstPort = 0; if (srcPort == icmp::Icmp6Types::ROUTER_SOLICITATION) - dstIP = (SfIp* )&fixed_addr; /* To get unique key, don't use multicast addr (RFC 4861) */ + dstIP = &empty_ip6; /* To get unique key, don't use multicast addr (RFC 4861) */ } } diff --git a/src/flow/flow_key.h b/src/flow/flow_key.h index ea83e9220..d4fca3b1e 100644 --- a/src/flow/flow_key.h +++ b/src/flow/flow_key.h @@ -82,11 +82,6 @@ private: const SfIp *srcIP, uint16_t srcPort, const SfIp *dstIP, uint16_t dstPort, uint32_t mplsId, bool order = true); - - void update_icmp4(const SfIp*& srcIP, uint16_t& srcPort, - const SfIp*& dstIP, uint16_t& dstPort); - void update_icmp6(const SfIp*& srcIP, uint16_t& srcPort, - const SfIp*& dstIP, uint16_t& dstPort); }; PADDING_GUARD_END diff --git a/src/framework/range.h b/src/framework/range.h index 80cf997a8..f42857eb1 100644 --- a/src/framework/range.h +++ b/src/framework/range.h @@ -43,9 +43,9 @@ public: // Warning: FragOffsetOption computes its hash function using all the data members of // RangeCheck. Any change to the following may require changes in ips_fragoffset.cc. - Op op; - long min; - long max; + Op op = MAX; + long min = 0; + long max = 0; bool operator==(const RangeCheck&) const; diff --git a/src/framework/value.cc b/src/framework/value.cc index c331b2a1d..f7d4d31f7 100644 --- a/src/framework/value.cc +++ b/src/framework/value.cc @@ -374,9 +374,8 @@ TEST_CASE("token test", "[Value]") CHECK(test_val.get_next_csv_token(test_str)); str_val = (const char *)test_str.c_str(); - CHECK((str_val !=nullptr)); + REQUIRE(str_val != nullptr); CHECK((strcmp(str_val,"123456")==0)); - } TEST_CASE("get as string", "[Value]") @@ -387,14 +386,13 @@ TEST_CASE("get as string", "[Value]") Value test_val(bool_val); str_val = (const char *)test_val.get_as_string(); - CHECK((str_val !=nullptr)); + REQUIRE(str_val != nullptr); CHECK((strcmp(str_val,"true")==0)); test_val.set(num_val); str_val = (const char *)test_val.get_as_string(); - CHECK((str_val !=nullptr)); + REQUIRE(str_val != nullptr); CHECK((strcmp(str_val,"6")==0)); - } diff --git a/src/lua/lua_stack_test.cc b/src/lua/lua_stack_test.cc index 5baab9ca1..ae82341da 100644 --- a/src/lua/lua_stack_test.cc +++ b/src/lua/lua_stack_test.cc @@ -218,6 +218,7 @@ static void test_cstring() s = nullptr; b = Lua::Stack::validate(L, -1, s); CHECK(b); + REQUIRE(s); CHECK(!strcmp(s, "foo")); } lua_pop(L, 1); @@ -230,6 +231,7 @@ static void test_cstring() s = nullptr; b = Lua::Stack::validate(L, -1, s, len); CHECK(b); + REQUIRE(s); CHECK(!strncmp(s, "f\0b", 3)); } lua_pop(L, 1); diff --git a/src/main.cc b/src/main.cc index 872deda19..618d1e266 100644 --- a/src/main.cc +++ b/src/main.cc @@ -127,7 +127,7 @@ public: void start(); void stop(); - bool queue_command(AnalyzerCommand*); + bool queue_command(AnalyzerCommand*, bool orphan = false); void reap_commands(); private: @@ -180,10 +180,14 @@ void Pig::stop() analyzer = nullptr; } -bool Pig::queue_command(AnalyzerCommand* ac) +bool Pig::queue_command(AnalyzerCommand* ac, bool orphan) { if (!analyzer || !athread) + { + if (orphan) + orphan_commands.push(ac); return false; + } #ifdef DEBUG_MSGS unsigned ac_ref_count = ac->get(); @@ -736,7 +740,7 @@ static void handle(Pig& pig, unsigned& swine, unsigned& pending_privileges) else { Snort::do_pidfile(); - pig.queue_command(new ACStart()); + pig.queue_command(new ACStart(), true); } break; @@ -761,7 +765,7 @@ static void handle(Pig& pig, unsigned& swine, unsigned& pending_privileges) else { Snort::do_pidfile(); - pig.queue_command(new ACRun(paused)); + pig.queue_command(new ACRun(paused), true); } break; diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index 4ee94edf1..9ff85ad42 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -50,6 +50,7 @@ #include "packet_io/sfdaq_config.h" #include "parser/parser.h" #include "parser/vars.h" +#include "ports/rule_port_tables.h" #include "profiler/profiler.h" #include "protocols/packet.h" #include "sfip/sf_ip.h" diff --git a/src/managers/codec_manager.cc b/src/managers/codec_manager.cc index 1ac0c2df4..251dcc8d4 100644 --- a/src/managers/codec_manager.cc +++ b/src/managers/codec_manager.cc @@ -43,7 +43,7 @@ std::array CodecManager::s_proto_map { { 0 } }; std::array CodecManager::s_protocols { - { 0 } + { nullptr } }; THREAD_LOCAL ProtocolId CodecManager::grinder_id = ProtocolId::ETHERTYPE_NOT_SET; diff --git a/src/network_inspectors/appid/appid_http_session.h b/src/network_inspectors/appid/appid_http_session.h index 5af7f1383..c5c66758e 100644 --- a/src/network_inspectors/appid/appid_http_session.h +++ b/src/network_inspectors/appid/appid_http_session.h @@ -47,50 +47,50 @@ public: AppIdSession* asd = nullptr; char* host = nullptr; - uint16_t host_buflen = 0; char* url = nullptr; char* uri = nullptr; - uint16_t uri_buflen = 0; char* via = nullptr; char* useragent = nullptr; - uint16_t useragent_buflen = 0; char* response_code = nullptr; - uint16_t response_code_buflen = 0; char* referer = nullptr; - uint16_t referer_buflen = 0; char* cookie = nullptr; - uint16_t cookie_buflen = 0; char* content_type = nullptr; - uint16_t content_type_buflen = 0; char* location = nullptr; - uint16_t location_buflen = 0; char* body = nullptr; - uint16_t body_buflen = 0; char* req_body = nullptr; - uint16_t req_body_buflen = 0; char* server = nullptr; char* x_working_with = nullptr; + SfIp* xffAddr = nullptr; + const char** xffPrecedence = nullptr; char* new_field[HTTP_FIELD_MAX + 1] = { nullptr }; - uint16_t new_field_len[HTTP_FIELD_MAX + 1] = { 0 }; - uint16_t fieldOffset[HTTP_FIELD_MAX + 1] = { 0 }; - uint16_t fieldEndOffset[HTTP_FIELD_MAX + 1] = { 0 }; - bool new_field_contents = false; - bool is_webdav = false; - bool chp_finished = false; AppId chp_candidate = APP_ID_NONE; AppId chp_alt_candidate = APP_ID_NONE; int chp_hold_flow = 0; - int ptype_req_counts[NUMBER_OF_PTYPES] = { 0 }; int total_found = 0; unsigned app_type_flags = 0; int num_matches = 0; int num_scans = 0; int get_offsets_from_rebuilt = 0; - bool skip_simple_detect = false; - SfIp* xffAddr = nullptr; - const char** xffPrecedence = nullptr; unsigned numXffFields = 0; + int ptype_req_counts[NUMBER_OF_PTYPES] = { 0 }; int ptype_scan_counts[NUMBER_OF_PTYPES] = { 0 }; + uint16_t host_buflen = 0; + uint16_t uri_buflen = 0; + uint16_t useragent_buflen = 0; + uint16_t response_code_buflen = 0; + uint16_t referer_buflen = 0; + uint16_t cookie_buflen = 0; + uint16_t content_type_buflen = 0; + uint16_t location_buflen = 0; + uint16_t body_buflen = 0; + uint16_t req_body_buflen = 0; + uint16_t new_field_len[HTTP_FIELD_MAX + 1] = { 0 }; + uint16_t fieldOffset[HTTP_FIELD_MAX + 1] = { 0 }; + uint16_t fieldEndOffset[HTTP_FIELD_MAX + 1] = { 0 }; + bool new_field_contents = false; + bool is_webdav = false; + bool chp_finished = false; + bool skip_simple_detect = false; #if RESPONSE_CODE_PACKET_THRESHHOLD unsigned response_code_packets = 0; diff --git a/src/network_inspectors/appid/detector_plugins/http_url_patterns.cc b/src/network_inspectors/appid/detector_plugins/http_url_patterns.cc index 8fd4c7731..b07630cac 100644 --- a/src/network_inspectors/appid/detector_plugins/http_url_patterns.cc +++ b/src/network_inspectors/appid/detector_plugins/http_url_patterns.cc @@ -1621,7 +1621,7 @@ bool HttpPatternMatchers::get_appid_from_url(char* host, const char* url, char** tMlpPattern query; char temp_ver[MAX_VERSION_SIZE]; temp_ver[0] = 0; - query.pattern = (uint8_t*)++q; + query.pattern = (const uint8_t*)++q; query.patternSize = strlen(q); match_query_elements(&query, &data->query, temp_ver, MAX_VERSION_SIZE); diff --git a/src/network_inspectors/appid/test/appid_http_event_test.cc b/src/network_inspectors/appid/test/appid_http_event_test.cc index 954470174..401a85b77 100644 --- a/src/network_inspectors/appid/test/appid_http_event_test.cc +++ b/src/network_inspectors/appid/test/appid_http_event_test.cc @@ -227,7 +227,7 @@ struct TestData const char* via = nullptr; }; -void run_event_handler(TestData test_data, TestData* expect_data = nullptr) +static void run_event_handler(TestData test_data, TestData* expect_data = nullptr) { HttpEvent event(nullptr); FakeHttpMsgHeader http_msg_header; diff --git a/src/network_inspectors/appid/test/appid_mock_http_session.h b/src/network_inspectors/appid/test/appid_mock_http_session.h index 13ddfe788..9e65d11e1 100644 --- a/src/network_inspectors/appid/test/appid_mock_http_session.h +++ b/src/network_inspectors/appid/test/appid_mock_http_session.h @@ -71,15 +71,15 @@ char const* RSP_BODY = "this is the body of the http response"; void init_hsession_new_fields(AppIdHttpSession* hsession) { hsession->new_field_contents = true; - hsession->new_field[REQ_AGENT_FID] = snort_strdup((char*)(USERAGENT)); - hsession->new_field[REQ_HOST_FID] = snort_strdup((char*)(HOST)); - hsession->new_field[REQ_REFERER_FID] = snort_strdup((char*)(REFERER)); - hsession->new_field[REQ_URI_FID] = snort_strdup((char*)(URI)); - hsession->new_field[REQ_COOKIE_FID] = snort_strdup((char*)(NEW_COOKIE)); - hsession->new_field[REQ_BODY_FID] = snort_strdup((char*)(REQ_BODY)); - hsession->new_field[RSP_CONTENT_TYPE_FID] = snort_strdup((char*)(CONTENT_TYPE)); - hsession->new_field[RSP_LOCATION_FID] = snort_strdup((char*)(LOCATION)); - hsession->new_field[RSP_BODY_FID] = snort_strdup((char*)(RSP_BODY)); + hsession->new_field[REQ_AGENT_FID] = snort_strdup(USERAGENT); + hsession->new_field[REQ_HOST_FID] = snort_strdup(HOST); + hsession->new_field[REQ_REFERER_FID] = snort_strdup(REFERER); + hsession->new_field[REQ_URI_FID] = snort_strdup(URI); + hsession->new_field[REQ_COOKIE_FID] = snort_strdup(NEW_COOKIE); + hsession->new_field[REQ_BODY_FID] = snort_strdup(REQ_BODY); + hsession->new_field[RSP_CONTENT_TYPE_FID] = snort_strdup(CONTENT_TYPE); + hsession->new_field[RSP_LOCATION_FID] = snort_strdup(LOCATION); + hsession->new_field[RSP_BODY_FID] = snort_strdup(RSP_BODY); } AppIdHttpSession* init_http_session(AppIdSession* asd) @@ -88,20 +88,20 @@ AppIdHttpSession* init_http_session(AppIdSession* asd) SfIp* ip = new SfIp; ip->pton(AF_INET, APPID_UT_XFF_IP_ADDR); hsession->xffAddr = ip; - hsession->content_type = snort_strdup((char*)(CONTENT_TYPE)); - hsession->cookie = snort_strdup((char*)(COOKIE)); - hsession->host = snort_strdup((char*)(HOST)); - hsession->location = snort_strdup((char*)(LOCATION)); - hsession->referer = snort_strdup((char*)(REFERER)); - hsession->response_code = snort_strdup((char*)(RESPONSE_CODE)); - hsession->server = snort_strdup((char*)(SERVER)); - hsession->url = snort_strdup((char*)(URL)); - hsession->uri = snort_strdup((char*)(URI)); - hsession->useragent = snort_strdup((char*)(USERAGENT)); - hsession->via = snort_strdup((char*)(VIA)); - hsession->x_working_with = snort_strdup((char*)(X_WORKING_WITH)); - hsession->body = snort_strdup((char*)(RSP_BODY)); - hsession->req_body = snort_strdup((char*)(REQ_BODY)); + hsession->content_type = snort_strdup(CONTENT_TYPE); + hsession->cookie = snort_strdup(COOKIE); + hsession->host = snort_strdup(HOST); + hsession->location = snort_strdup(LOCATION); + hsession->referer = snort_strdup(REFERER); + hsession->response_code = snort_strdup(RESPONSE_CODE); + hsession->server = snort_strdup(SERVER); + hsession->url = snort_strdup(URL); + hsession->uri = snort_strdup(URI); + hsession->useragent = snort_strdup(USERAGENT); + hsession->via = snort_strdup(VIA); + hsession->x_working_with = snort_strdup(X_WORKING_WITH); + hsession->body = snort_strdup(RSP_BODY); + hsession->req_body = snort_strdup(REQ_BODY); hsession->fieldOffset[REQ_URI_FID] = URI_OFFSET; hsession->fieldEndOffset[REQ_URI_FID] = URI_OFFSET + strlen(URI); hsession->fieldOffset[REQ_COOKIE_FID] = COOKIE_OFFSET; diff --git a/src/network_inspectors/appid/test/appid_mock_session.h b/src/network_inspectors/appid/test/appid_mock_session.h index 9a5150d3b..9a9f9ddf8 100644 --- a/src/network_inspectors/appid/test/appid_mock_session.h +++ b/src/network_inspectors/appid/test/appid_mock_session.h @@ -60,10 +60,10 @@ AppIdSession::AppIdSession(IpProtocol, const SfIp*, uint16_t) : FlowData(inspect service_port = APPID_UT_SERVICE_PORT; client.update_user(APPID_UT_ID, APPID_UT_USERNAME); - client.set_version((char*)APPID_UT_CLIENT_VERSION); + client.set_version(APPID_UT_CLIENT_VERSION); - service.set_vendor((char*)APPID_UT_SERVICE_VENDOR); - service.set_version((char*)APPID_UT_SERVICE_VERSION); + service.set_vendor(APPID_UT_SERVICE_VENDOR); + service.set_version(APPID_UT_SERVICE_VERSION); subtype = &APPID_UT_SERVICE_SUBTYPE; search_support_type = UNKNOWN_SEARCH_ENGINE; @@ -74,7 +74,7 @@ AppIdSession::AppIdSession(IpProtocol, const SfIp*, uint16_t) : FlowData(inspect service_ip.pton(AF_INET, APPID_UT_SERVICE_IP_ADDR); common.initiator_ip.pton(AF_INET, APPID_UT_INITIATOR_IP_ADDR); - netbios_name = (char*)snort_strdup(APPID_UT_NETBIOS_NAME); + netbios_name = snort_strdup(APPID_UT_NETBIOS_NAME); dsession = new DnsSession; dsession->host = (char*)APPID_ID_UT_DNS_HOST; diff --git a/src/network_inspectors/binder/binder.cc b/src/network_inspectors/binder/binder.cc index e80018376..334e14af4 100644 --- a/src/network_inspectors/binder/binder.cc +++ b/src/network_inspectors/binder/binder.cc @@ -203,7 +203,7 @@ bool Binding::check_service(const Flow* flow) const // binder is only evaluated once per flow and we need to capture the correct binding from // either side of the conversation template -Binding::DirResult directional_match(const When& when_src, const When& when_dst, +static Binding::DirResult directional_match(const When& when_src, const When& when_dst, const Traffic& traffic_src, const Traffic& traffic_dst, const Binding::DirResult dr, const Compare& compare) { diff --git a/src/network_inspectors/perf_monitor/csv_formatter.cc b/src/network_inspectors/perf_monitor/csv_formatter.cc index 9b92412ab..89b52a515 100644 --- a/src/network_inspectors/perf_monitor/csv_formatter.cc +++ b/src/network_inspectors/perf_monitor/csv_formatter.cc @@ -45,7 +45,12 @@ void CSVFormatter::finalize_fields() string section = section_names[i]; for( auto& field : field_names[i] ) - header += "," + section + "." + field; + { + header += ","; + header += section; + header += "."; + header += field; + } } header += "\n"; section_names.clear(); diff --git a/src/network_inspectors/perf_monitor/fbs_formatter.cc b/src/network_inspectors/perf_monitor/fbs_formatter.cc index 7ed024c10..30dd0cbd1 100644 --- a/src/network_inspectors/perf_monitor/fbs_formatter.cc +++ b/src/network_inspectors/perf_monitor/fbs_formatter.cc @@ -55,13 +55,13 @@ static string lowercase(string s) return s; } -void FbsFormatter::register_field(std::string name, PegCount* value) +void FbsFormatter::register_field(const std::string& name, PegCount* value) { non_offset_names.push_back(name); non_offset_values.push_back(value); } -void FbsFormatter::register_field(std::string name, const char* value) +void FbsFormatter::register_field(const std::string& name, const char* value) { FormatterValue fv; fv.s = value; @@ -71,7 +71,7 @@ void FbsFormatter::register_field(std::string name, const char* value) offset_values.push_back(fv); } -void FbsFormatter::register_field(std::string name, std::vector* value) +void FbsFormatter::register_field(const std::string& name, std::vector* value) { FormatterValue fv; fv.ipc = value; @@ -109,7 +109,7 @@ void FbsFormatter::commit_field_reorder() non_offset_values.clear(); } -void FbsFormatter::register_section(std::string section) +void FbsFormatter::register_section(const std::string& section) { commit_field_reorder(); PerfFormatter::register_section(section); diff --git a/src/network_inspectors/perf_monitor/fbs_formatter.h b/src/network_inspectors/perf_monitor/fbs_formatter.h index b72a4e6e1..04727402c 100644 --- a/src/network_inspectors/perf_monitor/fbs_formatter.h +++ b/src/network_inspectors/perf_monitor/fbs_formatter.h @@ -36,10 +36,10 @@ public: bool allow_append() override { return false; } - void register_section(std::string) override; - void register_field(std::string, PegCount*) override; - void register_field(std::string, const char*) override; - void register_field(std::string, std::vector*) override; + void register_section(const std::string&) override; + void register_field(const std::string&, PegCount*) override; + void register_field(const std::string&, const char*) override; + void register_field(const std::string&, std::vector*) override; void finalize_fields() override; void init_output(FILE*) override; void write(FILE*, time_t) override; diff --git a/src/network_inspectors/perf_monitor/perf_formatter.cc b/src/network_inspectors/perf_monitor/perf_formatter.cc index b01d39942..d967ca548 100644 --- a/src/network_inspectors/perf_monitor/perf_formatter.cc +++ b/src/network_inspectors/perf_monitor/perf_formatter.cc @@ -26,7 +26,7 @@ using namespace std; -void PerfFormatter::register_section(string name) +void PerfFormatter::register_section(const string& name) { types.push_back(vector()); values.push_back(vector()); @@ -37,7 +37,7 @@ void PerfFormatter::register_section(string name) last_section++; } -void PerfFormatter::register_field(string name, PegCount* val) +void PerfFormatter::register_field(const string& name, PegCount* val) { FormatterValue fv; fv.pc = val; @@ -48,7 +48,7 @@ void PerfFormatter::register_field(string name, PegCount* val) field_names[last_section].push_back(name); } -void PerfFormatter::register_field(string name, const char* val) +void PerfFormatter::register_field(const string& name, const char* val) { FormatterValue fv; fv.s = val; @@ -59,7 +59,7 @@ void PerfFormatter::register_field(string name, const char* val) field_names[last_section].push_back(name); } -void PerfFormatter::register_field(string name, vector* val) +void PerfFormatter::register_field(const string& name, vector* val) { FormatterValue fv; fv.ipc = val; diff --git a/src/network_inspectors/perf_monitor/perf_formatter.h b/src/network_inspectors/perf_monitor/perf_formatter.h index 5e891e7bf..da74636a8 100644 --- a/src/network_inspectors/perf_monitor/perf_formatter.h +++ b/src/network_inspectors/perf_monitor/perf_formatter.h @@ -79,10 +79,10 @@ public: virtual std::string get_tracker_name() final { return tracker_name; } - virtual void register_section(std::string); - virtual void register_field(std::string, PegCount*); - virtual void register_field(std::string, const char*); - virtual void register_field(std::string, std::vector*); + virtual void register_section(const std::string&); + virtual void register_field(const std::string&, PegCount*); + virtual void register_field(const std::string&, const char*); + virtual void register_field(const std::string&, std::vector*); virtual void finalize_fields() {} virtual void init_output(FILE*) {} virtual void write(FILE*, time_t) = 0; diff --git a/src/parser/parse_rule.h b/src/parser/parse_rule.h index 215894164..790daa248 100644 --- a/src/parser/parse_rule.h +++ b/src/parser/parse_rule.h @@ -44,9 +44,6 @@ void parse_rule_opt_end(SnortConfig*, const char* key, OptTreeNode*); OptTreeNode* parse_rule_open(SnortConfig*, RuleTreeNode&, bool stub = false); const char* parse_rule_close(SnortConfig*, RuleTreeNode&, OptTreeNode*); -bool is_fast_pattern_only(OptFpList*); -struct PatternMatchData* get_pmd(OptFpList*, int proto, RuleDirection); - int get_rule_count(); #endif diff --git a/src/parser/parser.h b/src/parser/parser.h index 54daa8769..95290d6e5 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -47,7 +47,6 @@ void SetRuleStates(SnortConfig*); void FreeRuleLists(SnortConfig*); void VarTablesFree(SnortConfig*); -void PortTablesFree(struct RulePortTables*); void parser_append_rules(const char*); diff --git a/src/search_engines/acsmx2.cc b/src/search_engines/acsmx2.cc index 8d34ef228..7796492c4 100644 --- a/src/search_engines/acsmx2.cc +++ b/src/search_engines/acsmx2.cc @@ -1758,7 +1758,7 @@ int acsm_search_dfa_full( if (ps[1]) \ { \ for ( mlist = MatchList[state]; \ - mlist!= NULL; \ + mlist!= nullptr; \ mlist = mlist->next ) \ { \ index = T - Tx; \ diff --git a/src/service_inspectors/ftp_telnet/ftp.cc b/src/service_inspectors/ftp_telnet/ftp.cc index 251ae0d19..eb02fc29e 100644 --- a/src/service_inspectors/ftp_telnet/ftp.cc +++ b/src/service_inspectors/ftp_telnet/ftp.cc @@ -243,7 +243,7 @@ static int ProcessFTPDataChanCmdsList( /* Add it to the list */ // note that struct includes 1 byte for null, so just add len FTPCmd = (FTP_CMD_CONF*)snort_calloc(sizeof(FTP_CMD_CONF)+strlen(cmd)); - strcpy(FTPCmd->cmd_name, cmd); + strncpy(FTPCmd->cmd_name, cmd, strlen(cmd) + 1); // FIXIT-L make sure pulled from server conf when used if not overridden //FTPCmd->max_param_len = ServerConf->def_max_param_len; diff --git a/src/service_inspectors/ftp_telnet/ftp_module.cc b/src/service_inspectors/ftp_telnet/ftp_module.cc index c99e5dbd0..1d3bc8cee 100644 --- a/src/service_inspectors/ftp_telnet/ftp_module.cc +++ b/src/service_inspectors/ftp_telnet/ftp_module.cc @@ -26,6 +26,8 @@ #include "log/messages.h" +#include "ftpp_si.h" + using namespace std; #define FTP_CLIENT "ftp_client" diff --git a/src/service_inspectors/ftp_telnet/ftp_module.h b/src/service_inspectors/ftp_telnet/ftp_module.h index d539527c7..9722abc3b 100644 --- a/src/service_inspectors/ftp_telnet/ftp_module.h +++ b/src/service_inspectors/ftp_telnet/ftp_module.h @@ -36,10 +36,8 @@ #define FTP_BOUNCE 8 #define FTP_EVASIVE_TELNET_CMD 9 -struct FtpStats; struct SnortConfig; -extern THREAD_LOCAL FtpStats ftstats; extern THREAD_LOCAL ProfileStats ftpPerfStats; //------------------------------------------------------------------------- diff --git a/src/service_inspectors/ftp_telnet/ftp_parse.cc b/src/service_inspectors/ftp_telnet/ftp_parse.cc index 5aab210e3..2f6332d66 100644 --- a/src/service_inspectors/ftp_telnet/ftp_parse.cc +++ b/src/service_inspectors/ftp_telnet/ftp_parse.cc @@ -607,7 +607,7 @@ int ProcessFTPCmdValidity( /* Add it to the list */ // note that struct includes 1 byte for null, so just add len FTPCmd = (FTP_CMD_CONF*)snort_calloc(sizeof(FTP_CMD_CONF)+strlen(cmd)); - strcpy(FTPCmd->cmd_name, cmd); + strncpy(FTPCmd->cmd_name, cmd, strlen(cmd) + 1); FTPCmd->max_param_len = ServerConf->def_max_param_len; ftp_cmd_lookup_add(ServerConf->cmd_lookup, cmd, strlen(cmd), FTPCmd); diff --git a/src/service_inspectors/ftp_telnet/telnet_module.cc b/src/service_inspectors/ftp_telnet/telnet_module.cc index 02ff56196..453a7baa4 100644 --- a/src/service_inspectors/ftp_telnet/telnet_module.cc +++ b/src/service_inspectors/ftp_telnet/telnet_module.cc @@ -26,6 +26,8 @@ #include +#include "ftpp_si.h" + using namespace std; //------------------------------------------------------------------------- diff --git a/src/service_inspectors/ftp_telnet/telnet_module.h b/src/service_inspectors/ftp_telnet/telnet_module.h index 44624310a..4b3917040 100644 --- a/src/service_inspectors/ftp_telnet/telnet_module.h +++ b/src/service_inspectors/ftp_telnet/telnet_module.h @@ -34,9 +34,7 @@ #define TEL_HELP "telnet inspection and normalization" struct SnortConfig; -struct TelnetStats; -extern THREAD_LOCAL TelnetStats tnstats; extern THREAD_LOCAL ProfileStats telnetPerfStats; class TelnetModule : public Module diff --git a/src/sfip/sf_ip.h b/src/sfip/sf_ip.h index a38bf6718..54d538710 100644 --- a/src/sfip/sf_ip.h +++ b/src/sfip/sf_ip.h @@ -34,6 +34,12 @@ struct SfCidr; struct SO_PUBLIC SfIp { + /* + * Constructors + */ + SfIp() = default; + SfIp(const void* src, int fam) { set(src, fam); } + /* * Modifiers */ diff --git a/src/sfip/sf_ipvar.cc b/src/sfip/sf_ipvar.cc index 1ccea0ad6..24d7bc527 100644 --- a/src/sfip/sf_ipvar.cc +++ b/src/sfip/sf_ipvar.cc @@ -1204,7 +1204,7 @@ TEST_CASE("SfIpVarCopyAddCompare", "[SfIpVar]") // add a negate node to original list node = sfipnode_alloc("!192.168.3.2", nullptr); - CHECK(node != NULL); + CHECK(node != nullptr); CHECK(SFIP_SUCCESS == sfvar_add_node(var1, node, 1)); print_var_list(var1->neg_head); CHECK(!strcmp("!192.168.3.2", sfipvar_test_buff)); @@ -1213,7 +1213,7 @@ TEST_CASE("SfIpVarCopyAddCompare", "[SfIpVar]") // add a node node = sfipnode_alloc("192.168.90.9", nullptr); - CHECK(node != NULL); + CHECK(node != nullptr); CHECK(SFIP_SUCCESS == sfvar_add_node(var1, node, 0)); print_var_list(var1->head); CHECK(!strcmp("192.168.0.1,192.168.0.2,192.168.5.0,192.168.90.9,255.255.248.0", @@ -1245,7 +1245,7 @@ TEST_CASE("SfIpVarAny", "[SfIpVar]") // create a list and add any to it node = sfipnode_alloc("any", nullptr); - CHECK(node != NULL); + CHECK(node != nullptr); CHECK(SFIP_SUCCESS == sfvar_add_node(var1, node, 0)); // after adding any, the original list should have any only diff --git a/src/sfrt/sfrt_test.cc b/src/sfrt/sfrt_test.cc index 38e0bb81a..0f54f07d9 100644 --- a/src/sfrt/sfrt_test.cc +++ b/src/sfrt/sfrt_test.cc @@ -75,7 +75,7 @@ static void test_sfrt_remove_after_insert() dir = sfrt_new(DIR_16_4x4_16x5_4x4, IPv6, num_entries + 1, 200); - CHECK(dir != NULL); // "sfrt_new()" + CHECK(dir != nullptr); // "sfrt_new()" for (index=0; indexip_str) - { - char* p; - char* ip2_str; - - ip.set(ip_entry->ip_str); - ip2_str = snort_strdup(ip_entry->ip_str); - p = strchr(ip2_str, '/'); - - if (p) - { - *p = 0; - } - ip2.set(ip2_str); - snort_free(ip2_str); - } + /*Parse IP*/ + ip.set(ip_entry->ip_str); + char* ip2_str = snort_strdup(ip_entry->ip_str); + char* p = strchr(ip2_str, '/'); + if (p) + *p = '\0'; + ip2.set(ip2_str); + snort_free(ip2_str); if ( s_debug ) { @@ -121,10 +112,10 @@ static void test_sfrt_remove_after_insert() if (result) printf("value input: %d, output: %d\n", ip_entry->value, *result); else - printf("value input: %d, output: NULL\n", ip_entry->value); + printf("value input: %d, output: nullptr\n", ip_entry->value); } - CHECK(result != NULL); // "sfrt_lookup()" + CHECK(result != nullptr); // "sfrt_lookup()" if ( s_debug ) { @@ -133,14 +124,14 @@ static void test_sfrt_remove_after_insert() } CHECK(sfrt_remove(&ip, ip.get_bits(), (void**)&result, RT_FAVOR_TIME, dir) == RT_SUCCESS); - CHECK(result != NULL); //sfrt_remove()" + CHECK(result != nullptr); //sfrt_remove()" val = *result; if ( s_debug ) printf("value expected: %d, actual: %d\n", ip_entry->value, val); CHECK(val == ip_entry->value); //sfrt_remove(): value return" - CHECK(sfrt_lookup(ip.get_addr(), dir) == NULL); // "sfrt_lookup(): value return" + CHECK(sfrt_lookup(ip.get_addr(), dir) == nullptr); // "sfrt_lookup(): value return" } if ( s_debug ) @@ -166,7 +157,7 @@ static void test_sfrt_remove_after_insert_all() dir = sfrt_new(DIR_16_4x4_16x5_4x4, IPv6, num_entries + 1, 200); - CHECK(dir != NULL); // "sfrt_new()" + CHECK(dir != nullptr); // "sfrt_new()" /*insert all entries*/ for (index=0; indexip_str) - { - char* p; - char* ip2_str; - - ip.set(ip_entry->ip_str); - - ip2_str = snort_strdup(ip_entry->ip_str); - p = strchr(ip2_str, '/'); - - if (p) - { - *p = 0; - } - ip2.set(ip2_str); - snort_free(ip2_str); - } + ip.set(ip_entry->ip_str); + char* ip2_str = snort_strdup(ip_entry->ip_str); + char* p = strchr(ip2_str, '/'); + if (p) + *p = '\0'; + ip2.set(ip2_str); + snort_free(ip2_str); CHECK(sfrt_insert(&ip, ip.get_bits(), &(ip_entry->value), RT_FAVOR_TIME, dir) == RT_SUCCESS); // "sfrt_insert()" @@ -203,7 +184,7 @@ static void test_sfrt_remove_after_insert_all() if ( s_debug ) printf("value input: %d, output: %d\n", ip_entry->value, result ? *result : -1); - CHECK(result != NULL); // "sfrt_lookup()" + CHECK(result != nullptr); // "sfrt_lookup()" } if ( s_debug ) @@ -221,8 +202,7 @@ static void test_sfrt_remove_after_insert_all() IP_entry* ip_entry = &(ip_lists[index]); /*Parse IP*/ - if (ip_entry->ip_str) - ip.set(ip_entry->ip_str); + ip.set(ip_entry->ip_str); CHECK(sfrt_remove(&ip, ip.get_bits(), (void**)&result, RT_FAVOR_TIME, dir) == RT_SUCCESS); @@ -238,8 +218,7 @@ static void test_sfrt_remove_after_insert_all() { ip_entry = &(ip_lists[index + 1]); /*Parse IP*/ - if (ip_entry->ip_str) - ip.set(ip_entry->ip_str); + ip.set(ip_entry->ip_str); CHECK(sfrt_lookup(ip.get_addr(), dir)); // "sfrt_lookup(): value return" } } diff --git a/src/stream/ip/ip_module.cc b/src/stream/ip/ip_module.cc index 4e05eff4f..0ccf02f87 100644 --- a/src/stream/ip/ip_module.cc +++ b/src/stream/ip/ip_module.cc @@ -24,6 +24,7 @@ #include "ip_module.h" +#include "ip_session.h" #include "stream_ip.h" using namespace std; diff --git a/src/stream/ip/ip_module.h b/src/stream/ip/ip_module.h index ccac251ad..6cb329408 100644 --- a/src/stream/ip/ip_module.h +++ b/src/stream/ip/ip_module.h @@ -79,7 +79,6 @@ struct IpStats }; extern const PegInfo ip_pegs[]; -extern THREAD_LOCAL struct IpStats ip_stats; extern THREAD_LOCAL ProfileStats ip_perf_stats; extern THREAD_LOCAL ProfileStats fragPerfStats; extern THREAD_LOCAL ProfileStats fragInsertPerfStats; diff --git a/src/stream/libtcp/tcp_segment_descriptor.cc b/src/stream/libtcp/tcp_segment_descriptor.cc index 6a6bca0a4..e5d69807a 100644 --- a/src/stream/libtcp/tcp_segment_descriptor.cc +++ b/src/stream/libtcp/tcp_segment_descriptor.cc @@ -53,11 +53,6 @@ TcpSegmentDescriptor::TcpSegmentDescriptor(Flow* flow, Packet* pkt, TcpEventLogg } } -TcpSegmentDescriptor::~TcpSegmentDescriptor() -{ - // TODO Auto-generated destructor stub -} - uint32_t TcpSegmentDescriptor::init_mss(uint16_t* value) { DebugMessage(DEBUG_STREAM_STATE, "Getting MSS...\n"); diff --git a/src/stream/libtcp/tcp_segment_descriptor.h b/src/stream/libtcp/tcp_segment_descriptor.h index 671c17b93..7365fc98b 100644 --- a/src/stream/libtcp/tcp_segment_descriptor.h +++ b/src/stream/libtcp/tcp_segment_descriptor.h @@ -31,7 +31,7 @@ class TcpSegmentDescriptor { public: TcpSegmentDescriptor(Flow*, Packet*, TcpEventLogger&); - virtual ~TcpSegmentDescriptor(); + virtual ~TcpSegmentDescriptor() = default; uint32_t init_mss(uint16_t* value); uint32_t init_wscale(uint16_t* value); diff --git a/src/stream/libtcp/tcp_state_handler.cc b/src/stream/libtcp/tcp_state_handler.cc index da61c18f6..931e77c44 100644 --- a/src/stream/libtcp/tcp_state_handler.cc +++ b/src/stream/libtcp/tcp_state_handler.cc @@ -49,11 +49,6 @@ TcpStateHandler::TcpStateHandler(TcpStreamTracker::TcpState state, TcpStateMachi //{ //} -TcpStateHandler::~TcpStateHandler() -{ - // TODO Auto-generated destructor stub -} - bool TcpStateHandler::do_pre_sm_packet_actions(TcpSegmentDescriptor&, TcpStreamTracker&) { return true; diff --git a/src/stream/libtcp/tcp_state_handler.h b/src/stream/libtcp/tcp_state_handler.h index 5fce59732..03b56fde0 100644 --- a/src/stream/libtcp/tcp_state_handler.h +++ b/src/stream/libtcp/tcp_state_handler.h @@ -32,7 +32,7 @@ class TcpStateHandler { public: TcpStateHandler(TcpStreamTracker::TcpState, TcpStateMachine&); - virtual ~TcpStateHandler(); + virtual ~TcpStateHandler() = default; virtual bool eval(TcpSegmentDescriptor&, TcpStreamTracker&); diff --git a/src/stream/libtcp/tcp_stream_tracker.cc b/src/stream/libtcp/tcp_stream_tracker.cc index d54f009ef..d6601bd67 100644 --- a/src/stream/libtcp/tcp_stream_tracker.cc +++ b/src/stream/libtcp/tcp_stream_tracker.cc @@ -52,11 +52,6 @@ TcpStreamTracker::TcpStreamTracker(bool client) : { } -TcpStreamTracker::~TcpStreamTracker() -{ - // TODO Auto-generated destructor stub -} - TcpStreamTracker::TcpEvent TcpStreamTracker::set_tcp_event(TcpSegmentDescriptor& tsd) { bool talker; diff --git a/src/stream/libtcp/tcp_stream_tracker.h b/src/stream/libtcp/tcp_stream_tracker.h index 221f83100..d021ee5b0 100644 --- a/src/stream/libtcp/tcp_stream_tracker.h +++ b/src/stream/libtcp/tcp_stream_tracker.h @@ -86,7 +86,7 @@ public: enum FinSeqNumStatus { FIN_NOT_SEEN, FIN_WITH_SEQ_SEEN, FIN_WITH_SEQ_ACKED }; TcpStreamTracker(bool); - virtual ~TcpStreamTracker(); + virtual ~TcpStreamTracker() = default; bool is_client_tracker() const { diff --git a/src/stream/tcp/ips_stream_reassemble.cc b/src/stream/tcp/ips_stream_reassemble.cc index cae5aef8b..97ea86986 100644 --- a/src/stream/tcp/ips_stream_reassemble.cc +++ b/src/stream/tcp/ips_stream_reassemble.cc @@ -295,7 +295,7 @@ TEST_CASE("IPS Stream Reassemble", "[ips_stream_reassemble][stream_tcp]") REQUIRE( ( ips_stream_reassemble->api_version == ((BASE_API_VERSION << 16) | 0) ) ); REQUIRE( ( strcmp(ips_stream_reassemble->name, s_name) == 0 ) ); ReassembleModule* reassembler = ( ReassembleModule* )ips_stream_reassemble->mod_ctor(); - REQUIRE( ( reassembler != nullptr ) ); + REQUIRE( reassembler != nullptr ); Flow* flow = new Flow; Packet* pkt = get_syn_packet(flow); diff --git a/src/stream/tcp/tcp_segment_node.cc b/src/stream/tcp/tcp_segment_node.cc index c98eab26c..bdd82c290 100644 --- a/src/stream/tcp/tcp_segment_node.cc +++ b/src/stream/tcp/tcp_segment_node.cc @@ -38,11 +38,6 @@ TcpSegmentNode::TcpSegmentNode() : { } -TcpSegmentNode::~TcpSegmentNode() -{ - // TODO Auto-generated destructor stub -} - //------------------------------------------------------------------------- // TcpSegment stuff //------------------------------------------------------------------------- diff --git a/src/stream/tcp/tcp_segment_node.h b/src/stream/tcp/tcp_segment_node.h index ef3dbd399..e6be61ded 100644 --- a/src/stream/tcp/tcp_segment_node.h +++ b/src/stream/tcp/tcp_segment_node.h @@ -35,7 +35,6 @@ struct TcpSegmentNode { TcpSegmentNode(); - ~TcpSegmentNode(); static TcpSegmentNode* init(TcpSegmentDescriptor& tsd); static TcpSegmentNode* init(TcpSegmentNode& tsn); diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index aabd7bb8a..00d1f6404 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -63,7 +63,10 @@ #include "tcp_reassemblers.h" #include "tcp_stream_state_machine.h" -DEBUG_WRAP(static THREAD_LOCAL const char* t_name = NULL; static THREAD_LOCAL const char* l_name = NULL; ) +#ifdef DEBUG_MSGS +static THREAD_LOCAL const char* t_name = nullptr; +static THREAD_LOCAL const char* l_name = nullptr; +#endif TcpSession::TcpSession(Flow* flow) : TcpStreamSession(flow) { diff --git a/src/stream/tcp/tcp_stream_state_machine.cc b/src/stream/tcp/tcp_stream_state_machine.cc index fc746889c..271cb34ce 100644 --- a/src/stream/tcp/tcp_stream_state_machine.cc +++ b/src/stream/tcp/tcp_stream_state_machine.cc @@ -55,7 +55,3 @@ TcpStreamStateMachine::TcpStreamStateMachine() new TcpStateTimeWait(*this); } -TcpStreamStateMachine::~TcpStreamStateMachine() -{ - // base class dtor deletes all the state handlers... -} diff --git a/src/stream/tcp/tcp_stream_state_machine.h b/src/stream/tcp/tcp_stream_state_machine.h index b81cd3fcc..ed6f16cb5 100644 --- a/src/stream/tcp/tcp_stream_state_machine.h +++ b/src/stream/tcp/tcp_stream_state_machine.h @@ -27,9 +27,6 @@ class TcpStreamStateMachine: public TcpStateMachine { public: - ~TcpStreamStateMachine() override; - - static TcpStateMachine* get_instance( ) { static TcpStreamStateMachine tsm; diff --git a/tools/snort2lua/config_states/config_checksums.cc b/tools/snort2lua/config_states/config_checksums.cc index f865d2b1f..7320a1573 100644 --- a/tools/snort2lua/config_states/config_checksums.cc +++ b/tools/snort2lua/config_states/config_checksums.cc @@ -54,7 +54,7 @@ public: if (lua_option == nullptr) lua_option = snort_option; - else if (snort_option->compare(*lua_option)) + else if (*snort_option != *lua_option) cv.get_table_api().add_diff_option_comment(*snort_option, *lua_option); while (stream >> val) diff --git a/tools/snort2lua/config_states/config_no_option.cc b/tools/snort2lua/config_states/config_no_option.cc index 5202f8668..c0f57683a 100644 --- a/tools/snort2lua/config_states/config_no_option.cc +++ b/tools/snort2lua/config_states/config_no_option.cc @@ -46,7 +46,7 @@ static ConversionState* config_true_no_opt_ctor(Converter& c) { c.get_table_api().open_table(*lua_table); - if (snort_option->compare(*lua_option)) + if (*snort_option != *lua_option) { c.get_table_api().add_diff_option_comment( "config " + *snort_option + ":", *lua_option); @@ -75,7 +75,7 @@ static ConversionState* config_false_no_opt_ctor(Converter& c) c.get_table_api().open_table(*lua_table); // WARNING: THIS WILL SEGFAULT if any variable is nullptr!! - if (snort_option->compare(*lua_option)) + if (*snort_option != *lua_option) c.get_table_api().add_diff_option_comment("config " + *snort_option + ":", *lua_option); c.get_table_api().add_option(*lua_option, false); diff --git a/tools/snort2lua/config_states/config_one_int_option.cc b/tools/snort2lua/config_states/config_one_int_option.cc index ce11d503c..1e18cdbaf 100644 --- a/tools/snort2lua/config_states/config_one_int_option.cc +++ b/tools/snort2lua/config_states/config_one_int_option.cc @@ -79,7 +79,7 @@ public: bool retval; // if the two names are not equal ... - if ((lua_option != nullptr) && snort_option->compare(*lua_option)) + if ((lua_option != nullptr) && *snort_option != *lua_option) { retval = parse_int_option(*lua_option, stream, false); table_api.add_diff_option_comment("config " + *snort_option + ":", *lua_option); diff --git a/tools/snort2lua/config_states/config_one_string_option.cc b/tools/snort2lua/config_states/config_one_string_option.cc index c623c1882..04f3b8b9f 100644 --- a/tools/snort2lua/config_states/config_one_string_option.cc +++ b/tools/snort2lua/config_states/config_one_string_option.cc @@ -67,7 +67,7 @@ public: table_api.open_table(*lua_table); - if ((lua_option != nullptr) && snort_option->compare(*lua_option)) + if ((lua_option != nullptr) && *snort_option != *lua_option) { table_api.add_diff_option_comment("config " + *snort_option + ":", *lua_option); diff --git a/tools/snort2lua/helpers/converter.cc b/tools/snort2lua/helpers/converter.cc index 28c2bea76..68990aade 100644 --- a/tools/snort2lua/helpers/converter.cc +++ b/tools/snort2lua/helpers/converter.cc @@ -43,7 +43,7 @@ TableDelegation table_delegation = { "network", true }, }; -std::string Converter::ips_pattern = ""; +std::string Converter::ips_pattern; bool Converter::parse_includes = true; bool Converter::empty_args = false; bool Converter::convert_rules_mult_files = true; diff --git a/tools/snort2lua/helpers/converter.h b/tools/snort2lua/helpers/converter.h index 8e42b5c7c..f0f1aaa9c 100644 --- a/tools/snort2lua/helpers/converter.h +++ b/tools/snort2lua/helpers/converter.h @@ -61,7 +61,7 @@ public: inline static void set_empty_args(bool val) { empty_args = val; } - inline static void set_ips_pattern(std::string val) + inline static void set_ips_pattern(const std::string& val) { ips_pattern = val; } inline static std::string get_ips_pattern() diff --git a/tools/snort2lua/preprocessor_states/pps_dcerpc_server.cc b/tools/snort2lua/preprocessor_states/pps_dcerpc_server.cc index 1d9ae1970..3f59086cc 100644 --- a/tools/snort2lua/preprocessor_states/pps_dcerpc_server.cc +++ b/tools/snort2lua/preprocessor_states/pps_dcerpc_server.cc @@ -387,7 +387,7 @@ bool DcerpcServer::parse_detect(std::istringstream& data_stream, { return false; } - ports = ports + tail; + ports += tail; } if (ports.back() == ',') diff --git a/tools/snort2lua/preprocessor_states/pps_sfportscan.cc b/tools/snort2lua/preprocessor_states/pps_sfportscan.cc index 89ff111ac..26b343f05 100644 --- a/tools/snort2lua/preprocessor_states/pps_sfportscan.cc +++ b/tools/snort2lua/preprocessor_states/pps_sfportscan.cc @@ -55,7 +55,10 @@ bool PortScan::parse_ip_list(const std::string& list_name, std::istringstream& d prev = "[" + elem; while (data_stream >> elem && elem != "}") - prev = prev + ' ' + elem; + { + prev += ' '; + prev += elem; + } prev = prev + "]"; return table_api.add_option(list_name, prev); diff --git a/tools/u2spewfoo/u2spewfoo.cc b/tools/u2spewfoo/u2spewfoo.cc index 5938f7068..811c715ca 100644 --- a/tools/u2spewfoo/u2spewfoo.cc +++ b/tools/u2spewfoo/u2spewfoo.cc @@ -24,6 +24,7 @@ #endif #include +#include #include #include