X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/de830910772f149c6b6cc0878b239dd19df3d309..62795f413a7222863b4aee76c08764071f94bd87:/tests/test.cpp diff --git a/tests/test.cpp b/tests/test.cpp index eeefa10849..96a64d0afd 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -2,9 +2,8 @@ // Name: test.cpp // Purpose: Test program for wxWidgets // Author: Mike Wetherell -// RCS-ID: $Id$ // Copyright: (c) 2004 Mike Wetherell -// Licence: wxWidgets licence +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ---------------------------------------------------------------------------- @@ -34,6 +33,7 @@ #include #include #include +#include #ifdef __VISUALC__ #pragma warning(default:4100) @@ -41,9 +41,10 @@ #include "wx/afterstd.h" #include "wx/cmdline.h" +#include #include -#ifdef __WXMSW__ +#ifdef __WINDOWS__ #include "wx/msw/msvcrt.h" #endif @@ -51,7 +52,12 @@ #include "wx/osx/private.h" #endif +#if wxUSE_GUI + #include "testableframe.h" +#endif + #include "wx/socket.h" +#include "wx/evtloop.h" using namespace std; @@ -78,6 +84,76 @@ struct CrtAssertFailure #endif // wxUSE_VC_CRTDBG +#if wxDEBUG_LEVEL + +// Information about the last not yet handled assertion. +static wxString s_lastAssertMessage; + +static wxString FormatAssertMessage(const wxString& file, + int line, + const wxString& func, + const wxString& cond, + const wxString& msg) +{ + wxString str; + str << "wxWidgets assert: " << cond << " failed " + "at " << file << ":" << line << " in " << func + << " with message '" << msg << "'"; + return str; +} + +static void TestAssertHandler(const wxString& file, + int line, + const wxString& func, + const wxString& cond, + const wxString& msg) +{ + // Determine whether we can safely throw an exception to just make the test + // fail or whether we need to abort (in this case "msg" will contain the + // explanation why did we decide to do it). + wxString abortReason; + + const wxString + assertMessage = FormatAssertMessage(file, line, func, cond, msg); + + if ( !wxIsMainThread() ) + { + // Exceptions thrown from worker threads are not caught currently and + // so we'd just die without any useful information -- abort instead. + abortReason << assertMessage << "in a worker thread."; + } + else if ( uncaught_exception() ) + { + // Throwing while already handling an exception would result in + // terminate() being called and we wouldn't get any useful information + // about why the test failed then. + if ( s_lastAssertMessage.empty() ) + { + abortReason << assertMessage << "while handling an exception"; + } + else // In this case the exception is due to a previous assert. + { + abortReason << s_lastAssertMessage << "\n and another " + << assertMessage << " while handling it."; + } + } + else // Can "safely" throw from here. + { + // Remember this in case another assert happens while handling this + // exception: we want to show the original assert as it's usually more + // useful to determine the real root of the problem. + s_lastAssertMessage = assertMessage; + + throw TestAssertFailure(file, line, func, cond, msg); + } + + wxFputs(abortReason, stderr); + fflush(stderr); + _exit(-1); +} + +#endif // wxDEBUG_LEVEL + // this function should only be called from a catch clause static string GetExceptionMessage() { @@ -88,11 +164,10 @@ static string GetExceptionMessage() throw; } #if wxDEBUG_LEVEL - catch ( TestAssertFailure& e ) + catch ( TestAssertFailure& ) { - msg << "wxWidgets assert: " << e.m_cond << " failed " - "at " << e.m_file << ":" << e.m_line << " in " << e.m_func - << " with message '" << e.m_msg << "'"; + msg = s_lastAssertMessage; + s_lastAssertMessage.clear(); } #endif // wxDEBUG_LEVEL #ifdef wxUSE_VC_CRTDBG @@ -155,7 +230,7 @@ public: virtual void startTest(CppUnit::Test *test) { - wxPrintf(" %-60s ", test->getName()); + printf(" %-60s ", test->getName().c_str()); m_result = RESULT_OK; m_watch.Start(); } @@ -168,10 +243,10 @@ public: virtual void endTest(CppUnit::Test * WXUNUSED(test)) { m_watch.Pause(); - wxPrintf(GetResultStr(m_result)); + printf("%s", GetResultStr(m_result)); if (m_timing) - wxPrintf(" %6d ms", m_watch.Time()); - wxPrintf("\n"); + printf(" %6ld ms", m_watch.Time()); + printf("\n"); } protected : @@ -183,7 +258,7 @@ protected : RESULT_MAX }; - wxString GetResultStr(ResultType type) const + const char* GetResultStr(ResultType type) const { static const char *resultTypeNames[] = { @@ -220,7 +295,6 @@ public: virtual void OnInitCmdLine(wxCmdLineParser& parser); virtual bool OnCmdLineParsed(wxCmdLineParser& parser); virtual bool OnInit(); - virtual int OnRun(); virtual int OnExit(); // used by events propagation test @@ -230,6 +304,46 @@ public: void SetFilterEventFunc(FilterEventFunc f) { m_filterEventFunc = f; } void SetProcessEventFunc(ProcessEventFunc f) { m_processEventFunc = f; } + // In console applications we run the tests directly from the overridden + // OnRun(), but in the GUI ones we run them when we get the first call to + // our EVT_IDLE handler to ensure that we do everything from inside the + // main event loop. This is especially important under wxOSX/Cocoa where + // the main event loop is different from the others but it's also safer to + // do it like this in the other ports as we test the GUI code in the same + // context as it's used usually, in normal programs, and it might behave + // differently without the event loop. +#if wxUSE_GUI + void OnIdle(wxIdleEvent& event) + { + if ( m_runTests ) + { + m_runTests = false; + +#ifdef __WXOSX__ + // we need to wait until the window is activated and fully ready + // otherwise no events can be posted + wxEventLoopBase* const loop = wxEventLoop::GetActive(); + if ( loop ) + { + loop->DispatchTimeout(1000); + loop->Yield(); + } +#endif // __WXOSX__ + + m_exitcode = RunTests(); + ExitMainLoop(); + } + + event.Skip(); + } +#else // !wxUSE_GUI + virtual int OnRun() + { + m_exitcode = RunTests(); + return m_exitcode; + } +#endif // wxUSE_GUI/!wxUSE_GUI + private: void List(Test *test, const string& parent = "") const; @@ -242,6 +356,11 @@ private: runner.addTest(test); } + int RunTests(); + + // flag telling us whether we should run tests from our EVT_IDLE handler + bool m_runTests; + // command lines options/parameters bool m_list; bool m_longlist; @@ -253,6 +372,9 @@ private: // event handling hooks FilterEventFunc m_filterEventFunc; ProcessEventFunc m_processEventFunc; + + // the program exit code + int m_exitcode; }; IMPLEMENT_APP_NO_MAIN(TestApp) @@ -274,19 +396,6 @@ static int TestCrtReportHook(int reportType, char *message, int *) #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 @@ -346,7 +455,26 @@ extern bool IsNetworkAvailable() return online; } -// helper of OnRun(): gets the test with the given name, returning NULL (and +extern bool IsAutomaticTest() +{ + static int s_isAutomatic = -1; + if ( s_isAutomatic == -1 ) + { + // Allow setting an environment variable to emulate buildslave user for + // testing. + wxString username; + if ( !wxGetEnv("WX_TEST_USER", &username) ) + username = wxGetUserId(); + + username.MakeLower(); + s_isAutomatic = username.Matches("buildslave*") || + username.Matches("sandbox*"); + } + + return s_isAutomatic == 1; +} + +// helper of RunTests(): gets the test with the given name, returning NULL (and // not an empty test suite) if there is no such test static Test *GetTestByName(const wxString& name) { @@ -375,10 +503,14 @@ TestApp::TestApp() : m_list(false), m_longlist(false) { + m_runTests = true; + m_filterEventFunc = NULL; m_processEventFunc = NULL; m_locale = NULL; + + m_exitcode = EXIT_SUCCESS; } // Init @@ -393,11 +525,23 @@ bool TestApp::OnInit() #else cout << "Test program for wxWidgets non-GUI features\n" #endif - << "build: " << WX_BUILD_OPTIONS_SIGNATURE << std::endl; + << "build: " << WX_BUILD_OPTIONS_SIGNATURE << "\n" + << "running under " << wxGetOsDescription() + << " as " << wxGetUserId() << std::endl; + + if ( m_detail ) + { + // Output some important information about the test environment. + cout << "Running under " << wxGetOsDescription() << ", " + "locale is " << setlocale(LC_ALL, NULL) << std::endl; + } #if wxUSE_GUI // create a hidden parent window to be used as parent for the GUI controls - new wxFrame(NULL, wxID_ANY, "Hidden wx test frame"); + wxTestableFrame* frame = new wxTestableFrame(); + frame->Show(); + + Connect(wxEVT_IDLE, wxIdleEventHandler(TestApp::OnIdle)); #endif // wxUSE_GUI return true; @@ -420,7 +564,7 @@ void TestApp::OnInitCmdLine(wxCmdLineParser& parser) "print the test case names, run them", wxCMD_LINE_VAL_NONE, 0 }, { wxCMD_LINE_SWITCH, "t", "timing", - "print names and mesure running time of individual test, run them", + "print names and measure running time of individual test, run them", wxCMD_LINE_VAL_NONE, 0 }, { wxCMD_LINE_OPTION, "", "locale", "locale to use when running the program", @@ -488,15 +632,8 @@ bool TestApp::ProcessEvent(wxEvent& event) // Run // -int TestApp::OnRun() +int TestApp::RunTests() { -#if wxUSE_GUI -#ifdef __WXOSX__ - // make sure there's always an autorelease pool ready - wxMacAutoreleasePool autoreleasepool; -#endif -#endif - #if wxUSE_LOG // Switch off logging unless --verbose bool verbose = wxLog::GetVerbose(); @@ -509,8 +646,17 @@ int TestApp::OnRun() if ( m_registries.empty() ) { - // run or list all tests + // run or list all tests which use the CPPUNIT_TEST_SUITE_REGISTRATION() macro + // (i.e. those registered in the "All tests" registry); if there are other + // tests not registered with the CPPUNIT_TEST_SUITE_REGISTRATION() macro + // then they won't be listed/run! AddTest(runner, TestFactoryRegistry::getRegistry().makeTest()); + + if (m_list) + { + cout << "\nNote that the list above is not complete as it doesn't include the \n"; + cout << "tests disabled by default.\n"; + } } else // run only the selected tests { @@ -556,7 +702,9 @@ int TestApp::OnRun() runner.eventManager().pushProtector(new wxUnitTestProtector); bool printProgress = !(verbose || m_detail || m_timing); - return runner.run("", false, true, printProgress) ? EXIT_SUCCESS : EXIT_FAILURE; + runner.run("", false, true, printProgress); + + return runner.result().testFailures() == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } int TestApp::OnExit() @@ -567,7 +715,7 @@ int TestApp::OnExit() delete GetTopWindow(); #endif // wxUSE_GUI - return 0; + return m_exitcode; } // List the tests