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 <sstream>
19 
20 namespace Catch {
21 
sortTests(IConfig const & config,std::vector<TestCase> const & unsortedTestCases)22     std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
23 
24         std::vector<TestCase> sorted = unsortedTestCases;
25 
26         switch( config.runOrder() ) {
27             case RunTests::InLexicographicalOrder:
28                 std::sort( sorted.begin(), sorted.end() );
29                 break;
30             case RunTests::InRandomOrder:
31                 seedRng( config );
32                 std::shuffle( sorted.begin(), sorted.end(), rng() );
33                 break;
34             case RunTests::InDeclarationOrder:
35                 // already in declaration order
36                 break;
37         }
38         return sorted;
39     }
40 
isThrowSafe(TestCase const & testCase,IConfig const & config)41     bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
42         return !testCase.throws() || config.allowThrows();
43     }
44 
matchTest(TestCase const & testCase,TestSpec const & testSpec,IConfig const & config)45     bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
46         return testSpec.matches( testCase ) && isThrowSafe( testCase, config );
47     }
48 
enforceNoDuplicateTestCases(std::vector<TestCase> const & functions)49     void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
50         std::set<TestCase> seenFunctions;
51         for( auto const& function : functions ) {
52             auto prev = seenFunctions.insert( function );
53             CATCH_ENFORCE( prev.second,
54                     "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n"
55                     << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
56                     << "\tRedefined at " << function.getTestCaseInfo().lineInfo );
57         }
58     }
59 
filterTests(std::vector<TestCase> const & testCases,TestSpec const & testSpec,IConfig const & config)60     std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
61         std::vector<TestCase> filtered;
62         filtered.reserve( testCases.size() );
63         for (auto const& testCase : testCases) {
64             if ((!testSpec.hasFilters() && !testCase.isHidden()) ||
65                 (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
66                 filtered.push_back(testCase);
67             }
68         }
69         return filtered;
70     }
getAllTestCasesSorted(IConfig const & config)71     std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
72         return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
73     }
74 
registerTest(TestCase const & testCase)75     void TestRegistry::registerTest( TestCase const& testCase ) {
76         std::string name = testCase.getTestCaseInfo().name;
77         if( name.empty() ) {
78             ReusableStringStream rss;
79             rss << "Anonymous test case " << ++m_unnamedCount;
80             return registerTest( testCase.withName( rss.str() ) );
81         }
82         m_functions.push_back( testCase );
83     }
84 
getAllTests() const85     std::vector<TestCase> const& TestRegistry::getAllTests() const {
86         return m_functions;
87     }
getAllTestsSorted(IConfig const & config) const88     std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
89         if( m_sortedFunctions.empty() )
90             enforceNoDuplicateTestCases( m_functions );
91 
92         if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
93             m_sortedFunctions = sortTests( config, m_functions );
94             m_currentSortOrder = config.runOrder();
95         }
96         return m_sortedFunctions;
97     }
98 
99 
100 
101     ///////////////////////////////////////////////////////////////////////////
TestInvokerAsFunction(void (* testAsFunction)())102     TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {}
103 
invoke() const104     void TestInvokerAsFunction::invoke() const {
105         m_testAsFunction();
106     }
107 
extractClassName(StringRef const & classOrQualifiedMethodName)108     std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
109         std::string className(classOrQualifiedMethodName);
110         if( startsWith( className, '&' ) )
111         {
112             std::size_t lastColons = className.rfind( "::" );
113             std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
114             if( penultimateColons == std::string::npos )
115                 penultimateColons = 1;
116             className = className.substr( penultimateColons, lastColons-penultimateColons );
117         }
118         return className;
119     }
120 
121 } // end namespace Catch
122