1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: Test program for wxWidgets
4 // Author: Mike Wetherell
6 // Copyright: (c) 2004 Mike Wetherell
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 // ----------------------------------------------------------------------------
12 // ----------------------------------------------------------------------------
14 // For compilers that support precompilation, includes "wx/wx.h"
22 // for all others, include the necessary headers
27 #include "wx/beforestd.h"
29 #pragma warning(disable:4100)
32 #include <cppunit/TestListener.h>
33 #include <cppunit/Protector.h>
34 #include <cppunit/Test.h>
35 #include <cppunit/TestResult.h>
36 #include <cppunit/TestFailure.h>
39 #pragma warning(default:4100)
41 #include "wx/afterstd.h"
43 #include "wx/cmdline.h"
48 #include "wx/msw/msvcrt.h"
52 #include "wx/osx/private.h"
56 #include "testableframe.h"
59 #include "wx/socket.h"
60 #include "wx/evtloop.h"
65 using CppUnit::TestSuite
;
66 using CppUnit::TestFactoryRegistry
;
69 // ----------------------------------------------------------------------------
71 // ----------------------------------------------------------------------------
73 // exception class for MSVC debug CRT assertion failures
74 #ifdef wxUSE_VC_CRTDBG
76 struct CrtAssertFailure
78 CrtAssertFailure(const char *message
) : m_msg(message
) { }
82 wxDECLARE_NO_ASSIGN_CLASS(CrtAssertFailure
);
85 #endif // wxUSE_VC_CRTDBG
89 static wxString
FormatAssertMessage(const wxString
& file
,
96 str
<< "wxWidgets assert: " << cond
<< " failed "
97 "at " << file
<< ":" << line
<< " in " << func
98 << " with message '" << msg
<< "'";
102 static void TestAssertHandler(const wxString
& file
,
104 const wxString
& func
,
105 const wxString
& cond
,
108 // Determine whether we can safely throw an exception to just make the test
109 // fail or whether we need to abort (in this case "msg" will contain the
110 // explanation why did we decide to do it).
111 wxString abortReason
;
112 if ( !wxIsMainThread() )
114 // Exceptions thrown from worker threads are not caught currently and
115 // so we'd just die without any useful information -- abort instead.
116 abortReason
= "in a worker thread";
118 else if ( uncaught_exception() )
120 // Throwing while already handling an exception would result in
121 // terminate() being called and we wouldn't get any useful information
122 // about why the test failed then.
123 abortReason
= "while handling an exception";
125 else // Can "safely" throw from here.
127 throw TestAssertFailure(file
, line
, func
, cond
, msg
);
130 wxFprintf(stderr
, "%s %s -- aborting.",
131 FormatAssertMessage(file
, line
, func
, cond
, msg
),
137 #endif // wxDEBUG_LEVEL
139 // this function should only be called from a catch clause
140 static string
GetExceptionMessage()
149 catch ( TestAssertFailure
& e
)
151 msg
<< FormatAssertMessage(e
.m_file
, e
.m_line
, e
.m_func
,
154 #endif // wxDEBUG_LEVEL
155 #ifdef wxUSE_VC_CRTDBG
156 catch ( CrtAssertFailure
& e
)
158 msg
<< "CRT assert failure: " << e
.m_msg
;
160 #endif // wxUSE_VC_CRTDBG
161 catch ( std::exception
& e
)
163 msg
<< "std::exception: " << e
.what();
167 msg
= "Unknown exception caught.";
170 return string(msg
.mb_str());
173 // Protector adding handling of wx-specific (this includes MSVC debug CRT in
174 // this context) exceptions
175 class wxUnitTestProtector
: public CppUnit::Protector
178 virtual bool protect(const CppUnit::Functor
&functor
,
179 const CppUnit::ProtectorContext
& context
)
185 catch ( std::exception
& )
187 // cppunit deals with the standard exceptions itself, let it do as
188 // it output more details (especially for std::exception-derived
189 // CppUnit::Exception) than we do
194 reportError(context
, CppUnit::Message("Uncaught exception",
195 GetExceptionMessage()));
202 // Displays the test name before starting to execute it: this helps with
203 // diagnosing where exactly does a test crash or hang when/if it does.
204 class DetailListener
: public CppUnit::TestListener
207 DetailListener(bool doTiming
= false):
208 CppUnit::TestListener(),
213 virtual void startTest(CppUnit::Test
*test
)
215 wxPrintf(" %-60s ", test
->getName());
216 m_result
= RESULT_OK
;
220 virtual void addFailure(const CppUnit::TestFailure
& failure
)
222 m_result
= failure
.isError() ? RESULT_ERROR
: RESULT_FAIL
;
225 virtual void endTest(CppUnit::Test
* WXUNUSED(test
))
228 wxPrintf(GetResultStr(m_result
));
230 wxPrintf(" %6ld ms", m_watch
.Time());
243 wxString
GetResultStr(ResultType type
) const
245 static const char *resultTypeNames
[] =
252 wxCOMPILE_TIME_ASSERT( WXSIZEOF(resultTypeNames
) == RESULT_MAX
,
253 ResultTypeNamesMismatch
);
255 return resultTypeNames
[type
];
264 typedef wxApp TestAppBase
;
266 typedef wxAppConsole TestAppBase
;
269 // The application class
271 class TestApp
: public TestAppBase
276 // standard overrides
277 virtual void OnInitCmdLine(wxCmdLineParser
& parser
);
278 virtual bool OnCmdLineParsed(wxCmdLineParser
& parser
);
279 virtual bool OnInit();
281 virtual int OnExit();
283 // used by events propagation test
284 virtual int FilterEvent(wxEvent
& event
);
285 virtual bool ProcessEvent(wxEvent
& event
);
287 void SetFilterEventFunc(FilterEventFunc f
) { m_filterEventFunc
= f
; }
288 void SetProcessEventFunc(ProcessEventFunc f
) { m_processEventFunc
= f
; }
291 void List(Test
*test
, const string
& parent
= "") const;
293 // call List() if m_list or runner.addTest() otherwise
294 void AddTest(CppUnit::TestRunner
& runner
, Test
*test
)
299 runner
.addTest(test
);
302 // command lines options/parameters
307 wxArrayString m_registries
;
310 // event loop for GUI tests
311 wxEventLoop
* m_eventloop
;
313 // event handling hooks
314 FilterEventFunc m_filterEventFunc
;
315 ProcessEventFunc m_processEventFunc
;
318 IMPLEMENT_APP_NO_MAIN(TestApp
)
321 // ----------------------------------------------------------------------------
323 // ----------------------------------------------------------------------------
325 #ifdef wxUSE_VC_CRTDBG
327 static int TestCrtReportHook(int reportType
, char *message
, int *)
329 if ( reportType
!= _CRT_ASSERT
)
332 throw CrtAssertFailure(message
);
335 #endif // wxUSE_VC_CRTDBG
337 int main(int argc
, char **argv
)
339 // tests can be ran non-interactively so make sure we don't show any assert
340 // dialog boxes -- neither our own nor from MSVC debug CRT -- which would
341 // prevent them from completing
344 wxSetAssertHandler(TestAssertHandler
);
345 #endif // wxDEBUG_LEVEL
347 #ifdef wxUSE_VC_CRTDBG
348 _CrtSetReportHook(TestCrtReportHook
);
349 #endif // wxUSE_VC_CRTDBG
353 return wxEntry(argc
, argv
);
357 cerr
<< "\n" << GetExceptionMessage() << endl
;
363 extern void SetFilterEventFunc(FilterEventFunc func
)
365 wxGetApp().SetFilterEventFunc(func
);
368 extern void SetProcessEventFunc(ProcessEventFunc func
)
370 wxGetApp().SetProcessEventFunc(func
);
373 extern bool IsNetworkAvailable()
375 // NOTE: we could use wxDialUpManager here if it was in wxNet; since it's in
376 // wxCore we use a simple rough test:
378 wxSocketBase::Initialize();
381 if (!addr
.Hostname("www.google.com") || !addr
.Service("www"))
383 wxSocketBase::Shutdown();
388 sock
.SetTimeout(10); // 10 secs
389 bool online
= sock
.Connect(addr
);
391 wxSocketBase::Shutdown();
396 // helper of OnRun(): gets the test with the given name, returning NULL (and
397 // not an empty test suite) if there is no such test
398 static Test
*GetTestByName(const wxString
& name
)
401 test
= TestFactoryRegistry::getRegistry(string(name
.mb_str())).makeTest();
404 TestSuite
* const suite
= dynamic_cast<TestSuite
*>(test
);
405 if ( !suite
|| !suite
->countTestCases() )
407 // it's a bogus test, don't use it
417 // ----------------------------------------------------------------------------
419 // ----------------------------------------------------------------------------
425 m_filterEventFunc
= NULL
;
426 m_processEventFunc
= NULL
;
434 bool TestApp::OnInit()
436 if ( !TestAppBase::OnInit() )
440 cout
<< "Test program for wxWidgets GUI features\n"
442 cout
<< "Test program for wxWidgets non-GUI features\n"
444 << "build: " << WX_BUILD_OPTIONS_SIGNATURE
<< std::endl
;
447 // create a hidden parent window to be used as parent for the GUI controls
448 wxTestableFrame
* frame
= new wxTestableFrame();
451 m_eventloop
= new wxEventLoop
;
452 wxEventLoop::SetActive(m_eventloop
);
458 // The table of command line options
460 void TestApp::OnInitCmdLine(wxCmdLineParser
& parser
)
462 TestAppBase::OnInitCmdLine(parser
);
464 static const wxCmdLineEntryDesc cmdLineDesc
[] = {
465 { wxCMD_LINE_SWITCH
, "l", "list",
466 "list the test suites, do not run them",
467 wxCMD_LINE_VAL_NONE
, 0 },
468 { wxCMD_LINE_SWITCH
, "L", "longlist",
469 "list the test cases, do not run them",
470 wxCMD_LINE_VAL_NONE
, 0 },
471 { wxCMD_LINE_SWITCH
, "d", "detail",
472 "print the test case names, run them",
473 wxCMD_LINE_VAL_NONE
, 0 },
474 { wxCMD_LINE_SWITCH
, "t", "timing",
475 "print names and measure running time of individual test, run them",
476 wxCMD_LINE_VAL_NONE
, 0 },
477 { wxCMD_LINE_OPTION
, "", "locale",
478 "locale to use when running the program",
479 wxCMD_LINE_VAL_STRING
, 0 },
480 { wxCMD_LINE_PARAM
, NULL
, NULL
, "REGISTRY", wxCMD_LINE_VAL_STRING
,
481 wxCMD_LINE_PARAM_OPTIONAL
| wxCMD_LINE_PARAM_MULTIPLE
},
485 parser
.SetDesc(cmdLineDesc
);
488 // Handle command line options
490 bool TestApp::OnCmdLineParsed(wxCmdLineParser
& parser
)
492 if (parser
.GetParamCount())
494 for (size_t i
= 0; i
< parser
.GetParamCount(); i
++)
495 m_registries
.push_back(parser
.GetParam(i
));
498 m_longlist
= parser
.Found("longlist");
499 m_list
= m_longlist
|| parser
.Found("list");
500 m_timing
= parser
.Found("timing");
501 m_detail
= !m_timing
&& parser
.Found("detail");
504 if ( parser
.Found("locale", &loc
) )
506 const wxLanguageInfo
* const info
= wxLocale::FindLanguageInfo(loc
);
509 cerr
<< "Locale \"" << string(loc
.mb_str()) << "\" is unknown.\n";
513 m_locale
= new wxLocale(info
->Language
);
514 if ( !m_locale
->IsOk() )
516 cerr
<< "Using locale \"" << string(loc
.mb_str()) << "\" failed.\n";
521 return TestAppBase::OnCmdLineParsed(parser
);
525 int TestApp::FilterEvent(wxEvent
& event
)
527 if ( m_filterEventFunc
)
528 return (*m_filterEventFunc
)(event
);
530 return TestAppBase::FilterEvent(event
);
533 bool TestApp::ProcessEvent(wxEvent
& event
)
535 if ( m_processEventFunc
)
536 return (*m_processEventFunc
)(event
);
538 return TestAppBase::ProcessEvent(event
);
547 // make sure there's always an autorelease pool ready
548 wxMacAutoreleasePool autoreleasepool
;
553 // Switch off logging unless --verbose
554 bool verbose
= wxLog::GetVerbose();
555 wxLog::EnableLogging(verbose
);
557 bool verbose
= false;
560 CppUnit::TextTestRunner runner
;
562 if ( m_registries
.empty() )
564 // run or list all tests which use the CPPUNIT_TEST_SUITE_REGISTRATION() macro
565 // (i.e. those registered in the "All tests" registry); if there are other
566 // tests not registered with the CPPUNIT_TEST_SUITE_REGISTRATION() macro
567 // then they won't be listed/run!
568 AddTest(runner
, TestFactoryRegistry::getRegistry().makeTest());
572 cout
<< "\nNote that the list above is not complete as it doesn't include the \n";
573 cout
<< "tests disabled by default.\n";
576 else // run only the selected tests
578 for (size_t i
= 0; i
< m_registries
.size(); i
++)
580 const wxString reg
= m_registries
[i
];
581 Test
*test
= GetTestByName(reg
);
583 if ( !test
&& !reg
.EndsWith("TestCase") )
585 test
= GetTestByName(reg
+ "TestCase");
590 cerr
<< "No such test suite: " << string(reg
.mb_str()) << endl
;
594 AddTest(runner
, test
);
601 runner
.setOutputter(new CppUnit::CompilerOutputter(&runner
.result(), cout
));
604 // (http://sf.net/tracker/index.php?func=detail&aid=1649369&group_id=11795&atid=111795)
605 // in some versions of cppunit: they write progress dots to cout (and not
606 // cerr) and don't flush it so all the dots appear at once at the end which
607 // is not very useful so unbuffer cout to work around this
608 cout
.setf(ios::unitbuf
);
610 // add detail listener if needed
611 DetailListener
detailListener(m_timing
);
612 if ( m_detail
|| m_timing
)
613 runner
.eventManager().addListener(&detailListener
);
615 // finally ensure that we report our own exceptions nicely instead of
616 // giving "uncaught exception of unknown type" messages
617 runner
.eventManager().pushProtector(new wxUnitTestProtector
);
619 bool printProgress
= !(verbose
|| m_detail
|| m_timing
);
620 return runner
.run("", false, true, printProgress
) ? EXIT_SUCCESS
: EXIT_FAILURE
;
623 int TestApp::OnExit()
628 delete GetTopWindow();
629 wxEventLoop::SetActive(NULL
);
638 void TestApp::List(Test
*test
, const string
& parent
/*=""*/) const
640 TestSuite
*suite
= dynamic_cast<TestSuite
*>(test
);
644 // take the last component of the name and append to the parent
645 name
= test
->getName();
646 string::size_type i
= name
.find_last_of(".:");
647 if (i
!= string::npos
)
648 name
= name
.substr(i
+ 1);
649 name
= parent
+ "." + name
;
651 // drop the 1st component from the display and indent
653 string::size_type j
= i
= name
.find('.', 1);
654 while ((j
= name
.find('.', j
+ 1)) != string::npos
)
656 cout
<< " " << name
.substr(i
+ 1) << "\n";
659 typedef vector
<Test
*> Tests
;
660 typedef Tests::const_iterator Iter
;
662 const Tests
& tests
= suite
->getTests();
664 for (Iter it
= tests
.begin(); it
!= tests
.end(); ++it
)
667 else if (m_longlist
) {
668 string::size_type i
= 0;
669 while ((i
= parent
.find('.', i
+ 1)) != string::npos
)
671 cout
<< " " << test
->getName() << "\n";