From b33e98f0bdeb53e0eaf63cd41de4e219e7d19ff9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 25 Mar 2009 10:42:11 +0000 Subject: [PATCH 1/1] trap CRT assertions and report assertions which happen inside CppUnit tests in a better way git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59838 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- tests/test.cpp | 147 ++++++++++++++++++++++++++++++++++++++++++----- tests/testprec.h | 25 +++++++- 2 files changed, 157 insertions(+), 15 deletions(-) diff --git a/tests/test.cpp b/tests/test.cpp index 1701ad36f5..fe22ad10cd 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -28,6 +28,7 @@ #ifdef __VISUALC__ #pragma warning(default:4100) #endif +#include #include #include #include "wx/afterstd.h" @@ -35,10 +36,86 @@ #include "wx/cmdline.h" #include +#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; } diff --git a/tests/testprec.h b/tests/testprec.h index 901a745575..923d45fc06 100644 --- a/tests/testprec.h +++ b/tests/testprec.h @@ -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 -- 2.45.2