catch_test_case_registry_impl.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. #include "catch_test_case_registry_impl.h"
  8. #include "catch_context.h"
  9. #include "catch_enforce.h"
  10. #include "catch_interfaces_registry_hub.h"
  11. #include "catch_random_number_generator.h"
  12. #include "catch_run_context.h"
  13. #include "catch_string_manip.h"
  14. #include "catch_test_case_info.h"
  15. #include <algorithm>
  16. #include <sstream>
  17. namespace Catch {
  18. namespace {
  19. struct TestHasher {
  20. using hash_t = uint64_t;
  21. explicit TestHasher( hash_t hashSuffix ):
  22. m_hashSuffix{ hashSuffix } {}
  23. uint32_t operator()( TestCase const& t ) const {
  24. // FNV-1a hash with multiplication fold.
  25. const hash_t prime = 1099511628211u;
  26. hash_t hash = 14695981039346656037u;
  27. for ( const char c : t.name ) {
  28. hash ^= c;
  29. hash *= prime;
  30. }
  31. hash ^= m_hashSuffix;
  32. hash *= prime;
  33. const uint32_t low{ static_cast<uint32_t>( hash ) };
  34. const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
  35. return low * high;
  36. }
  37. private:
  38. hash_t m_hashSuffix;
  39. };
  40. } // end unnamed namespace
  41. std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
  42. switch( config.runOrder() ) {
  43. case RunTests::InDeclarationOrder:
  44. // already in declaration order
  45. break;
  46. case RunTests::InLexicographicalOrder: {
  47. std::vector<TestCase> sorted = unsortedTestCases;
  48. std::sort( sorted.begin(), sorted.end() );
  49. return sorted;
  50. }
  51. case RunTests::InRandomOrder: {
  52. seedRng( config );
  53. TestHasher h{ config.rngSeed() };
  54. using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>;
  55. std::vector<hashedTest> indexed_tests;
  56. indexed_tests.reserve( unsortedTestCases.size() );
  57. for (auto const& testCase : unsortedTestCases) {
  58. indexed_tests.emplace_back(h(testCase), &testCase);
  59. }
  60. std::sort(indexed_tests.begin(), indexed_tests.end(),
  61. [](hashedTest const& lhs, hashedTest const& rhs) {
  62. if (lhs.first == rhs.first) {
  63. return lhs.second->name < rhs.second->name;
  64. }
  65. return lhs.first < rhs.first;
  66. });
  67. std::vector<TestCase> sorted;
  68. sorted.reserve( indexed_tests.size() );
  69. for (auto const& hashed : indexed_tests) {
  70. sorted.emplace_back(*hashed.second);
  71. }
  72. return sorted;
  73. }
  74. }
  75. return unsortedTestCases;
  76. }
  77. bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
  78. return !testCase.throws() || config.allowThrows();
  79. }
  80. bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
  81. return testSpec.matches( testCase ) && isThrowSafe( testCase, config );
  82. }
  83. void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
  84. std::set<TestCase> seenFunctions;
  85. for( auto const& function : functions ) {
  86. auto prev = seenFunctions.insert( function );
  87. CATCH_ENFORCE( prev.second,
  88. "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n"
  89. << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
  90. << "\tRedefined at " << function.getTestCaseInfo().lineInfo );
  91. }
  92. }
  93. std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
  94. std::vector<TestCase> filtered;
  95. filtered.reserve( testCases.size() );
  96. for (auto const& testCase : testCases) {
  97. if ((!testSpec.hasFilters() && !testCase.isHidden()) ||
  98. (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
  99. filtered.push_back(testCase);
  100. }
  101. }
  102. return filtered;
  103. }
  104. std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
  105. return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
  106. }
  107. void TestRegistry::registerTest( TestCase const& testCase ) {
  108. std::string name = testCase.getTestCaseInfo().name;
  109. if( name.empty() ) {
  110. ReusableStringStream rss;
  111. rss << "Anonymous test case " << ++m_unnamedCount;
  112. return registerTest( testCase.withName( rss.str() ) );
  113. }
  114. m_functions.push_back( testCase );
  115. }
  116. std::vector<TestCase> const& TestRegistry::getAllTests() const {
  117. return m_functions;
  118. }
  119. std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
  120. if( m_sortedFunctions.empty() )
  121. enforceNoDuplicateTestCases( m_functions );
  122. if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
  123. m_sortedFunctions = sortTests( config, m_functions );
  124. m_currentSortOrder = config.runOrder();
  125. }
  126. return m_sortedFunctions;
  127. }
  128. ///////////////////////////////////////////////////////////////////////////
  129. TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {}
  130. void TestInvokerAsFunction::invoke() const {
  131. m_testAsFunction();
  132. }
  133. std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
  134. std::string className(classOrQualifiedMethodName);
  135. if( startsWith( className, '&' ) )
  136. {
  137. std::size_t lastColons = className.rfind( "::" );
  138. std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
  139. if( penultimateColons == std::string::npos )
  140. penultimateColons = 1;
  141. className = className.substr( penultimateColons, lastColons-penultimateColons );
  142. }
  143. return className;
  144. }
  145. } // end namespace Catch