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 }