diff --git a/.gitignore b/.gitignore index c7c3fc88..bf296d96 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,5 @@ DerivedData *.xccheckout Build .idea -cmake-build-debug -cmake-build-release -.vs \ No newline at end of file +.vs +cmake-build-* diff --git a/.travis.yml b/.travis.yml index 7be58e63..9e127233 100644 --- a/.travis.yml +++ b/.travis.yml @@ -203,9 +203,13 @@ install: before_script: - export CXX=${COMPILER} - cd ${TRAVIS_BUILD_DIR} - # Only run valgrind in debug build - - cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_VALGRIND=${VALGRIND} -DNO_SELFTEST=${ENV_NO_SELFTEST} -DBUILD_EXAMPLES=${ENV_BUILD_EXAMPLES} - - cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14} -DNO_SELFTEST=${ENV_NO_SELFTEST} -DBUILD_EXAMPLES=${ENV_BUILD_EXAMPLES} + # Regenerate single header file, so it is tested in the examples... + - python scripts/generateSingleHeader.py + + # Use Debug builds for running Valgrind and building examples + - cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_VALGRIND=${VALGRIND} -DBUILD_EXAMPLES=ON + # Check that we don't miscompile with optimalizations... + - cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14} script: - cd Build-Debug diff --git a/CMakeLists.txt b/CMakeLists.txt index aaa8877a..e1208a9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.0) project(CatchSelfTest) option(USE_VALGRIND "Perform SelfTests with Valgrind" OFF) +option(BUILD_EXAMPLES "Build documentation examples" OFF) set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -177,6 +178,7 @@ set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_timer.h ${HEADER_DIR}/internal/catch_tostring.h ${HEADER_DIR}/internal/catch_totals.h + ${HEADER_DIR}/internal/catch_user_interfaces.h ${HEADER_DIR}/internal/catch_version.h ${HEADER_DIR}/internal/catch_wildcard_pattern.h ${HEADER_DIR}/internal/catch_windows_h_proxy.h diff --git a/appveyor.yml b/appveyor.yml index 2f7084ae..f3a2c5bd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,24 +20,11 @@ environment: - additional_flags: "/D_UNICODE /DUNICODE" wmain: 1 - - additional_flags: "" - wmain: 0 - env_build_examples: 1 - env_no_selftest: 1 - matrix: exclude: - os: Visual Studio 2015 additional_flags: "/permissive- /std:c++latest" - - os: Visual Studio 2015 - env_build_examples: 1 - env_no_selftest: 1 - - - configuration: Debug - env_build_examples: 1 - env_no_selftest: 1 - init: - git config --global core.autocrlf input # Set build version to git commit-hash @@ -59,8 +46,9 @@ configuration: #Cmake will autodetect the compiler, but we set the arch before_build: + - python scripts/generateSingleHeader.py - set CXXFLAGS=%additional_flags% - - cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DNO_SELFTEST=%env_no_selftest% -DBUILD_EXAMPLES=%env_build_examples% + - cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DBUILD_EXAMPLES=ON # build with MSBuild build: diff --git a/include/catch.hpp b/include/catch.hpp index ef141d8f..34c551be 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -30,6 +30,7 @@ # if defined(CATCH_CONFIG_DISABLE_MATCHERS) # undef CATCH_CONFIG_DISABLE_MATCHERS # endif +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER #endif #if !defined(CATCH_CONFIG_IMPL_ONLY) @@ -42,6 +43,7 @@ # endif #endif +#include "internal/catch_user_interfaces.h" #include "internal/catch_tag_alias_autoregistrar.h" #include "internal/catch_test_registry.h" #include "internal/catch_capture.hpp" diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 9f205465..595336d4 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -63,7 +63,7 @@ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look + } while( Catch::isTrue(false) && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. /////////////////////////////////////////////////////////////////////////////// diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h index 5b75bc07..2c2962f8 100644 --- a/include/internal/catch_common.h +++ b/include/internal/catch_common.h @@ -62,7 +62,8 @@ namespace Catch { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // This is just here to avoid compiler warnings with macro constants and boolean literals - inline bool isTrue( bool value ) { return value; } + inline bool isTrue( bool value ){ return value; } + bool alwaysTrue(); bool alwaysFalse(); diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index 6748d3e0..d6ab1576 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -8,8 +8,6 @@ #include #include -static auto const& defaultExpression = "{Unknown expression after the reported line}"; - namespace Catch { StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString) @@ -129,9 +127,13 @@ namespace Catch { static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); // Reset working state - m_lastAssertionInfo = { "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition }; + resetAssertionInfo(); m_lastResult = result; } + void RunContext::resetAssertionInfo() { + m_lastAssertionInfo.macroName = StringRef(); + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; + } bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); @@ -255,8 +257,7 @@ namespace Catch { void RunContext::assertionPassed() { ++m_totals.assertions.passed; - m_lastAssertionInfo.capturedExpression = StringRef(defaultExpression, sizeof(defaultExpression) - 1); - m_lastAssertionInfo.macroName = StringRef("", 0); + resetAssertionInfo(); } void RunContext::assertionRun() { @@ -274,18 +275,19 @@ namespace Catch { Counts prevAssertions = m_totals.assertions; double duration = 0; m_shouldReportUnexpected = true; + m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; + + seedRng(*m_config); + + Timer timer; try { - m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; - - seedRng(*m_config); - - Timer timer; - timer.start(); if (m_reporter->getPreferences().shouldRedirectStdOut) { StreamRedirect coutRedir(cout(), redirectedCout); StdErrRedirect errRedir(redirectedCerr); + timer.start(); invokeActiveTestCase(); } else { + timer.start(); invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); diff --git a/include/internal/catch_run_context.h b/include/internal/catch_run_context.h index 0d10a19b..22c4d76a 100644 --- a/include/internal/catch_run_context.h +++ b/include/internal/catch_run_context.h @@ -116,6 +116,8 @@ namespace Catch { void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr); void invokeActiveTestCase(); + void resetAssertionInfo(); + private: void handleUnfinishedSections(); diff --git a/include/internal/catch_stringref.cpp b/include/internal/catch_stringref.cpp index 49d9629f..bac8b1d8 100644 --- a/include/internal/catch_stringref.cpp +++ b/include/internal/catch_stringref.cpp @@ -14,8 +14,12 @@ #include "catch_stringref.h" #include +#include namespace Catch { + StringRef::StringRef( char const* rawChars ) noexcept + : StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) + {} StringRef::operator std::string() const { return std::string( m_start, m_size ); diff --git a/include/internal/catch_stringref.h b/include/internal/catch_stringref.h index 2a9ad4c2..0f9e7801 100644 --- a/include/internal/catch_stringref.h +++ b/include/internal/catch_stringref.h @@ -10,8 +10,6 @@ #include #include #include -#include -#include namespace Catch { @@ -25,10 +23,12 @@ namespace Catch { /// visible - but it does mean (substring) StringRefs should not be shared between /// threads. class StringRef { + public: + using size_type = std::size_t; + + private: friend struct StringRefTestAccess; - using size_type = std::size_t; - char const* m_start; size_type m_size; @@ -56,12 +56,7 @@ namespace Catch { other.m_data = nullptr; } - StringRef( char const* rawChars ) noexcept - : m_start( rawChars ), - m_size( static_cast(std::strlen(rawChars))) - { - assert( rawChars ); - } + StringRef( char const* rawChars ) noexcept; StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), @@ -121,6 +116,10 @@ namespace Catch { auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } + } // namespace Catch #endif // CATCH_STRINGREF_H_INCLUDED diff --git a/include/internal/catch_test_registry.h b/include/internal/catch_test_registry.h index afba1dbc..84001018 100644 --- a/include/internal/catch_test_registry.h +++ b/include/internal/catch_test_registry.h @@ -35,7 +35,7 @@ auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { } struct NameAndTags { - NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept; + NameAndTags( StringRef name_ = StringRef(), StringRef tags_ = StringRef() ) noexcept; StringRef name; StringRef tags; }; diff --git a/include/internal/catch_tostring.cpp b/include/internal/catch_tostring.cpp index 700315de..a9f7735e 100644 --- a/include/internal/catch_tostring.cpp +++ b/include/internal/catch_tostring.cpp @@ -12,6 +12,10 @@ # pragma clang diagnostic ignored "-Wglobal-constructors" #endif +// Enable specific decls locally +#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif #include "catch_tostring.h" #include "catch_interfaces_config.h" @@ -221,6 +225,13 @@ std::string StringMaker::convert(double value) { return fpToString(value, 10); } +std::string ratio_string::symbol() { return "a"; } +std::string ratio_string::symbol() { return "f"; } +std::string ratio_string::symbol() { return "p"; } +std::string ratio_string::symbol() { return "n"; } +std::string ratio_string::symbol() { return "u"; } +std::string ratio_string::symbol() { return "m"; } + } // end namespace Catch diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h index 40d61479..79e02448 100644 --- a/include/internal/catch_tostring.h +++ b/include/internal/catch_tostring.h @@ -26,7 +26,7 @@ // We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy; +struct Catch_global_namespace_dummy {}; std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { @@ -351,6 +351,9 @@ namespace Catch { #include #include + +namespace Catch { + template struct ratio_string { static std::string symbol(); @@ -365,30 +368,29 @@ std::string ratio_string::symbol() { } template <> struct ratio_string { - static std::string symbol() { return "a"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "f"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "p"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "n"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "u"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "m"; } + static std::string symbol(); }; -namespace Catch { //////////// // std::chrono::duration specializations template diff --git a/include/internal/catch_user_interfaces.h b/include/internal/catch_user_interfaces.h new file mode 100644 index 00000000..35acb77b --- /dev/null +++ b/include/internal/catch_user_interfaces.h @@ -0,0 +1,18 @@ +/* + * Created by Martin on 21/11/2017. + * + * This file collects declaration that we want to expose to test files. + * These declarations are expected to be duplicated elsewhere, + * together with their implementation. + * + * 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) + */ +#ifndef TWOBLUECUBES_CATCH_USER_INTERFACES_H_INCLUDED +#define TWOBLUECUBES_CATCH_USER_INTERFACES_H_INCLUDED + +namespace Catch { + unsigned int rngSeed(); +} + +#endif // TWOBLUECUBES_CATCH_USER_INTERFACES_H_INCLUDED diff --git a/scripts/releaseCommon.py b/scripts/releaseCommon.py index 2acd4869..688b13ce 100644 --- a/scripts/releaseCommon.py +++ b/scripts/releaseCommon.py @@ -6,8 +6,6 @@ import re import string from scriptCommon import catchPath -import generateSingleHeader -import updateWandbox versionParser = re.compile( r'(\s*static\sVersion\sversion)\s*\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*\"(.*)\"\s*,\s*(.*)\s*\).*' ) rootPath = os.path.join( catchPath, 'include/' ) @@ -80,6 +78,8 @@ class Version: f.write( line + "\n" ) def updateReadmeFile(version): + import updateWandbox + downloadParser = re.compile( r'' ) success, wandboxLink = updateWandbox.uploadFiles() if not success: @@ -142,7 +142,10 @@ def performUpdates(version): # First update version file, so we can regenerate single header and # have it ready for upload to wandbox, when updating readme version.updateVersionFile() + + import generateSingleHeader generateSingleHeader.generate(version) + updateReadmeFile(version) updateConanFile(version) updateConanTestFile(version)