]> git.saurik.com Git - wxWidgets.git/commitdiff
trap CRT assertions and report assertions which happen inside CppUnit tests in a...
authorVadim Zeitlin <vadim@wxwidgets.org>
Wed, 25 Mar 2009 10:42:11 +0000 (10:42 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Wed, 25 Mar 2009 10:42:11 +0000 (10:42 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59838 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

tests/test.cpp
tests/testprec.h

index 1701ad36f593d3fceb350681bbfea443f3f5a2a2..fe22ad10cd28aa633423b69c6e87650de45b2375 100644 (file)
@@ -28,6 +28,7 @@
 #ifdef __VISUALC__
     #pragma warning(default:4100)
 #endif
+#include <cppunit/Protector.h>
 #include <cppunit/Test.h>
 #include <cppunit/TestResult.h>
 #include "wx/afterstd.h"
 #include "wx/cmdline.h"
 #include <iostream>
 
+#ifdef __WXMSW__
+    #include "wx/msw/msvcrt.h"
+#endif
+
+using namespace std;
+
 using CppUnit::Test;
 using CppUnit::TestSuite;
 using CppUnit::TestFactoryRegistry;
 
+// exception class for MSVC debug CRT assertion failures
+#ifdef wxUSE_VC_CRTDBG
+
+struct CrtAssertFailure
+{
+    CrtAssertFailure(const char *message) : m_msg(message) { }
+
+    const wxString m_msg;
+
+    wxDECLARE_NO_ASSIGN_CLASS(CrtAssertFailure);
+};
+
+#endif // wxUSE_VC_CRTDBG
+
+// this function should only be called from a catch clause
+static string GetExceptionMessage()
+{
+    wxString msg;
+
+    try
+    {
+        throw;
+    }
+#if wxDEBUG_LEVEL
+    catch ( TestAssertFailure& e )
+    {
+        msg << "wxWidgets assert: " << e.m_cond << " failed "
+               "at " << e.m_file << ":" << e.m_line << " in " << e.m_func
+            << " with message " << e.m_msg;
+    }
+#endif // wxDEBUG_LEVEL
+#ifdef wxUSE_VC_CRTDBG
+    catch ( CrtAssertFailure& e )
+    {
+        msg << "CRT assert failure: " << e.m_msg;
+    }
+#endif // wxUSE_VC_CRTDBG
+    catch ( std::exception& e )
+    {
+        msg << "std::exception: " << e.what();
+    }
+    catch ( ... )
+    {
+        msg = "Unknown exception caught.";
+    }
+
+    return string(msg.mb_str());
+}
+
+// Protector adding handling of wx-specific (this includes MSVC debug CRT in
+// this context) exceptions
+class wxUnitTestProtector : public CppUnit::Protector
+{
+public:
+    virtual bool protect(const CppUnit::Functor &functor,
+                         const CppUnit::ProtectorContext& context)
+    {
+        try
+        {
+            return functor();
+        }
+        catch ( ... )
+        {
+            reportError(context, CppUnit::Message("Uncaught exception",
+                                                  GetExceptionMessage()));
+        }
+
+        return false;
+    }
+};
 
 // Displays the test name before starting to execute it: this helps with
 // diagnosing where exactly does a test crash or hang when/if it does.
@@ -70,8 +147,6 @@ protected :
     wxStopWatch m_watch;
 };
 
-using namespace std;
-
 #if wxUSE_GUI
     typedef wxApp TestAppBase;
 #else
@@ -99,17 +174,6 @@ public:
     void SetFilterEventFunc(FilterEventFunc f) { m_filterEventFunc = f; }
     void SetProcessEventFunc(ProcessEventFunc f) { m_processEventFunc = f; }
 
-#ifdef __WXDEBUG__
-    virtual void OnAssertFailure(const wxChar *,
-                                 int,
-                                 const wxChar *,
-                                 const wxChar *,
-                                 const wxChar *)
-    {
-        throw TestAssertFailure();
-    }
-#endif // __WXDEBUG__
-
 private:
     void List(Test *test, const string& parent = "") const;
 
@@ -125,7 +189,58 @@ private:
     ProcessEventFunc m_processEventFunc;
 };
 
-IMPLEMENT_APP_CONSOLE(TestApp)
+IMPLEMENT_APP_NO_MAIN(TestApp)
+
+#ifdef wxUSE_VC_CRTDBG
+
+static int TestCrtReportHook(int reportType, char *message, int *)
+{
+    if ( reportType != _CRT_ASSERT )
+        return FALSE;
+
+    throw CrtAssertFailure(message);
+}
+
+#endif // wxUSE_VC_CRTDBG
+
+#if wxDEBUG_LEVEL
+
+static void TestAssertHandler(const wxString& file,
+                              int line,
+                              const wxString& func,
+                              const wxString& cond,
+                              const wxString& msg)
+{
+    throw TestAssertFailure(file, line, func, cond, msg);
+}
+
+#endif // wxDEBUG_LEVEL
+
+int main(int argc, char **argv)
+{
+    // tests can be ran non-interactively so make sure we don't show any assert
+    // dialog boxes -- neither our own nor from MSVC debug CRT -- which would
+    // prevent them from completing
+
+#if wxDEBUG_LEVEL
+    wxSetAssertHandler(TestAssertHandler);
+#endif // wxDEBUG_LEVEL
+
+#ifdef wxUSE_VC_CRTDBG
+    _CrtSetReportHook(TestCrtReportHook);
+#endif // wxUSE_VC_CRTDBG
+
+    try
+    {
+        return wxEntry(argc, argv);
+    }
+    catch ( ... )
+    {
+        cerr << "\n" << GetExceptionMessage() << endl;
+    }
+
+    return -1;
+}
 
 TestApp::TestApp()
   : m_list(false),
@@ -278,6 +393,10 @@ int TestApp::OnRun()
     if ( m_detail || m_timing )
         runner.eventManager().addListener(&detailListener);
 
+    // finally ensure that we report our own exceptions nicely instead of
+    // giving "uncaught exception of unknown type" messages
+    runner.eventManager().pushProtector(new wxUnitTestProtector);
+
     return runner.run("", false, true, !verbose) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
index 901a7455750a170858ad007f423bc82a7e30dbae..923d45fc06ce02eb4221bbf0fab04ea8e9682da9 100644 (file)
@@ -8,7 +8,30 @@
 #endif
 
 // thrown when assert fails in debug build
-class TestAssertFailure { };
+class TestAssertFailure
+{
+public:
+    TestAssertFailure(const wxString& file,
+                      int line,
+                      const wxString& func,
+                      const wxString& cond,
+                      const wxString& msg)
+        : m_file(file),
+          m_line(line),
+          m_func(func),
+          m_cond(cond),
+          m_msg(msg)
+    {
+    }
+
+    const wxString m_file;
+    const int m_line;
+    const wxString m_func;
+    const wxString m_cond;
+    const wxString m_msg;
+
+    wxDECLARE_NO_ASSIGN_CLASS(TestAssertFailure);
+};
 
 // macro to use for the functions which are supposed to fail an assertion
 #if wxDEBUG_LEVEL