From 6234e3d54d05982d4e01f2c77099a94a46921aa4 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Fri, 23 Jun 2017 10:34:56 -0300 Subject: [PATCH 01/24] #926 Conan recipe for Catch single header - Insert catch.hpp (single header) to package - Copy BDDTests and TrickyTest to validate Catch package Signed-off-by: Uilian Ries --- conanfile.py | 19 ++ test_package/CMakeLists.txt | 19 ++ test_package/conanfile.py | 31 +++ test_package/src/BDDTests.cpp | 103 ++++++++ test_package/src/MainTests.cpp | 10 + test_package/src/TrickyTests.cpp | 409 +++++++++++++++++++++++++++++++ 6 files changed, 591 insertions(+) create mode 100644 conanfile.py create mode 100644 test_package/CMakeLists.txt create mode 100644 test_package/conanfile.py create mode 100644 test_package/src/BDDTests.cpp create mode 100644 test_package/src/MainTests.cpp create mode 100644 test_package/src/TrickyTests.cpp diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 00000000..e891046f --- /dev/null +++ b/conanfile.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +from conans import ConanFile + + +class CatchConan(ConanFile): + name = "Catch" + version = "1.9.5" + description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD" + author = "philsquared" + generators = "cmake" + exports_sources = "single_include/*" + url = "https://github.com/philsquared/Catch" + license = "BSL-1.0" + + def build(self): + pass + + def package(self): + self.copy(pattern="catch.hpp", src="single_include", dst="include") diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt new file mode 100644 index 00000000..afc9f338 --- /dev/null +++ b/test_package/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0) +project(CatchTest CXX) + +# Conan setup ################################################################## +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup() + +include(CTest) + +# Build Test ################################################################### +file(GLOB SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) + +add_executable(${CMAKE_PROJECT_NAME} ${SOURCE_FILES}) + +# Execute Test ################################################################# +enable_testing() +add_test(NAME test-single-header + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin + COMMAND ${CMAKE_PROJECT_NAME}) diff --git a/test_package/conanfile.py b/test_package/conanfile.py new file mode 100644 index 00000000..f103439e --- /dev/null +++ b/test_package/conanfile.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +from os import getenv +from conans import ConanFile +from conans import CMake + + +class CatchConanTest(ConanFile): + """Build test using target package and execute all tests + """ + target = "Catch" + name = "%s-test" % target + version = "1.9.5" + description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD" + author = "philsquared" + generators = "cmake" + settings = "os", "compiler", "arch", "build_type" + url = "https://github.com/philsquared/Catch" + license = "BSL-1.0" + username = getenv("CONAN_USERNAME", author) + channel = getenv("CONAN_CHANNEL", "testing") + requires = "%s/%s@%s/%s" % (target, version, username, channel) + + def build(self): + cmake = CMake(self) + cmake.configure(build_dir="./") + cmake.build() + + def test(self): + cmake = CMake(self) + cmake.configure(build_dir="./") + cmake.test() diff --git a/test_package/src/BDDTests.cpp b/test_package/src/BDDTests.cpp new file mode 100644 index 00000000..ed89bfbc --- /dev/null +++ b/test_package/src/BDDTests.cpp @@ -0,0 +1,103 @@ +/* + * Created by Phil on 29/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#include "catch.hpp" + +inline bool itDoesThis(){ return true; } +inline bool itDoesThat(){ return true; } + +SCENARIO( "Do that thing with the thing", "[Tags]" ) { + GIVEN( "This stuff exists" ) { + // make stuff exist + WHEN( "I do this" ) { + // do this + THEN( "it should do this") + { + REQUIRE( itDoesThis() ); + AND_THEN( "do that") + REQUIRE( itDoesThat() ); + } + } + } +} + +SCENARIO( "Vector resizing affects size and capacity", "[vector][bdd][size][capacity]" ) { + GIVEN( "an empty vector" ) { + std::vector v; + REQUIRE( v.size() == 0 ); + + WHEN( "it is made larger" ) { + v.resize( 10 ); + THEN( "the size and capacity go up" ) { + REQUIRE( v.size() == 10 ); + REQUIRE( v.capacity() >= 10 ); + + AND_WHEN( "it is made smaller again" ) { + v.resize( 5 ); + THEN( "the size goes down but the capacity stays the same" ) { + REQUIRE( v.size() == 5 ); + REQUIRE( v.capacity() >= 10 ); + } + } + } + } + + WHEN( "we reserve more space" ) { + v.reserve( 10 ); + THEN( "The capacity is increased but the size remains the same" ) { + REQUIRE( v.capacity() >= 10 ); + REQUIRE( v.size() == 0 ); + } + } + } +} + +SCENARIO( "This is a really long scenario name to see how the list command deals with wrapping", + "[very long tags][lots][long][tags][verbose]" + "[one very long tag name that should cause line wrapping writing out using the list command]" + "[anotherReallyLongTagNameButThisOneHasNoObviousWrapPointsSoShouldSplitWithinAWordUsingADashCharacter]" ) { + GIVEN( "A section name that is so long that it cannot fit in a single console width" ) + WHEN( "The test headers are printed as part of the normal running of the scenario" ) + THEN( "The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent" ) + SUCCEED("boo!"); +} + +namespace { + +// a trivial fixture example to support SCENARIO_METHOD tests +struct Fixture +{ + Fixture() + : d_counter(0) + { + } + + int counter() + { + return d_counter++; + } + + int d_counter; +}; + +} + +SCENARIO_METHOD(Fixture, + "BDD tests requiring Fixtures to provide commonly-accessed data or methods", + "[bdd][fixtures]") { + const int before(counter()); + GIVEN("No operations precede me") { + REQUIRE(before == 0); + WHEN("We get the count") { + const int after(counter()); + THEN("Subsequently values are higher") { + REQUIRE(after > before); + } + } + } +} diff --git a/test_package/src/MainTests.cpp b/test_package/src/MainTests.cpp new file mode 100644 index 00000000..e5f8d3e9 --- /dev/null +++ b/test_package/src/MainTests.cpp @@ -0,0 +1,10 @@ +/* + * Created by Phil on 22/10/2010. + * Copyright 2010 Two Blue Cubes Ltd + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/test_package/src/TrickyTests.cpp b/test_package/src/TrickyTests.cpp new file mode 100644 index 00000000..26625b03 --- /dev/null +++ b/test_package/src/TrickyTests.cpp @@ -0,0 +1,409 @@ +/* + * Created by Phil on 09/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wpadded" +#endif + +#include + +#include "catch.hpp" + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wc++98-compat" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +namespace Catch +{ + template<> + std::string toString >( const std::pair& value ) + { + std::ostringstream oss; + oss << "std::pair( " << value.first << ", " << value.second << " )"; + return oss.str(); + + } +} + +/////////////////////////////////////////////////////////////////////////////// +TEST_CASE +( + "Parsing a std::pair", + "[Tricky][std::pair]" +) +{ + std::pair aNicePair( 1, 2 ); + + REQUIRE( (std::pair( 1, 2 )) == aNicePair ); +} + +/////////////////////////////////////////////////////////////////////////////// +TEST_CASE +( + "Where there is more to the expression after the RHS", + "[Tricky][failing][.]" +) +{ +// int a = 1, b = 2; +// REQUIRE( a == 2 || b == 2 ); + WARN( "Uncomment the code in this test to check that it gives a sensible compiler error" ); +} +/////////////////////////////////////////////////////////////////////////////// +TEST_CASE +( + "Where the LHS is not a simple value", + "[Tricky][failing][.]" +) +{ + /* + int a = 1; + int b = 2; + + // This only captures part of the expression, but issues a warning about the rest + REQUIRE( a+1 == b-1 ); + */ + WARN( "Uncomment the code in this test to check that it gives a sensible compiler error" ); +} + +struct Opaque +{ + int val; + bool operator ==( const Opaque& o ) const + { + return val == o.val; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +TEST_CASE +( + "A failing expression with a non streamable type is still captured", + "[Tricky][failing][.]" +) +{ + + Opaque o1, o2; + o1.val = 7; + o2.val = 8; + + CHECK( &o1 == &o2 ); + CHECK( o1 == o2 ); +} + +/////////////////////////////////////////////////////////////////////////////// +TEST_CASE +( + "string literals of different sizes can be compared", + "[Tricky][failing][.]" +) +{ + REQUIRE( std::string( "first" ) == "second" ); + +} + +/////////////////////////////////////////////////////////////////////////////// +TEST_CASE +( + "An expression with side-effects should only be evaluated once", + "[Tricky]" +) +{ + int i = 7; + + REQUIRE( i++ == 7 ); + REQUIRE( i++ == 8 ); + +} + +namespace A { + struct X + { + X() : a(4), b(2), c(7) {} + X(int v) : a(v), b(2), c(7) {} + int a; + int b; + int c; + }; +} + +namespace B { + struct Y + { + Y() : a(4), b(2), c(7) {} + Y(int v) : a(v), b(2), c(7) {} + int a; + int b; + int c; + }; +} + +inline bool operator==(const A::X& lhs, const B::Y& rhs) +{ + return (lhs.a == rhs.a); +} + +inline bool operator==(const B::Y& lhs, const A::X& rhs) +{ + return (lhs.a == rhs.a); +} + + +/////////////////////////////////////////////////////////////////////////////// +/* This, currently, does not compile with LLVM +TEST_CASE +( + "Operators at different namespace levels not hijacked by Koenig lookup" + "[Tricky]" +) +{ + A::X x; + B::Y y; + REQUIRE( x == y ); +} +*/ + +namespace ObjectWithConversions +{ + struct Object + { + operator unsigned int() {return 0xc0000000;} + }; + + /////////////////////////////////////////////////////////////////////////////// + TEST_CASE + ( + "Operators at different namespace levels not hijacked by Koenig lookup", + "[Tricky]" + ) + { + Object o; + REQUIRE(0xc0000000 == o ); + } +} + +namespace ObjectWithNonConstEqualityOperator +{ + struct Test + { + Test( unsigned int v ) + : m_value(v) + {} + + bool operator==( const Test&rhs ) + { + return (m_value == rhs.m_value); + } + bool operator==( const Test&rhs ) const + { + return (m_value != rhs.m_value); + } + unsigned int m_value; + }; + + TEST_CASE("Demonstrate that a non-const == is not used", "[Tricky]" ) + { + Test t( 1 ); + REQUIRE( t == 1u ); + } +} + +namespace EnumBitFieldTests +{ + enum Bits {bit0 = 0x0001, bit1 = 0x0002, bit2 = 0x0004, bit3 = 0x0008, bit1and2 = 0x0006, + bit30 = 0x40000000, bit31 = 0x80000000, + bit30and31 = 0xc0000000}; + + TEST_CASE( "Test enum bit values", "[Tricky]" ) + { + REQUIRE( 0xc0000000 == bit30and31 ); + } +} + +struct Obj +{ + Obj():prop(&p){} + + int p; + int* prop; +}; + +TEST_CASE("boolean member", "[Tricky]") +{ + Obj obj; + REQUIRE( obj.prop != CATCH_NULL ); +} + +// Tests for a problem submitted by Ralph McArdell +// +// The static bool value should not need to be defined outside the +// struct it is declared in - but when evaluating it in a deduced +// context it appears to require the extra definition. +// The issue was fixed by adding bool overloads to bypass the +// templates that were there to deduce it. +template +struct is_true +{ + static const bool value = B; +}; + +TEST_CASE( "(unimplemented) static bools can be evaluated", "[Tricky]" ) +{ + SECTION("compare to true","") + { + REQUIRE( is_true::value == true ); + REQUIRE( true == is_true::value ); + } + SECTION("compare to false","") + { + REQUIRE( is_true::value == false ); + REQUIRE( false == is_true::value ); + } + + SECTION("negation", "") + { + REQUIRE( !is_true::value ); + } + + SECTION("double negation","") + { + REQUIRE( !!is_true::value ); + } + + SECTION("direct","") + { + REQUIRE( is_true::value ); + REQUIRE_FALSE( is_true::value ); + } +} + +// Uncomment these tests to produce an error at test registration time +/* +TEST_CASE( "Tests with the same name are not allowed", "[Tricky]" ) +{ + +} +TEST_CASE( "Tests with the same name are not allowed", "[Tricky]" ) +{ + +} +*/ + +struct Boolable +{ + explicit Boolable( bool value ) : m_value( value ) {} + + operator Catch::SafeBool::type() const { + return Catch::SafeBool::makeSafe( m_value ); + } + + bool m_value; +}; + +TEST_CASE( "Objects that evaluated in boolean contexts can be checked", "[Tricky][SafeBool]" ) +{ + Boolable True( true ); + Boolable False( false ); + + CHECK( True ); + CHECK( !False ); + CHECK_FALSE( False ); +} + +TEST_CASE( "Assertions then sections", "[Tricky]" ) +{ + // This was causing a failure due to the way the console reporter was handling + // the current section + + REQUIRE( Catch::alwaysTrue() ); + + SECTION( "A section", "" ) + { + REQUIRE( Catch::alwaysTrue() ); + + SECTION( "Another section", "" ) + { + REQUIRE( Catch::alwaysTrue() ); + } + SECTION( "Another other section", "" ) + { + REQUIRE( Catch::alwaysTrue() ); + } + } +} + +struct Awkward +{ + operator int() const { return 7; } +}; + +TEST_CASE( "non streamable - with conv. op", "[Tricky]" ) +{ + Awkward awkward; + std::string s = Catch::toString( awkward ); + REQUIRE( s == "7" ); +} + +inline void foo() {} + +typedef void (*fooptr_t)(); + +TEST_CASE( "Comparing function pointers", "[Tricky][function pointer]" ) +{ + // This was giving a warning in VS2010 + // #179 + fooptr_t a = foo; + + REQUIRE( a ); + REQUIRE( a == &foo ); +} + +struct S +{ + void f() {} +}; + + +TEST_CASE( "Comparing member function pointers", "[Tricky][member function pointer]" ) +{ + typedef void (S::*MF)(); + MF m = &S::f; + + CHECK( m == &S::f ); +} + +class ClassName {}; + +TEST_CASE( "pointer to class", "[Tricky]" ) +{ + ClassName *p = 0; + REQUIRE( p == 0 ); +} + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + +#include + +TEST_CASE( "null_ptr", "[Tricky][c++11][.]" ) +{ + std::unique_ptr ptr; + REQUIRE(ptr.get() == nullptr); +} + +#endif + +TEST_CASE( "X/level/0/a", "[Tricky]" ) { SUCCEED(""); } +TEST_CASE( "X/level/0/b", "[Tricky][fizz]" ){ SUCCEED(""); } +TEST_CASE( "X/level/1/a", "[Tricky]" ) { SUCCEED(""); } +TEST_CASE( "X/level/1/b", "[Tricky]" ) { SUCCEED(""); } + +TEST_CASE( "has printf", "" ) { + + // This can cause problems as, currently, stdout itself is not redirect - only the cout (and cerr) buffer + printf( "spanner" ); +} From 34918045981bfb1cfe95741512ba3a3a61e40cd3 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Fri, 23 Jun 2017 11:06:49 -0300 Subject: [PATCH 02/24] #926 Update Conan version by release - Update release scripts to increment Conan version Signed-off-by: Uilian Ries --- conanfile.py | 3 - scripts/developBuild.py | 3 +- scripts/majorRelease.py | 3 +- scripts/minorRelease.py | 3 +- scripts/patchRelease.py | 3 +- scripts/releaseCommon.py | 15 ++ test_package/CMakeLists.txt | 14 +- test_package/MainTest.cpp | 21 ++ test_package/conanfile.py | 18 +- test_package/src/BDDTests.cpp | 103 -------- test_package/src/MainTests.cpp | 10 - test_package/src/TrickyTests.cpp | 409 ------------------------------- 12 files changed, 49 insertions(+), 556 deletions(-) create mode 100644 test_package/MainTest.cpp delete mode 100644 test_package/src/BDDTests.cpp delete mode 100644 test_package/src/MainTests.cpp delete mode 100644 test_package/src/TrickyTests.cpp diff --git a/conanfile.py b/conanfile.py index e891046f..564b6514 100644 --- a/conanfile.py +++ b/conanfile.py @@ -12,8 +12,5 @@ class CatchConan(ConanFile): url = "https://github.com/philsquared/Catch" license = "BSL-1.0" - def build(self): - pass - def package(self): self.copy(pattern="catch.hpp", src="single_include", dst="include") diff --git a/scripts/developBuild.py b/scripts/developBuild.py index c16c8a6d..3d3f6f0a 100755 --- a/scripts/developBuild.py +++ b/scripts/developBuild.py @@ -7,5 +7,6 @@ v = Version() v.incrementBuildNumber() v.updateVersionFile() v.updateReadmeFile() +v.updateConanFile() -print( "Updated Version.hpp and README to v{0}".format( v.getVersionString() ) ) \ No newline at end of file +print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) ) diff --git a/scripts/majorRelease.py b/scripts/majorRelease.py index f367506a..2341ecb5 100755 --- a/scripts/majorRelease.py +++ b/scripts/majorRelease.py @@ -7,5 +7,6 @@ v = Version() v.incrementMajorVersion() v.updateVersionFile() v.updateReadmeFile() +v.updateConanFile() -print( "Updated Version.hpp and README to v{0}".format( v.getVersionString() ) ) \ No newline at end of file +print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) ) diff --git a/scripts/minorRelease.py b/scripts/minorRelease.py index ac36df96..585b7019 100755 --- a/scripts/minorRelease.py +++ b/scripts/minorRelease.py @@ -7,5 +7,6 @@ v = Version() v.incrementMinorVersion() v.updateVersionFile() v.updateReadmeFile() +v.updateConanFile() -print( "Updated Version.hpp and README to v{0}".format( v.getVersionString() ) ) \ No newline at end of file +print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) ) diff --git a/scripts/patchRelease.py b/scripts/patchRelease.py index 878662f8..312b4d5a 100755 --- a/scripts/patchRelease.py +++ b/scripts/patchRelease.py @@ -7,5 +7,6 @@ v = Version() v.incrementPatchNumber() v.updateVersionFile() v.updateReadmeFile() +v.updateConanFile() -print( "Updated Version.hpp and README to v{0}".format( v.getVersionString() ) ) \ No newline at end of file +print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) ) diff --git a/scripts/releaseCommon.py b/scripts/releaseCommon.py index c49f7461..16b5f199 100644 --- a/scripts/releaseCommon.py +++ b/scripts/releaseCommon.py @@ -11,6 +11,7 @@ versionParser = re.compile( r'(\s*static\sVersion\sversion)\s*\(\s*(.*)\s*,\s*(. rootPath = os.path.join( catchPath, 'include/' ) versionPath = os.path.join( rootPath, "internal/catch_version.hpp" ) readmePath = os.path.join( catchPath, "README.md" ) +conanPath = os.path.join(catchPath, 'conanfile.py') class Version: def __init__(self): @@ -86,3 +87,17 @@ class Version: line = downloadParser.sub( r''.format(self.getVersionString()) , line) f.write( line + "\n" ) + def updateConanFile(self): + conanParser = re.compile( r' version = "\d+\.\d+\.\d+.*"') + f = open( conanPath, 'r' ) + lines = [] + for line in f: + m = conanParser.match( line ) + if m: + lines.append( ' version = "{0}"'.format(format(self.getVersionString())) ) + else: + lines.append( line.rstrip() ) + f.close() + f = open( conanPath, 'w' ) + for line in lines: + f.write( line + "\n" ) diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt index afc9f338..339facbf 100644 --- a/test_package/CMakeLists.txt +++ b/test_package/CMakeLists.txt @@ -1,19 +1,7 @@ cmake_minimum_required(VERSION 3.0) project(CatchTest CXX) -# Conan setup ################################################################## include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) conan_basic_setup() -include(CTest) - -# Build Test ################################################################### -file(GLOB SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) - -add_executable(${CMAKE_PROJECT_NAME} ${SOURCE_FILES}) - -# Execute Test ################################################################# -enable_testing() -add_test(NAME test-single-header - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin - COMMAND ${CMAKE_PROJECT_NAME}) +add_executable(${CMAKE_PROJECT_NAME} MainTest.cpp) diff --git a/test_package/MainTest.cpp b/test_package/MainTest.cpp new file mode 100644 index 00000000..b8ed744e --- /dev/null +++ b/test_package/MainTest.cpp @@ -0,0 +1,21 @@ +/* + * Created by Phil on 22/10/2010. + * Copyright 2010 Two Blue Cubes Ltd + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#define CATCH_CONFIG_MAIN +#include "catch.hpp" + +unsigned int Factorial( unsigned int number ) { + return number > 1 ? Factorial(number-1)*number : 1; +} + +TEST_CASE( "Factorials are computed", "[factorial]" ) { + REQUIRE( Factorial(0) == 1 ); + REQUIRE( Factorial(1) == 1 ); + REQUIRE( Factorial(2) == 2 ); + REQUIRE( Factorial(3) == 6 ); + REQUIRE( Factorial(10) == 3628800 ); +} diff --git a/test_package/conanfile.py b/test_package/conanfile.py index f103439e..9444b737 100644 --- a/test_package/conanfile.py +++ b/test_package/conanfile.py @@ -1,24 +1,16 @@ #!/usr/bin/env python from os import getenv +from os import path from conans import ConanFile from conans import CMake class CatchConanTest(ConanFile): - """Build test using target package and execute all tests - """ - target = "Catch" - name = "%s-test" % target - version = "1.9.5" - description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD" - author = "philsquared" generators = "cmake" settings = "os", "compiler", "arch", "build_type" - url = "https://github.com/philsquared/Catch" - license = "BSL-1.0" - username = getenv("CONAN_USERNAME", author) + username = getenv("CONAN_USERNAME", "philsquared") channel = getenv("CONAN_CHANNEL", "testing") - requires = "%s/%s@%s/%s" % (target, version, username, channel) + requires = "Catch/1.9.5@%s/%s" % (username, channel) def build(self): cmake = CMake(self) @@ -26,6 +18,4 @@ class CatchConanTest(ConanFile): cmake.build() def test(self): - cmake = CMake(self) - cmake.configure(build_dir="./") - cmake.test() + self.run(path.join("bin", "CatchTest")) diff --git a/test_package/src/BDDTests.cpp b/test_package/src/BDDTests.cpp deleted file mode 100644 index ed89bfbc..00000000 --- a/test_package/src/BDDTests.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Created by Phil on 29/11/2010. - * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#include "catch.hpp" - -inline bool itDoesThis(){ return true; } -inline bool itDoesThat(){ return true; } - -SCENARIO( "Do that thing with the thing", "[Tags]" ) { - GIVEN( "This stuff exists" ) { - // make stuff exist - WHEN( "I do this" ) { - // do this - THEN( "it should do this") - { - REQUIRE( itDoesThis() ); - AND_THEN( "do that") - REQUIRE( itDoesThat() ); - } - } - } -} - -SCENARIO( "Vector resizing affects size and capacity", "[vector][bdd][size][capacity]" ) { - GIVEN( "an empty vector" ) { - std::vector v; - REQUIRE( v.size() == 0 ); - - WHEN( "it is made larger" ) { - v.resize( 10 ); - THEN( "the size and capacity go up" ) { - REQUIRE( v.size() == 10 ); - REQUIRE( v.capacity() >= 10 ); - - AND_WHEN( "it is made smaller again" ) { - v.resize( 5 ); - THEN( "the size goes down but the capacity stays the same" ) { - REQUIRE( v.size() == 5 ); - REQUIRE( v.capacity() >= 10 ); - } - } - } - } - - WHEN( "we reserve more space" ) { - v.reserve( 10 ); - THEN( "The capacity is increased but the size remains the same" ) { - REQUIRE( v.capacity() >= 10 ); - REQUIRE( v.size() == 0 ); - } - } - } -} - -SCENARIO( "This is a really long scenario name to see how the list command deals with wrapping", - "[very long tags][lots][long][tags][verbose]" - "[one very long tag name that should cause line wrapping writing out using the list command]" - "[anotherReallyLongTagNameButThisOneHasNoObviousWrapPointsSoShouldSplitWithinAWordUsingADashCharacter]" ) { - GIVEN( "A section name that is so long that it cannot fit in a single console width" ) - WHEN( "The test headers are printed as part of the normal running of the scenario" ) - THEN( "The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent" ) - SUCCEED("boo!"); -} - -namespace { - -// a trivial fixture example to support SCENARIO_METHOD tests -struct Fixture -{ - Fixture() - : d_counter(0) - { - } - - int counter() - { - return d_counter++; - } - - int d_counter; -}; - -} - -SCENARIO_METHOD(Fixture, - "BDD tests requiring Fixtures to provide commonly-accessed data or methods", - "[bdd][fixtures]") { - const int before(counter()); - GIVEN("No operations precede me") { - REQUIRE(before == 0); - WHEN("We get the count") { - const int after(counter()); - THEN("Subsequently values are higher") { - REQUIRE(after > before); - } - } - } -} diff --git a/test_package/src/MainTests.cpp b/test_package/src/MainTests.cpp deleted file mode 100644 index e5f8d3e9..00000000 --- a/test_package/src/MainTests.cpp +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Created by Phil on 22/10/2010. - * Copyright 2010 Two Blue Cubes Ltd - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#define CATCH_CONFIG_MAIN -#include "catch.hpp" diff --git a/test_package/src/TrickyTests.cpp b/test_package/src/TrickyTests.cpp deleted file mode 100644 index 26625b03..00000000 --- a/test_package/src/TrickyTests.cpp +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Created by Phil on 09/11/2010. - * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#endif - -#include - -#include "catch.hpp" - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wc++98-compat" -#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" -#endif - -namespace Catch -{ - template<> - std::string toString >( const std::pair& value ) - { - std::ostringstream oss; - oss << "std::pair( " << value.first << ", " << value.second << " )"; - return oss.str(); - - } -} - -/////////////////////////////////////////////////////////////////////////////// -TEST_CASE -( - "Parsing a std::pair", - "[Tricky][std::pair]" -) -{ - std::pair aNicePair( 1, 2 ); - - REQUIRE( (std::pair( 1, 2 )) == aNicePair ); -} - -/////////////////////////////////////////////////////////////////////////////// -TEST_CASE -( - "Where there is more to the expression after the RHS", - "[Tricky][failing][.]" -) -{ -// int a = 1, b = 2; -// REQUIRE( a == 2 || b == 2 ); - WARN( "Uncomment the code in this test to check that it gives a sensible compiler error" ); -} -/////////////////////////////////////////////////////////////////////////////// -TEST_CASE -( - "Where the LHS is not a simple value", - "[Tricky][failing][.]" -) -{ - /* - int a = 1; - int b = 2; - - // This only captures part of the expression, but issues a warning about the rest - REQUIRE( a+1 == b-1 ); - */ - WARN( "Uncomment the code in this test to check that it gives a sensible compiler error" ); -} - -struct Opaque -{ - int val; - bool operator ==( const Opaque& o ) const - { - return val == o.val; - } -}; - -/////////////////////////////////////////////////////////////////////////////// -TEST_CASE -( - "A failing expression with a non streamable type is still captured", - "[Tricky][failing][.]" -) -{ - - Opaque o1, o2; - o1.val = 7; - o2.val = 8; - - CHECK( &o1 == &o2 ); - CHECK( o1 == o2 ); -} - -/////////////////////////////////////////////////////////////////////////////// -TEST_CASE -( - "string literals of different sizes can be compared", - "[Tricky][failing][.]" -) -{ - REQUIRE( std::string( "first" ) == "second" ); - -} - -/////////////////////////////////////////////////////////////////////////////// -TEST_CASE -( - "An expression with side-effects should only be evaluated once", - "[Tricky]" -) -{ - int i = 7; - - REQUIRE( i++ == 7 ); - REQUIRE( i++ == 8 ); - -} - -namespace A { - struct X - { - X() : a(4), b(2), c(7) {} - X(int v) : a(v), b(2), c(7) {} - int a; - int b; - int c; - }; -} - -namespace B { - struct Y - { - Y() : a(4), b(2), c(7) {} - Y(int v) : a(v), b(2), c(7) {} - int a; - int b; - int c; - }; -} - -inline bool operator==(const A::X& lhs, const B::Y& rhs) -{ - return (lhs.a == rhs.a); -} - -inline bool operator==(const B::Y& lhs, const A::X& rhs) -{ - return (lhs.a == rhs.a); -} - - -/////////////////////////////////////////////////////////////////////////////// -/* This, currently, does not compile with LLVM -TEST_CASE -( - "Operators at different namespace levels not hijacked by Koenig lookup" - "[Tricky]" -) -{ - A::X x; - B::Y y; - REQUIRE( x == y ); -} -*/ - -namespace ObjectWithConversions -{ - struct Object - { - operator unsigned int() {return 0xc0000000;} - }; - - /////////////////////////////////////////////////////////////////////////////// - TEST_CASE - ( - "Operators at different namespace levels not hijacked by Koenig lookup", - "[Tricky]" - ) - { - Object o; - REQUIRE(0xc0000000 == o ); - } -} - -namespace ObjectWithNonConstEqualityOperator -{ - struct Test - { - Test( unsigned int v ) - : m_value(v) - {} - - bool operator==( const Test&rhs ) - { - return (m_value == rhs.m_value); - } - bool operator==( const Test&rhs ) const - { - return (m_value != rhs.m_value); - } - unsigned int m_value; - }; - - TEST_CASE("Demonstrate that a non-const == is not used", "[Tricky]" ) - { - Test t( 1 ); - REQUIRE( t == 1u ); - } -} - -namespace EnumBitFieldTests -{ - enum Bits {bit0 = 0x0001, bit1 = 0x0002, bit2 = 0x0004, bit3 = 0x0008, bit1and2 = 0x0006, - bit30 = 0x40000000, bit31 = 0x80000000, - bit30and31 = 0xc0000000}; - - TEST_CASE( "Test enum bit values", "[Tricky]" ) - { - REQUIRE( 0xc0000000 == bit30and31 ); - } -} - -struct Obj -{ - Obj():prop(&p){} - - int p; - int* prop; -}; - -TEST_CASE("boolean member", "[Tricky]") -{ - Obj obj; - REQUIRE( obj.prop != CATCH_NULL ); -} - -// Tests for a problem submitted by Ralph McArdell -// -// The static bool value should not need to be defined outside the -// struct it is declared in - but when evaluating it in a deduced -// context it appears to require the extra definition. -// The issue was fixed by adding bool overloads to bypass the -// templates that were there to deduce it. -template -struct is_true -{ - static const bool value = B; -}; - -TEST_CASE( "(unimplemented) static bools can be evaluated", "[Tricky]" ) -{ - SECTION("compare to true","") - { - REQUIRE( is_true::value == true ); - REQUIRE( true == is_true::value ); - } - SECTION("compare to false","") - { - REQUIRE( is_true::value == false ); - REQUIRE( false == is_true::value ); - } - - SECTION("negation", "") - { - REQUIRE( !is_true::value ); - } - - SECTION("double negation","") - { - REQUIRE( !!is_true::value ); - } - - SECTION("direct","") - { - REQUIRE( is_true::value ); - REQUIRE_FALSE( is_true::value ); - } -} - -// Uncomment these tests to produce an error at test registration time -/* -TEST_CASE( "Tests with the same name are not allowed", "[Tricky]" ) -{ - -} -TEST_CASE( "Tests with the same name are not allowed", "[Tricky]" ) -{ - -} -*/ - -struct Boolable -{ - explicit Boolable( bool value ) : m_value( value ) {} - - operator Catch::SafeBool::type() const { - return Catch::SafeBool::makeSafe( m_value ); - } - - bool m_value; -}; - -TEST_CASE( "Objects that evaluated in boolean contexts can be checked", "[Tricky][SafeBool]" ) -{ - Boolable True( true ); - Boolable False( false ); - - CHECK( True ); - CHECK( !False ); - CHECK_FALSE( False ); -} - -TEST_CASE( "Assertions then sections", "[Tricky]" ) -{ - // This was causing a failure due to the way the console reporter was handling - // the current section - - REQUIRE( Catch::alwaysTrue() ); - - SECTION( "A section", "" ) - { - REQUIRE( Catch::alwaysTrue() ); - - SECTION( "Another section", "" ) - { - REQUIRE( Catch::alwaysTrue() ); - } - SECTION( "Another other section", "" ) - { - REQUIRE( Catch::alwaysTrue() ); - } - } -} - -struct Awkward -{ - operator int() const { return 7; } -}; - -TEST_CASE( "non streamable - with conv. op", "[Tricky]" ) -{ - Awkward awkward; - std::string s = Catch::toString( awkward ); - REQUIRE( s == "7" ); -} - -inline void foo() {} - -typedef void (*fooptr_t)(); - -TEST_CASE( "Comparing function pointers", "[Tricky][function pointer]" ) -{ - // This was giving a warning in VS2010 - // #179 - fooptr_t a = foo; - - REQUIRE( a ); - REQUIRE( a == &foo ); -} - -struct S -{ - void f() {} -}; - - -TEST_CASE( "Comparing member function pointers", "[Tricky][member function pointer]" ) -{ - typedef void (S::*MF)(); - MF m = &S::f; - - CHECK( m == &S::f ); -} - -class ClassName {}; - -TEST_CASE( "pointer to class", "[Tricky]" ) -{ - ClassName *p = 0; - REQUIRE( p == 0 ); -} - -#ifdef CATCH_CONFIG_CPP11_NULLPTR - -#include - -TEST_CASE( "null_ptr", "[Tricky][c++11][.]" ) -{ - std::unique_ptr ptr; - REQUIRE(ptr.get() == nullptr); -} - -#endif - -TEST_CASE( "X/level/0/a", "[Tricky]" ) { SUCCEED(""); } -TEST_CASE( "X/level/0/b", "[Tricky][fizz]" ){ SUCCEED(""); } -TEST_CASE( "X/level/1/a", "[Tricky]" ) { SUCCEED(""); } -TEST_CASE( "X/level/1/b", "[Tricky]" ) { SUCCEED(""); } - -TEST_CASE( "has printf", "" ) { - - // This can cause problems as, currently, stdout itself is not redirect - only the cout (and cerr) buffer - printf( "spanner" ); -} From ee67ac6b7c3595251342671485c65cf81d725896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Tue, 27 Jun 2017 12:21:48 +0200 Subject: [PATCH 03/24] v1.9.6 --- README.md | 2 +- docs/release-notes.md | 9 +++ include/internal/catch_version.hpp | 2 +- single_include/catch.hpp | 110 ++++++++++++++++++----------- 4 files changed, 81 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 76035f34..3de01ea9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Build Status](https://travis-ci.org/philsquared/Catch.svg?branch=master)](https://travis-ci.org/philsquared/Catch) [![Build status](https://ci.appveyor.com/api/projects/status/hrtk60hv6tw6fght/branch/master?svg=true)](https://ci.appveyor.com/project/philsquared/catch/branch/master) -The latest, single header, version can be downloaded directly using this link +The latest, single header, version can be downloaded directly using this link ## What's the Catch? diff --git a/docs/release-notes.md b/docs/release-notes.md index e5fa9531..2c510c3c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,3 +1,12 @@ +# 1.9.6 + +### Improvements +* Catch's runtime overhead has been significantly decreased (#937, #939) +* Added `--list-extra-info` cli option (#934). + * It lists all tests together with extra information, ie filename, line number and description. + + + # 1.9.5 ### Fixes diff --git a/include/internal/catch_version.hpp b/include/internal/catch_version.hpp index f7d1618f..0f51fbe8 100644 --- a/include/internal/catch_version.hpp +++ b/include/internal/catch_version.hpp @@ -38,7 +38,7 @@ namespace Catch { } inline Version libraryVersion() { - static Version version( 1, 9, 5, "", 0 ); + static Version version( 1, 9, 6, "", 0 ); return version; } diff --git a/single_include/catch.hpp b/single_include/catch.hpp index 2c93e370..f7681f49 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v1.9.5 - * Generated: 2017-06-15 12:03:23.301505 + * 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. @@ -934,15 +934,17 @@ namespace Catch { 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 @@ -1217,7 +1219,7 @@ namespace Catch { template ResultBuilder& operator << ( T const& value ) { - m_stream.oss << value; + m_stream().oss << value; return *this; } @@ -1250,7 +1252,12 @@ namespace Catch { private: AssertionInfo m_assertionInfo; AssertionResultData m_data; - CopyableStream m_stream; + + static CopyableStream &m_stream() + { + static CopyableStream s; + return s; + } bool m_shouldDebugBreak; bool m_shouldThrow; @@ -3938,6 +3945,7 @@ namespace Catch { listTags( false ), listReporters( false ), listTestNamesOnly( false ), + listExtraInfo( false ), showSuccessfulTests( false ), shouldDebugBreak( false ), noThrow( false ), @@ -3957,6 +3965,7 @@ namespace Catch { bool listTags; bool listReporters; bool listTestNamesOnly; + bool listExtraInfo; bool showSuccessfulTests; bool shouldDebugBreak; @@ -4015,6 +4024,7 @@ 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; } @@ -5276,6 +5286,10 @@ namespace Catch { .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 ); @@ -5804,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 matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); @@ -5820,6 +5835,13 @@ 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; } @@ -5843,9 +5865,12 @@ namespace Catch { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); if( startsWith( testCaseInfo.name, '#' ) ) - Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl; + 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; } @@ -5937,7 +5962,7 @@ namespace Catch { inline Option list( Config const& config ) { Option listedCount; - if( config.listTests() ) + if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) ) listedCount = listedCount.valueOr(0) + listTests( config ); if( config.listTestNamesOnly() ) listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); @@ -6647,7 +6672,7 @@ namespace Catch { static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); // Reset working state - m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); m_lastResult = result; } @@ -6777,7 +6802,7 @@ namespace Catch { double duration = 0; m_shouldReportUnexpected = true; try { - m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal ); + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); seedRng( *m_config ); @@ -6829,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 ); } @@ -8008,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() {} @@ -8042,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 { @@ -8309,7 +8342,7 @@ namespace Catch { } inline Version libraryVersion() { - static Version version( 1, 9, 5, "", 0 ); + static Version version( 1, 9, 6, "", 0 ); return version; } @@ -9009,26 +9042,23 @@ 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_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"; + m_stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; captureResult( ResultWas::ThrewException ); getCurrentContext().getResultCapture()->exceptionEarlyReported(); } @@ -9051,7 +9081,7 @@ namespace Catch { void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { m_assertionInfo.resultDisposition = resultDisposition; - m_stream.oss << Catch::translateActiveException(); + m_stream().oss << Catch::translateActiveException(); captureResult( ResultWas::ThrewException ); } @@ -9072,7 +9102,7 @@ namespace Catch { 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 ) ) { @@ -9138,13 +9168,13 @@ namespace Catch { data.negate( expr.isBinaryExpression() ); } - data.message = m_stream.oss.str(); + data.message = m_stream().oss.str(); data.decomposedExpression = &expr; // for lazy reconstruction return AssertionResult( m_assertionInfo, data ); } void ResultBuilder::reconstructExpression( std::string& dest ) const { - dest = m_assertionInfo.capturedExpression; + dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); } void ResultBuilder::setExceptionGuard() { From 0270afb21b2ce7bacab515ef38a0371b567fcbd9 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 28 Jun 2017 16:44:46 +0100 Subject: [PATCH 04/24] Updated license --- conanfile.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index 564b6514..81e9c708 100644 --- a/conanfile.py +++ b/conanfile.py @@ -4,13 +4,13 @@ from conans import ConanFile class CatchConan(ConanFile): name = "Catch" - version = "1.9.5" + version = "1.9.6" description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD" author = "philsquared" generators = "cmake" exports_sources = "single_include/*" url = "https://github.com/philsquared/Catch" - license = "BSL-1.0" + license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt" def package(self): self.copy(pattern="catch.hpp", src="single_include", dst="include") From 7013e388f758cad7455b6bd51f52c1fc9c910fd1 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Tue, 27 Jun 2017 11:03:27 -0300 Subject: [PATCH 05/24] #926 Update Conan test version by release Signed-off-by: Uilian Ries --- scripts/developBuild.py | 1 + scripts/majorRelease.py | 1 + scripts/minorRelease.py | 1 + scripts/patchRelease.py | 1 + scripts/releaseCommon.py | 16 ++++++++++++++++ 5 files changed, 20 insertions(+) diff --git a/scripts/developBuild.py b/scripts/developBuild.py index 3d3f6f0a..d751f108 100755 --- a/scripts/developBuild.py +++ b/scripts/developBuild.py @@ -8,5 +8,6 @@ v.incrementBuildNumber() v.updateVersionFile() v.updateReadmeFile() v.updateConanFile() +v.updateConanTestFile() print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) ) diff --git a/scripts/majorRelease.py b/scripts/majorRelease.py index 2341ecb5..e8116d3b 100755 --- a/scripts/majorRelease.py +++ b/scripts/majorRelease.py @@ -8,5 +8,6 @@ v.incrementMajorVersion() v.updateVersionFile() v.updateReadmeFile() v.updateConanFile() +v.updateConanTestFile() print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) ) diff --git a/scripts/minorRelease.py b/scripts/minorRelease.py index 585b7019..dff2d8c8 100755 --- a/scripts/minorRelease.py +++ b/scripts/minorRelease.py @@ -8,5 +8,6 @@ v.incrementMinorVersion() v.updateVersionFile() v.updateReadmeFile() v.updateConanFile() +v.updateConanTestFile() print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) ) diff --git a/scripts/patchRelease.py b/scripts/patchRelease.py index 312b4d5a..e33e4064 100755 --- a/scripts/patchRelease.py +++ b/scripts/patchRelease.py @@ -8,5 +8,6 @@ v.incrementPatchNumber() v.updateVersionFile() v.updateReadmeFile() v.updateConanFile() +v.updateConanTestFile() print( "Updated Version.hpp, README and Conan to v{0}".format( v.getVersionString() ) ) diff --git a/scripts/releaseCommon.py b/scripts/releaseCommon.py index 16b5f199..9a62690d 100644 --- a/scripts/releaseCommon.py +++ b/scripts/releaseCommon.py @@ -12,6 +12,7 @@ rootPath = os.path.join( catchPath, 'include/' ) versionPath = os.path.join( rootPath, "internal/catch_version.hpp" ) readmePath = os.path.join( catchPath, "README.md" ) conanPath = os.path.join(catchPath, 'conanfile.py') +conanTestPath = os.path.join(catchPath, 'test_package', 'conanfile.py') class Version: def __init__(self): @@ -101,3 +102,18 @@ class Version: f = open( conanPath, 'w' ) for line in lines: f.write( line + "\n" ) + + def updateConanTestFile(self): + conanParser = re.compile( r' requires = \"Catch\/\d+\.\d+\.\d+.*@%s\/%s\" % \(username, channel\)') + f = open( conanTestPath, 'r' ) + lines = [] + for line in f: + m = conanParser.match( line ) + if m: + lines.append( ' requires = "Catch/{0}@%s/%s" % (username, channel)'.format(format(self.getVersionString())) ) + else: + lines.append( line.rstrip() ) + f.close() + f = open( conanTestPath, 'w' ) + for line in lines: + f.write( line + "\n" ) From 6f32db35af06b30701d159b9e16a21e76d82aada Mon Sep 17 00:00:00 2001 From: Markus Werle Date: Wed, 28 Jun 2017 17:22:54 +0200 Subject: [PATCH 06/24] Update tutorial.md --- docs/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index 3a0f9468..600ba3ba 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -80,7 +80,7 @@ unsigned int Factorial( unsigned int number ) { Now all the tests pass. -Of course there are still more issues to do deal with. For example we'll hit problems when the return value starts to exceed the range of an unsigned int. With factorials that can happen quite quickly. You might want to add tests for such cases and decide how to handle them. We'll stop short of doing that here. +Of course there are still more issues to deal with. For example we'll hit problems when the return value starts to exceed the range of an unsigned int. With factorials that can happen quite quickly. You might want to add tests for such cases and decide how to handle them. We'll stop short of doing that here. ## What did we do here? From 431e8d06e757d48f298f5b95aaa9a5192864a87f Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 4 Jul 2017 09:10:36 +0100 Subject: [PATCH 07/24] Added survey monkey link --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3de01ea9..c07d117b 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,7 @@ This documentation comprises these three parts: * Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/philsquared/Catch/issues) * For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum) * See [who else is using Catch](docs/opensource-users.md) + +## Help us out +We're currently running a survey to help us shape the future of Catch. +Please take a few moments to full it out (there's only ten questions): From 3083de9ea6878cbd6475787054751d97fb2a8e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Wed, 5 Jul 2017 15:54:38 +0200 Subject: [PATCH 08/24] Fix typo in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c07d117b..f42c33ed 100644 --- a/README.md +++ b/README.md @@ -23,5 +23,5 @@ This documentation comprises these three parts: * See [who else is using Catch](docs/opensource-users.md) ## Help us out -We're currently running a survey to help us shape the future of Catch. -Please take a few moments to full it out (there's only ten questions): +We're currently running [a survey](https://www.surveymonkey.co.uk/r/TLLYQJW) to help us shape the future of Catch. +Please take a few moments to fill it out (there's only ten questions). From 8d380a7399663868c73185c4dc2f9c6177b66437 Mon Sep 17 00:00:00 2001 From: Ivan Kush Date: Tue, 4 Jul 2017 16:45:56 +0300 Subject: [PATCH 09/24] added 'args' argument parser library --- docs/opensource-users.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/opensource-users.md b/docs/opensource-users.md index d4a96902..ab7a8ae1 100644 --- a/docs/opensource-users.md +++ b/docs/opensource-users.md @@ -55,6 +55,9 @@ A library of algorithms for values-distributed-in-time ### [Trompeloeil](https://github.com/rollbear/trompeloeil) A thread safe header only mocking framework for C++14 +### [args](https://github.com/Taywee/args) +A simple header-only C++ argument parser library. + ## Applications & Tools ### [ArangoDB](https://github.com/arangodb/arangodb) From a53ea307239095920270af807938e7870fa36362 Mon Sep 17 00:00:00 2001 From: Neal Coombes Date: Mon, 26 Jun 2017 14:30:23 -0500 Subject: [PATCH 10/24] Eliminate some work when results won't be reported. --- include/internal/catch_capture.hpp | 4 +-- include/internal/catch_interfaces_capture.h | 4 +++ include/internal/catch_result_builder.h | 13 +++++++- include/internal/catch_result_builder.hpp | 35 ++++++++++++--------- include/internal/catch_run_context.hpp | 18 +++++++++++ 5 files changed, 57 insertions(+), 17 deletions(-) diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index a6d25dad..b64cb965 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -83,12 +83,12 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ - if( Catch::getResultCapture().getLastResult()->succeeded() ) + if( Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ - if( !Catch::getResultCapture().getLastResult()->succeeded() ) + if( !Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \ diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h index 35b62dd9..54cf0e4d 100644 --- a/include/internal/catch_interfaces_capture.h +++ b/include/internal/catch_interfaces_capture.h @@ -41,6 +41,10 @@ namespace Catch { virtual void exceptionEarlyReported() = 0; virtual void handleFatalErrorCondition( std::string const& message ) = 0; + + virtual bool lastAssertionPassed() = 0; + virtual void assertionPassed() = 0; + virtual void assertionRun() = 0; }; IResultCapture& getResultCapture(); diff --git a/include/internal/catch_result_builder.h b/include/internal/catch_result_builder.h index b1808cc0..995be818 100644 --- a/include/internal/catch_result_builder.h +++ b/include/internal/catch_result_builder.h @@ -47,7 +47,7 @@ namespace Catch { template ResultBuilder& operator << ( T const& value ) { - m_stream().oss << value; + stream().oss << value; return *this; } @@ -81,6 +81,16 @@ namespace Catch { AssertionInfo m_assertionInfo; AssertionResultData m_data; + CopyableStream &stream() + { + if(!m_usedStream) + { + m_usedStream = true; + m_stream().oss.str(""); + } + return m_stream(); + } + static CopyableStream &m_stream() { static CopyableStream s; @@ -90,6 +100,7 @@ namespace Catch { bool m_shouldDebugBreak; bool m_shouldThrow; bool m_guardException; + bool m_usedStream; }; } // namespace Catch diff --git a/include/internal/catch_result_builder.hpp b/include/internal/catch_result_builder.hpp index 2abb9a91..e7a5bdd2 100644 --- a/include/internal/catch_result_builder.hpp +++ b/include/internal/catch_result_builder.hpp @@ -26,15 +26,14 @@ namespace Catch { : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ), m_shouldDebugBreak( false ), m_shouldThrow( false ), - m_guardException( false ) - { - m_stream().oss.str(""); - } + m_guardException( false ), + m_usedStream( false ) + {} ResultBuilder::~ResultBuilder() { #if defined(CATCH_CONFIG_FAST_COMPILE) if ( m_guardException ) { - m_stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; captureResult( ResultWas::ThrewException ); getCurrentContext().getResultCapture()->exceptionEarlyReported(); } @@ -51,13 +50,25 @@ namespace Catch { } void ResultBuilder::endExpression( DecomposedExpression const& expr ) { - AssertionResult result = build( expr ); - handleResult( result ); + // Flip bool results if FalseTest flag is set + if( isFalseTest( m_assertionInfo.resultDisposition ) ) { + m_data.negate( expr.isBinaryExpression() ); + } + + getResultCapture().assertionRun(); + + if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok) + { + AssertionResult result = build( expr ); + handleResult( result ); + } + else + getResultCapture().assertionPassed(); } void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { m_assertionInfo.resultDisposition = resultDisposition; - m_stream().oss << Catch::translateActiveException(); + stream().oss << Catch::translateActiveException(); captureResult( ResultWas::ThrewException ); } @@ -140,12 +151,8 @@ namespace Catch { assert( m_data.resultType != ResultWas::Unknown ); AssertionResultData data = m_data; - // Flip bool results if FalseTest flag is set - if( isFalseTest( m_assertionInfo.resultDisposition ) ) { - data.negate( expr.isBinaryExpression() ); - } - - data.message = m_stream().oss.str(); + if(m_usedStream) + data.message = m_stream().oss.str(); data.decomposedExpression = &expr; // for lazy reconstruction return AssertionResult( m_assertionInfo, data ); } diff --git a/include/internal/catch_run_context.hpp b/include/internal/catch_run_context.hpp index b3dee17f..88c56603 100644 --- a/include/internal/catch_run_context.hpp +++ b/include/internal/catch_run_context.hpp @@ -154,6 +154,23 @@ namespace Catch { m_lastResult = result; } + virtual bool lastAssertionPassed() + { + return m_totals.assertions.passed == (m_prevPassed + 1); + } + + virtual void assertionPassed() + { + m_totals.assertions.passed++; + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; + m_lastAssertionInfo.macroName = ""; + } + + virtual void assertionRun() + { + m_prevPassed = m_totals.assertions.passed; + } + virtual bool sectionStarted ( SectionInfo const& sectionInfo, Counts& assertions @@ -364,6 +381,7 @@ namespace Catch { std::vector m_unfinishedSections; std::vector m_activeSections; TrackerContext m_trackerContext; + size_t m_prevPassed; bool m_shouldReportUnexpected; }; From 106d7e2a743041075346ef11ab5347f3c86a7ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Mon, 10 Jul 2017 10:28:10 +0200 Subject: [PATCH 11/24] Initialize JunitReporter::unexpectedExceptions in constructor This is not needed for correctness, but will prevent PVS warning from triggering, and there is basically no performance difference. Closes #951 --- include/reporters/catch_reporter_junit.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/reporters/catch_reporter_junit.hpp b/include/reporters/catch_reporter_junit.hpp index a671c68f..28a671cd 100644 --- a/include/reporters/catch_reporter_junit.hpp +++ b/include/reporters/catch_reporter_junit.hpp @@ -52,6 +52,7 @@ namespace Catch { JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ), + unexpectedExceptions( 0 ), m_okToFail( false ) { m_reporterPrefs.shouldRedirectStdOut = true; From 8ebe94ca2ea1e6ae7765f65d2f3aec08c9a85ae2 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Mon, 10 Jul 2017 18:43:07 +0100 Subject: [PATCH 12/24] Added NOLINT annotations to selectively suppress clang_tidy warnings --- include/internal/catch_debugger.h | 6 +++--- include/internal/catch_test_registry.hpp | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/internal/catch_debugger.h b/include/internal/catch_debugger.h index 15a4c64b..65361c24 100644 --- a/include/internal/catch_debugger.h +++ b/include/internal/catch_debugger.h @@ -26,9 +26,9 @@ namespace Catch{ #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" ) + : : : "memory","r0","r3","r4" ) /* NOLINT */ #else - #define CATCH_TRAP() __asm__("int $3\n" : : ) + #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ ) #endif #elif defined(CATCH_PLATFORM_LINUX) @@ -36,7 +36,7 @@ namespace Catch{ // 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") + #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ #else // Fall back to the generic way. #include diff --git a/include/internal/catch_test_registry.hpp b/include/internal/catch_test_registry.hpp index 075ad1c6..3a86dfdc 100644 --- a/include/internal/catch_test_registry.hpp +++ b/include/internal/catch_test_registry.hpp @@ -88,7 +88,7 @@ void registerTestCaseFunction #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ @@ -97,7 +97,7 @@ void registerTestCaseFunction /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// @@ -107,7 +107,7 @@ void registerTestCaseFunction struct TestName : ClassName{ \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestName::test() @@ -117,7 +117,7 @@ void registerTestCaseFunction /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #else @@ -125,7 +125,7 @@ void registerTestCaseFunction #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 ) ); }\ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ @@ -134,7 +134,7 @@ void registerTestCaseFunction /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// @@ -144,7 +144,7 @@ void registerTestCaseFunction struct TestCaseName : ClassName{ \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestCaseName::test() @@ -154,7 +154,7 @@ void registerTestCaseFunction /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS #endif From 7a22bad76340f8b48094b46bc586e76ac9ea93ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Wed, 19 Jul 2017 09:50:08 +0200 Subject: [PATCH 13/24] Addressed some static analysis warnings Based on findings in #957 --- include/catch_session.hpp | 4 ++-- include/external/clara.h | 2 +- include/internal/catch_approx.hpp | 7 ------- include/internal/catch_common.h | 4 ++-- include/internal/catch_evaluate.hpp | 4 ++-- include/internal/catch_matchers.hpp | 10 +++++----- include/internal/catch_notimplemented_exception.h | 1 - include/internal/catch_result_builder.h | 4 ++-- include/internal/catch_tostring.h | 2 +- 9 files changed, 15 insertions(+), 23 deletions(-) diff --git a/include/catch_session.hpp b/include/catch_session.hpp index a501634d..a24c0c2c 100644 --- a/include/catch_session.hpp +++ b/include/catch_session.hpp @@ -95,11 +95,11 @@ namespace Catch { if( lastSlash != std::string::npos ) filename = filename.substr( lastSlash+1 ); - std::string::size_type lastDot = filename.find_last_of( "." ); + std::string::size_type lastDot = filename.find_last_of( '.' ); if( lastDot != std::string::npos ) filename = filename.substr( 0, lastDot ); - tags.insert( "#" + filename ); + tags.insert( '#' + filename ); setTags( test, tags ); } } diff --git a/include/external/clara.h b/include/external/clara.h index bf758eb5..a641dda5 100644 --- a/include/external/clara.h +++ b/include/external/clara.h @@ -151,7 +151,7 @@ namespace Tbc { return oss.str(); } - inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) diff --git a/include/internal/catch_approx.hpp b/include/internal/catch_approx.hpp index fc681436..663dabf0 100644 --- a/include/internal/catch_approx.hpp +++ b/include/internal/catch_approx.hpp @@ -29,13 +29,6 @@ namespace Detail { 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 ) - {} - static Approx custom() { return Approx( 0 ); } diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h index d325a089..f1ce01ea 100644 --- a/include/internal/catch_common.h +++ b/include/internal/catch_common.h @@ -61,14 +61,14 @@ namespace Catch { }; template - inline void deleteAll( ContainerT& container ) { + void deleteAll( ContainerT& container ) { typename ContainerT::const_iterator it = container.begin(); typename ContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete *it; } template - inline void deleteAllValues( AssociativeContainerT& container ) { + void deleteAllValues( AssociativeContainerT& container ) { typename AssociativeContainerT::const_iterator it = container.begin(); typename AssociativeContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) diff --git a/include/internal/catch_evaluate.hpp b/include/internal/catch_evaluate.hpp index 87fcc17f..36b4cd5a 100644 --- a/include/internal/catch_evaluate.hpp +++ b/include/internal/catch_evaluate.hpp @@ -37,7 +37,7 @@ namespace Internal { template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; template - inline T& opCast(T const& t) { return const_cast(t); } + T& opCast(T const& t) { return const_cast(t); } // nullptr_t support based on pull request #154 from Konstantin Baumann #ifdef CATCH_CONFIG_CPP11_NULLPTR @@ -48,7 +48,7 @@ namespace Internal { // So the compare overloads can be operator agnostic we convey the operator as a template // enum, which is used to specialise an Evaluator for doing the comparison. template - class Evaluator{}; + struct Evaluator{}; template struct Evaluator { diff --git a/include/internal/catch_matchers.hpp b/include/internal/catch_matchers.hpp index 2193c540..7c00e9c2 100644 --- a/include/internal/catch_matchers.hpp +++ b/include/internal/catch_matchers.hpp @@ -147,23 +147,23 @@ namespace Matchers { // This allows the types to be inferred // - deprecated: prefer ||, && and ! template - inline Impl::MatchNotOf Not( Impl::MatcherBase const& underlyingMatcher ) { + Impl::MatchNotOf Not( Impl::MatcherBase const& underlyingMatcher ) { return Impl::MatchNotOf( underlyingMatcher ); } template - inline Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { + Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { return Impl::MatchAllOf() && m1 && m2; } template - inline Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { + Impl::MatchAllOf AllOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { return Impl::MatchAllOf() && m1 && m2 && m3; } template - inline Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { + Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2 ) { return Impl::MatchAnyOf() || m1 || m2; } template - inline Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { + Impl::MatchAnyOf AnyOf( Impl::MatcherBase const& m1, Impl::MatcherBase const& m2, Impl::MatcherBase const& m3 ) { return Impl::MatchAnyOf() || m1 || m2 || m3; } diff --git a/include/internal/catch_notimplemented_exception.h b/include/internal/catch_notimplemented_exception.h index 128fff28..a448268d 100644 --- a/include/internal/catch_notimplemented_exception.h +++ b/include/internal/catch_notimplemented_exception.h @@ -16,7 +16,6 @@ namespace Catch { { public: NotImplementedException( SourceLineInfo const& lineInfo ); - NotImplementedException( NotImplementedException const& ) {} virtual ~NotImplementedException() CATCH_NOEXCEPT {} diff --git a/include/internal/catch_result_builder.h b/include/internal/catch_result_builder.h index 995be818..3ee1fca6 100644 --- a/include/internal/catch_result_builder.h +++ b/include/internal/catch_result_builder.h @@ -111,7 +111,7 @@ namespace Catch { namespace Catch { template - inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { return ExpressionLhs( *this, operand ); } @@ -120,7 +120,7 @@ namespace Catch { } template - inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, + void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ) { MatchExpression expr( arg, matcher, matcherString ); setResultType( matcher.match( arg ) ); diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h index 93b93c4d..01d518a1 100644 --- a/include/internal/catch_tostring.h +++ b/include/internal/catch_tostring.h @@ -153,7 +153,7 @@ namespace Detail { std::string rawMemoryToString( const void *object, std::size_t size ); template - inline std::string rawMemoryToString( const T& object ) { + std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } From d65091fa06b02bac5969e44ca877b3ab0c73734d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=20Garc=C3=ADa=20Salom=C3=B3n?= Date: Sun, 23 Jul 2017 17:13:44 +0200 Subject: [PATCH 14/24] Fix for JUnit reporter when using dynamically generated sections (#963) * BySectionInfo should also take into account the section name in addition to the source code line --- include/reporters/catch_reporter_bases.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp index de7d96d5..9df096c7 100644 --- a/include/reporters/catch_reporter_bases.hpp +++ b/include/reporters/catch_reporter_bases.hpp @@ -137,7 +137,8 @@ namespace Catch { BySectionInfo( SectionInfo const& other ) : m_other( other ) {} BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} bool operator() ( Ptr const& node ) const { - return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + return ((node->stats.sectionInfo.name == m_other.name) && + (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); } private: void operator=( BySectionInfo const& ); From c5dfa73d56764ae1c3bfb0d644955caa0b1883f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Sat, 29 Jul 2017 08:45:52 +0200 Subject: [PATCH 15/24] Disable build broken by travis changes It should be reenabled later, but I don't have time to investigate right now. --- .travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 278ea40b..6195c1e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -192,15 +192,15 @@ matrix: env: COMPILER='g++-6' BUILD_TYPE='Debug' CPP14=1 # 4b/ Linux C++14 Clang builds - - os: linux - compiler: clang - addons: *clang38 - env: COMPILER='clang++-3.8' BUILD_TYPE='Release' CPP14=1 - - - os: linux - compiler: clang - addons: *clang38 - env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' CPP14=1 +# - os: linux +# compiler: clang +# addons: *clang38 +# env: COMPILER='clang++-3.8' BUILD_TYPE='Release' CPP14=1 +# +# - os: linux +# compiler: clang +# addons: *clang38 +# env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' CPP14=1 # 5/ OSX Clang Builds From d3377c791de8311333a7ebd6aa3d51fa124495d0 Mon Sep 17 00:00:00 2001 From: Anton Vorobyev Date: Mon, 31 Jul 2017 11:47:42 +0300 Subject: [PATCH 16/24] Initial support for native IBM i ILE C++ (#976) * - Initial support for native IBM i ILE C++ Signed-off-by: zeromem --- include/internal/catch_compiler_capabilities.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h index 01964499..49575c44 100644 --- a/include/internal/catch_compiler_capabilities.h +++ b/include/internal/catch_compiler_capabilities.h @@ -89,6 +89,10 @@ #endif +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif //////////////////////////////////////////////////////////////////////////////// // Cygwin From 8a2ff209826a9b2f52535577c1567b26e28dfd1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Mon, 31 Jul 2017 12:28:13 +0200 Subject: [PATCH 17/24] Address some of the Resharper finds for Catch 1 Closes #957 as the other findings are mostly noise that is pointless to fix in a branch that will be soon EoLd. --- include/internal/catch_assertionresult.h | 2 +- include/internal/catch_assertionresult.hpp | 2 ++ include/internal/catch_test_spec_parser.hpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/internal/catch_assertionresult.h b/include/internal/catch_assertionresult.h index 5d6c86d1..39958498 100644 --- a/include/internal/catch_assertionresult.h +++ b/include/internal/catch_assertionresult.h @@ -39,7 +39,7 @@ namespace Catch { struct AssertionInfo { - AssertionInfo() {} + AssertionInfo(); AssertionInfo( char const * _macroName, SourceLineInfo const& _lineInfo, char const * _capturedExpression, diff --git a/include/internal/catch_assertionresult.hpp b/include/internal/catch_assertionresult.hpp index 2fa3373d..9a9fce63 100644 --- a/include/internal/catch_assertionresult.hpp +++ b/include/internal/catch_assertionresult.hpp @@ -13,6 +13,8 @@ namespace Catch { + AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Flags::Normal), secondArg(""){} + AssertionInfo::AssertionInfo( char const * _macroName, SourceLineInfo const& _lineInfo, char const * _capturedExpression, diff --git a/include/internal/catch_test_spec_parser.hpp b/include/internal/catch_test_spec_parser.hpp index 05bdcf4c..055bf1dc 100644 --- a/include/internal/catch_test_spec_parser.hpp +++ b/include/internal/catch_test_spec_parser.hpp @@ -30,7 +30,7 @@ namespace Catch { ITagAliasRegistry const* m_tagAliases; public: - TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {} TestSpecParser& parse( std::string const& arg ) { m_mode = None; From 7575749e56c7a5744d9a8ddc9e43bad30c09db0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Tue, 1 Aug 2017 17:21:06 +0200 Subject: [PATCH 18/24] Fix compilation error on older compilers --- include/internal/catch_assertionresult.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/internal/catch_assertionresult.hpp b/include/internal/catch_assertionresult.hpp index 9a9fce63..0a746b2f 100644 --- a/include/internal/catch_assertionresult.hpp +++ b/include/internal/catch_assertionresult.hpp @@ -13,7 +13,7 @@ namespace Catch { - AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Flags::Normal), secondArg(""){} + AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){} AssertionInfo::AssertionInfo( char const * _macroName, SourceLineInfo const& _lineInfo, From ec2074e55808d83117f70c633eb9ae47b433dd0d Mon Sep 17 00:00:00 2001 From: Danila Sukharev Date: Tue, 1 Aug 2017 18:33:53 +0300 Subject: [PATCH 19/24] Adding more flexibility into the cmake catch parsing script (#971) * Adding more flexibility into the cmake catch parsing script --- contrib/ParseAndAddCatchTests.cmake | 44 ++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/contrib/ParseAndAddCatchTests.cmake b/contrib/ParseAndAddCatchTests.cmake index bd1da755..700357fd 100644 --- a/contrib/ParseAndAddCatchTests.cmake +++ b/contrib/ParseAndAddCatchTests.cmake @@ -30,12 +30,21 @@ # # # PARSE_CATCH_TESTS_VERBOSE (Default OFF) # # -- enables debug messages # +# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) # +# -- excludes tests marked with [!hide], [.] or [.foo] tags # +# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) # +# -- adds fixture class name to the test name # +# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) # +# -- adds cmake target name to the test name # # # #==================================================================================================# cmake_minimum_required(VERSION 2.8.8) option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF) +option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF) +option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON) +option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON) function(PrintDebugMessage) if(PARSE_CATCH_TESTS_VERBOSE) @@ -103,12 +112,14 @@ function(ParseFile SourceFile TestTarget) if("${TestType}" STREQUAL "SCENARIO") set(Name "Scenario: ${Name}") endif() - if(TestFixture) + if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture) set(CTestName "${TestFixture}:${Name}") else() set(CTestName "${Name}") endif() - set(CTestName "${TestTarget}:${CTestName}") + if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME) + set(CTestName "${TestTarget}:${CTestName}") + endif() # add target to labels to enable running all tests added from this target set(Labels ${TestTarget}) if(TestStringsLength EQUAL 2) @@ -124,15 +135,28 @@ function(ParseFile SourceFile TestTarget) list(APPEND Labels ${Tags}) - PrintDebugMessage("Adding test \"${CTestName}\"") - if(Labels) - PrintDebugMessage("Setting labels to ${Labels}") - endif() + list(FIND Labels "!hide" IndexOfHideLabel) + set(HiddenTagFound OFF) + foreach(label ${Labels}) + string(REGEX MATCH "^!hide|^\\." result ${label}) + if(result) + set(HiddenTagFound ON) + break() + endif(result) + endforeach(label) + if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound}) + PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label") + else() + PrintDebugMessage("Adding test \"${CTestName}\"") + if(Labels) + PrintDebugMessage("Setting labels to ${Labels}") + endif() - # Add the test and set its properties - add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters}) - set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran" - LABELS "${Labels}") + # Add the test and set its properties + add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters}) + set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran" + LABELS "${Labels}") + endif() endforeach() endfunction() From 62875c857ed1726948c7796a7b4d9408d952f886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Tue, 1 Aug 2017 23:45:35 +0200 Subject: [PATCH 20/24] Add a landing page link to wandbox with catch preloaded Idea shamelessly stolen from nlohmann/json --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f42c33ed..ff7aac00 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Github Releases](https://img.shields.io/github/release/philsquared/catch.svg)](https://github.com/philsquared/catch/releases) [![Build Status](https://travis-ci.org/philsquared/Catch.svg?branch=master)](https://travis-ci.org/philsquared/Catch) [![Build status](https://ci.appveyor.com/api/projects/status/hrtk60hv6tw6fght/branch/master?svg=true)](https://ci.appveyor.com/project/philsquared/catch/branch/master) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/y7uyNvTCS263P5VG) The latest, single header, version can be downloaded directly using this link From d5613fb18a6a2bc54ac5a4ce50f3e36ea2560166 Mon Sep 17 00:00:00 2001 From: Cody Han Date: Wed, 2 Aug 2017 22:47:39 -0400 Subject: [PATCH 21/24] Update matchers docs to reflect namespace usage --- docs/matchers.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/matchers.md b/docs/matchers.md index 93f6a27f..5daf68d7 100644 --- a/docs/matchers.md +++ b/docs/matchers.md @@ -13,6 +13,7 @@ which consists of either a single matcher or one or more matchers combined using For example, to assert that a string ends with a certain substring: ```c++ +using Catch::Matchers::EndsWith; // or Catch::EndsWith std::string str = getStringFromSomewhere(); REQUIRE_THAT( str, EndsWith( "as a service" ) ); ``` @@ -34,7 +35,7 @@ REQUIRE_THAT( str, ``` ## Built in matchers -Currently Catch has some string matchers and some vector matchers. +Currently Catch has some string matchers and some vector matchers. They are in the `Catch::Matchers` and `Catch` namespaces. The string matchers are `StartsWith`, `EndsWith`, `Contains` and `Equals`. Each of them also takes an optional second argument, that decides case sensitivity (by-default, they are case sensitive). The vector matchers are `Contains`, `VectorContains` and `Equals`. `VectorContains` looks for a single element in the matched vector, `Contains` looks for a set (vector) of elements inside the matched vector. From 705a1bf527061fa81383059442ccf4a42f652d10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Tue, 8 Aug 2017 23:04:10 +0200 Subject: [PATCH 22/24] Add wandbox to release process documentation Also some formatting and wording changes. --- docs/release-process.md | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/docs/release-process.md b/docs/release-process.md index cfb7a289..8e93a942 100644 --- a/docs/release-process.md +++ b/docs/release-process.md @@ -2,43 +2,62 @@ When enough changes have accumulated, it is time to release new version of Catch. This document describes the proces in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory. +## Neccessary steps -## Approval testing +These steps are neccessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places. + + +### Approval testing Catch's releases are primarily validated against output from previous release, stored in `projects/SelfTest/Baselines`. To validate current sources, build the SelfTest binary and pass it to the `approvalTests.py` script: `approvalTests.py `. There should be no differences, as Approval tests should be updated when changes to Catch are made, but if there are, then they need to be manually reviewed and either approved (using `approve.py`) or Catch requires other fixes. -## Incrementing version number +### Incrementing version number Catch uses a variant of [semantic versioning](http://semver.org/), with breaking API changes (and thus major version increments) being very rare. Thus, the release will usually increment the patch version, when it only contains couple of bugfixes, or minor version, when it contains new functionality, or larger changes in implementation of current functionality. After deciding which part of version number should be incremented, you can use one of the `*Release.py` scripts to perform the required changes to Catch. -## Generate updated single-include header +### Generate updated single-include header After updating version number, regenerate single-include header using `generateSingleHeader.py`. -## Release notes +### Release notes Once a release is ready, release notes need to be written. They should summarize changes done since last release. For rough idea of expected notes see previous releases. Once written, release notes should be placed in `docs/release-notes.md`. -## Commit and push update to GitHub +### Commit and push update to GitHub After version number is incremented, single-include header is regenerated and release notes are updated, changes should be commited and pushed to GitHub. -## Release on GitHub +### Release on GitHub After pushing changes to GitHub, GitHub release *needs* to be created. Tag version and release title should be same as the new version, description should contain the release notes for the current release. Single header version of `catch.hpp` *needs* to be attached as a binary, as that is where the official download link links to. Preferably it should use linux line endings. +## Optional steps -## vcpkg update +The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they are *should* happen, but they can happen the next day without losing anything significant. -As a last step, optionally update Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg) with Catch's new version. `updateVcpkgPackage.py` can do a lot of neccessary work for you, but it assumes that you have your fork of vcpkg checked out in a directory next to the directory, where you have checked out Catch. -It creates a branch and commits neccessary changes, that you then should review, synchronize and open a PR against. +### vcpkg update + +Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of neccessary work for you, it creates a branch and commits neccessary changes. You should review these changes, push and open a PR against vcpkg's upstream. + +Note that the script assumes you have your fork of vcpkg checked out in a directory next to the directory where you have checked out Catch, like so: +``` +GitHub + Catch + vcpkg +``` + + +### Wandbox update + +Recently we also included a link to wandbox with preloaded Catch on the main page. Strictly speaking it is unneccessary to update this after every release, Catch usually does not change that much between versions, but it should be kept up to date anyway. + From 92d714ee12714ab760eaaaf95d76237859a342d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Tue, 8 Aug 2017 23:04:39 +0200 Subject: [PATCH 23/24] Update `updateVcpkgPackage` script for the new port format --- scripts/updateVcpkgPackage.py | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/scripts/updateVcpkgPackage.py b/scripts/updateVcpkgPackage.py index a7c8dee6..4d20d11c 100644 --- a/scripts/updateVcpkgPackage.py +++ b/scripts/updateVcpkgPackage.py @@ -57,24 +57,21 @@ def update_portfile(path, header_hash, licence_hash): for line in f: lines.append(line) with open(portfile_path, 'w') as f: - # Two things we need to change/update - # 1) Link and hash of releaseCommon - # 2) Link and hash of licence + # There are three things we need to change/update + # 1) CATCH_VERSION cmake variable + # 2) Hash of header + # 3) Hash of licence # We could assume licence never changes, but where is the fun in that? - first_hash = True for line in lines: - # Check what we are updating + # Update the version + if 'set(CATCH_VERSION' in line: + line = 'set(CATCH_VERSION v{})'.format(v.getVersionString()) + + # Determine which file we are updating if 'vcpkg_download_distfile' in line: kind = line.split('(')[-1].strip() - print(kind) - # Deal with URLS - if 'URLS' in line and kind == 'HEADER': - line = ' URLS "https://github.com/philsquared/Catch/releases/download/v{}/catch.hpp"\n'.format(v.getVersionString()) - if 'URLS' in line and kind == 'LICENSE': - line = ' URLS "https://raw.githubusercontent.com/philsquared/Catch/v{}/LICENSE.txt"\n'.format(v.getVersionString()) - - # Deal with hashes + # Update the hashes if 'SHA512' in line and kind == 'HEADER': line = ' SHA512 {}\n'.format(header_hash) if 'SHA512' in line and kind == 'LICENSE': @@ -86,8 +83,6 @@ def git_push(path_to_repo): v = Version() ver_string = v.getVersionString() - # Move to the repo dir - old_path = os.getcwd() os.chdir(path_to_repo) # Work with git From 7e4038d8488596e850a11c8fe236b59bca605444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Wed, 9 Aug 2017 15:28:40 +0200 Subject: [PATCH 24/24] Capture std::clog writes and combine them with std::cerr writes (#989) This also introduces Catch::clog() method to allow embedded targets to override std::clog usage with their own stream (presumably null-sink), similarly to how Catch::cout() and Catch::cerr() are used. Fixes #989 --- include/internal/catch_run_context.hpp | 26 ++++++++++++- include/internal/catch_stream.h | 1 + include/internal/catch_stream.hpp | 3 ++ .../Baselines/console.std.approved.txt | 5 ++- .../Baselines/console.sw.approved.txt | 37 ++++++++++++++++++- .../SelfTest/Baselines/junit.sw.approved.txt | 12 +++++- .../SelfTest/Baselines/xml.sw.approved.txt | 22 ++++++++++- projects/SelfTest/MessageTests.cpp | 17 +++++++++ 8 files changed, 116 insertions(+), 7 deletions(-) diff --git a/include/internal/catch_run_context.hpp b/include/internal/catch_run_context.hpp index 88c56603..8cd637c6 100644 --- a/include/internal/catch_run_context.hpp +++ b/include/internal/catch_run_context.hpp @@ -22,6 +22,7 @@ #include "catch_result_builder.h" #include "catch_fatal_condition.hpp" + #include #include @@ -50,6 +51,29 @@ namespace Catch { std::string& m_targetString; }; + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes and cannot use StreamRedirect on its own + class StdErrRedirect { + public: + StdErrRedirect(std::string& targetString) + :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()), + m_targetString(targetString){ + cerr().rdbuf(m_oss.rdbuf()); + clog().rdbuf(m_oss.rdbuf()); + } + ~StdErrRedirect() { + m_targetString += m_oss.str(); + cerr().rdbuf(m_cerrBuf); + clog().rdbuf(m_clogBuf); + } + private: + std::streambuf* m_cerrBuf; + std::streambuf* m_clogBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { @@ -305,7 +329,7 @@ namespace Catch { timer.start(); if( m_reporter->getPreferences().shouldRedirectStdOut ) { StreamRedirect coutRedir( Catch::cout(), redirectedCout ); - StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + StdErrRedirect errRedir( redirectedCerr ); invokeActiveTestCase(); } else { diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h index d8deebab..4323c318 100644 --- a/include/internal/catch_stream.h +++ b/include/internal/catch_stream.h @@ -21,6 +21,7 @@ namespace Catch { std::ostream& cout(); std::ostream& cerr(); + std::ostream& clog(); struct IStream { diff --git a/include/internal/catch_stream.hpp b/include/internal/catch_stream.hpp index 42f51e82..b8838d34 100644 --- a/include/internal/catch_stream.hpp +++ b/include/internal/catch_stream.hpp @@ -103,6 +103,9 @@ namespace Catch { std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { + return std::clog; + } #endif } diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 19e545ba..439da767 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -622,6 +622,9 @@ with messages: A string sent directly to stdout A string sent directly to stderr +Write to std::cerr +Write to std::clog +Interleaved writes to error streams Message from section one Message from section two ------------------------------------------------------------------------------- @@ -953,6 +956,6 @@ with expansion: "first" == "second" =============================================================================== -test cases: 168 | 119 passed | 45 failed | 4 failed as expected +test cases: 169 | 120 passed | 45 failed | 4 failed as expected assertions: 968 | 859 passed | 88 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index cdc414a4..9cb93b13 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -6786,6 +6786,39 @@ PASSED: with expansion: Approx( 1.23 ) != 1.24 +Write to std::cerr +------------------------------------------------------------------------------- +Standard error is reported and redirected + std::cerr +------------------------------------------------------------------------------- +MessageTests.cpp: +............................................................................... + + +No assertions in section 'std::cerr' + +Write to std::clog +------------------------------------------------------------------------------- +Standard error is reported and redirected + std::clog +------------------------------------------------------------------------------- +MessageTests.cpp: +............................................................................... + + +No assertions in section 'std::clog' + +Interleaved writes to error streams +------------------------------------------------------------------------------- +Standard error is reported and redirected + Interleaved writes to cerr and clog +------------------------------------------------------------------------------- +MessageTests.cpp: +............................................................................... + + +No assertions in section 'Interleaved writes to cerr and clog' + Message from section one ------------------------------------------------------------------------------- Standard output from all sections is reported @@ -9483,6 +9516,6 @@ MiscTests.cpp:: PASSED: =============================================================================== -test cases: 168 | 118 passed | 46 failed | 4 failed as expected -assertions: 970 | 859 passed | 90 failed | 21 failed as expected +test cases: 169 | 118 passed | 47 failed | 4 failed as expected +assertions: 973 | 859 passed | 93 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index b723f207..d8b788e3 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,6 +1,6 @@ - + @@ -475,6 +475,13 @@ A string sent directly to stderr + + +Write to std::cerr +Write to std::clog +Interleaved writes to error streams + + Message from section one @@ -750,6 +757,9 @@ hello A string sent directly to stderr +Write to std::cerr +Write to std::clog +Interleaved writes to error streams diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index 6361fee3..e1030964 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -7309,6 +7309,24 @@ A string sent directly to stderr + +
+ +
+
+ +
+
+ +
+ + +Write to std::cerr +Write to std::clog +Interleaved writes to error streams + + +
@@ -10143,7 +10161,7 @@ spanner
- + - + diff --git a/projects/SelfTest/MessageTests.cpp b/projects/SelfTest/MessageTests.cpp index bed9c137..047bead7 100644 --- a/projects/SelfTest/MessageTests.cpp +++ b/projects/SelfTest/MessageTests.cpp @@ -99,6 +99,23 @@ TEST_CASE( "Standard output from all sections is reported", "[messages][.]" ) } } +TEST_CASE( "Standard error is reported and redirected", "[messages][.]" ) { + SECTION( "std::cerr" ) { + std::cerr << "Write to std::cerr" << std::endl; + } + SECTION( "std::clog" ) { + std::clog << "Write to std::clog" << std::endl; + } + SECTION( "Interleaved writes to cerr and clog" ) { + std::cerr << "Inter"; + std::clog << "leaved"; + std::cerr << ' '; + std::clog << "writes"; + std::cerr << " to error"; + std::clog << " streams\n"; + } +} + TEST_CASE( "SCOPED_INFO is reset for each loop", "[messages][failing][.]" ) { for( int i=0; i<100; i++ )