text: /////////////////////////////////////////////////////////////////////////////
  // Name:        wx/catch_cppunit.h
  // Purpose:     Reimplementation of CppUnit macros in terms of CATCH
  // Author:      Vadim Zeitlin
  // Created:     2017-10-30
  // Copyright:   (c) 2017 Vadim Zeitlin <vadim@wxwidgets.org>
  /////////////////////////////////////////////////////////////////////////////
  
  #ifndef _WX_CATCH_CPPUNIT_H_
  #define _WX_CATCH_CPPUNIT_H_
  
  #include "catch.hpp"
  
  // CppUnit-compatible macros.
  
  // CPPUNIT_ASSERTs are mapped to REQUIRE(), not CHECK(), as this is how CppUnit
  // works but in many cases they really should be CHECK()s instead, i.e. the
  // test should continue to run even if one assert failed. Unfortunately there
  // is no automatic way to know it, so the existing code will need to be
  // reviewed and CHECK() used explicitly where appropriate.
  //
  // Also notice that we don't use parentheses around x and y macro arguments in
  // the macro expansion, as usual. This is because these parentheses would then
  // appear in CATCH error messages if the assertion fails, making them much less
  // readable and omitting should be fine here, exceptionally, as the arguments
  // of these macros are usually just simple expressions.
  #define CPPUNIT_ASSERT(cond) REQUIRE(cond)
  #define CPPUNIT_ASSERT_EQUAL(x, y) REQUIRE(x == y)
  
  // Using INFO() disallows putting more than one of these macros on the same
  // line but this can happen if they're used inside another macro, so wrap it
  // inside a scope.
  #define CPPUNIT_ASSERT_MESSAGE(msg, cond) \
      do { INFO(msg); REQUIRE(cond); } while (Catch::alwaysFalse())
  
  #define CPPUNIT_ASSERT_EQUAL_MESSAGE(msg, x, y) \
      do { INFO(msg); REQUIRE(x == y); } while (Catch::alwaysFalse())
  
  // CATCH Approx class uses the upper bound of "epsilon*(scale + max(|x|, |y|))"
  // for |x - y| which is not really compatible with our fixed delta, so we can't
  // use it here.
  #define CPPUNIT_ASSERT_DOUBLES_EQUAL(x, y, delta) \
      REQUIRE(std::abs(x - y) < delta)
  
  #define CPPUNIT_FAIL(msg) FAIL(msg)
  
  #define CPPUNIT_ASSERT_THROW(expr, exception)         \
      try                                               \
      {                                                 \
          expr;                                         \
          FAIL("Expected exception of type " #exception \
                     " not thrown by " #expr);          \
      }                                                 \
      catch ( exception& ) {}
  
  // Define conversions to strings for some common wxWidgets types.
  namespace Catch
  {
      template <>
      struct StringMaker<wxUniChar>
      {
          static std::string convert(wxUniChar uc)
          {
              return wxString(uc).ToStdString(wxConvUTF8);
          }
      };
  
      template <>
      struct StringMaker<wxUniCharRef>
      {
          static std::string convert(wxUniCharRef ucr)
          {
              return wxString(ucr).ToStdString(wxConvUTF8);
          }
      };
  
      // While this conversion already works due to the existence of the stream
      // insertion operator for wxString, define a custom one making it more
      // obvious when strings containing non-printable characters differ.
      template <>
      struct StringMaker<wxString>
      {
          static std::string convert(const wxString& wxs)
          {
              std::string s;
              s.reserve(wxs.length());
              for ( wxString::const_iterator i = wxs.begin();
                    i != wxs.end();
                    ++i )
              {
  #if wxUSE_UNICODE
                  if ( !iswprint(*i) )
                      s += wxString::Format("\\u%04X", *i).ToStdString();
                  else
  #endif // wxUSE_UNICODE
                      s += *i;
              }
  
              return s;
          }
      };
  }
  
  // Use a different namespace for our mock ups of the real declarations in
  // CppUnit namespace to avoid clashes if we end up being linked with the real
  // CppUnit library, but bring it into scope with a using directive below to
  // make it possible to compile the original code using CppUnit unmodified.
  namespace CatchCppUnit
  {
  
  namespace CppUnit
  {
  
  // These classes don't really correspond to the real CppUnit ones, but contain
  // just the minimum we need to make CPPUNIT_TEST() macro and our mock up of
  // TestSuite class work.
  
  class Test
  {
  public:
      // Name argument exists only for compatibility with the real CppUnit but is
      // not used here.
      explicit Test(const std::string& name = std::string()) : m_name(name) { }
  
      virtual ~Test() { }
  
      virtual void runTest() = 0;
  
      const std::string& getName() const { return m_name; }
  
  private:
      std::string m_name;
  };
  
  class TestCase : public Test
  {
  public:
      explicit TestCase(const std::string& name = std::string()) : Test(name) { }
  
      virtual void setUp() {}
      virtual void tearDown() {}
  };
  
  class TestSuite : public Test
  {
  public:
      explicit TestSuite(const std::string& name = std::string()) : Test(name) { }
  
      ~TestSuite()
      {
          for ( size_t n = 0; n < m_tests.size(); ++n )
          {
              delete m_tests[n];
          }
      }
  
      void addTest(Test* test) { m_tests.push_back(test); }
      size_t getChildTestCount() const { return m_tests.size(); }
  
      void runTest() wxOVERRIDE
      {
          for ( size_t n = 0; n < m_tests.size(); ++n )
          {
              m_tests[n]->runTest();
          }
      }
  
  private:
      std::vector<Test*> m_tests;
  
      wxDECLARE_NO_COPY_CLASS(TestSuite);
  };
  
  } // namespace CppUnit
  
  } // namespace CatchCppUnit
  
  using namespace CatchCppUnit;
  
  // Helpers used in the implementation of the macros below.
  namespace wxPrivate
  {
  
  // An object which resets a string to its old value when going out of scope.
  class TempStringAssign
  {
  public:
      explicit TempStringAssign(std::string& str, const char* value)
          : m_str(str),
            m_orig(str)
      {
          str = value;
      }
  
      ~TempStringAssign()
      {
          m_str = m_orig;
      }
  
  private:
      std::string& m_str;
      const std::string m_orig;
  
      wxDECLARE_NO_COPY_CLASS(TempStringAssign);
  };
  
  // These two strings are used to implement wxGetCurrentTestName() and must be
  // defined in the test driver.
  extern std::string wxTheCurrentTestClass, wxTheCurrentTestMethod;
  
  } // namespace wxPrivate
  
  inline std::string wxGetCurrentTestName()
  {
      std::string s = wxPrivate::wxTheCurrentTestClass;
      if ( !s.empty() && !wxPrivate::wxTheCurrentTestMethod.empty() )
          s += "::";
      s += wxPrivate::wxTheCurrentTestMethod;
  
      return s;
  }
  
  // Notice that the use of this macro unconditionally changes the protection for
  // everything that follows it to "public". This is necessary to allow taking
  // the address of the runTest() method in CPPUNIT_TEST_SUITE_REGISTRATION()
  // below and there just doesn't seem to be any way around it.
  #define CPPUNIT_TEST_SUITE(testclass)   \
      public:                             \
      void runTest() wxOVERRIDE           \
      {                                   \
          using namespace wxPrivate;      \
          TempStringAssign setClass(wxTheCurrentTestClass, #testclass)
  
  #define CPPUNIT_TEST(testname)                                             \
          SECTION(#testname)                                                 \
          {                                                                  \
              TempStringAssign setMethod(wxTheCurrentTestMethod, #testname); \
              setUp();                                                       \
              try                                                            \
              {                                                              \
                  testname();                                                \
              }                                                              \
              catch ( ... )                                                  \
              {                                                              \
                  tearDown();                                                \
                  throw;                                                     \
              }                                                              \
              tearDown();                                                    \
          }
  
  #define CPPUNIT_TEST_SUITE_END()        \
      }                                   \
      struct EatNextSemicolon
  
  #define wxREGISTER_UNIT_TEST_WITH_TAGS(testclass, tags)       \
      METHOD_AS_TEST_CASE(testclass::runTest, #testclass, tags) \
      struct EatNextSemicolon
  
  #define CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(testclass, suitename) \
      wxREGISTER_UNIT_TEST_WITH_TAGS(testclass, "[" suitename "]")
  
  // Existings tests always use both this macro and the named registration one
  // above, but we can't register the same test case twice with CATCH, so simply
  // ignore this one.
  #define CPPUNIT_TEST_SUITE_REGISTRATION(testclass) \
      struct EatNextSemicolon
  
  // ----------------------------------------------------------------------------
  // wxWidgets-specific macros
  // ----------------------------------------------------------------------------
  
  // Convenient variant of INFO() which uses wxString::Format() internally.
  #define wxINFO_FMT_HELPER(fmt, ...) \
      wxString::Format(fmt, __VA_ARGS__).ToStdString(wxConvUTF8)
  
  #define wxINFO_FMT(...) INFO(wxINFO_FMT_HELPER(__VA_ARGS__))
  
  // Use this macro to assert with the given formatted message (it should contain
  // the format string and arguments in a separate pair of parentheses)
  #define WX_ASSERT_MESSAGE(msg, cond) \
      CPPUNIT_ASSERT_MESSAGE(std::string(wxString::Format msg .mb_str()), (cond))
  
  #define WX_ASSERT_EQUAL_MESSAGE(msg, expected, actual) \
      CPPUNIT_ASSERT_EQUAL_MESSAGE(std::string(wxString::Format msg .mb_str()), \
                                   (expected), (actual))
  
  #endif // _WX_CATCH_CPPUNIT_H_
  