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_run_context.h" 15 #include "catch_string_manip.h" 16 #include "catch_test_case_info.h" 17 18 #include <algorithm> 19 #include <sstream> 20 21 namespace Catch { 22 23 namespace { 24 struct TestHasher { TestHasherCatch::__anonee2b127c0111::TestHasher25 explicit TestHasher(Catch::SimplePcg32& rng_instance) { 26 basis = rng_instance(); 27 basis <<= 32; 28 basis |= rng_instance(); 29 } 30 31 uint64_t basis; 32 operator ()Catch::__anonee2b127c0111::TestHasher33 uint64_t operator()(TestCase const& t) const { 34 // Modified FNV-1a hash 35 static constexpr uint64_t prime = 1099511628211; 36 uint64_t hash = basis; 37 for (const char c : t.name) { 38 hash ^= c; 39 hash *= prime; 40 } 41 return hash; 42 } 43 }; 44 } // end unnamed namespace 45 46 sortTests(IConfig const & config,std::vector<TestCase> const & unsortedTestCases)47 std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { 48 switch( config.runOrder() ) { 49 case RunTests::InDeclarationOrder: 50 // already in declaration order 51 break; 52 53 case RunTests::InLexicographicalOrder: { 54 std::vector<TestCase> sorted = unsortedTestCases; 55 std::sort( sorted.begin(), sorted.end() ); 56 return sorted; 57 } 58 59 case RunTests::InRandomOrder: { 60 seedRng( config ); 61 TestHasher h( rng() ); 62 63 using hashedTest = std::pair<uint64_t, TestCase const*>; 64 std::vector<hashedTest> indexed_tests; 65 indexed_tests.reserve( unsortedTestCases.size() ); 66 67 for (auto const& testCase : unsortedTestCases) { 68 indexed_tests.emplace_back(h(testCase), &testCase); 69 } 70 71 std::sort(indexed_tests.begin(), indexed_tests.end(), 72 [](hashedTest const& lhs, hashedTest const& rhs) { 73 if (lhs.first == rhs.first) { 74 return lhs.second->name < rhs.second->name; 75 } 76 return lhs.first < rhs.first; 77 }); 78 79 std::vector<TestCase> sorted; 80 sorted.reserve( indexed_tests.size() ); 81 82 for (auto const& hashed : indexed_tests) { 83 sorted.emplace_back(*hashed.second); 84 } 85 86 return sorted; 87 } 88 } 89 return unsortedTestCases; 90 } 91 isThrowSafe(TestCase const & testCase,IConfig const & config)92 bool isThrowSafe( TestCase const& testCase, IConfig const& config ) { 93 return !testCase.throws() || config.allowThrows(); 94 } 95 matchTest(TestCase const & testCase,TestSpec const & testSpec,IConfig const & config)96 bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { 97 return testSpec.matches( testCase ) && isThrowSafe( testCase, config ); 98 } 99 enforceNoDuplicateTestCases(std::vector<TestCase> const & functions)100 void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { 101 std::set<TestCase> seenFunctions; 102 for( auto const& function : functions ) { 103 auto prev = seenFunctions.insert( function ); 104 CATCH_ENFORCE( prev.second, 105 "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" 106 << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" 107 << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); 108 } 109 } 110 filterTests(std::vector<TestCase> const & testCases,TestSpec const & testSpec,IConfig const & config)111 std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { 112 std::vector<TestCase> filtered; 113 filtered.reserve( testCases.size() ); 114 for (auto const& testCase : testCases) { 115 if ((!testSpec.hasFilters() && !testCase.isHidden()) || 116 (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { 117 filtered.push_back(testCase); 118 } 119 } 120 return filtered; 121 } getAllTestCasesSorted(IConfig const & config)122 std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { 123 return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); 124 } 125 registerTest(TestCase const & testCase)126 void TestRegistry::registerTest( TestCase const& testCase ) { 127 std::string name = testCase.getTestCaseInfo().name; 128 if( name.empty() ) { 129 ReusableStringStream rss; 130 rss << "Anonymous test case " << ++m_unnamedCount; 131 return registerTest( testCase.withName( rss.str() ) ); 132 } 133 m_functions.push_back( testCase ); 134 } 135 getAllTests() const136 std::vector<TestCase> const& TestRegistry::getAllTests() const { 137 return m_functions; 138 } getAllTestsSorted(IConfig const & config) const139 std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { 140 if( m_sortedFunctions.empty() ) 141 enforceNoDuplicateTestCases( m_functions ); 142 143 if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { 144 m_sortedFunctions = sortTests( config, m_functions ); 145 m_currentSortOrder = config.runOrder(); 146 } 147 return m_sortedFunctions; 148 } 149 150 151 152 /////////////////////////////////////////////////////////////////////////// TestInvokerAsFunction(void (* testAsFunction)())153 TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} 154 invoke() const155 void TestInvokerAsFunction::invoke() const { 156 m_testAsFunction(); 157 } 158 extractClassName(StringRef const & classOrQualifiedMethodName)159 std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { 160 std::string className(classOrQualifiedMethodName); 161 if( startsWith( className, '&' ) ) 162 { 163 std::size_t lastColons = className.rfind( "::" ); 164 std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); 165 if( penultimateColons == std::string::npos ) 166 penultimateColons = 1; 167 className = className.substr( penultimateColons, lastColons-penultimateColons ); 168 } 169 return className; 170 } 171 172 } // end namespace Catch 173