/ externals / catch / src / catch2 / internal / catch_test_registry.cpp
catch_test_registry.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_registry.hpp>
 9  #include <catch2/internal/catch_compiler_capabilities.hpp>
10  #include <catch2/catch_test_case_info.hpp>
11  #include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
12  #include <catch2/internal/catch_string_manip.hpp>
13  #include <catch2/internal/catch_move_and_forward.hpp>
14  
15  #include <algorithm>
16  #include <iterator>
17  
18  namespace Catch {
19      ITestInvoker::~ITestInvoker() = default;
20  
21      namespace {
22          static StringRef extractClassName( StringRef classOrMethodName ) {
23              if ( !startsWith( classOrMethodName, '&' ) ) {
24                  return classOrMethodName;
25              }
26  
27              // Remove the leading '&' to avoid having to special case it later
28              const auto methodName =
29                  classOrMethodName.substr( 1, classOrMethodName.size() );
30  
31              auto reverseStart = std::make_reverse_iterator( methodName.end() );
32              auto reverseEnd = std::make_reverse_iterator( methodName.begin() );
33  
34              // We make a simplifying assumption that ":" is only present
35              // in the input as part of "::" from C++ typenames (this is
36              // relatively safe assumption because the input is generated
37              // as stringification of type through preprocessor).
38              auto lastColons = std::find( reverseStart, reverseEnd, ':' ) + 1;
39              auto secondLastColons =
40                  std::find( lastColons + 1, reverseEnd, ':' );
41  
42              auto const startIdx = reverseEnd - secondLastColons;
43              auto const classNameSize = secondLastColons - lastColons - 1;
44  
45              return methodName.substr(
46                  static_cast<std::size_t>( startIdx ),
47                  static_cast<std::size_t>( classNameSize ) );
48          }
49  
50          class TestInvokerAsFunction final : public ITestInvoker {
51              using TestType = void ( * )();
52              TestType m_testAsFunction;
53  
54          public:
55              TestInvokerAsFunction( TestType testAsFunction ) noexcept:
56                  m_testAsFunction( testAsFunction ) {}
57  
58              void invoke() const override { m_testAsFunction(); }
59          };
60  
61      } // namespace
62  
63      Detail::unique_ptr<ITestInvoker> makeTestInvoker( void(*testAsFunction)() ) {
64          return Detail::make_unique<TestInvokerAsFunction>( testAsFunction );
65      }
66  
67      AutoReg::AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept {
68          CATCH_TRY {
69              getMutableRegistryHub()
70                      .registerTest(
71                          makeTestCaseInfo(
72                              extractClassName( classOrMethod ),
73                              nameAndTags,
74                              lineInfo),
75                          CATCH_MOVE(invoker)
76                      );
77          } CATCH_CATCH_ALL {
78              // Do not throw when constructing global objects, instead register the exception to be processed later
79              getMutableRegistryHub().registerStartupException();
80          }
81      }
82  }