text: /*
   *  Created by Phil on 18/10/2010.
   *  Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
   *
   *  Distributed under the Boost Software License, Version 1.0. (See accompanying
   *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
   */
  #ifndef TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
  #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
  
  #include "catch_common.h"
  #include "catch_interfaces_testcase.h"
  #include "catch_compiler_capabilities.h"
  #include "catch_stringref.h"
  #include "catch_type_traits.hpp"
  #include "catch_preprocessor.hpp"
  
  namespace Catch {
  
  template<typename C>
  class TestInvokerAsMethod : public ITestInvoker {
      void (C::*m_testAsMethod)();
  public:
      TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {}
  
      void invoke() const override {
          C obj;
          (obj.*m_testAsMethod)();
      }
  };
  
  auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*;
  
  template<typename C>
  auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {
      return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod );
  }
  
  struct NameAndTags {
      NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept;
      StringRef name;
      StringRef tags;
  };
  
  struct AutoReg : NonCopyable {
      AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept;
      ~AutoReg();
  };
  
  } // end namespace Catch
  
  #if defined(CATCH_CONFIG_DISABLE)
      #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
          static void TestName()
      #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
          namespace{                        \
              struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
                  void test();              \
              };                            \
          }                                 \
          void TestName::test()
      #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... )  \
          template<typename TestType>                                             \
          static void TestName()
      #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... )    \
          namespace{                                                                                  \
              template<typename TestType>                                                             \
              struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) {     \
                  void test();                                                                        \
              };                                                                                      \
          }                                                                                           \
          template<typename TestType>                                                                 \
          void TestName::test()
  #endif
  
      ///////////////////////////////////////////////////////////////////////////////
      #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
          static void TestName(); \
          CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
          namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
          CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
          static void TestName()
      #define INTERNAL_CATCH_TESTCASE( ... ) \
          INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
  
      ///////////////////////////////////////////////////////////////////////////////
      #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
          CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
          namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
          CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
  
      ///////////////////////////////////////////////////////////////////////////////
      #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
          CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
          namespace{ \
              struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
                  void test(); \
              }; \
              Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
          } \
          CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
          void TestName::test()
      #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
          INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
  
      ///////////////////////////////////////////////////////////////////////////////
      #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
          CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
          Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
          CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
  
      ///////////////////////////////////////////////////////////////////////////////
      #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\
          CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
          template<typename TestType> \
          static void TestFunc();\
          namespace {\
              template<typename...Types> \
              struct TestName{\
                  template<typename...Ts> \
                  TestName(Ts...names){\
                      CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
                      using expander = int[];\
                      (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
                  }\
              };\
              INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \
          }\
          CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
          template<typename TestType> \
          static void TestFunc()
  
  #if defined(CATCH_CPP17_OR_GREATER)
  #define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case");
  #else
  #define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case");
  #endif
  
  #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
      #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
          INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ )
  #else
      #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
          INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
  #endif
  
      #define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\
          static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
              TestName<CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)>(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\
              return 0;\
          }();
  
      #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
          CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
          namespace{ \
              template<typename TestType> \
              struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
                  void test();\
              };\
              template<typename...Types> \
              struct TestNameClass{\
                  template<typename...Ts> \
                  TestNameClass(Ts...names){\
                      CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
                      using expander = int[];\
                      (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
                  }\
              };\
              INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\
          }\
          CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\
          template<typename TestType> \
          void TestName<TestType>::test()
  
  #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
      #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
          INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ )
  #else
      #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
          INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) )
  #endif
  
  #endif // TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
  