mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 04:07:10 +01:00 
			
		
		
		
	Split out more headers into separate .cpp files
This commit is contained in:
		
							
								
								
									
										113
									
								
								include/internal/catch_test_case_registry_impl.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								include/internal/catch_test_case_registry_impl.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | ||||
| /* | ||||
|  *  Created by Martin on 25/07/2017 | ||||
|  * | ||||
|  *  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_test_case_registry_impl.hpp" | ||||
|  | ||||
| #include "catch_context.h" | ||||
| #include "catch_interfaces_registry_hub.h" | ||||
| #include "catch_string_manip.h" | ||||
| #include "catch_test_case_info.h" | ||||
|  | ||||
| #include <sstream> | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const { return std::rand() % n; } | ||||
|     RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const { return std::rand() % max(); } | ||||
|  | ||||
|     std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { | ||||
|  | ||||
|         std::vector<TestCase> sorted = unsortedTestCases; | ||||
|  | ||||
|         switch( config.runOrder() ) { | ||||
|             case RunTests::InLexicographicalOrder: | ||||
|                 std::sort( sorted.begin(), sorted.end() ); | ||||
|                 break; | ||||
|             case RunTests::InRandomOrder: | ||||
|                 seedRng( config ); | ||||
|                 RandomNumberGenerator::shuffle( sorted ); | ||||
|                 break; | ||||
|             case RunTests::InDeclarationOrder: | ||||
|                 // already in declaration order | ||||
|                 break; | ||||
|         } | ||||
|         return sorted; | ||||
|     } | ||||
|     bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { | ||||
|         return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); | ||||
|     } | ||||
|  | ||||
|     void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { | ||||
|         std::set<TestCase> seenFunctions; | ||||
|         for( auto const& function : functions ) { | ||||
|             auto prev = seenFunctions.insert( function ); | ||||
|             CATCH_ENFORCE( prev.second, | ||||
|                     "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" | ||||
|                     << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" | ||||
|                     << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { | ||||
|         std::vector<TestCase> filtered; | ||||
|         filtered.reserve( testCases.size() ); | ||||
|         for( auto const& testCase : testCases ) | ||||
|             if( matchTest( testCase, testSpec, config ) ) | ||||
|                 filtered.push_back( testCase ); | ||||
|         return filtered; | ||||
|     } | ||||
|     std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { | ||||
|         return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); | ||||
|     } | ||||
|  | ||||
|     void TestRegistry::registerTest( TestCase const& testCase ) { | ||||
|         std::string name = testCase.getTestCaseInfo().name; | ||||
|         if( name.empty() ) { | ||||
|             std::ostringstream oss; | ||||
|             oss << "Anonymous test case " << ++m_unnamedCount; | ||||
|             return registerTest( testCase.withName( oss.str() ) ); | ||||
|         } | ||||
|         m_functions.push_back( testCase ); | ||||
|     } | ||||
|  | ||||
|     std::vector<TestCase> const& TestRegistry::getAllTests() const { | ||||
|         return m_functions; | ||||
|     } | ||||
|     std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { | ||||
|         if( m_sortedFunctions.empty() ) | ||||
|             enforceNoDuplicateTestCases( m_functions ); | ||||
|  | ||||
|         if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { | ||||
|             m_sortedFunctions = sortTests( config, m_functions ); | ||||
|             m_currentSortOrder = config.runOrder(); | ||||
|         } | ||||
|         return m_sortedFunctions; | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|     TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} | ||||
|  | ||||
|     void TestInvokerAsFunction::invoke() const { | ||||
|         m_testAsFunction(); | ||||
|     } | ||||
|  | ||||
|     std::string extractClassName( std::string const& classOrQualifiedMethodName ) { | ||||
|         std::string className = classOrQualifiedMethodName; | ||||
|         if( startsWith( className, '&' ) ) | ||||
|         { | ||||
|             std::size_t lastColons = className.rfind( "::" ); | ||||
|             std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); | ||||
|             if( penultimateColons == std::string::npos ) | ||||
|                 penultimateColons = 1; | ||||
|             className = className.substr( penultimateColons, lastColons-penultimateColons ); | ||||
|         } | ||||
|         return className; | ||||
|     } | ||||
|  | ||||
| } // end namespace Catch | ||||
| @@ -9,28 +9,27 @@ | ||||
| #define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED | ||||
|  | ||||
| #include "catch_test_registry.hpp" | ||||
| #include "catch_test_case_info.h" | ||||
| #include "catch_test_spec.hpp" | ||||
| #include "catch_context.h" | ||||
| #include "catch_interfaces_config.h" | ||||
| #include "catch_string_manip.h" | ||||
|  | ||||
| #include <vector> | ||||
| #include <set> | ||||
| #include <sstream> | ||||
| #include <algorithm> | ||||
|  | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     struct RandomNumberGenerator { | ||||
|         typedef std::ptrdiff_t result_type; | ||||
|     class TestCase; | ||||
|     class IConfig; | ||||
|  | ||||
|         result_type operator()( result_type n ) const { return std::rand() % n; } | ||||
|     struct RandomNumberGenerator { | ||||
|         using result_type = std::ptrdiff_t; | ||||
|  | ||||
|         result_type operator()( result_type n ) const; | ||||
|  | ||||
|         static constexpr result_type min() { return 0; } | ||||
|         static constexpr result_type max() { return 1000000; } | ||||
|         result_type operator()() const { return std::rand() % max(); } | ||||
|         result_type operator()() const; | ||||
|         template<typename V> | ||||
|         static void shuffle( V& vector ) { | ||||
|             RandomNumberGenerator rng; | ||||
| @@ -38,78 +37,22 @@ namespace Catch { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { | ||||
|     std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );  | ||||
|     bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); | ||||
|  | ||||
|         std::vector<TestCase> sorted = unsortedTestCases; | ||||
|     void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ); | ||||
|  | ||||
|         switch( config.runOrder() ) { | ||||
|             case RunTests::InLexicographicalOrder: | ||||
|                 std::sort( sorted.begin(), sorted.end() ); | ||||
|                 break; | ||||
|             case RunTests::InRandomOrder: | ||||
|                 seedRng( config ); | ||||
|                 RandomNumberGenerator::shuffle( sorted ); | ||||
|                 break; | ||||
|             case RunTests::InDeclarationOrder: | ||||
|                 // already in declaration order | ||||
|                 break; | ||||
|         } | ||||
|         return sorted; | ||||
|     } | ||||
|     bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { | ||||
|         return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); | ||||
|     } | ||||
|  | ||||
|     void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { | ||||
|         std::set<TestCase> seenFunctions; | ||||
|         for( auto const& function : functions ) { | ||||
|             auto prev = seenFunctions.insert( function ); | ||||
|             CATCH_ENFORCE( prev.second, | ||||
|                     "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" | ||||
|                     << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" | ||||
|                     << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { | ||||
|         std::vector<TestCase> filtered; | ||||
|         filtered.reserve( testCases.size() ); | ||||
|         for( auto const& testCase : testCases ) | ||||
|             if( matchTest( testCase, testSpec, config ) ) | ||||
|                 filtered.push_back( testCase ); | ||||
|         return filtered; | ||||
|     } | ||||
|     std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { | ||||
|         return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); | ||||
|     } | ||||
|     std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); | ||||
|     std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); | ||||
|  | ||||
|     class TestRegistry : public ITestCaseRegistry { | ||||
|     public: | ||||
|         virtual ~TestRegistry(); | ||||
|         virtual ~TestRegistry() = default; | ||||
|  | ||||
|         virtual void registerTest( TestCase const& testCase ) { | ||||
|             std::string name = testCase.getTestCaseInfo().name; | ||||
|             if( name.empty() ) { | ||||
|                 std::ostringstream oss; | ||||
|                 oss << "Anonymous test case " << ++m_unnamedCount; | ||||
|                 return registerTest( testCase.withName( oss.str() ) ); | ||||
|             } | ||||
|             m_functions.push_back( testCase ); | ||||
|         } | ||||
|         virtual void registerTest( TestCase const& testCase ); | ||||
|  | ||||
|         std::vector<TestCase> const& getAllTests() const override { | ||||
|             return m_functions; | ||||
|         } | ||||
|         std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override { | ||||
|             if( m_sortedFunctions.empty() ) | ||||
|                 enforceNoDuplicateTestCases( m_functions ); | ||||
|  | ||||
|             if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { | ||||
|                 m_sortedFunctions = sortTests( config, m_functions ); | ||||
|                 m_currentSortOrder = config.runOrder(); | ||||
|             } | ||||
|             return m_sortedFunctions; | ||||
|         } | ||||
|         std::vector<TestCase> const& getAllTests() const override; | ||||
|         std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override; | ||||
|  | ||||
|     private: | ||||
|         std::vector<TestCase> m_functions; | ||||
| @@ -119,57 +62,21 @@ namespace Catch { | ||||
|         std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised | ||||
|     }; | ||||
|  | ||||
|     TestRegistry::~TestRegistry() {} | ||||
|  | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     class TestInvokerAsFunction : public ITestInvoker { | ||||
|         void(*m_testAsFunction)(); | ||||
|     public: | ||||
|         TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} | ||||
|         TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; | ||||
|  | ||||
|         void invoke() const override { | ||||
|             m_testAsFunction(); | ||||
|         } | ||||
|         void invoke() const override; | ||||
|     }; | ||||
|     auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { | ||||
|         return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { | ||||
|         std::string className = classOrQualifiedMethodName; | ||||
|         if( startsWith( className, '&' ) ) | ||||
|         { | ||||
|             std::size_t lastColons = className.rfind( "::" ); | ||||
|             std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); | ||||
|             if( penultimateColons == std::string::npos ) | ||||
|                 penultimateColons = 1; | ||||
|             className = className.substr( penultimateColons, lastColons-penultimateColons ); | ||||
|         } | ||||
|         return className; | ||||
|     } | ||||
|     std::string extractClassName( std::string const& classOrQualifiedMethodName ); | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept | ||||
|     { | ||||
|         try { | ||||
|             getMutableRegistryHub() | ||||
|                     .registerTest( | ||||
|                         makeTestCase( | ||||
|                             invoker, | ||||
|                             extractClassName( classOrMethod.c_str() ), | ||||
|                             nameAndTags.name.c_str(), | ||||
|                             nameAndTags.tags.c_str(), | ||||
|                             lineInfo)); | ||||
|         } catch (...) { | ||||
|             // Do not throw when constructing global objects, instead register the exception to be processed later | ||||
|             getMutableRegistryHub().registerStartupException( std::current_exception() ); | ||||
|         } | ||||
|     } | ||||
|     AutoReg::~AutoReg() {} | ||||
|  | ||||
| } // end namespace Catch | ||||
|  | ||||
|   | ||||
							
								
								
									
										35
									
								
								include/internal/catch_test_registry.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								include/internal/catch_test_registry.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| /* | ||||
|  *  Created by Martin on 25/07/2017. | ||||
|  * | ||||
|  *  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_test_registry.hpp" | ||||
| #include "catch_test_case_registry_impl.hpp" | ||||
| #include "catch_interfaces_registry_hub.h" | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { | ||||
|         return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); | ||||
|     } | ||||
|  | ||||
|     NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {} | ||||
|  | ||||
|     AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept { | ||||
|         try { | ||||
|             getMutableRegistryHub() | ||||
|                     .registerTest( | ||||
|                         makeTestCase( | ||||
|                             invoker, | ||||
|                             extractClassName( classOrMethod.c_str() ), | ||||
|                             nameAndTags.name.c_str(), | ||||
|                             nameAndTags.tags.c_str(), | ||||
|                             lineInfo)); | ||||
|         } catch (...) { | ||||
|             // Do not throw when constructing global objects, instead register the exception to be processed later | ||||
|             getMutableRegistryHub().registerStartupException( std::current_exception() ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -35,16 +35,14 @@ auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { | ||||
| } | ||||
|  | ||||
| struct NameAndTags { | ||||
|  | ||||
|     NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept : name( name_ ), tags( tags_ ) {} | ||||
|  | ||||
|     NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept; | ||||
|     StringRef name; | ||||
|     StringRef tags; | ||||
| }; | ||||
|  | ||||
| struct AutoReg : NonCopyable { | ||||
|     AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; | ||||
|     ~AutoReg(); | ||||
|     ~AutoReg() = default; | ||||
| }; | ||||
|  | ||||
| } // end namespace Catch | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Martin Hořeňovský
					Martin Hořeňovský