This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository protozero.
commit 75e5eb1b317e90d0c5aeef258e51921a40eb8e3d Author: Bas Couwenberg <[email protected]> Date: Fri Nov 18 16:11:40 2016 +0100 Imported Upstream version 1.4.5 --- .travis.yml | 29 +- CHANGELOG.md | 11 +- README.md | 39 +-- UPGRADING.md | 5 + doc/Doxyfile | 2 +- doc/macros.md | 14 - include/protozero/config.hpp | 11 - include/protozero/iterators.hpp | 33 -- include/protozero/pbf_reader.hpp | 5 +- include/protozero/version.hpp | 4 +- package.json | 2 +- test/include/catch.hpp | 664 +++++++++++++++++++++++++++++---------- test/include/test.hpp | 2 +- test/t/int64/testcase.cpp | 2 +- 14 files changed, 550 insertions(+), 273 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8a83b9c..de09019 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,11 +12,15 @@ addons_shortcuts: apt: sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8' ] packages: [ 'clang-3.8', 'libprotobuf-dev','protobuf-compiler' ] - addons_gcc49: &gcc47 +# addons_clang39: &clang39 +# apt: +# sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.9' ] +# packages: [ 'clang-3.9', 'libprotobuf-dev','protobuf-compiler' ] + addons_gcc47: &gcc47 apt: sources: [ 'ubuntu-toolchain-r-test' ] packages: [ 'g++-4.7', 'gcc-4.7', 'libprotobuf-dev','protobuf-compiler' ] - addons_gcc49: &gcc48 + addons_gcc48: &gcc48 apt: sources: [ 'ubuntu-toolchain-r-test' ] packages: [ 'g++-4.8', 'gcc-4.8', 'libprotobuf-dev','protobuf-compiler' ] @@ -24,10 +28,14 @@ addons_shortcuts: apt: sources: [ 'ubuntu-toolchain-r-test' ] packages: [ 'g++-4.9', 'gcc-4.9', 'libprotobuf-dev','protobuf-compiler' ] - addons_gcc49: &gcc5 + addons_gcc5: &gcc5 apt: sources: [ 'ubuntu-toolchain-r-test' ] packages: [ 'g++-5', 'gcc-5', 'libprotobuf-dev','protobuf-compiler' ] + addons_gcc6: &gcc6 + apt: + sources: [ 'ubuntu-toolchain-r-test' ] + packages: [ 'g++-6', 'gcc-6', 'libprotobuf-dev','protobuf-compiler' ] matrix: include: @@ -37,6 +45,9 @@ matrix: - os: osx osx_image: xcode7 compiler: clang + - os: osx + osx_image: xcode8 + compiler: clang - os: linux compiler: "clang35" env: CXX=clang++-3.5 @@ -50,10 +61,6 @@ matrix: env: CXX=clang++-3.8 CXX_STD=c++14 addons: *clang38 - os: linux - compiler: "clang38" - env: CXX=clang++-3.8 CXXFLAGS="-DPROTOZERO_DO_NOT_USE_BARE_POINTER=1" - addons: *clang38 - - os: linux compiler: "gcc47" env: CXX=g++-4.7 addons: *gcc47 @@ -70,10 +77,6 @@ matrix: env: CXX=g++-4.9 CXX_STD=c++14 addons: *gcc49 - os: linux - compiler: "gcc49" - env: CXX=g++-4.9 CXXFLAGS="-DPROTOZERO_DO_NOT_USE_BARE_POINTER=1" - addons: *gcc49 - - os: linux compiler: "gcc5" env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" addons: *gcc5 @@ -81,6 +84,10 @@ matrix: compiler: "gcc5" env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1" addons: *gcc5 + - os: linux + compiler: "gcc6" + env: CXX=g++-6 + addons: *gcc6 before_install: - echo ${CXX} diff --git a/CHANGELOG.md b/CHANGELOG.md index 46af379..b8dbbca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +## [1.4.5] - 2016-11-18 + +### Fixed + +- Undefined behaviour in packed fixed iterator. As a result, the macro + `PROTOZERO_DO_NOT_USE_BARE_POINTER` is not used any more. + + ## [1.4.4] - 2016-11-15 ### Fixed @@ -123,7 +131,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.4.4...HEAD +[unreleased]: https://github.com/osmcode/libosmium/compare/v1.4.5...HEAD +[1.4.5]: https://github.com/osmcode/libosmium/compare/v1.4.4...v1.4.5 [1.4.4]: https://github.com/osmcode/libosmium/compare/v1.4.3...v1.4.4 [1.4.3]: https://github.com/osmcode/libosmium/compare/v1.4.2...v1.4.3 [1.4.2]: https://github.com/osmcode/libosmium/compare/v1.4.1...v1.4.2 diff --git a/README.md b/README.md index fef52e2..0fa752b 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ Designed for high performance. Suitable for writing zero copy parsers and encoders with minimal need for run-time allocation of memory. Low-level: this is designed to be a building block for writing a very -customized decoder for a stable protobuf schema. If your protobuf schema -is changing frequently or lazy decoding is not critical for your application -then this approach offers no value: just use the decoding API available via the -C++ API that can be generated via the Google Protobufs `protoc` program. +customized decoder for a stable protobuf schema. If your protobuf schema is +changing frequently or lazy decoding is not critical for your application then +this approach offers no value: just use the C++ API that can be generated with +the Google Protobufs `protoc` program. [](https://travis-ci.org/mapbox/protozero) [](https://ci.appveyor.com/project/Mapbox/protozero) @@ -17,7 +17,9 @@ C++ API that can be generated via the Google Protobufs `protoc` program. ## Depends - - C++11 compiler +* C++11 compiler +* Tests depend on the Google Protobuf library, but use of Protozero doesn't + need it ## How it works @@ -78,26 +80,12 @@ Call `make install` to install include files in `/usr/include/protozero`. Call https://developers.google.com/protocol-buffers/docs/proto3#maps. -## Memory Alignment Issues and Endianness +## Endianness -Protobuf-encoded data is not necessarily properly aligned for the machine we -are using. For single values this isn't a problem, because we copy those into -a properly aligned variable and return that one. But for repeated packed values -it can be a problem, because we give users access to them through an iterator. -To get the best performance this iterator is usually just a raw pointer. This -works fine on Intel processors, non-aligned access is just slower than aligned -access. On ARM this is not necessarily the case (depends on machine type and -compile options), so we need to go through a special iterator there -which makes sure to return aligned data on member access. Basically the same -iterator is used on big endian architectures to put the bytes in the correct -order before handing them back to the application. - -Detection of endianess and those architectures which have problems with -non-aligned data is not perfect. If tests fail for you, this might be a problem -in your setup. Please open an issue on Github in this case and tell us about -your system. - -See also the discussion on https://github.com/mapbox/protozero/issues/33 . +Protozero uses a very simplistic test to check the byte order of the system it +compiles on. If this check is wrong, you'll get test failures. If this is the +case, please [open an issue](https://github.com/mapbox/protozero/issues) and +tell us about your system. ## Tests @@ -153,8 +141,9 @@ For extra checks with [Cppcheck](http://cppcheck.sourceforge.net/) you can call * [Carmen](https://github.com/mapbox/carmen-cache) * [Libosmium](https://github.com/osmcode/libosmium) -* [Mapnik](https://github.com/mapbox/mapnik-vector-tile) * [Mapbox GL Native](https://github.com/mapbox/mapbox-gl-native) +* [Mapbox Vector Tile library](https://github.com/mapbox/vector-tile) +* [Mapnik](https://github.com/mapbox/mapnik-vector-tile) * [OSRM](https://github.com/Project-OSRM/osrm-backend) * [Tippecanoe](https://github.com/mapbox/tippecanoe) diff --git a/UPGRADING.md b/UPGRADING.md index 16b0fa3..002ab99 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -13,6 +13,11 @@ macro `PROTOZERO_STRICT_API` in which case Protozero will compile without the code used for backwards compatibilty. You will then get compile errors for older API usages. +## Upgrading from *v1.4.4* to *v1.4.5* + +* The macro `PROTOZERO_DO_NOT_USE_BARE_POINTER` is not used any more. If you + have been setting this, remove it. + ## Upgrading from *v1.4.0* to *v1.4.1* * You can now do `require('protozero')` in nodejs to print the path diff --git a/doc/Doxyfile b/doc/Doxyfile index b4e20d4..d0a076c 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -815,7 +815,7 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = protozero::detail protozero_assert PROTOZERO_*_ENDIAN PROTOZERO_BYTE_ORDER PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED +EXCLUDE_SYMBOLS = protozero::detail protozero_assert PROTOZERO_*_ENDIAN PROTOZERO_BYTE_ORDER # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include diff --git a/doc/macros.md b/doc/macros.md index 37780a1..e16ab1e 100644 --- a/doc/macros.md +++ b/doc/macros.md @@ -38,17 +38,3 @@ an alias to the class you specify. This affects the result type of the `pbf_reader::get_view()` method and a few others taking a `protozero::data_view` as parameters. -## `PROTOZERO_DO_NOT_USE_BARE_POINTER` - -Can be set to force Protozero to not use bare pointers for some iterators -returned from `get_packed_*` calls. Use of the bare pointers leads to undefined -behaviour according to the C++ standard, so define this if you don't want to -have that. - -But it is usually not necessary to use this and might affect performance if you -do. If you are getting errors about unaligned memory access or a SIGBUS, you -can try to set this. (Please also report an error if this is the case.) - -If you don't set this, the clang UBSan (Undefined behaviour sanitizer) will -report unaligned memory accesses. - diff --git a/include/protozero/config.hpp b/include/protozero/config.hpp index 8465c96..6fc7749 100644 --- a/include/protozero/config.hpp +++ b/include/protozero/config.hpp @@ -35,17 +35,6 @@ documentation. # define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN #endif -// On some ARM machines and depending on compiler settings access to unaligned -// floating point values will result in a SIGBUS. Do not use the bare pointers -// in this case. -#if PROTOZERO_BYTE_ORDER == PROTOZERO_LITTLE_ENDIAN -# if !defined(__arm__) && !defined(_M_ARM) -# ifndef PROTOZERO_DO_NOT_USE_BARE_POINTER -# define PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED -# endif -# endif -#endif - // Check whether __builtin_bswap is available #if defined(__GNUC__) || defined(__clang__) # define PROTOZERO_USE_BUILTIN_BSWAP diff --git a/include/protozero/iterators.hpp b/include/protozero/iterators.hpp index 40259a9..a19f202 100644 --- a/include/protozero/iterators.hpp +++ b/include/protozero/iterators.hpp @@ -138,25 +138,6 @@ inline void swap(iterator_range<T>& lhs, iterator_range<T>& rhs) noexcept { lhs.swap(rhs); } -#ifdef PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED - -template <typename T> -using const_fixed_iterator = const T*; - -/** - * Create iterator_range from char pointers to beginning and end of range. - * - * @param first Beginning of range. - * @param last End of range. - */ -template <typename T> -inline iterator_range<const_fixed_iterator<T>> create_fixed_iterator_range(const char* first, const char* last) { - return iterator_range<const_fixed_iterator<T>>{reinterpret_cast<const T*>(first), - reinterpret_cast<const T*>(last)}; -} - -#else - /** * A forward iterator used for accessing packed repeated fields of fixed * length (fixed32, sfixed32, float, double). @@ -227,20 +208,6 @@ public: }; // class const_fixed_iterator /** - * Create iterator_range from char pointers to beginning and end of range. - * - * @param first Beginning of range. - * @param last End of range. - */ -template <typename T> -inline iterator_range<const_fixed_iterator<T>> create_fixed_iterator_range(const char* first, const char* last) { - return iterator_range<const_fixed_iterator<T>>{const_fixed_iterator<T>(first, last), - const_fixed_iterator<T>(last, last)}; -} - -#endif - -/** * A forward iterator used for accessing packed repeated varint fields * (int32, uint32, int64, uint64, bool, enum). */ diff --git a/include/protozero/pbf_reader.hpp b/include/protozero/pbf_reader.hpp index 69f2d72..8754cab 100644 --- a/include/protozero/pbf_reader.hpp +++ b/include/protozero/pbf_reader.hpp @@ -87,7 +87,8 @@ class pbf_reader { protozero_assert(tag() != 0 && "call next() before accessing field value"); const auto len = get_len_and_skip(); protozero_assert(len % sizeof(T) == 0); - return create_fixed_iterator_range<T>(m_data - len, m_data); + return iterator_range<const_fixed_iterator<T>>{const_fixed_iterator<T>(m_data - len, m_data), + const_fixed_iterator<T>(m_data, m_data)}; } template <typename T> @@ -178,7 +179,7 @@ public: * * @post There is no current field. */ - pbf_reader(std::pair<const char*, std::size_t> data) noexcept + 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), diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp index c3e91a3..d7cea48 100644 --- a/include/protozero/version.hpp +++ b/include/protozero/version.hpp @@ -23,13 +23,13 @@ documentation. #define PROTOZERO_VERSION_MINOR 4 /// The patch number -#define PROTOZERO_VERSION_PATCH 4 +#define PROTOZERO_VERSION_PATCH 5 /// 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.4.4" +#define PROTOZERO_VERSION_STRING "1.4.5" #endif // PROTOZERO_VERSION_HPP diff --git a/package.json b/package.json index 3208303..1a81c51 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "protozero", - "version": "1.4.4", + "version": "1.4.5", "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 f042149..2e6fe8d 100644 --- a/test/include/catch.hpp +++ b/test/include/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v1.3.3 - * Generated: 2016-01-22 07:51:36.661106 + * Catch v1.5.8 + * Generated: 2016-10-26 12:07:30.938259 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -62,7 +62,11 @@ #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 ) -#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( 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 ) @@ -89,7 +93,7 @@ // 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? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too @@ -102,6 +106,18 @@ // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 +#ifdef __cplusplus + +# if __cplusplus >= 201103L +# define CATCH_CPP11_OR_GREATER +# endif + +# if __cplusplus >= 201402L +# define CATCH_CPP14_OR_GREATER +# endif + +#endif + #ifdef __clang__ # if __has_feature(cxx_nullptr) @@ -112,6 +128,10 @@ # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif +# if defined(CATCH_CPP11_OR_GREATER) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# endif + #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// @@ -136,9 +156,13 @@ // GCC #ifdef __GNUC__ -#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -#endif +# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# 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,13 +197,20 @@ #endif +// Use __COUNTER__ if the compiler supports it +#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ + ( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \ + ( defined __clang__ && __clang_major__ >= 3 ) + +#define CATCH_INTERNAL_CONFIG_COUNTER + +#endif + //////////////////////////////////////////////////////////////////////////////// // C++ language feature support // catch all support for C++11 -#if defined(__cplusplus) && __cplusplus >= 201103L - -# define CATCH_CPP11_OR_GREATER +#if defined(CATCH_CPP11_OR_GREATER) # if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR @@ -246,6 +277,13 @@ #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) # define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif // noexcept support: #if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) @@ -672,24 +710,28 @@ void registerTestCaseFunction #ifdef CATCH_CONFIG_VARIADIC_MACROS /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ + static void TestName(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + 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 ); } /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ namespace{ \ - struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + struct TestName : ClassName{ \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ } \ - void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + 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, ... ) \ @@ -697,24 +739,28 @@ void registerTestCaseFunction #else /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \ + static void TestName(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void TestName() #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ - static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + 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 ); } /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\ namespace{ \ - struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + struct TestCaseName : ClassName{ \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ } \ - void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + 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 ) \ @@ -1287,37 +1333,37 @@ namespace Internal { template<typename T1, typename T2> struct Evaluator<T1, T2, IsEqualTo> { static bool evaluate( T1 const& lhs, T2 const& rhs) { - return opCast( lhs ) == opCast( rhs ); + return bool( opCast( lhs ) == opCast( rhs ) ); } }; template<typename T1, typename T2> struct Evaluator<T1, T2, IsNotEqualTo> { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) != opCast( rhs ); + return bool( opCast( lhs ) != opCast( rhs ) ); } }; template<typename T1, typename T2> struct Evaluator<T1, T2, IsLessThan> { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) < opCast( rhs ); + return bool( opCast( lhs ) < opCast( rhs ) ); } }; template<typename T1, typename T2> struct Evaluator<T1, T2, IsGreaterThan> { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) > opCast( rhs ); + return bool( opCast( lhs ) > opCast( rhs ) ); } }; template<typename T1, typename T2> struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) >= opCast( rhs ); + return bool( opCast( lhs ) >= opCast( rhs ) ); } }; template<typename T1, typename T2> struct Evaluator<T1, T2, IsLessThanOrEqualTo> { static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return opCast( lhs ) <= opCast( rhs ); + return bool( opCast( lhs ) <= opCast( rhs ) ); } }; @@ -2020,13 +2066,14 @@ namespace Catch { do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ ( __catchResult <= expr ).endExpression(); \ } \ catch( ... ) { \ __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ } \ 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 && !!(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ @@ -2563,10 +2610,12 @@ namespace Catch { } /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ - static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ - namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ - static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ + static std::string translatorName( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\ + static std::string translatorName( signature ) + +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) // #included from: internal/catch_approx.hpp #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED @@ -3174,10 +3223,11 @@ namespace Catch { bool matches( TestCaseInfo const& testCase ) const { // All patterns in a filter must match for the filter to be a match - for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { if( !(*it)->matches( testCase ) ) return false; - return true; + } + return true; } }; @@ -3331,6 +3381,11 @@ namespace Catch { InLexicographicalOrder, InRandomOrder }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; class TestSpec; @@ -3350,7 +3405,7 @@ namespace Catch { virtual TestSpec const& testSpec() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; - virtual bool forceColour() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; }; } @@ -3404,7 +3459,7 @@ namespace Catch { }; class DebugOutStream : public IStream { - std::auto_ptr<StreamBufBase> m_streamBuf; + CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; mutable std::ostream m_os; public: DebugOutStream(); @@ -3439,14 +3494,14 @@ namespace Catch { noThrow( false ), showHelp( false ), showInvisibles( false ), - forceColour( false ), filenamesAsTags( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), warnings( WarnAbout::Nothing ), showDurations( ShowDurations::DefaultForReporter ), - runOrder( RunTests::InDeclarationOrder ) + runOrder( RunTests::InDeclarationOrder ), + useColour( UseColour::Auto ) {} bool listTests; @@ -3459,7 +3514,6 @@ namespace Catch { bool noThrow; bool showHelp; bool showInvisibles; - bool forceColour; bool filenamesAsTags; int abortAfter; @@ -3469,6 +3523,7 @@ namespace Catch { WarnAbout::What warnings; ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; + UseColour::YesOrNo useColour; std::string outputFilename; std::string name; @@ -3534,7 +3589,7 @@ namespace Catch { 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 bool forceColour() const { return m_data.forceColour; } + virtual UseColour::YesOrNo useColour() const { return m_data.useColour; } private: @@ -3552,7 +3607,7 @@ namespace Catch { } ConfigData m_data; - std::auto_ptr<IStream const> m_stream; + CATCH_AUTO_PTR( IStream const ) m_stream; TestSpec m_testSpec; }; @@ -3572,6 +3627,8 @@ namespace Catch { #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { // #included from: ../external/clara.h +// Version 0.0.2.4 + // Only use header guard if we are not using an outer namespace #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) @@ -3596,6 +3653,7 @@ namespace Catch { #include <string> #include <vector> #include <sstream> +#include <algorithm> // Use optional outer namespace #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE @@ -3730,15 +3788,165 @@ namespace Tbc { #endif // TBC_TEXT_FORMAT_H_INCLUDED // ----------- end of #include from tbc_text_format.h ----------- -// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h +// ........... back in clara.h #undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE +// ----------- #included from clara_compilers.h ----------- + +#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED +#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? +// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_<feature name> form +// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + +#ifdef __clang__ + +#if __has_feature(cxx_nullptr) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if __has_feature(cxx_noexcept) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + +#define CLARA_CPP11_OR_GREATER + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) +#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT +#endif + +#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) +#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE +#endif +#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +#endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NULLPTR +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) +#define CLARA_CONFIG_CPP11_UNIQUE_PTR +#endif + +// noexcept support: +#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) +#define CLARA_NOEXCEPT noexcept +# define CLARA_NOEXCEPT_IS(x) noexcept(x) +#else +#define CLARA_NOEXCEPT throw() +# define CLARA_NOEXCEPT_IS(x) +#endif + +// nullptr support +#ifdef CLARA_CONFIG_CPP11_NULLPTR +#define CLARA_NULL nullptr +#else +#define CLARA_NULL NULL +#endif + +// override support +#ifdef CLARA_CONFIG_CPP11_OVERRIDE +#define CLARA_OVERRIDE override +#else +#define CLARA_OVERRIDE +#endif + +// unique_ptr support +#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR +# define CLARA_AUTO_PTR( T ) std::unique_ptr<T> +#else +# define CLARA_AUTO_PTR( T ) std::auto_ptr<T> +#endif + +#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + +// ----------- end of #include from clara_compilers.h ----------- +// ........... back in clara.h + #include <map> -#include <algorithm> #include <stdexcept> #include <memory> +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CLARA_PLATFORM_WINDOWS +#endif + // Use optional outer namespace #ifdef STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE @@ -3797,23 +4005,15 @@ namespace Clara { else throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); } - inline void convertInto( bool _source, bool& _dest ) { - _dest = _source; - } - template<typename T> - inline void convertInto( bool, T& ) { - throw std::runtime_error( "Invalid conversion" ); - } template<typename ConfigT> struct IArgFunction { virtual ~IArgFunction() {} -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS +#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS IArgFunction() = default; IArgFunction( IArgFunction const& ) = default; -# endif +#endif virtual void set( ConfigT& config, std::string const& value ) const = 0; - virtual void setFlag( ConfigT& config ) const = 0; virtual bool takesArg() const = 0; virtual IArgFunction* clone() const = 0; }; @@ -3821,11 +4021,11 @@ namespace Clara { template<typename ConfigT> class BoundArgFunction { public: - BoundArgFunction() : functionObj( CATCH_NULL ) {} + BoundArgFunction() : functionObj( CLARA_NULL ) {} BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CATCH_NULL ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL; + IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; delete functionObj; functionObj = newFunctionObj; return *this; @@ -3835,13 +4035,10 @@ namespace Clara { void set( ConfigT& config, std::string const& value ) const { functionObj->set( config, value ); } - void setFlag( ConfigT& config ) const { - functionObj->setFlag( config ); - } bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { - return functionObj != CATCH_NULL; + return functionObj != CLARA_NULL; } private: IArgFunction<ConfigT>* functionObj; @@ -3850,7 +4047,6 @@ namespace Clara { template<typename C> struct NullBinder : IArgFunction<C>{ virtual void set( C&, std::string const& ) const {} - virtual void setFlag( C& ) const {} virtual bool takesArg() const { return true; } virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } }; @@ -3861,9 +4057,6 @@ namespace Clara { virtual void set( C& p, std::string const& stringValue ) const { convertInto( stringValue, p.*member ); } - virtual void setFlag( C& p ) const { - convertInto( true, p.*member ); - } virtual bool takesArg() const { return !IsBool<M>::value; } virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } M C::* member; @@ -3876,11 +4069,6 @@ namespace Clara { convertInto( stringValue, value ); (p.*member)( value ); } - virtual void setFlag( C& p ) const { - typename RemoveConstRef<M>::type value; - convertInto( true, value ); - (p.*member)( value ); - } virtual bool takesArg() const { return !IsBool<M>::value; } virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } void (C::*member)( M ); @@ -3894,9 +4082,6 @@ namespace Clara { if( value ) (p.*member)(); } - virtual void setFlag( C& p ) const { - (p.*member)(); - } virtual bool takesArg() const { return false; } virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } void (C::*member)(); @@ -3911,9 +4096,6 @@ namespace Clara { if( value ) function( obj ); } - virtual void setFlag( C& p ) const { - function( p ); - } virtual bool takesArg() const { return false; } virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } void (*function)( C& ); @@ -3927,11 +4109,6 @@ namespace Clara { convertInto( stringValue, value ); function( obj, value ); } - virtual void setFlag( C& obj ) const { - typename RemoveConstRef<T>::type value; - convertInto( true, value ); - function( obj, value ); - } virtual bool takesArg() const { return !IsBool<T>::value; } virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } void (*function)( C&, T ); @@ -3939,8 +4116,20 @@ namespace Clara { } // namespace Detail - struct Parser { - Parser() : separators( " \t=:" ) {} + inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) { + std::vector<std::string> args( static_cast<std::size_t>( argc ) ); + for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i ) + args[i] = argv[i]; + + return args; + } + + class Parser { + enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; + Mode mode; + std::size_t from; + bool inQuotes; + public: struct Token { enum Type { Positional, ShortOpt, LongOpt }; @@ -3949,38 +4138,75 @@ namespace Clara { std::string data; }; - void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const { + Parser() : mode( None ), from( 0 ), inQuotes( false ){} + + void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) { const std::string doubleDash = "--"; - for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) - parseIntoTokens( argv[i] , tokens); - } - void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const { - while( !arg.empty() ) { - Parser::Token token( Parser::Token::Positional, arg ); - arg = ""; - if( token.data[0] == '-' ) { - if( token.data.size() > 1 && token.data[1] == '-' ) { - token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); - } - else { - token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); - if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { - arg = "-" + token.data.substr( 1 ); - token.data = token.data.substr( 0, 1 ); - } - } - } - if( token.type != Parser::Token::Positional ) { - std::size_t pos = token.data.find_first_of( separators ); - if( pos != std::string::npos ) { - arg = token.data.substr( pos+1 ); - token.data = token.data.substr( 0, pos ); - } - } - tokens.push_back( token ); + for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) + parseIntoTokens( args[i], tokens); + } + + void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) { + 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( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { + switch( mode ) { + case None: return handleNone( i, c ); + case MaybeShortOpt: return handleMaybeShortOpt( i, c ); + case ShortOpt: + case LongOpt: + case SlashOpt: return handleOpt( i, c, arg, tokens ); + case Positional: return handlePositional( i, c, arg, tokens ); + default: throw std::logic_error( "Unknown mode" ); } } - std::string separators; + + Mode handleNone( std::size_t i, char c ) { + if( inQuotes ) { + from = i; + return Positional; + } + switch( c ) { + case '-': return MaybeShortOpt; +#ifdef CLARA_PLATFORM_WINDOWS + case '/': from = i+1; return SlashOpt; +#endif + default: from = i; return Positional; + } + } + Mode handleMaybeShortOpt( std::size_t i, char c ) { + switch( c ) { + case '-': from = i+1; return LongOpt; + 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; + + std::string optName = arg.substr( from, i-from ); + if( mode == ShortOpt ) + for( std::size_t j = 0; j < optName.size(); ++j ) + tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); + else if( mode == SlashOpt && optName.size() == 1 ) + tokens.push_back( Token( Token::ShortOpt, optName ) ); + else + tokens.push_back( Token( Token::LongOpt, optName ) ); + return None; + } + Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { + if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) + return mode; + + std::string data = arg.substr( from, i-from ); + tokens.push_back( Token( Token::Positional, data ) ); + return None; + } }; template<typename ConfigT> @@ -4059,7 +4285,7 @@ namespace Clara { } }; - typedef CATCH_AUTO_PTR( Arg ) ArgAutoPtr; + typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; friend void addOptName( Arg& arg, std::string const& optName ) { @@ -4135,8 +4361,8 @@ namespace Clara { m_arg->description = description; return *this; } - ArgBuilder& detail( std::string const& _detail ) { - m_arg->detail = _detail; + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; return *this; } @@ -4219,14 +4445,14 @@ namespace Clara { maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usageText( it->commands(), Detail::TextAttributes() + Detail::Text usage( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); - for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) { - std::string usageCol = i < usageText.size() ? usageText[i] : ""; + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) @@ -4283,21 +4509,21 @@ namespace Clara { return oss.str(); } - ConfigT parse( int argc, char const * const * argv ) const { + ConfigT parse( std::vector<std::string> const& args ) const { ConfigT config; - parseInto( argc, argv, config ); + parseInto( args, config ); return config; } - std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const { - std::string processName = argv[0]; + std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const { + std::string processName = args[0]; std::size_t lastSlash = processName.find_last_of( "/\\" ); if( lastSlash != std::string::npos ) processName = processName.substr( lastSlash+1 ); m_boundProcessName.set( config, processName ); std::vector<Parser::Token> tokens; Parser parser; - parser.parseIntoTokens( argc, argv, tokens ); + parser.parseIntoTokens( args, tokens ); return populate( tokens, config ); } @@ -4328,7 +4554,7 @@ namespace Clara { arg.boundField.set( config, tokens[++i].data ); } else { - arg.boundField.setFlag( config ); + arg.boundField.set( config, "true" ); } break; } @@ -4471,6 +4697,21 @@ namespace Catch { ? ShowDurations::Always : ShowDurations::Never; } + inline void setUseColour( ConfigData& config, std::string const& value ) { + std::string mode = toLower( value ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); + } + inline void forceColour( ConfigData& config ) { + config.useColour = UseColour::Yes; + } inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { std::ifstream f( _filename.c_str() ); if( !f.is_open() ) @@ -4479,8 +4720,11 @@ namespace Catch { std::string line; while( std::getline( f, line ) ) { line = trim(line); - if( !line.empty() && !startsWith( line, "#" ) ) - addTestOrTags( config, "\"" + line + "\"," ); + if( !line.empty() && !startsWith( line, "#" ) ) { + if( !startsWith( line, "\"" ) ) + line = "\"" + line + "\""; + addTestOrTags( config, line + "," ); + } } } @@ -4557,7 +4801,7 @@ namespace Catch { cli["-d"]["--durations"] .describe( "show test durations" ) - .bind( &setShowDurations, "yes/no" ); + .bind( &setShowDurations, "yes|no" ); cli["-f"]["--input-file"] .describe( "load test names to run from a file" ) @@ -4585,8 +4829,12 @@ namespace Catch { .bind( &setRngSeed, "'time'|number" ); cli["--force-colour"] - .describe( "force colourised output" ) - .bind( &ConfigData::forceColour ); + .describe( "force colourised output (deprecated)" ) + .bind( &forceColour ); + + cli["--use-colour"] + .describe( "should output be colourised" ) + .bind( &setUseColour, "yes|no" ); return cli; } @@ -5017,6 +5265,8 @@ namespace Catch bool aborting; }; + class MultipleReporters; + struct IStreamingReporter : IShared { virtual ~IStreamingReporter(); @@ -5044,6 +5294,8 @@ namespace Catch virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + + virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } }; struct IReporterFactory : IShared { @@ -5120,7 +5372,10 @@ namespace Catch { ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Catch::cout() << testCaseInfo.name << std::endl; + if( startsWith( testCaseInfo.name, "#" ) ) + Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl; + else + Catch::cout() << testCaseInfo.name << std::endl; } return matchedTests; } @@ -5261,6 +5516,10 @@ namespace TestCaseTracking { virtual void addChild( Ptr<ITracker> const& child ) = 0; virtual ITracker* findChild( std::string const& name ) = 0; virtual void openChild() = 0; + + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isIndexTracker() const = 0; }; class TrackerContext { @@ -5385,6 +5644,10 @@ namespace TestCaseTracking { m_parent->openChild(); } } + + virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } + virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } + void open() { m_runState = Executing; moveToThis(); @@ -5448,13 +5711,16 @@ namespace TestCaseTracking { {} virtual ~SectionTracker(); + virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { SectionTracker* section = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( name ) ) { - section = dynamic_cast<SectionTracker*>( childTracker ); - assert( section ); + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = static_cast<SectionTracker*>( childTracker ); } else { section = new SectionTracker( name, ctx, ¤tTracker ); @@ -5479,13 +5745,16 @@ namespace TestCaseTracking { {} virtual ~IndexTracker(); + virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { IndexTracker* tracker = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( name ) ) { - tracker = dynamic_cast<IndexTracker*>( childTracker ); - assert( tracker ); + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = static_cast<IndexTracker*>( childTracker ); } else { tracker = new IndexTracker( name, ctx, ¤tTracker, size ); @@ -5692,6 +5961,11 @@ namespace Catch { while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); + if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) { + deltaTotals.assertions.failed++; + deltaTotals.testCases.passed--; + deltaTotals.testCases.failed++; + } m_totals.testCases += deltaTotals.testCases; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, @@ -6083,10 +6357,10 @@ namespace Catch { Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } - int applyCommandLine( int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); - m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); if( m_configData.showHelp ) showHelp( m_configData.processName ); m_config.reset(); @@ -6110,7 +6384,7 @@ namespace Catch { m_config.reset(); } - int run( int argc, char const* const argv[] ) { + int run( int argc, char const* const* const argv ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) @@ -6180,13 +6454,31 @@ namespace Catch { #include <iostream> #include <algorithm> +#ifdef CATCH_CPP14_OR_GREATER +#include <random> +#endif + namespace Catch { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i<j);} - }; struct RandomNumberGenerator { - int operator()( int n ) const { return std::rand() % n; } + typedef std::ptrdiff_t result_type; + + result_type operator()( result_type n ) const { return std::rand() % n; } + +#ifdef CATCH_CPP14_OR_GREATER + static constexpr result_type min() { return 0; } + static constexpr result_type max() { return 1000000; } + result_type operator()() const { return std::rand() % max(); } +#endif + template<typename V> + static void shuffle( V& vector ) { + RandomNumberGenerator rng; +#ifdef CATCH_CPP14_OR_GREATER + std::shuffle( vector.begin(), vector.end(), rng ); +#else + std::random_shuffle( vector.begin(), vector.end(), rng ); +#endif + } }; inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { @@ -6195,14 +6487,12 @@ namespace Catch { switch( config.runOrder() ) { case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end(), LexSort() ); + std::sort( sorted.begin(), sorted.end() ); break; case RunTests::InRandomOrder: { seedRng( config ); - - RandomNumberGenerator rng; - std::random_shuffle( sorted.begin(), sorted.end(), rng ); + RandomNumberGenerator::shuffle( sorted ); } break; case RunTests::InDeclarationOrder: @@ -6221,13 +6511,15 @@ namespace Catch { it != itEnd; ++it ) { std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it ); - if( !prev.second ){ - Catch::cerr() - << Colour( Colour::Red ) - << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; - exit(1); + if( !prev.second ) { + std::ostringstream ss; + + ss << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + + throw std::runtime_error(ss.str()); } } } @@ -6815,7 +7107,18 @@ namespace { IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; - return &s_instance; + + Ptr<IConfig const> config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = !isDebuggerActive() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); } } // end anon namespace @@ -6866,7 +7169,14 @@ namespace { IColourImpl* platformColourInstance() { Ptr<IConfig const> config = getCurrentContext().getConfig(); - return (config && config->forceColour()) || isatty(STDOUT_FILENO) + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes ? PosixColourImpl::instance() : NoColourImpl::instance(); } @@ -6891,9 +7201,7 @@ namespace Catch { Colour::~Colour(){ if( !m_moved ) use( None ); } void Colour::use( Code _colourCode ) { - static IColourImpl* impl = isDebuggerActive() - ? NoColourImpl::instance() - : platformColourInstance(); + static IColourImpl* impl = platformColourInstance(); impl->use( _colourCode ); } @@ -7270,7 +7578,7 @@ namespace Catch { return os; } - Version libraryVersion( 1, 3, 3, "", 0 ); + Version libraryVersion( 1, 5, 8, "", 0 ); } @@ -7501,8 +7809,11 @@ namespace Catch { 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 ) ); + } void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); } std::string toLower( std::string const& s ) { std::string lc = s; @@ -8249,13 +8560,18 @@ public: // IStreamingReporter ++it ) (*it)->skipTest( testInfo ); } + + virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { + return this; + } + }; Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) { Ptr<IStreamingReporter> resultingReporter; if( existingReporter ) { - MultipleReporters* multi = dynamic_cast<MultipleReporters*>( existingReporter.get() ); + MultipleReporters* multi = existingReporter->tryAsMulti(); if( !multi ) { multi = new MultipleReporters; resultingReporter = Ptr<IStreamingReporter>( multi ); @@ -8435,7 +8751,7 @@ namespace Catch { virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& sectionNode = *m_sectionStack.back(); sectionNode.assertions.push_back( assertionStats ); @@ -8645,9 +8961,10 @@ namespace Catch { break; default: - // Escape control chars - based on contribution by @espenalb in PR #465 + // 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 << static_cast<int>( c ); + os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';'; else os << c; } @@ -8702,13 +9019,20 @@ namespace Catch { : m_tagIsOpen( false ), m_needsNewline( false ), 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"; + } XmlWriter( std::ostream& os ) : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &os ) - {} + { + *m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n"; + } ~XmlWriter() { while( !m_tags.empty() ) @@ -8875,7 +9199,7 @@ namespace Catch { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.name ); if ( m_config->showDurations() == ShowDurations::Always ) m_testCaseTimer.start(); @@ -8937,7 +9261,7 @@ namespace Catch { .writeText( assertionResult.getMessage() ); break; case ResultWas::FatalErrorCondition: - m_xml.scopedElement( "Fatal Error Condition" ) + m_xml.scopedElement( "FatalErrorCondition" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() ); @@ -9566,7 +9890,7 @@ namespace Catch { if( totals.testCases.total() == 0 ) { stream << Colour( Colour::Warning ) << "No tests ran\n"; } - else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) { stream << Colour( Colour::ResultSuccess ) << "All tests passed"; stream << " (" << pluralise( totals.assertions.passed, "assertion" ) << " in " diff --git a/test/include/test.hpp b/test/include/test.hpp index 5e3e704..0f99c11 100644 --- a/test/include/test.hpp +++ b/test/include/test.hpp @@ -9,7 +9,7 @@ // Define protozero_assert() to throw this error. This allows the tests to // check that the assert fails. struct assert_error : public std::runtime_error { - assert_error(const char* what_arg) : std::runtime_error(what_arg) { + explicit assert_error(const char* what_arg) : std::runtime_error(what_arg) { } }; #define protozero_assert(x) if (!(x)) { throw(assert_error(#x)); } diff --git a/test/t/int64/testcase.cpp b/test/t/int64/testcase.cpp index 1c4d65d..ce09789 100644 --- a/test/t/int64/testcase.cpp +++ b/test/t/int64/testcase.cpp @@ -24,6 +24,6 @@ int main(int c, char *argv[]) { write_to_file(msg, "data-max.pbf"); msg.set_i(std::numeric_limits<int64_t>::min()); - std::string data = write_to_file(msg, "data-min.pbf"); + write_to_file(msg, "data-min.pbf"); } -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/protozero.git _______________________________________________ Pkg-grass-devel mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel

