/ externals / catch / src / catch2 / internal / catch_test_case_registry_impl.cpp
catch_test_case_registry_impl.cpp
  1  
  2  //              Copyright Catch2 Authors
  3  // Distributed under the Boost Software License, Version 1.0.
  4  //   (See accompanying file LICENSE.txt or copy at
  5  //        https://www.boost.org/LICENSE_1_0.txt)
  6  
  7  // SPDX-License-Identifier: BSL-1.0
  8  #include <catch2/internal/catch_test_case_registry_impl.hpp>
  9  
 10  #include <catch2/internal/catch_context.hpp>
 11  #include <catch2/internal/catch_enforce.hpp>
 12  #include <catch2/interfaces/catch_interfaces_config.hpp>
 13  #include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
 14  #include <catch2/internal/catch_random_number_generator.hpp>
 15  #include <catch2/internal/catch_run_context.hpp>
 16  #include <catch2/internal/catch_sharding.hpp>
 17  #include <catch2/catch_test_case_info.hpp>
 18  #include <catch2/catch_test_spec.hpp>
 19  #include <catch2/internal/catch_move_and_forward.hpp>
 20  #include <catch2/internal/catch_test_case_info_hasher.hpp>
 21  
 22  #include <algorithm>
 23  #include <set>
 24  
 25  namespace Catch {
 26  
 27      namespace {
 28          static void enforceNoDuplicateTestCases(
 29              std::vector<TestCaseHandle> const& tests ) {
 30              auto testInfoCmp = []( TestCaseInfo const* lhs,
 31                                     TestCaseInfo const* rhs ) {
 32                  return *lhs < *rhs;
 33              };
 34              std::set<TestCaseInfo const*, decltype( testInfoCmp )&> seenTests(
 35                  testInfoCmp );
 36              for ( auto const& test : tests ) {
 37                  const auto infoPtr = &test.getTestCaseInfo();
 38                  const auto prev = seenTests.insert( infoPtr );
 39                  CATCH_ENFORCE( prev.second,
 40                                 "error: test case \""
 41                                     << infoPtr->name << "\", with tags \""
 42                                     << infoPtr->tagsAsString()
 43                                     << "\" already defined.\n"
 44                                     << "\tFirst seen at "
 45                                     << ( *prev.first )->lineInfo << "\n"
 46                                     << "\tRedefined at " << infoPtr->lineInfo );
 47              }
 48          }
 49  
 50          static bool matchTest( TestCaseHandle const& testCase,
 51                                 TestSpec const& testSpec,
 52                                 IConfig const& config ) {
 53              return testSpec.matches( testCase.getTestCaseInfo() ) &&
 54                     isThrowSafe( testCase, config );
 55          }
 56  
 57      } // end unnamed namespace
 58  
 59      std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ) {
 60          switch (config.runOrder()) {
 61          case TestRunOrder::Declared:
 62              return unsortedTestCases;
 63  
 64          case TestRunOrder::LexicographicallySorted: {
 65              std::vector<TestCaseHandle> sorted = unsortedTestCases;
 66              std::sort(
 67                  sorted.begin(),
 68                  sorted.end(),
 69                  []( TestCaseHandle const& lhs, TestCaseHandle const& rhs ) {
 70                      return lhs.getTestCaseInfo() < rhs.getTestCaseInfo();
 71                  }
 72              );
 73              return sorted;
 74          }
 75          case TestRunOrder::Randomized: {
 76              seedRng(config);
 77              using TestWithHash = std::pair<TestCaseInfoHasher::hash_t, TestCaseHandle>;
 78  
 79              TestCaseInfoHasher h{ config.rngSeed() };
 80              std::vector<TestWithHash> indexed_tests;
 81              indexed_tests.reserve(unsortedTestCases.size());
 82  
 83              for (auto const& handle : unsortedTestCases) {
 84                  indexed_tests.emplace_back(h(handle.getTestCaseInfo()), handle);
 85              }
 86  
 87              std::sort( indexed_tests.begin(),
 88                         indexed_tests.end(),
 89                         []( TestWithHash const& lhs, TestWithHash const& rhs ) {
 90                             if ( lhs.first == rhs.first ) {
 91                                 return lhs.second.getTestCaseInfo() <
 92                                        rhs.second.getTestCaseInfo();
 93                             }
 94                             return lhs.first < rhs.first;
 95                         } );
 96  
 97              std::vector<TestCaseHandle> randomized;
 98              randomized.reserve(indexed_tests.size());
 99  
100              for (auto const& indexed : indexed_tests) {
101                  randomized.push_back(indexed.second);
102              }
103  
104              return randomized;
105          }
106          }
107  
108          CATCH_INTERNAL_ERROR("Unknown test order value!");
109      }
110  
111      bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ) {
112          return !testCase.getTestCaseInfo().throws() || config.allowThrows();
113      }
114  
115      std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
116          std::vector<TestCaseHandle> filtered;
117          filtered.reserve( testCases.size() );
118          for (auto const& testCase : testCases) {
119              if ((!testSpec.hasFilters() && !testCase.getTestCaseInfo().isHidden()) ||
120                  (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
121                  filtered.push_back(testCase);
122              }
123          }
124          return createShard(filtered, config.shardCount(), config.shardIndex());
125      }
126      std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config ) {
127          return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
128      }
129  
130      void TestRegistry::registerTest(Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker) {
131          m_handles.emplace_back(testInfo.get(), testInvoker.get());
132          m_viewed_test_infos.push_back(testInfo.get());
133          m_owned_test_infos.push_back(CATCH_MOVE(testInfo));
134          m_invokers.push_back(CATCH_MOVE(testInvoker));
135      }
136  
137      std::vector<TestCaseInfo*> const& TestRegistry::getAllInfos() const {
138          return m_viewed_test_infos;
139      }
140  
141      std::vector<TestCaseHandle> const& TestRegistry::getAllTests() const {
142          return m_handles;
143      }
144      std::vector<TestCaseHandle> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
145          if( m_sortedFunctions.empty() )
146              enforceNoDuplicateTestCases( m_handles );
147  
148          if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
149              m_sortedFunctions = sortTests( config, m_handles );
150              m_currentSortOrder = config.runOrder();
151          }
152          return m_sortedFunctions;
153      }
154  
155  } // end namespace Catch