diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 00000000..81e9c708 --- /dev/null +++ b/conanfile.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +from conans import ConanFile + + +class CatchConan(ConanFile): + name = "Catch" + 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 = "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") 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. 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/docs/release-process.md b/docs/release-process.md index a82c82cc..725779ea 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. + diff --git a/include/catch_session.hpp b/include/catch_session.hpp index 93c75cf3..d31896c7 100644 --- a/include/catch_session.hpp +++ b/include/catch_session.hpp @@ -90,7 +90,7 @@ namespace Catch { if( lastDot != std::string::npos ) filename = filename.substr( 0, lastDot ); - tags.push_back( "#" + filename ); + tags.push_back( '#' + filename ); setTags( testCase, tags ); } } diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index b54742ff..d25b958a 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -18,6 +18,19 @@ namespace Catch { m_stream.rdbuf(m_prevBuf); } + StdErrRedirect::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::~StdErrRedirect() { + m_targetString += m_oss.str(); + cerr().rdbuf(m_cerrBuf); + clog().rdbuf(m_clogBuf); + } + RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) : m_runInfo(_config->name()), m_context(getCurrentMutableContext()), @@ -256,7 +269,7 @@ namespace Catch { timer.start(); if (m_reporter->getPreferences().shouldRedirectStdOut) { StreamRedirect coutRedir(cout(), redirectedCout); - StreamRedirect cerrRedir(cerr(), redirectedCerr); + StdErrRedirect errRedir(redirectedCerr); invokeActiveTestCase(); } else { invokeActiveTestCase(); @@ -318,5 +331,4 @@ namespace Catch { else CATCH_INTERNAL_ERROR("No result capture instance"); } - } \ No newline at end of file diff --git a/include/internal/catch_run_context.hpp b/include/internal/catch_run_context.hpp index ee923e88..de24ec95 100644 --- a/include/internal/catch_run_context.hpp +++ b/include/internal/catch_run_context.hpp @@ -40,6 +40,20 @@ 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); + ~StdErrRedirect(); + private: + std::streambuf* m_cerrBuf; + std::streambuf* m_clogBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h index 8f2fb5a6..488e8b20 100644 --- a/include/internal/catch_stream.h +++ b/include/internal/catch_stream.h @@ -20,6 +20,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 3b7bbe60..dbcda110 100644 --- a/include/internal/catch_stream.hpp +++ b/include/internal/catch_stream.hpp @@ -101,6 +101,9 @@ namespace Catch { std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { + return std::clog; + } #endif } diff --git a/include/internal/catch_test_registry.hpp b/include/internal/catch_test_registry.hpp index 1cd5fa40..07334c34 100644 --- a/include/internal/catch_test_registry.hpp +++ b/include/internal/catch_test_registry.hpp @@ -51,7 +51,7 @@ struct AutoReg : NonCopyable { #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ @@ -60,7 +60,7 @@ struct AutoReg : NonCopyable { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS /////////////////////////////////////////////////////////////////////////////// @@ -70,7 +70,7 @@ struct AutoReg : NonCopyable { struct TestName : ClassName{ \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ void TestName::test() @@ -80,7 +80,7 @@ struct AutoReg : NonCopyable { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - Catch::AutoReg( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); \ + Catch::AutoReg( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 9e41f7f5..c01923c1 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -671,6 +671,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 ------------------------------------------------------------------------------- @@ -1016,6 +1019,6 @@ with expansion: "{?}" == "1" =============================================================================== -test cases: 182 | 131 passed | 47 failed | 4 failed as expected +test cases: 183 | 132 passed | 47 failed | 4 failed as expected assertions: 896 | 779 passed | 96 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 971c0e32..6b64aee8 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -4177,6 +4177,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 @@ -7590,6 +7623,6 @@ MiscTests.cpp:: PASSED: =============================================================================== -test cases: 182 | 130 passed | 48 failed | 4 failed as expected -assertions: 898 | 779 passed | 98 failed | 21 failed as expected +test cases: 183 | 130 passed | 49 failed | 4 failed as expected +assertions: 901 | 779 passed | 101 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index 58807c18..7a8d78e2 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,6 +1,6 @@ - + @@ -486,6 +486,13 @@ A string sent directly to stderr + + +Write to std::cerr +Write to std::clog +Interleaved writes to error streams + + Message from section one @@ -792,6 +799,9 @@ Message from section two 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 e70ad12e..188d734c 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -4817,6 +4817,24 @@ A string sent directly to stderr + +
+ +
+
+ +
+
+ +
+ + +Write to std::cerr +Write to std::clog +Interleaved writes to error streams + + +
@@ -8441,7 +8459,7 @@ spanner
- + - + diff --git a/projects/SelfTest/MessageTests.cpp b/projects/SelfTest/MessageTests.cpp index 21802ccd..0faa4d72 100644 --- a/projects/SelfTest/MessageTests.cpp +++ b/projects/SelfTest/MessageTests.cpp @@ -85,6 +85,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++ ) { diff --git a/scripts/developBuild.py b/scripts/developBuild.py index c16c8a6d..d751f108 100755 --- a/scripts/developBuild.py +++ b/scripts/developBuild.py @@ -7,5 +7,7 @@ v = Version() v.incrementBuildNumber() v.updateVersionFile() v.updateReadmeFile() +v.updateConanFile() +v.updateConanTestFile() -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..e8116d3b 100755 --- a/scripts/majorRelease.py +++ b/scripts/majorRelease.py @@ -7,5 +7,7 @@ v = Version() v.incrementMajorVersion() v.updateVersionFile() v.updateReadmeFile() +v.updateConanFile() +v.updateConanTestFile() -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..dff2d8c8 100755 --- a/scripts/minorRelease.py +++ b/scripts/minorRelease.py @@ -7,5 +7,7 @@ v = Version() v.incrementMinorVersion() v.updateVersionFile() v.updateReadmeFile() +v.updateConanFile() +v.updateConanTestFile() -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..e33e4064 100755 --- a/scripts/patchRelease.py +++ b/scripts/patchRelease.py @@ -7,5 +7,7 @@ v = Version() v.incrementPatchNumber() v.updateVersionFile() v.updateReadmeFile() +v.updateConanFile() +v.updateConanTestFile() -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 652985c9..6737f13b 100644 --- a/scripts/releaseCommon.py +++ b/scripts/releaseCommon.py @@ -11,6 +11,8 @@ 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.cpp" ) 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): @@ -86,3 +88,32 @@ 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" ) + + 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" ) 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 diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt new file mode 100644 index 00000000..339facbf --- /dev/null +++ b/test_package/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.0) +project(CatchTest CXX) + +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup() + +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 new file mode 100644 index 00000000..9444b737 --- /dev/null +++ b/test_package/conanfile.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +from os import getenv +from os import path +from conans import ConanFile +from conans import CMake + + +class CatchConanTest(ConanFile): + generators = "cmake" + settings = "os", "compiler", "arch", "build_type" + username = getenv("CONAN_USERNAME", "philsquared") + channel = getenv("CONAN_CHANNEL", "testing") + requires = "Catch/1.9.5@%s/%s" % (username, channel) + + def build(self): + cmake = CMake(self) + cmake.configure(build_dir="./") + cmake.build() + + def test(self): + self.run(path.join("bin", "CatchTest"))