diff --git a/src/test/GUI/test_harness_gui.cpp b/src/test/GUI/test_harness_gui.cpp index 3c3c6f2f5..3ff5ef555 100644 --- a/src/test/GUI/test_harness_gui.cpp +++ b/src/test/GUI/test_harness_gui.cpp @@ -1,2 +1,239 @@ -#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#define CATCH_CONFIG_RUNNER #include +#include "wx/wx.h" + +#include "wx/apptrait.h" +#include "testableframe.h" + +#undef wxUSE_GUI +#define wxUSE_GUI 1 +#undef wxUSE_LOG +#define wxUSE_LOG 0 + +typedef int (*FilterEventFunc)(wxEvent&); +typedef bool (*ProcessEventFunc)(wxEvent&); + +typedef wxApp TestAppBase; +typedef wxGUIAppTraits TestAppTraitsBase; +using namespace std; + +// The application class +// +class TestApp : public TestAppBase +{ +public: + TestApp(); + + // standard overrides + virtual bool OnInit(); + virtual int OnExit(); + +#ifdef __WIN32__ + virtual wxAppTraits *CreateTraits() + { + // Define a new class just to customize CanUseStderr() behaviour. + class TestAppTraits : public TestAppTraitsBase + { + public: + // We want to always use stderr, tests are also run unattended and + // in this case we really don't want to show any message boxes, as + // wxMessageOutputBest, used e.g. from the default implementation + // of wxApp::OnUnhandledException(), would do by default. + virtual bool CanUseStderr() { return true; } + + // Overriding CanUseStderr() is not enough, we also need to + // override this one to avoid returning false from it. + virtual bool WriteToStderr(const wxString& text) + { + wxFputs(text, stderr); + fflush(stderr); + + // Intentionally ignore any errors, we really don't want to + // show any message boxes in any case. + return true; + } + }; + + return new TestAppTraits; + } +#endif // __WIN32__ + + // Also override this method to avoid showing any dialogs from here -- and + // show some details about the exception along the way. + virtual bool OnExceptionInMainLoop() + { + wxFprintf(stderr, "Unhandled exception in the main loop: %s\n", + Catch::translateActiveException()); + + throw; + } + + // used by events propagation test + virtual int FilterEvent(wxEvent& event); + virtual bool ProcessEvent(wxEvent& event); + + 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(); + } + + virtual int OnRun() + { + if ( TestAppBase::OnRun() != 0 ) + m_exitcode = EXIT_FAILURE; + + return m_exitcode; + } +#else // !wxUSE_GUI + virtual int OnRun() + { + return RunTests(); + } +#endif // wxUSE_GUI/!wxUSE_GUI + +private: + int RunTests(); + + // flag telling us whether we should run tests from our EVT_IDLE handler + bool m_runTests; + + // event handling hooks + FilterEventFunc m_filterEventFunc; + ProcessEventFunc m_processEventFunc; + +#if wxUSE_GUI + // the program exit code + int m_exitcode; +#endif // wxUSE_GUI +}; + +wxIMPLEMENT_APP_NO_MAIN(TestApp); + +// ---------------------------------------------------------------------------- +// TestApp +// ---------------------------------------------------------------------------- + +TestApp::TestApp() +{ + m_runTests = true; + + m_filterEventFunc = NULL; + m_processEventFunc = NULL; + +#if wxUSE_GUI + m_exitcode = EXIT_SUCCESS; +#endif // wxUSE_GUI +} + +// Init +// +bool TestApp::OnInit() +{ + // Hack: don't call TestAppBase::OnInit() to let CATCH handle command line. + + // Output some important information about the test environment. +#if wxUSE_GUI + cout << "Test program for wxWidgets GUI features\n" +#else + cout << "Test program for wxWidgets non-GUI features\n" +#endif + << "build: " << WX_BUILD_OPTIONS_SIGNATURE << "\n" + << "running under " << wxGetOsDescription() + << " as " << wxGetUserId() + << ", locale is " << setlocale(LC_ALL, NULL) + << std::endl; + +#if wxUSE_GUI + // create a parent window to be used as parent for the GUI controls + new wxTestableFrame(); + + Connect(wxEVT_IDLE, wxIdleEventHandler(TestApp::OnIdle)); + +#ifdef GDK_WINDOWING_X11 + XSetErrorHandler(wxTestX11ErrorHandler); +#endif // GDK_WINDOWING_X11 + +#endif // wxUSE_GUI + + return true; +} + +// Event handling +int TestApp::FilterEvent(wxEvent& event) +{ + if ( m_filterEventFunc ) + return (*m_filterEventFunc)(event); + + return TestAppBase::FilterEvent(event); +} + +bool TestApp::ProcessEvent(wxEvent& event) +{ + if ( m_processEventFunc ) + return (*m_processEventFunc)(event); + + return TestAppBase::ProcessEvent(event); +} + +// Run +// +int TestApp::RunTests() +{ +#if wxUSE_LOG + // Switch off logging unless --verbose + bool verbose = wxLog::GetVerbose(); + wxLog::EnableLogging(verbose); +#else + bool verbose = false; +#endif + + // Cast is needed under MSW where Catch also provides an overload taking + // wchar_t, but as it simply converts arguments to char internally anyhow, + // we can just as well always use the char version. + return Catch::Session().run(argc, static_cast(argv)); +} + +int TestApp::OnExit() +{ +#if wxUSE_GUI + delete GetTopWindow(); +#endif // wxUSE_GUI + + return TestAppBase::OnExit(); +} + +int main(int argc, char **argv) +{ + return wxEntry(argc, argv); +}