[protozero] 01/06: New upstream version 1.5.2
Bas Couwenberg
sebastic at debian.org
Sat Jul 1 09:13:08 UTC 2017
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository protozero.
commit 621f7b8167bf7b43f2b81b796de3c702acf6b3f6
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Sat Jul 1 11:02:57 2017 +0200
New upstream version 1.5.2
---
.travis.yml | 25 +-
CHANGELOG.md | 27 +-
README.md | 2 +-
doc/tutorial.md | 6 -
include/protozero/pbf_builder.hpp | 18 +-
include/protozero/pbf_message.hpp | 4 +
include/protozero/pbf_reader.hpp | 8 +-
include/protozero/pbf_writer.hpp | 11 +
include/protozero/types.hpp | 8 +-
include/protozero/version.hpp | 4 +-
package.json | 2 +-
test/include/catch.hpp | 3030 ++++++++++++++++++++++++------------
test/t/basic/test_cases.cpp | 5 +-
test/t/bytes/test_cases.cpp | 10 +-
test/t/data_view/test_cases.cpp | 36 +-
test/t/rollback/test_cases.cpp | 16 +-
test/t/tag_and_type/test_cases.cpp | 30 +
17 files changed, 2178 insertions(+), 1064 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 1035a0d..19d4de2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -91,15 +91,8 @@ matrix:
before_install:
- echo ${CXX}
- - if [[ $(uname -s) == 'Linux' ]]; then
- export PYTHONPATH=$(pwd)/.local/lib/python2.7/site-packages;
- else
+ - if [[ $(uname -s) == 'Darwin' ]]; then
brew install protobuf;
- export PYTHONPATH=$(pwd)/.local/lib/python/site-packages;
- fi
- - if [ -n "${COVERAGE}" ]; then
- PYTHONUSERBASE=$(pwd)/.local pip install --user urllib3[secure];
- PYTHONUSERBASE=$(pwd)/.local pip install --user cpp-coveralls;
fi
install:
@@ -107,9 +100,13 @@ install:
- if [ -n "${BUILD_DOC}" ]; then make doc; fi
script:
- - if [ -n "${COVERAGE}" ]; then
- make clean;
- CXXFLAGS="--coverage ${CXXFLAGS}" LDFLAGS="--coverage ${LDFLAGS}" make test;
- ${COVERAGE} -lp test/*tests.o test/t/*/*test_cases.o;
- ./.local/bin/cpp-coveralls --no-gcov -i include/protozero;
- fi
+ - |
+ if [ -n "${COVERAGE}" ]; then
+ make clean
+ CXXFLAGS="--coverage ${CXXFLAGS}" LDFLAGS="--coverage ${LDFLAGS}" make test
+ which ${COVERAGE}
+ curl -S -f https://codecov.io/bash -o codecov
+ chmod +x codecov
+ ${COVERAGE} -p $(find test/ -name '*.o')
+ ./codecov -Z -f '*protozero*' -X search
+ fi
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c1acdf..10a5684 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,30 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
+## [1.5.2] - 2017-06-30
+
+### Added
+
+- Add missing two-parameter version of `pbf_message::next()` function.
+- Add `data_view::empty()` function.
+- Add missing versions of `add_bytes()`, `add_string()`, and `add_message()`
+ to `pbf_builder`.
+
+### Changed
+
+- Clarify include file usage in tutorial.
+- Updated included Catch unit test framework to version 1.9.6 and updated
+ tests to work with the current version.
+- Make some constructors explicit (best practice to avoid silent conversions).
+
+### Fixed
+
+- Important bugfix in `data_view` equality operator. The equality operator is
+ actually never used in the protozero code itself, but users of protozero
+ might use it. This is a serious bug that could lead to buffer overrun type
+ problems.
+
+
## [1.5.1] - 2017-01-14
### Added
@@ -167,7 +191,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Make pbf reader and writer code endianess-aware.
-[unreleased]: https://github.com/osmcode/libosmium/compare/v1.5.1...HEAD
+[unreleased]: https://github.com/osmcode/libosmium/compare/v1.5.2...HEAD
+[1.5.2]: https://github.com/osmcode/libosmium/compare/v1.5.1...v1.5.2
[1.5.1]: https://github.com/osmcode/libosmium/compare/v1.5.0...v1.5.1
[1.5.0]: https://github.com/osmcode/libosmium/compare/v1.4.5...v1.5.0
[1.4.5]: https://github.com/osmcode/libosmium/compare/v1.4.4...v1.4.5
diff --git a/README.md b/README.md
index 5d19fff..473f4e8 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ the Google Protobufs `protoc` program.
[![Travis Build Status](https://travis-ci.org/mapbox/protozero.svg?branch=master)](https://travis-ci.org/mapbox/protozero)
[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/o354pq10y96mnr6d?svg=true)](https://ci.appveyor.com/project/Mapbox/protozero)
-[![Coverage Status](https://coveralls.io/repos/mapbox/protozero/badge.svg?branch=master&service=github)](https://coveralls.io/github/mapbox/protozero?branch=master)
+[![Coverage Status](https://codecov.io/gh/mapbox/protozero/branch/master/graph/badge.svg)](https://codecov.io/gh/mapbox/protozero)
## Depends
diff --git a/doc/tutorial.md b/doc/tutorial.md
index 0254eba..79b1e35 100644
--- a/doc/tutorial.md
+++ b/doc/tutorial.md
@@ -29,12 +29,6 @@ Keep the `protozero` directory and include the files in the form
#include <protozero/FILENAME.hpp>
```
-You always need `byteswap.hpp`, `config.hpp`, `types.hpp`, `varint.hpp`,
-and `exception.hpp`. For reading you need `pbf_reader.hpp` and probably
-`pbf_message.hpp`, for writing you need `pbf_writer.hpp` and probably
-`pbf_builder.hpp`. You only need `version.hpp` if you want access to the macros
-defining the library version.
-
## Parsing protobuf-encoded messages
diff --git a/include/protozero/pbf_builder.hpp b/include/protozero/pbf_builder.hpp
index c40727c..8197395 100644
--- a/include/protozero/pbf_builder.hpp
+++ b/include/protozero/pbf_builder.hpp
@@ -46,7 +46,7 @@ public:
using enum_type = T;
- pbf_builder(std::string& data) noexcept :
+ explicit pbf_builder(std::string& data) noexcept :
pbf_writer(data) {
}
@@ -83,10 +83,18 @@ public:
pbf_writer::add_bytes(pbf_tag_type(tag), value, size);
}
+ void add_bytes(T tag, const data_view& value) {
+ pbf_writer::add_bytes(pbf_tag_type(tag), value);
+ }
+
void add_bytes(T tag, const std::string& value) {
pbf_writer::add_bytes(pbf_tag_type(tag), value);
}
+ void add_bytes(T tag, const char* value) {
+ pbf_writer::add_bytes(pbf_tag_type(tag), value);
+ }
+
template <typename... Ts>
void add_bytes_vectored(T tag, Ts&&... values) {
pbf_writer::add_bytes_vectored(pbf_tag_type(tag), std::forward<Ts>(values)...);
@@ -96,6 +104,10 @@ public:
pbf_writer::add_string(pbf_tag_type(tag), value, size);
}
+ void add_string(T tag, const data_view& value) {
+ pbf_writer::add_string(pbf_tag_type(tag), value);
+ }
+
void add_string(T tag, const std::string& value) {
pbf_writer::add_string(pbf_tag_type(tag), value);
}
@@ -108,6 +120,10 @@ public:
pbf_writer::add_message(pbf_tag_type(tag), value, size);
}
+ void add_message(T tag, const data_view& value) {
+ pbf_writer::add_message(pbf_tag_type(tag), value);
+ }
+
void add_message(T tag, const std::string& value) {
pbf_writer::add_message(pbf_tag_type(tag), value);
}
diff --git a/include/protozero/pbf_message.hpp b/include/protozero/pbf_message.hpp
index f66604a..c599cf1 100644
--- a/include/protozero/pbf_message.hpp
+++ b/include/protozero/pbf_message.hpp
@@ -83,6 +83,10 @@ public:
return pbf_reader::next(pbf_tag_type(next_tag));
}
+ bool next(T next_tag, pbf_wire_type type) {
+ return pbf_reader::next(pbf_tag_type(next_tag), type);
+ }
+
T tag() const noexcept {
return T(pbf_reader::tag());
}
diff --git a/include/protozero/pbf_reader.hpp b/include/protozero/pbf_reader.hpp
index 98920fa..905ca0a 100644
--- a/include/protozero/pbf_reader.hpp
+++ b/include/protozero/pbf_reader.hpp
@@ -179,7 +179,7 @@ public:
*
* @post There is no current field.
*/
- pbf_reader(const std::pair<const char*, std::size_t>& data) noexcept
+ explicit pbf_reader(const std::pair<const char*, std::size_t>& data) noexcept
: m_data(data.first),
m_end(data.first + data.second),
m_wire_type(pbf_wire_type::unknown),
@@ -196,7 +196,7 @@ public:
*
* @post There is no current field.
*/
- pbf_reader(const std::string& data) noexcept
+ explicit pbf_reader(const std::string& data) noexcept
: m_data(data.data()),
m_end(data.data() + data.size()),
m_wire_type(pbf_wire_type::unknown),
@@ -367,9 +367,9 @@ public:
* @pre There must be no current field.
* @post If it returns `true` there is a current field now with the given tag.
*/
- bool next(pbf_tag_type next_tag, pbf_wire_type wire_type) {
+ bool next(pbf_tag_type next_tag, pbf_wire_type type) {
while (next()) {
- if (m_tag == next_tag && m_wire_type == wire_type) {
+ if (m_tag == next_tag && m_wire_type == type) {
return true;
} else {
skip();
diff --git a/include/protozero/pbf_writer.hpp b/include/protozero/pbf_writer.hpp
index 39dd795..af626bd 100644
--- a/include/protozero/pbf_writer.hpp
+++ b/include/protozero/pbf_writer.hpp
@@ -502,6 +502,17 @@ public:
}
/**
+ * Add "bytes" field to data. Bytes from the value are written until
+ * a null byte is encountered. The null byte is not added.
+ *
+ * @param tag Tag (field number) of the field
+ * @param value Pointer to zero-delimited value to be written
+ */
+ void add_bytes(pbf_tag_type tag, const char* value) {
+ add_bytes(tag, value, std::strlen(value));
+ }
+
+ /**
* Add "bytes" field to data using vectored input. All the data in the
* 2nd and further arguments is "concatenated" with only a single copy
* into the final buffer.
diff --git a/include/protozero/types.hpp b/include/protozero/types.hpp
index 5e14972..3dbdaf1 100644
--- a/include/protozero/types.hpp
+++ b/include/protozero/types.hpp
@@ -16,6 +16,7 @@ documentation.
* @brief Contains the declaration of low-level types used in the pbf format.
*/
+#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
@@ -138,6 +139,11 @@ public:
return m_size;
}
+ /// Returns true if size is 0.
+ constexpr bool empty() const noexcept {
+ return m_size == 0;
+ }
+
/**
* Convert data view to string.
*
@@ -178,7 +184,7 @@ inline void swap(data_view& lhs, data_view& rhs) noexcept {
* @param rhs Second object.
*/
inline bool operator==(const data_view& lhs, const data_view& rhs) noexcept {
- return lhs.size() == rhs.size() && !std::strcmp(lhs.data(), rhs.data());
+ return lhs.size() == rhs.size() && std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data());
}
/**
diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp
index 9103bdc..6d82823 100644
--- a/include/protozero/version.hpp
+++ b/include/protozero/version.hpp
@@ -23,12 +23,12 @@ documentation.
#define PROTOZERO_VERSION_MINOR 5
/// The patch number
-#define PROTOZERO_VERSION_PATCH 1
+#define PROTOZERO_VERSION_PATCH 2
/// The complete version number
#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
/// Version number as string
-#define PROTOZERO_VERSION_STRING "1.5.1"
+#define PROTOZERO_VERSION_STRING "1.5.2"
#endif // PROTOZERO_VERSION_HPP
diff --git a/package.json b/package.json
index 7e1b863..b858b59 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "protozero",
- "version": "1.5.1",
+ "version": "1.5.2",
"description": "Minimalist protocol buffer decoder and encoder in C++",
"main": "include_dirs.js",
"repository" : {
diff --git a/test/include/catch.hpp b/test/include/catch.hpp
index 3d18ead..f7681f4 100644
--- a/test/include/catch.hpp
+++ b/test/include/catch.hpp
@@ -1,6 +1,6 @@
/*
- * Catch v1.5.9
- * Generated: 2016-11-29 12:14:38.049276
+ * Catch v1.9.6
+ * Generated: 2017-06-27 12:19:54.557875
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@@ -40,6 +40,8 @@
#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 <sstream>
-#include <stdexcept>
-#include <algorithm>
-
// #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,12 +120,42 @@
# 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
+
+////////////////////////////////////////////////////////////////////////////////
+// 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 +181,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 +190,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 +200,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 +220,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 +267,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 +295,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 +363,20 @@
# define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
#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 <sstream>
+#include <algorithm>
+
namespace Catch {
struct IConfig;
@@ -367,7 +429,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 +451,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 +461,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,8 +495,6 @@ namespace Catch {
#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
-#include <ostream>
-
namespace Catch {
class NotImplementedException : public std::exception
@@ -565,10 +627,6 @@ namespace Catch {
#pragma clang diagnostic pop
#endif
-#include <memory>
-#include <vector>
-#include <stdlib.h>
-
namespace Catch {
class TestCase;
@@ -712,59 +770,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__ ) ); } \
+ 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 ); } \
+ 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_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__ ) ); \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
#else
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
static void TestName(); \
+ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
+ 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 ); } \
+ 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_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 ) ); \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
#endif
// #included from: internal/catch_capture.hpp
@@ -832,27 +907,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<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
+ template<typename T> 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( 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 +1010,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 +1027,161 @@ namespace Catch {
namespace Matchers {
namespace Impl {
- namespace Generic {
- template<typename ExpressionT> class AllOf;
- template<typename ExpressionT> class AnyOf;
- template<typename ExpressionT> class Not;
- }
-
- template<typename ExpressionT>
- struct Matcher : SharedImpl<IShared>
- {
- typedef ExpressionT ExpressionType;
-
- virtual ~Matcher() {}
- virtual Ptr<Matcher> clone() const = 0;
- virtual bool match( ExpressionT const& expr ) const = 0;
- virtual std::string toString() const = 0;
-
- Generic::AllOf<ExpressionT> operator && ( Matcher<ExpressionT> const& other ) const;
- Generic::AnyOf<ExpressionT> operator || ( Matcher<ExpressionT> const& other ) const;
- Generic::Not<ExpressionT> operator ! () const;
- };
-
- template<typename DerivedT, typename ExpressionT>
- struct MatcherImpl : Matcher<ExpressionT> {
-
- virtual Ptr<Matcher<ExpressionT> > clone() const {
- return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
- }
- };
+ template<typename ArgT> struct MatchAllOf;
+ template<typename ArgT> struct MatchAnyOf;
+ template<typename ArgT> struct MatchNotOf;
- namespace Generic {
- template<typename ExpressionT>
- class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT> {
+ class MatcherUntypedBase {
public:
- explicit Not( Matcher<ExpressionT> 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<ExpressionT> > m_matcher;
+ MatcherUntypedBase& operator = ( MatcherUntypedBase const& );
};
- template<typename ExpressionT>
- class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
- public:
+ template<typename ObjectT>
+ struct MatcherMethod {
+ virtual bool match( ObjectT const& arg ) const = 0;
+ };
+ template<typename PtrT>
+ struct MatcherMethod<PtrT*> {
+ virtual bool match( PtrT* arg ) const = 0;
+ };
- AllOf() {}
- AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
+ template<typename ObjectT, typename ComparatorT = ObjectT>
+ struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> {
- AllOf& add( Matcher<ExpressionT> 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<ComparatorT> operator && ( MatcherBase const& other ) const;
+ MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const;
+ MatchNotOf<ComparatorT> operator ! () const;
+ };
+
+ template<typename ArgT>
+ struct MatchAllOf : MatcherBase<ArgT> {
+ 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<ExpressionT> const& other ) const {
- AllOf allOfExpr( *this );
- allOfExpr.add( other );
- return allOfExpr;
+ MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
+ m_matchers.push_back( &other );
+ return *this;
}
- private:
- std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
+ std::vector<MatcherBase<ArgT> const*> m_matchers;
};
+ template<typename ArgT>
+ struct MatchAnyOf : MatcherBase<ArgT> {
- template<typename ExpressionT>
- class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
- public:
-
- AnyOf() {}
- AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
-
- AnyOf& add( Matcher<ExpressionT> 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<ExpressionT> const& other ) const {
- AnyOf anyOfExpr( *this );
- anyOfExpr.add( other );
- return anyOfExpr;
- }
-
- private:
- std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
- };
-
- } // namespace Generic
-
- template<typename ExpressionT>
- Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator && ( Matcher<ExpressionT> const& other ) const {
- Generic::AllOf<ExpressionT> allOfExpr;
- allOfExpr.add( *this );
- allOfExpr.add( other );
- return allOfExpr;
- }
-
- template<typename ExpressionT>
- Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator || ( Matcher<ExpressionT> const& other ) const {
- Generic::AnyOf<ExpressionT> anyOfExpr;
- anyOfExpr.add( *this );
- anyOfExpr.add( other );
- return anyOfExpr;
- }
-
- template<typename ExpressionT>
- Generic::Not<ExpressionT> Matcher<ExpressionT>::operator ! () const {
- return Generic::Not<ExpressionT>( *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;
-
- }
- std::string toStringSuffix() const
- {
- return m_caseSensitivity == CaseSensitive::No
- ? " (case insensitive)"
- : "";
+ description += " )";
+ return description;
}
- CaseSensitive::Choice m_caseSensitivity;
- std::string m_str;
- };
-
- struct Equals : MatcherImpl<Equals, std::string> {
- 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<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
+ m_matchers.push_back( &other );
+ return *this;
}
- CasedString m_data;
+ std::vector<MatcherBase<ArgT> const*> m_matchers;
};
- struct Contains : MatcherImpl<Contains, std::string> {
- Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
- : m_data( substr, caseSensitivity ){}
- Contains( Contains const& other ) : m_data( other.m_data ){}
+ template<typename ArgT>
+ struct MatchNotOf : MatcherBase<ArgT> {
- virtual ~Contains();
+ MatchNotOf( MatcherBase<ArgT> 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> {
- 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 toString() const {
- return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
+ virtual std::string describe() const CATCH_OVERRIDE {
+ return "not " + m_underlyingMatcher.toString();
}
-
- CasedString m_data;
+ MatcherBase<ArgT> const& m_underlyingMatcher;
};
- struct EndsWith : MatcherImpl<EndsWith, std::string> {
- 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<typename ObjectT, typename ComparatorT>
+ MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const {
+ return MatchAllOf<ComparatorT>() && *this && other;
+ }
+ template<typename ObjectT, typename ComparatorT>
+ MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const {
+ return MatchAnyOf<ComparatorT>() || *this || other;
+ }
+ template<typename ObjectT, typename ComparatorT>
+ MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const {
+ return MatchNotOf<ComparatorT>( *this );
+ }
- CasedString m_data;
- };
- } // namespace StdString
} // namespace Impl
// The following functions create the actual matcher objects.
// This allows the types to be inferred
- template<typename ExpressionT>
- inline Impl::Generic::Not<ExpressionT> Not( Impl::Matcher<ExpressionT> const& m ) {
- return Impl::Generic::Not<ExpressionT>( m );
- }
-
- template<typename ExpressionT>
- inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2 ) {
- return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
- }
- template<typename ExpressionT>
- inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2,
- Impl::Matcher<ExpressionT> const& m3 ) {
- return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
- }
- template<typename ExpressionT>
- inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2 ) {
- return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
- }
- template<typename ExpressionT>
- inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
- Impl::Matcher<ExpressionT> const& m2,
- Impl::Matcher<ExpressionT> const& m3 ) {
- return Impl::Generic::AnyOf<ExpressionT>().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<typename T>
+ inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
+ return Impl::MatchNotOf<T>( underlyingMatcher );
}
- inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
- return Impl::StdString::StartsWith( substr );
+ template<typename T>
+ inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+ return Impl::MatchAllOf<T>() && m1 && m2;
}
- inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
- return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
+ template<typename T>
+ inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+ return Impl::MatchAllOf<T>() && m1 && m2 && m3;
}
- inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
- return Impl::StdString::EndsWith( substr );
+ template<typename T>
+ inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+ return Impl::MatchAnyOf<T>() || m1 || m2;
}
- inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
- return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
+ template<typename T>
+ inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+ return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
}
} // namespace Matchers
using namespace Matchers;
+using Matchers::Impl::MatcherBase;
} // namespace Catch
@@ -1210,28 +1191,27 @@ namespace Catch {
template<typename T> 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<typename T>
ExpressionLhs<T const&> operator <= ( T const& operand );
@@ -1239,46 +1219,49 @@ namespace Catch {
template<typename T>
ResultBuilder& operator << ( T const& value ) {
- m_stream.oss << value;
+ m_stream().oss << value;
return *this;
}
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
- template<typename RhsT> 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<std::string> const& matcher );
+ void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher );
void handleResult( AssertionResult const& result );
void react();
bool shouldDebugBreak() const;
bool allowThrows() const;
+ template<typename ArgT, typename MatcherT>
+ 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;
+
+ static CopyableStream &m_stream()
+ {
+ static CopyableStream s;
+ return s;
+ }
bool m_shouldDebugBreak;
bool m_shouldThrow;
+ bool m_guardException;
};
} // namespace Catch
@@ -1293,6 +1276,7 @@ namespace Catch {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
#endif
#include <cstddef>
@@ -1594,7 +1578,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 +1586,7 @@ namespace Detail {
extern const std::string unprintableString;
+ #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK)
struct BorgType {
template<typename T> BorgType( T const& );
};
@@ -1620,6 +1605,20 @@ namespace Detail {
static T const&t;
enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
};
+#else
+ template<typename T>
+ class IsStreamInsertable {
+ template<typename SS, typename TT>
+ static auto test(int)
+ -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() );
+
+ template<typename, typename>
+ static auto test(...) -> std::false_type;
+
+ public:
+ static const bool value = decltype(test<std::ostream,const T&>(0))::value;
+ };
+#endif
#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
template<typename T,
@@ -1796,90 +1795,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<typename T>
-class ExpressionLhs {
- ExpressionLhs& operator = ( ExpressionLhs const& );
-# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
- ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
-# endif
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression;
+template<typename ArgT, typename MatcherT>
+class MatchExpression;
+
+// Wraps the LHS of an expression and overloads comparison operators
+// for also capturing those and RHS (if any)
+template<typename T>
+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<typename RhsT>
- ResultBuilder& operator == ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
+ operator == ( RhsT const& rhs ) {
return captureExpression<Internal::IsEqualTo>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator != ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
+ operator != ( RhsT const& rhs ) {
return captureExpression<Internal::IsNotEqualTo>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator < ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsLessThan, RhsT const&>
+ operator < ( RhsT const& rhs ) {
return captureExpression<Internal::IsLessThan>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator > ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
+ operator > ( RhsT const& rhs ) {
return captureExpression<Internal::IsGreaterThan>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator <= ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
+ operator <= ( RhsT const& rhs ) {
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
}
template<typename RhsT>
- ResultBuilder& operator >= ( RhsT const& rhs ) {
+ BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
+ operator >= ( RhsT const& rhs ) {
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
}
- ResultBuilder& operator == ( bool rhs ) {
+ BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
return captureExpression<Internal::IsEqualTo>( rhs );
}
- ResultBuilder& operator != ( bool rhs ) {
+ BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
return captureExpression<Internal::IsNotEqualTo>( 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<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
- template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
- template<typename RhsT> 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<Internal::Operator Op, typename RhsT>
- ResultBuilder& captureExpression( RhsT const& rhs ) {
- return m_rb
- .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
- .setLhs( Catch::toString( m_lhs ) )
- .setRhs( Catch::toString( rhs ) )
- .setOp( Internal::OperatorTraits<Op>::getName() );
+ BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
+ return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
+ }
+
+ template<Internal::Operator Op>
+ BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
+ return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
}
private:
ResultBuilder& m_rb;
T m_lhs;
+ bool m_truthy;
+};
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+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::compare<Op>( 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<Op>::getName();
+ dest += delim;
+ dest += rhs;
+ }
+
+private:
+ ResultBuilder& m_rb;
+ LhsT m_lhs;
+ RhsT m_rhs;
+};
+
+template<typename ArgT, typename MatcherT>
+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
@@ -1896,6 +1964,14 @@ namespace Catch {
return ExpressionLhs<bool>( *this, value );
}
+ template<typename ArgT, typename MatcherT>
+ inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
+ char const* matcherString ) {
+ MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
+ setResultType( matcher.match( arg ) );
+ endExpression( expr );
+ }
+
} // namespace Catch
// #included from: catch_message.h
@@ -1985,6 +2061,8 @@ 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;
};
@@ -1998,11 +2076,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 <string>
@@ -2017,27 +2103,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" )
+ #else
+ #define CATCH_TRAP() __asm__("int $3\n" : : )
#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")
+ #else // Fall back to the generic way.
+ #include <signal.h>
+
+ #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 +2147,41 @@ namespace Catch {
};
}
+#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, #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<bool>( !!(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, #arg ", " #matcher, resultDisposition ); \
+ __catchResult.setExceptionGuard(); \
+ __catchResult.captureMatch( arg, matcher, #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 +2190,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 ); \
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<bool>( !!(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 ); \
+#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
+ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
if( Catch::getResultCapture().getLastResult()->succeeded() )
///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
- INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
+ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
if( !Catch::getResultCapture().getLastResult()->succeeded() )
///////////////////////////////////////////////////////////////////////////////
-#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 ); \
try { \
- expr; \
+ static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
} \
catch( ... ) { \
@@ -2100,12 +2233,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 ); \
if( __catchResult.allowThrows() ) \
try { \
- expr; \
+ static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
} \
catch( ... ) { \
@@ -2117,12 +2250,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, #expr ", " #exceptionType, resultDisposition ); \
if( __catchResult.allowThrows() ) \
try { \
- expr; \
+ static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
} \
catch( exceptionType ) { \
@@ -2138,7 +2271,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 +2279,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 +2289,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 ); \
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, #matcher ); \
} catch( ... ) { \
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
} \
@@ -2253,6 +2380,8 @@ namespace Catch {
};
}
+#include <string>
+
namespace Catch {
struct SectionInfo {
@@ -2281,14 +2410,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 <stdint.h>
+namespace Catch {
+ typedef uint64_t UInt64;
+}
#endif
namespace Catch {
-
class Timer {
public:
Timer() : m_ticks( 0 ) {}
@@ -2298,7 +2432,7 @@ namespace Catch {
double getElapsedSeconds() const;
private:
- uint64_t m_ticks;
+ UInt64 m_ticks;
};
} // namespace Catch
@@ -2337,7 +2471,6 @@ namespace Catch {
// #included from: internal/catch_generators.hpp
#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
-#include <iterator>
#include <vector>
#include <string>
#include <stdlib.h>
@@ -2451,7 +2584,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 +2666,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 +2684,7 @@ namespace Catch {
virtual void registerListener( Ptr<IReporterFactory> 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 +2760,10 @@ namespace Catch {
#include <cmath>
#include <limits>
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+#include <type_traits>
+#endif
+
namespace Catch {
namespace Detail {
@@ -2630,12 +2771,14 @@ namespace Detail {
public:
explicit Approx ( double value )
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+ m_margin( 0.0 ),
m_scale( 1.0 ),
m_value( value )
{}
Approx( Approx const& other )
: m_epsilon( other.m_epsilon ),
+ m_margin( other.m_margin ),
m_scale( other.m_scale ),
m_value( other.m_value )
{}
@@ -2644,16 +2787,102 @@ namespace Detail {
return Approx( 0 );
}
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx operator()( T value ) {
+ Approx approx( static_cast<double>(value) );
+ approx.epsilon( m_epsilon );
+ approx.margin( m_margin );
+ approx.scale( m_scale );
+ return approx;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ explicit Approx( T value ): Approx(static_cast<double>(value))
+ {}
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::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 <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator == ( Approx const& lhs, const T& rhs ) {
+ return operator==( rhs, lhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator != ( T lhs, Approx const& rhs ) {
+ return !operator==( lhs, rhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator != ( Approx const& lhs, T rhs ) {
+ return !operator==( rhs, lhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator <= ( T lhs, Approx const& rhs ) {
+ return double(lhs) < rhs.m_value || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator <= ( Approx const& lhs, T rhs ) {
+ return lhs.m_value < double(rhs) || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator >= ( T lhs, Approx const& rhs ) {
+ return double(lhs) > rhs.m_value || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator >= ( Approx const& lhs, T rhs ) {
+ return lhs.m_value > double(rhs) || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx& epsilon( T newEpsilon ) {
+ m_epsilon = double(newEpsilon);
+ return *this;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx& margin( T newMargin ) {
+ m_margin = double(newMargin);
+ return *this;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::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 +2897,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 +2937,7 @@ namespace Detail {
private:
double m_epsilon;
+ double m_margin;
double m_scale;
double m_value;
};
@@ -2696,7 +2948,154 @@ inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
return value.toString();
}
-} // end namespace Catch
+} // 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<std::string> {
+ 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<typename T>
+ struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> {
+
+ ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
+
+ bool match(std::vector<T> 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<typename T>
+ struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+ ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+ bool match(std::vector<T> 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<T> const& m_comparator;
+ };
+
+ template<typename T>
+ struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+ EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+ bool match(std::vector<T> 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<T> 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<T> const& m_comparator;
+ };
+
+ } // namespace Vector
+
+ // The following functions create the actual matcher objects.
+ // This allows the types to be inferred
+
+ template<typename T>
+ Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
+ return Vector::ContainsMatcher<T>( comparator );
+ }
+
+ template<typename T>
+ Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
+ return Vector::ContainsElementMatcher<T>( comparator );
+ }
+
+ template<typename T>
+ Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
+ return Vector::EqualsMatcher<T>( 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 +3108,7 @@ inline std::string toString<Detail::Approx>( 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 +3180,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 +3231,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 +3390,67 @@ namespace Catch {
namespace Impl {
namespace NSStringMatchers {
- template<typename MatcherT>
- struct StringHolder : MatcherImpl<MatcherT, NSString*>{
+ struct StringHolder : MatcherBase<NSString*>{
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<Equals> {
+ 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<Contains> {
+ 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<StartsWith> {
+ 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<EndsWith> {
+ 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 +3491,29 @@ return @ desc; \
#endif
#ifdef CATCH_IMPL
+
+// !TBD: Move the leak detector code into a separate header
+#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
+#include <crtdbg.h>
+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 +3553,8 @@ return @ desc; \
// #included from: catch_wildcard_pattern.hpp
#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+#include <stdexcept>
+
namespace Catch
{
class WildcardPattern {
@@ -3134,11 +3572,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<WildcardPosition>( m_wildcard | WildcardAtEnd );
}
@@ -3257,11 +3695,12 @@ 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<std::size_t> m_escapeChars;
TestSpec::Filter m_currentFilter;
TestSpec m_testSpec;
ITagAliasRegistry const* m_tagAliases;
@@ -3274,6 +3713,7 @@ namespace Catch {
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 )
@@ -3292,6 +3732,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;
}
}
@@ -3307,7 +3748,11 @@ namespace Catch {
addPattern<TestSpec::NamePattern>();
startNewMode( Tag, ++m_pos );
}
+ else if( c == '\\' )
+ escape();
}
+ else if( m_mode == EscapedName )
+ m_mode = Name;
else if( m_mode == QuotedName && c == '"' )
addPattern<TestSpec::NamePattern>();
else if( m_mode == Tag && c == ']' )
@@ -3317,10 +3762,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<typename T>
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 );
@@ -3354,7 +3808,7 @@ namespace Catch {
// #included from: catch_interfaces_config.h
#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
-#include <iostream>
+#include <iosfwd>
#include <string>
#include <vector>
@@ -3406,6 +3860,8 @@ namespace Catch {
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
virtual UseColour::YesOrNo useColour() const = 0;
+ virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+
};
}
@@ -3474,8 +3930,7 @@ namespace Catch {
#include <memory>
#include <vector>
#include <string>
-#include <iostream>
-#include <ctime>
+#include <stdexcept>
#ifndef CATCH_CONFIG_CONSOLE_WIDTH
#define CATCH_CONFIG_CONSOLE_WIDTH 80
@@ -3490,6 +3945,7 @@ namespace Catch {
listTags( false ),
listReporters( false ),
listTestNamesOnly( false ),
+ listExtraInfo( false ),
showSuccessfulTests( false ),
shouldDebugBreak( false ),
noThrow( false ),
@@ -3509,6 +3965,7 @@ namespace Catch {
bool listTags;
bool listReporters;
bool listTestNamesOnly;
+ bool listExtraInfo;
bool showSuccessfulTests;
bool shouldDebugBreak;
@@ -3532,6 +3989,7 @@ namespace Catch {
std::vector<std::string> reporterNames;
std::vector<std::string> testsOrTags;
+ std::vector<std::string> sectionsToRun;
};
class Config : public SharedImpl<IConfig> {
@@ -3556,8 +4014,7 @@ namespace Catch {
}
}
- virtual ~Config() {
- }
+ virtual ~Config() {}
std::string const& getFilename() const {
return m_data.outputFilename ;
@@ -3567,30 +4024,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<std::string> const& getReporterNames() const { return m_data.reporterNames; }
+ std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
- std::vector<std::string> 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:
@@ -3655,6 +4112,7 @@ namespace Catch {
#include <vector>
#include <sstream>
#include <algorithm>
+#include <cctype>
// Use optional outer namespace
#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
@@ -3997,7 +4455,7 @@ namespace Clara {
_dest = _source;
}
char toLowerCh(char c) {
- return static_cast<char>( ::tolower( c ) );
+ return static_cast<char>( std::tolower( c ) );
}
inline void convertInto( std::string const& _source, bool& _dest ) {
std::string sourceLC = _source;
@@ -4151,12 +4609,13 @@ namespace Clara {
}
void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
- for( std::size_t i = 0; i <= arg.size(); ++i ) {
+ for( std::size_t i = 0; i < arg.size(); ++i ) {
char c = arg[i];
if( c == '"' )
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<Token>& tokens ) {
switch( mode ) {
@@ -4189,6 +4648,7 @@ namespace Clara {
default: from = i; return ShortOpt;
}
}
+
Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
return mode;
@@ -4520,7 +4980,7 @@ namespace Clara {
}
std::vector<Parser::Token> parseInto( std::vector<std::string> 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 );
@@ -4652,6 +5112,7 @@ STITCH_CLARA_CLOSE_NAMESPACE
#endif
#include <fstream>
+#include <ctime>
namespace Catch {
@@ -4662,13 +5123,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<WarnAbout::What>( 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 ) )
@@ -4678,7 +5140,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" ) {
@@ -4689,7 +5151,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 ) {
@@ -4724,10 +5186,10 @@ namespace Catch {
std::string line;
while( std::getline( f, line ) ) {
line = trim(line);
- if( !line.empty() && !startsWith( line, "#" ) ) {
- if( !startsWith( line, "\"" ) )
- line = "\"" + line + "\"";
- addTestOrTags( config, line + "," );
+ if( !line.empty() && !startsWith( line, '#' ) ) {
+ if( !startsWith( line, '"' ) )
+ line = '"' + line + '"';
+ addTestOrTags( config, line + ',' );
}
}
}
@@ -4815,11 +5277,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 );
@@ -4887,19 +5357,16 @@ 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 {
@@ -4907,62 +5374,76 @@ namespace Tbc {
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;
+ 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 ) {
- 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;
- }
- 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<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( 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<std::string>::const_iterator const_iterator;
@@ -5071,7 +5552,6 @@ namespace Catch {
#include <string>
#include <ostream>
#include <map>
-#include <assert.h>
namespace Catch
{
@@ -5338,8 +5818,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<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
@@ -5354,14 +5835,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;
}
@@ -5376,10 +5864,13 @@ namespace Catch {
++it ) {
matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
- if( startsWith( testCaseInfo.name, "#" ) )
- Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl;
+ if( startsWith( testCaseInfo.name, '#' ) )
+ Catch::cout() << '"' << testCaseInfo.name << '"';
else
- Catch::cout() << testCaseInfo.name << std::endl;
+ Catch::cout() << testCaseInfo.name;
+ if ( config.listExtraInfo() )
+ Catch::cout() << "\t@" << testCaseInfo.lineInfo;
+ Catch::cout() << std::endl;
}
return matchedTests;
}
@@ -5440,9 +5931,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();
}
@@ -5461,9 +5952,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();
@@ -5471,7 +5962,7 @@ namespace Catch {
inline Option<std::size_t> list( Config const& config ) {
Option<std::size_t> 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 );
@@ -5490,19 +5981,32 @@ namespace Catch {
// #included from: catch_test_case_tracker.hpp
#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
-#include <map>
+#include <algorithm>
#include <string>
#include <assert.h>
#include <vector>
+#include <stdexcept>
+
+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
@@ -5518,7 +6022,7 @@ namespace TestCaseTracking {
virtual void markAsNeedingAnotherRun() = 0;
virtual void addChild( Ptr<ITracker> const& child ) = 0;
- virtual ITracker* findChild( std::string const& name ) = 0;
+ virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
virtual void openChild() = 0;
// Debug/ checking
@@ -5526,7 +6030,7 @@ namespace TestCaseTracking {
virtual bool isIndexTracker() const = 0;
};
- class TrackerContext {
+ class TrackerContext {
enum RunState {
NotStarted,
@@ -5588,30 +6092,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<ITracker> const& tracker ) {
- return tracker->name() == m_name;
+ return
+ tracker->nameAndLocation().name == m_nameAndLocation.name &&
+ tracker->nameAndLocation().location == m_nameAndLocation.location;
}
};
typedef std::vector<Ptr<ITracker> > 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;
@@ -5630,8 +6136,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;
@@ -5709,32 +6215,56 @@ namespace TestCaseTracking {
};
class SectionTracker : public TrackerBase {
+ std::vector<std::string> 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<SectionTracker&>( *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<SectionTracker*>( 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<std::string> 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<std::string> const& filters ) {
+ if( filters.size() > 1 )
+ m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
}
};
@@ -5742,8 +6272,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 )
{}
@@ -5751,17 +6281,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<IndexTracker*>( childTracker );
}
else {
- tracker = new IndexTracker( name, ctx, ¤tTracker, size );
+ tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size );
currentTracker.addChild( tracker );
}
@@ -5789,7 +6319,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;
@@ -5804,40 +6334,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 <AfxWin.h>
+#else
+#include <windows.h>
+#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 <signal.h>
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" },
@@ -5846,37 +6480,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( "<unknown signal>", -sig );
+ std::string name = "<unknown signal>";
+ 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 <set>
@@ -5921,7 +6588,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 );
@@ -5953,10 +6621,12 @@ namespace Catch {
m_activeTestCase = &testCase;
do {
- m_trackerContext.startRun();
+ ITracker& rootTracker = m_trackerContext.startRun();
+ assert( rootTracker.isSectionTracker() );
+ static_cast<SectionTracker&>( 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() );
@@ -5997,8 +6667,9 @@ namespace Catch {
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<void>(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 );
@@ -6010,10 +6681,7 @@ namespace Catch {
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 );
@@ -6072,18 +6740,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();
@@ -6102,11 +6778,11 @@ namespace Catch {
deltaTotals.testCases.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 ) );
}
@@ -6124,6 +6800,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 );
@@ -6145,7 +6822,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();
@@ -6173,9 +6854,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 );
}
@@ -6205,6 +6886,7 @@ namespace Catch {
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
+ bool m_shouldReportUnexpected;
};
IResultCapture& getResultCapture() {
@@ -6226,7 +6908,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;
@@ -6234,7 +6916,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 );
@@ -6243,7 +6925,7 @@ namespace Catch {
void operator=( Version const& );
};
- extern Version libraryVersion;
+ inline Version libraryVersion();
}
#include <fstream>
@@ -6355,7 +7037,7 @@ 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;
@@ -6396,6 +7078,32 @@ namespace Catch {
return returnCode;
}
+ #if defined(WIN32) && defined(UNICODE)
+ int run( int argc, wchar_t const* const* const argv ) {
+
+ char **utf8Argv = new char *[ argc ];
+
+ for ( int i = 0; i < argc; ++i ) {
+ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
+
+ utf8Argv[ i ] = new char[ bufSize ];
+
+ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
+ }
+
+ 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.showHelp )
return 0;
@@ -6455,13 +7163,8 @@ namespace Catch {
#include <vector>
#include <set>
#include <sstream>
-#include <iostream>
#include <algorithm>
-#ifdef CATCH_CPP14_OR_GREATER
-#include <random>
-#endif
-
namespace Catch {
struct RandomNumberGenerator {
@@ -6469,7 +7172,7 @@ namespace Catch {
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(); }
@@ -6477,7 +7180,7 @@ namespace Catch {
template<typename V>
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 );
@@ -6520,7 +7223,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());
@@ -6552,7 +7255,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() ) );
@@ -6601,7 +7304,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 );
@@ -6748,6 +7451,26 @@ namespace Catch {
};
}
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+ class TagAliasRegistry : public ITagAliasRegistry {
+ public:
+ virtual ~TagAliasRegistry();
+ virtual Option<TagAlias> 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<std::string, TagAlias> m_registry;
+ };
+
+} // end namespace Catch
+
namespace Catch {
namespace {
@@ -6769,6 +7492,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<IReporterFactory> const& factory ) CATCH_OVERRIDE {
@@ -6783,11 +7509,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
@@ -6819,7 +7549,7 @@ namespace Catch {
// #included from: catch_notimplemented_exception.hpp
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
-#include <ostream>
+#include <sstream>
namespace Catch {
@@ -6891,7 +7621,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() );
}
}
@@ -6944,6 +7674,11 @@ namespace Catch {
Context( Context const& );
void operator=( Context const& );
+ public:
+ virtual ~Context() {
+ deleteAllValues( m_generatorsByTestName );
+ }
+
public: // IContext
virtual IResultCapture* getResultCapture() {
return m_resultCapture;
@@ -7027,6 +7762,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 <cerrno>
+
+namespace Catch {
+
+ class ErrnoGuard {
+ public:
+ ErrnoGuard():m_oldErrno(errno){}
+ ~ErrnoGuard() { errno = m_oldErrno; }
+ private:
+ int m_oldErrno;
+ };
+
+}
+
namespace Catch {
namespace {
@@ -7052,21 +7804,11 @@ namespace Catch {
# define CATCH_CONFIG_COLOUR_WINDOWS
# else
# define CATCH_CONFIG_COLOUR_ANSI
-# endif
-#endif
-
-#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
-
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-
-#ifdef __AFXDLL
-#include <AfxWin.h>
-#else
-#include <windows.h>
+# endif
#endif
+#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
+
namespace Catch {
namespace {
@@ -7147,7 +7889,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" );
@@ -7172,6 +7914,7 @@ namespace {
};
IColourImpl* platformColourInstance() {
+ ErrnoGuard guard;
Ptr<IConfig const> config = getCurrentContext().getConfig();
UseColour::YesOrNo colourMode = config
? config->useColour()
@@ -7290,14 +8033,16 @@ namespace Catch {
namespace Catch {
- 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)
: macroName( _macroName ),
lineInfo( _lineInfo ),
capturedExpression( _capturedExpression ),
- resultDisposition( _resultDisposition )
+ resultDisposition( _resultDisposition ),
+ secondArg( _secondArg )
{}
AssertionResult::AssertionResult() {}
@@ -7324,24 +8069,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 {
@@ -7349,7 +8100,7 @@ namespace Catch {
}
std::string AssertionResult::getExpandedExpression() const {
- return m_resultData.reconstructedExpression;
+ return m_resultData.reconstructExpression();
}
std::string AssertionResult::getMessage() const {
@@ -7363,15 +8114,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 <cctype>
+
namespace Catch {
inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
- if( startsWith( tag, "." ) ||
+ if( startsWith( tag, '.' ) ||
tag == "hide" ||
tag == "!hide" )
return TestCaseInfo::IsHidden;
@@ -7381,25 +8142,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());
}
}
@@ -7455,7 +8214,7 @@ namespace Catch {
std::ostringstream oss;
for( std::set<std::string>::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::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
testCaseInfo.lcaseTags.insert( lcaseTag );
@@ -7561,7 +8320,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 ),
@@ -7571,18 +8330,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, 9, "", 0 );
+ inline Version libraryVersion() {
+ static Version version( 1, 9, 6, "", 0 );
+ return version;
+ }
}
@@ -7616,7 +8378,9 @@ namespace Catch {
{}
ScopedMessage::~ScopedMessage() {
- getResultCapture().popScopedMessage( m_info );
+ if ( !std::uncaught_exception() ){
+ getResultCapture().popScopedMessage(m_info);
+ }
}
} // end namespace Catch
@@ -7753,30 +8517,32 @@ namespace Catch
#endif
#ifdef CATCH_PLATFORM_WINDOWS
-#include <windows.h>
+
#else
+
#include <sys/time.h>
+
#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<LARGE_INTEGER*>( &hz ) );
QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
}
- uint64_t t;
+ UInt64 t;
QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
return ((t-hzo)*1000000)/hz;
}
#else
- uint64_t getCurrentTicks() {
+ UInt64 getCurrentTicks() {
timeval t;
gettimeofday(&t,CATCH_NULL);
- return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
+ return static_cast<UInt64>( t.tv_sec ) * 1000000ull + static_cast<UInt64>( t.tv_usec );
}
#endif
}
@@ -7802,19 +8568,28 @@ namespace Catch {
// #included from: catch_common.hpp
#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+#include <cstring>
+#include <cctype>
+
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<char>( ::tolower( c ) );
+ return static_cast<char>( std::tolower( c ) );
}
void toLowerInPlace( std::string& s ) {
std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
@@ -7829,7 +8604,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 ) {
@@ -7852,29 +8627,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 ) {
@@ -7887,16 +8658,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() );
}
@@ -7923,6 +8694,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() );
@@ -7932,6 +8707,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 {
@@ -7943,8 +8721,6 @@ namespace Catch {
// #included from: catch_debugger.hpp
#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
-#include <iostream>
-
#ifdef CATCH_PLATFORM_MAC
#include <assert.h>
@@ -7993,6 +8769,36 @@ namespace Catch {
}
} // namespace Catch
+#elif defined(CATCH_PLATFORM_LINUX)
+ #include <fstream>
+ #include <string>
+
+ 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 {
@@ -8014,7 +8820,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() );
@@ -8090,7 +8896,7 @@ std::string toString( std::string const& value ) {
}
}
}
- return "\"" + s + "\"";
+ return '"' + s + '"';
}
std::string toString( std::wstring const& value ) {
@@ -8111,19 +8917,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<const wchar_t*>( value ) );
+ return Catch::toString( static_cast<const wchar_t*>( 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();
}
@@ -8131,7 +8937,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();
}
@@ -8159,7 +8965,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 ) {
@@ -8167,9 +8973,19 @@ std::string toString( bool value ) {
}
std::string toString( char value ) {
- return value < ' '
- ? toString( static_cast<unsigned int>( 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<unsigned int>( value ) );
+ char chstr[] = "' '";
+ chstr[1] = value;
+ return chstr;
}
std::string toString( signed char value ) {
@@ -8185,14 +9001,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
@@ -8209,7 +9025,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]);
@@ -8226,20 +9042,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_stream().oss.str("");
+ }
+
+ ResultBuilder::~ResultBuilder() {
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+ if ( m_guardException ) {
+ m_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;
@@ -8249,27 +9073,15 @@ 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 ) {
+ AssertionResult result = build( expr );
+ handleResult( result );
}
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
m_assertionInfo.resultDisposition = resultDisposition;
- m_stream.oss << Catch::translateActiveException();
+ m_stream().oss << Catch::translateActiveException();
captureResult( ResultWas::ThrewException );
}
@@ -8277,19 +9089,20 @@ namespace Catch {
setResultType( resultType );
captureExpression();
}
+
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
if( expectedMessage.empty() )
- captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() );
+ captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() );
else
captureExpectedException( Matchers::Equals( expectedMessage ) );
}
- void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) {
+ void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> 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 ) ) {
@@ -8304,6 +9117,7 @@ namespace Catch {
AssertionResult result = build();
handleResult( result );
}
+
void ResultBuilder::handleResult( AssertionResult const& result )
{
getResultCapture().assertionEnded( result );
@@ -8315,7 +9129,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();
}
@@ -8325,43 +9149,39 @@ 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;
+ // Flip bool results if FalseTest flag is set
+ if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
+ data.negate( expr.isBinaryExpression() );
}
- 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 + ")";
- }
+ 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
@@ -8369,30 +9189,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 <map>
-
-namespace Catch {
-
- class TagAliasRegistry : public ITagAliasRegistry {
- public:
- virtual ~TagAliasRegistry();
- virtual Option<TagAlias> 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<std::string, TagAlias> m_registry;
- };
-
-} // end namespace Catch
-
-#include <map>
-#include <iostream>
-
namespace Catch {
TagAliasRegistry::~TagAliasRegistry() {}
@@ -8420,44 +9216,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
@@ -8601,9 +9473,34 @@ Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingRepo
#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
#include <cstring>
+#include <cfloat>
+#include <cstdio>
+#include <assert.h>
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<IStreamingReporter> {
StreamingReporterBase( ReporterConfig const& _config )
@@ -8698,12 +9595,12 @@ 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<SectionNode> const& node ) const {
return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
}
private:
- void operator=( BySectionInfo const& );
+ void operator=( BySectionInfo const& );
SectionInfo const& m_other;
};
@@ -8759,6 +9656,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 {
@@ -8793,6 +9696,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<IConfig const> m_config;
std::ostream& stream;
std::vector<AssertionStats> m_assertions;
@@ -8813,7 +9723,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;
@@ -8898,7 +9808,7 @@ namespace Catch {
return new T( config );
}
virtual std::string getDescription() const {
- return "";
+ return std::string();
}
};
@@ -8916,9 +9826,13 @@ namespace Catch {
#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+// Deprecated - use the form without INTERNAL_
#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+#define CATCH_REGISTER_LISTENER( listenerType ) \
+ namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+
// #included from: ../internal/catch_xmlwriter.hpp
#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
@@ -8967,8 +9881,11 @@ namespace Catch {
default:
// Escape control chars - based on contribution by @espenalb in PR #465 and
// by @mrpi PR #588
- if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
- os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';';
+ 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<int>( c );
+ }
else
os << c;
}
@@ -9022,20 +9939,17 @@ namespace Catch {
XmlWriter()
: m_tagIsOpen( false ),
m_needsNewline( false ),
- m_os( &Catch::cout() )
+ m_os( Catch::cout() )
{
- // We encode control characters, which requires
- // XML 1.1
- // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
- *m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
+ writeDeclaration();
}
XmlWriter( std::ostream& os )
: m_tagIsOpen( false ),
m_needsNewline( false ),
- m_os( &os )
+ m_os( os )
{
- *m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
+ writeDeclaration();
}
~XmlWriter() {
@@ -9046,7 +9960,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;
@@ -9063,24 +9977,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 << "</" << m_tags.back() << ">\n";
+ m_os << m_indent << "</" << m_tags.back() << ">";
}
+ 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;
}
@@ -9096,8 +10011,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;
@@ -9105,39 +10020,39 @@ namespace Catch {
XmlWriter& writeComment( std::string const& text ) {
ensureTagClosed();
- stream() << m_indent << "<!--" << text << "-->";
+ m_os << m_indent << "<!--" << text << "-->";
m_needsNewline = true;
return *this;
}
+ void writeStylesheetRef( std::string const& url ) {
+ m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\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 << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
}
void newlineIfNecessary() {
if( m_needsNewline ) {
- stream() << "\n";
+ m_os << std::endl;
m_needsNewline = false;
}
}
@@ -9146,24 +10061,10 @@ namespace Catch {
bool m_needsNewline;
std::vector<std::string> 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 __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
-
namespace Catch {
class XmlReporter : public StreamingReporterBase {
@@ -9182,6 +10083,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 {
@@ -9190,6 +10101,9 @@ namespace Catch {
virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testRunStarting( testInfo );
+ 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() );
@@ -9203,10 +10117,16 @@ namespace Catch {
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseStarting(testInfo);
- m_xml.startElement( "TestCase" ).writeAttribute( "name", 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 {
@@ -9215,77 +10135,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 <Info> 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 <Info> tags.
for( std::vector<MessageInfo>::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( "FatalErrorCondition" )
- .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;
@@ -9314,6 +10241,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();
}
@@ -9353,11 +10285,41 @@ 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() ),
+ m_okToFail( false )
{
m_reporterPrefs.shouldRedirectStdOut = true;
}
@@ -9383,8 +10345,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 );
}
@@ -9417,7 +10382,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
@@ -9452,7 +10417,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() ||
@@ -9530,14 +10495,14 @@ namespace Catch {
std::ostringstream oss;
if( !result.getMessage().empty() )
- oss << result.getMessage() << "\n";
+ oss << result.getMessage() << '\n';
for( std::vector<MessageInfo>::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 );
@@ -9549,6 +10514,7 @@ namespace Catch {
std::ostringstream stdOutForSuite;
std::ostringstream stdErrForSuite;
unsigned int unexpectedExceptions;
+ bool m_okToFail;
};
INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
@@ -9558,6 +10524,9 @@ namespace Catch {
// #included from: ../reporters/catch_reporter_console.hpp
#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+#include <cfloat>
+#include <cstdio>
+
namespace Catch {
struct ConsoleReporter : StreamingReporterBase {
@@ -9572,7 +10541,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 {
@@ -9581,18 +10550,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;
@@ -9612,15 +10578,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 );
}
@@ -9633,7 +10596,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 );
}
@@ -9685,7 +10648,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;
@@ -9725,13 +10692,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();
}
@@ -9748,25 +10715,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<MessageInfo>::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 {
@@ -9798,10 +10765,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 )
@@ -9829,22 +10796,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 );
@@ -9861,7 +10828,7 @@ namespace Catch {
i = 0;
stream << Text( _string, TextAttributes()
.setIndent( indent+i)
- .setInitialIndent( indent ) ) << "\n";
+ .setInitialIndent( indent ) ) << '\n';
}
struct SummaryColumn {
@@ -9876,9 +10843,9 @@ namespace Catch {
std::string row = oss.str();
for( std::vector<std::string>::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;
@@ -9898,8 +10865,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 {
@@ -9934,10 +10901,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 ) {
@@ -9973,10 +10940,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:
@@ -10011,11 +10978,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;
@@ -10036,9 +11002,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 );
}
@@ -10138,26 +11110,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:";
@@ -10168,7 +11140,7 @@ namespace Catch {
void printOriginalExpression() const {
if( result.hasExpression() ) {
- stream << " " << result.getExpression();
+ stream << ' ' << result.getExpression();
}
}
@@ -10184,7 +11156,7 @@ namespace Catch {
void printMessage() {
if ( itMessage != messages.end() ) {
- stream << " '" << itMessage->message << "'";
+ stream << " '" << itMessage->message << '\'';
++itMessage;
}
}
@@ -10199,13 +11171,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";
@@ -10231,7 +11203,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 {
@@ -10242,12 +11214,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 <<
@@ -10259,14 +11231,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" ) << '.';
}
}
};
@@ -10322,11 +11294,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() {}
@@ -10350,9 +11318,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__
@@ -10370,7 +11345,7 @@ int main (int argc, char * const argv[]) {
[pool drain];
#endif
- return result;
+ return ( result < 0xff ? result : 0xff );
}
#endif // __OBJC__
@@ -10386,33 +11361,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( 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_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_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( 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_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_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 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" )
+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#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__ )
@@ -10420,16 +11405,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( "", "" )
@@ -10455,50 +11442,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( "", "" )
@@ -10527,5 +11527,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/test/t/basic/test_cases.cpp b/test/t/basic/test_cases.cpp
index 96b5d55..8f66d4e 100644
--- a/test/t/basic/test_cases.cpp
+++ b/test/t/basic/test_cases.cpp
@@ -26,10 +26,7 @@ TEST_CASE("check every possible value for single byte in buffer") {
REQUIRE(item.length() == 1);
REQUIRE(!!item); // test operator bool()
- REQUIRE_THROWS({
- item.next();
- item.skip();
- });
+ REQUIRE_THROWS((item.next(), item.skip()));
}
}
diff --git a/test/t/bytes/test_cases.cpp b/test/t/bytes/test_cases.cpp
index 05d772d..b3284c0 100644
--- a/test/t/bytes/test_cases.cpp
+++ b/test/t/bytes/test_cases.cpp
@@ -9,7 +9,7 @@ TEST_CASE("read bytes field") {
protozero::pbf_reader item(buffer);
REQUIRE(item.next());
- REQUIRE(item.get_string() == "");
+ REQUIRE(item.get_bytes() == "");
REQUIRE(!item.next());
}
@@ -19,7 +19,7 @@ TEST_CASE("read bytes field") {
protozero::pbf_reader item(buffer);
REQUIRE(item.next());
- REQUIRE(item.get_string() == "x");
+ REQUIRE(item.get_bytes() == "x");
REQUIRE(!item.next());
}
@@ -29,7 +29,7 @@ TEST_CASE("read bytes field") {
protozero::pbf_reader item(buffer);
REQUIRE(item.next());
- REQUIRE(item.get_string() == "foobar");
+ REQUIRE(item.get_bytes() == "foobar");
REQUIRE(!item.next());
}
@@ -39,7 +39,7 @@ TEST_CASE("read bytes field") {
protozero::pbf_reader item(buffer);
REQUIRE(item.next());
- const std::string data = item.get_string();
+ const std::string data = item.get_bytes();
REQUIRE(data.size() == 3);
REQUIRE(data[0] == char(1));
REQUIRE(data[1] == char(2));
@@ -53,7 +53,7 @@ TEST_CASE("read bytes field") {
for (std::string::size_type i = 1; i < buffer.size(); ++i) {
protozero::pbf_reader item(buffer.data(), i);
REQUIRE(item.next());
- REQUIRE_THROWS_AS(item.get_string(), protozero::end_of_buffer_exception);
+ REQUIRE_THROWS_AS(item.get_bytes(), protozero::end_of_buffer_exception);
}
}
diff --git a/test/t/data_view/test_cases.cpp b/test/t/data_view/test_cases.cpp
index f71b9b1..43c8c1c 100644
--- a/test/t/data_view/test_cases.cpp
+++ b/test/t/data_view/test_cases.cpp
@@ -1,4 +1,6 @@
+#include <array>
+
#include <test.hpp>
#include <protozero/types.hpp>
@@ -7,12 +9,14 @@ TEST_CASE("default constructed data_view") {
protozero::data_view view;
REQUIRE(view.data() == nullptr);
REQUIRE(view.size() == 0);
+ REQUIRE(view.empty());
}
TEST_CASE("data_view from C string") {
protozero::data_view view{"foobar"};
REQUIRE(view.data());
REQUIRE(view.size() == 6);
+ REQUIRE_FALSE(view.empty());
}
TEST_CASE("data_view from std::string") {
@@ -29,6 +33,20 @@ TEST_CASE("data_view from ptr, size") {
REQUIRE(view.size() == 6);
}
+TEST_CASE("data_view from C array") {
+ const char str[] = "foobar";
+ protozero::data_view view{str};
+ REQUIRE(view.data());
+ REQUIRE(view.size() == 6);
+}
+
+TEST_CASE("data_view from std::array") {
+ std::array<char, 7> str{"foobar"};
+ protozero::data_view view{str.data(), 6};
+ REQUIRE(view.data());
+ REQUIRE(view.size() == 6);
+}
+
TEST_CASE("convert data_view to std::string") {
protozero::data_view view{"foobar"};
@@ -40,9 +58,7 @@ TEST_CASE("convert data_view to std::string") {
TEST_CASE("converting default constructed data_view to string fails") {
protozero::data_view view;
- REQUIRE_THROWS_AS({
- view.to_string();
- }, assert_error);
+ REQUIRE_THROWS_AS(view.to_string(), assert_error);
}
TEST_CASE("swapping data_view") {
@@ -64,20 +80,32 @@ TEST_CASE("comparing data_views") {
protozero::data_view v2{"bar"};
protozero::data_view v3{"foox"};
protozero::data_view v4{"foo"};
+ protozero::data_view v5{"fooooooo", 3};
+ protozero::data_view v6{"f\0o", 3};
+ protozero::data_view v7{"f\0obar", 3};
REQUIRE_FALSE(v1 == v2);
REQUIRE_FALSE(v1 == v3);
REQUIRE(v1 == v4);
+ REQUIRE(v1 == v5);
+ REQUIRE_FALSE(v1 == v6);
+ REQUIRE_FALSE(v1 == v7);
REQUIRE_FALSE(v2 == v3);
REQUIRE_FALSE(v2 == v4);
REQUIRE_FALSE(v3 == v4);
+ REQUIRE(v4 == v5);
+ REQUIRE(v6 == v7);
REQUIRE(v1 != v2);
REQUIRE(v1 != v3);
REQUIRE_FALSE(v1 != v4);
+ REQUIRE_FALSE(v1 != v5);
+ REQUIRE(v1 != v6);
+ REQUIRE(v1 != v7);
REQUIRE(v2 != v3);
REQUIRE(v2 != v4);
REQUIRE(v3 != v4);
+ REQUIRE_FALSE(v4 != v5);
+ REQUIRE_FALSE(v6 != v7);
}
-
diff --git a/test/t/rollback/test_cases.cpp b/test/t/rollback/test_cases.cpp
index 99ab6d6..bdf6f3d 100644
--- a/test/t/rollback/test_cases.cpp
+++ b/test/t/rollback/test_cases.cpp
@@ -132,9 +132,7 @@ TEST_CASE("rollback when using packed_field functions") {
protozero::packed_field_sint64 field{pw, 1};
field.add_element(1L);
field.rollback();
- REQUIRE_THROWS_AS({
- field.add_element(1L);
- }, assert_error);
+ REQUIRE_THROWS_AS(field.add_element(1L), assert_error);
}
}
}
@@ -174,9 +172,7 @@ TEST_CASE("rollback when using submessages") {
TEST_CASE("rollback on parent message is never allowed") {
std::string buffer;
protozero::pbf_writer pw(buffer);
- REQUIRE_THROWS_AS({
- pw.rollback();
- }, assert_error);
+ REQUIRE_THROWS_AS(pw.rollback(), assert_error);
}
TEST_CASE("rollback on parent message is not allowed even if there is a submessage") {
@@ -189,9 +185,7 @@ TEST_CASE("rollback on parent message is not allowed even if there is a submessa
{
protozero::pbf_writer pws(pw, 1);
pws.add_string(1, "foobar");
- REQUIRE_THROWS_AS({
- pw.rollback();
- }, assert_error);
+ REQUIRE_THROWS_AS(pw.rollback(), assert_error);
}
}
@@ -206,9 +200,7 @@ TEST_CASE("rollback on message is not allowed if there is a nested submessage")
protozero::pbf_writer pws(pw, 1);
pws.add_string(1, "foobar");
protozero::pbf_writer pws2(pws, 1);
- REQUIRE_THROWS_AS({
- pws.rollback();
- }, assert_error);
+ REQUIRE_THROWS_AS(pws.rollback(), assert_error);
}
}
diff --git a/test/t/tag_and_type/test_cases.cpp b/test/t/tag_and_type/test_cases.cpp
index 3175388..71851b4 100644
--- a/test/t/tag_and_type/test_cases.cpp
+++ b/test/t/tag_and_type/test_cases.cpp
@@ -1,4 +1,6 @@
+#include <cstdint>
+#include <string>
#include <vector>
#include <test.hpp>
@@ -33,6 +35,20 @@ inline std::vector<uint32_t> read_data(const std::string& data) {
return values;
}
+inline std::vector<uint32_t> read_data_packed(const std::string& data) {
+ std::vector<uint32_t> values;
+
+ protozero::pbf_message<ExampleMsg> message{data};
+ while (message.next(ExampleMsg::repeated_uint32_x, protozero::pbf_wire_type::length_delimited)) {
+ const auto xit = message.get_packed_uint32();
+ for (const auto value : xit) {
+ values.push_back(value);
+ }
+ }
+
+ return values;
+}
+
TEST_CASE("read not packed repeated field with tag_and_type") {
const auto values = read_data(load_data("tag_and_type/data-not-packed"));
@@ -41,6 +57,12 @@ TEST_CASE("read not packed repeated field with tag_and_type") {
REQUIRE(values == result);
}
+TEST_CASE("read not packed repeated field with tag_and_type using next(...)") {
+ const auto values = read_data_packed(load_data("tag_and_type/data-not-packed"));
+
+ REQUIRE(values.size() == 0);
+}
+
TEST_CASE("read packed repeated field with tag_and_type") {
const auto values = read_data(load_data("tag_and_type/data-packed"));
@@ -49,6 +71,14 @@ TEST_CASE("read packed repeated field with tag_and_type") {
REQUIRE(values == result);
}
+TEST_CASE("read packed repeated field with tag_and_type using next(...)") {
+ const auto values = read_data_packed(load_data("tag_and_type/data-packed"));
+
+ REQUIRE(values.size() == 3);
+ const std::vector<uint32_t> result{20, 21, 22};
+ REQUIRE(values == result);
+}
+
TEST_CASE("read combined packed and not-packed repeated field with tag_and_type") {
const auto values = read_data(load_data("tag_and_type/data-combined"));
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/protozero.git
More information about the Pkg-grass-devel
mailing list