1 /* 2 * Created by Martin on 25/07/2017 3 * 4 * Distributed under the Boost Software License, Version 1.0. (See accompanying 5 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 */ 7 8 #include "catch_test_case_registry_impl.h" 9 10 #include "catch_context.h" 11 #include "catch_enforce.h" 12 #include "catch_interfaces_registry_hub.h" 13 #include "catch_random_number_generator.h" 14 #include "catch_string_manip.h" 15 #include "catch_test_case_info.h" 16 17 #include <sstream> 18 19 namespace Catch { 20 sortTests(IConfig const & config,std::vector<TestCase> const & unsortedTestCases)21 std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { 22 23 std::vector<TestCase> sorted = unsortedTestCases; 24 25 switch( config.runOrder() ) { 26 case RunTests::InLexicographicalOrder: 27 std::sort( sorted.begin(), sorted.end() ); 28 break; 29 case RunTests::InRandomOrder: 30 seedRng( config ); 31 std::shuffle( sorted.begin(), sorted.end(), rng() ); 32 break; 33 case RunTests::InDeclarationOrder: 34 // already in declaration order 35 break; 36 } 37 return sorted; 38 } matchTest(TestCase const & testCase,TestSpec const & testSpec,IConfig const & config)39 bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { 40 return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); 41 } 42 enforceNoDuplicateTestCases(std::vector<TestCase> const & functions)43 void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { 44 std::set<TestCase> seenFunctions; 45 for( auto const& function : functions ) { 46 auto prev = seenFunctions.insert( function ); 47 CATCH_ENFORCE( prev.second, 48 "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" 49 << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" 50 << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); 51 } 52 } 53 filterTests(std::vector<TestCase> const & testCases,TestSpec const & testSpec,IConfig const & config)54 std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { 55 std::vector<TestCase> filtered; 56 filtered.reserve( testCases.size() ); 57 for (auto const& testCase : testCases) { 58 if ((!testSpec.hasFilters() && !testCase.isHidden()) || 59 (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { 60 filtered.push_back(testCase); 61 } 62 } 63 return filtered; 64 } getAllTestCasesSorted(IConfig const & config)65 std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { 66 return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); 67 } 68 registerTest(TestCase const & testCase)69 void TestRegistry::registerTest( TestCase const& testCase ) { 70 std::string name = testCase.getTestCaseInfo().name; 71 if( name.empty() ) { 72 ReusableStringStream rss; 73 rss << "Anonymous test case " << ++m_unnamedCount; 74 return registerTest( testCase.withName( rss.str() ) ); 75 } 76 m_functions.push_back( testCase ); 77 } 78 getAllTests() const79 std::vector<TestCase> const& TestRegistry::getAllTests() const { 80 return m_functions; 81 } getAllTestsSorted(IConfig const & config) const82 std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { 83 if( m_sortedFunctions.empty() ) 84 enforceNoDuplicateTestCases( m_functions ); 85 86 if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { 87 m_sortedFunctions = sortTests( config, m_functions ); 88 m_currentSortOrder = config.runOrder(); 89 } 90 return m_sortedFunctions; 91 } 92 93 94 95 /////////////////////////////////////////////////////////////////////////// TestInvokerAsFunction(void (* testAsFunction)())96 TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} 97 invoke() const98 void TestInvokerAsFunction::invoke() const { 99 m_testAsFunction(); 100 } 101 extractClassName(StringRef const & classOrQualifiedMethodName)102 std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { 103 std::string className = classOrQualifiedMethodName; 104 if( startsWith( className, '&' ) ) 105 { 106 std::size_t lastColons = className.rfind( "::" ); 107 std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); 108 if( penultimateColons == std::string::npos ) 109 penultimateColons = 1; 110 className = className.substr( penultimateColons, lastColons-penultimateColons ); 111 } 112 return className; 113 } 114 115 } // end namespace Catch 116