1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/log/logtest.cpp
3 // Purpose: wxLog unit test
4 // Author: Vadim Zeitlin
5 // Created: 2009-07-07
6 // Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
7 ///////////////////////////////////////////////////////////////////////////////
8
9 // ----------------------------------------------------------------------------
10 // headers
11 // ----------------------------------------------------------------------------
12
13 #include "testprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/log.h"
21 #include "wx/filefn.h"
22 #endif // WX_PRECOMP
23
24 #include "wx/scopeguard.h"
25
26 #ifdef __WINDOWS__
27 #include "wx/msw/wrapwin.h"
28 #else
29 #include <errno.h>
30 #endif
31
32 #if WXWIN_COMPATIBILITY_2_8
33 // we override deprecated DoLog() and DoLogString() in this test, suppress
34 // warnings about it
35 #if wxCHECK_VISUALC_VERSION(7)
36 #pragma warning(disable: 4996)
37 #endif // VC++ 7+
38 #endif // WXWIN_COMPATIBILITY_2_8
39
40 // all calls to wxLogXXX() functions from this file will use this log component
41 #define wxLOG_COMPONENT "test"
42
43 // ----------------------------------------------------------------------------
44 // test loggers
45 // ----------------------------------------------------------------------------
46
47 // base class for all test loggers which simply store all logged messages for
48 // future examination in the test code
49 class TestLogBase : public wxLog
50 {
51 public:
TestLogBase()52 TestLogBase() { }
53
GetLog(wxLogLevel level) const54 const wxString& GetLog(wxLogLevel level) const
55 {
56 return m_logs[level];
57 }
58
GetInfo(wxLogLevel level) const59 const wxLogRecordInfo& GetInfo(wxLogLevel level) const
60 {
61 return m_logsInfo[level];
62 }
63
Clear()64 void Clear()
65 {
66 for ( unsigned n = 0; n < WXSIZEOF(m_logs); n++ )
67 {
68 m_logs[n].clear();
69 m_logsInfo[n] = wxLogRecordInfo();
70 }
71 }
72
73 protected:
74 wxString m_logs[wxLOG_Trace + 1];
75 wxLogRecordInfo m_logsInfo[wxLOG_Trace + 1];
76
77 wxDECLARE_NO_COPY_CLASS(TestLogBase);
78 };
79
80 // simple log sink which just stores the messages logged for each level
81 class TestLog : public TestLogBase
82 {
83 public:
TestLog()84 TestLog() { }
85
86 protected:
DoLogRecord(wxLogLevel level,const wxString & msg,const wxLogRecordInfo & info)87 virtual void DoLogRecord(wxLogLevel level,
88 const wxString& msg,
89 const wxLogRecordInfo& info)
90 {
91 m_logs[level] = msg;
92 m_logsInfo[level] = info;
93 }
94
95 private:
96 wxDECLARE_NO_COPY_CLASS(TestLog);
97 };
98
99 #if WXWIN_COMPATIBILITY_2_8
100
101 // log sink overriding the old DoLogXXX() functions should still work too
102
103 // this one overrides DoLog(char*)
104 class CompatTestLog : public TestLogBase
105 {
106 public:
CompatTestLog()107 CompatTestLog() { }
108
109 protected:
DoLog(wxLogLevel level,const char * str,time_t WXUNUSED (t))110 virtual void DoLog(wxLogLevel level, const char *str, time_t WXUNUSED(t))
111 {
112 m_logs[level] = str;
113 }
114
115 // get rid of the warning about hiding the other overload
DoLog(wxLogLevel WXUNUSED (level),const wchar_t * WXUNUSED (str),time_t WXUNUSED (t))116 virtual void DoLog(wxLogLevel WXUNUSED(level),
117 const wchar_t *WXUNUSED(str),
118 time_t WXUNUSED(t))
119 {
120 }
121
122 private:
123 wxDECLARE_NO_COPY_CLASS(CompatTestLog);
124 };
125
126 // and this one overload DoLogString(wchar_t*)
127 class CompatTestLog2 : public wxLog
128 {
129 public:
CompatTestLog2()130 CompatTestLog2() { }
131
Get() const132 const wxString& Get() const { return m_msg; }
133
134 protected:
DoLogString(const wchar_t * msg,time_t WXUNUSED (t))135 virtual void DoLogString(const wchar_t *msg, time_t WXUNUSED(t))
136 {
137 m_msg = msg;
138 }
139
140 // get rid of the warning
DoLogString(const char * WXUNUSED (msg),time_t WXUNUSED (t))141 virtual void DoLogString(const char *WXUNUSED(msg), time_t WXUNUSED(t))
142 {
143 }
144
145 private:
146 wxString m_msg;
147
148 wxDECLARE_NO_COPY_CLASS(CompatTestLog2);
149 };
150
151 #endif // WXWIN_COMPATIBILITY_2_8
152
153 // ----------------------------------------------------------------------------
154 // test class
155 // ----------------------------------------------------------------------------
156
157 class LogTestCase : public CppUnit::TestCase
158 {
159 public:
LogTestCase()160 LogTestCase() { }
161
162 virtual void setUp();
163 virtual void tearDown();
164
165 private:
166 CPPUNIT_TEST_SUITE( LogTestCase );
167 CPPUNIT_TEST( Functions );
168 CPPUNIT_TEST( Null );
169 CPPUNIT_TEST( Component );
170 #if wxDEBUG_LEVEL
171 CPPUNIT_TEST( Trace );
172 #endif // wxDEBUG_LEVEL
173 #if WXWIN_COMPATIBILITY_2_8
174 CPPUNIT_TEST( CompatLogger );
175 CPPUNIT_TEST( CompatLogger2 );
176 #endif // WXWIN_COMPATIBILITY_2_8
177 CPPUNIT_TEST( SysError );
178 CPPUNIT_TEST( NoWarnings );
179 CPPUNIT_TEST_SUITE_END();
180
181 void Functions();
182 void Null();
183 void Component();
184 #if wxDEBUG_LEVEL
185 void Trace();
186 #endif // wxDEBUG_LEVEL
187 #if WXWIN_COMPATIBILITY_2_8
188 void CompatLogger();
189 void CompatLogger2();
190 #endif // WXWIN_COMPATIBILITY_2_8
191 void SysError();
192 void NoWarnings();
193
194 TestLog *m_log;
195 wxLog *m_logOld;
196 bool m_logWasEnabled;
197
198 wxDECLARE_NO_COPY_CLASS(LogTestCase);
199 };
200
201 // register in the unnamed registry so that these tests are run by default
202 CPPUNIT_TEST_SUITE_REGISTRATION( LogTestCase );
203
204 // also include in its own registry so that these tests can be run alone
205 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( LogTestCase, "LogTestCase" );
206
setUp()207 void LogTestCase::setUp()
208 {
209 m_logOld = wxLog::SetActiveTarget(m_log = new TestLog);
210 m_logWasEnabled = wxLog::EnableLogging();
211 }
212
tearDown()213 void LogTestCase::tearDown()
214 {
215 delete wxLog::SetActiveTarget(m_logOld);
216 wxLog::EnableLogging(m_logWasEnabled);
217 }
218
Functions()219 void LogTestCase::Functions()
220 {
221 wxLogMessage("Message");
222 CPPUNIT_ASSERT_EQUAL( "Message", m_log->GetLog(wxLOG_Message) );
223
224 wxLogError("Error %d", 17);
225 CPPUNIT_ASSERT_EQUAL( "Error 17", m_log->GetLog(wxLOG_Error) );
226
227 wxLogDebug("Debug");
228 #if wxDEBUG_LEVEL
229 CPPUNIT_ASSERT_EQUAL( "Debug", m_log->GetLog(wxLOG_Debug) );
230 #else
231 CPPUNIT_ASSERT_EQUAL( "", m_log->GetLog(wxLOG_Debug) );
232 #endif
233 }
234
Null()235 void LogTestCase::Null()
236 {
237 {
238 wxLogNull noLog;
239 wxLogWarning("%s warning", "Not important");
240
241 CPPUNIT_ASSERT_EQUAL( "", m_log->GetLog(wxLOG_Warning) );
242 }
243
244 wxLogWarning("%s warning", "Important");
245 CPPUNIT_ASSERT_EQUAL( "Important warning", m_log->GetLog(wxLOG_Warning) );
246 }
247
Component()248 void LogTestCase::Component()
249 {
250 wxLogMessage("Message");
251 CPPUNIT_ASSERT_EQUAL( wxLOG_COMPONENT,
252 m_log->GetInfo(wxLOG_Message).component );
253
254 // completely disable logging for this component
255 wxLog::SetComponentLevel("test/ignore", wxLOG_FatalError);
256
257 // but enable it for one of its subcomponents
258 wxLog::SetComponentLevel("test/ignore/not", wxLOG_Max);
259
260 #undef wxLOG_COMPONENT
261 #define wxLOG_COMPONENT "test/ignore"
262
263 // this shouldn't be output as this component is ignored
264 wxLogError("Error");
265 CPPUNIT_ASSERT_EQUAL( "", m_log->GetLog(wxLOG_Error) );
266
267 // and so are its subcomponents
268 #undef wxLOG_COMPONENT
269 #define wxLOG_COMPONENT "test/ignore/sub/subsub"
270 wxLogError("Error");
271 CPPUNIT_ASSERT_EQUAL( "", m_log->GetLog(wxLOG_Error) );
272
273 // but one subcomponent is not
274 #undef wxLOG_COMPONENT
275 #define wxLOG_COMPONENT "test/ignore/not"
276 wxLogError("Error");
277 CPPUNIT_ASSERT_EQUAL( "Error", m_log->GetLog(wxLOG_Error) );
278
279 // restore the original value
280 #undef wxLOG_COMPONENT
281 #define wxLOG_COMPONENT "test"
282 }
283
284 #if wxDEBUG_LEVEL
285
286 namespace
287 {
288
289 const char *TEST_MASK = "test";
290
291 // this is a test vararg function (a real one, not a variadic-template-like as
292 // wxVLogTrace(), so care should be taken with its arguments)
TraceTest(const char * format,...)293 void TraceTest(const char *format, ...)
294 {
295 va_list argptr;
296 va_start(argptr, format);
297 wxVLogTrace(TEST_MASK, format, argptr);
298 va_end(argptr);
299 }
300
301 } // anonymous namespace
302
Trace()303 void LogTestCase::Trace()
304 {
305 // we use wxLogTrace() or wxVLogTrace() from inside TraceTest()
306 // interchangeably here, it shouldn't make any difference
307
308 wxLogTrace(TEST_MASK, "Not shown");
309 CPPUNIT_ASSERT_EQUAL( "", m_log->GetLog(wxLOG_Trace) );
310
311 wxLog::AddTraceMask(TEST_MASK);
312 TraceTest("Shown");
313 CPPUNIT_ASSERT_EQUAL( wxString::Format("(%s) Shown", TEST_MASK),
314 m_log->GetLog(wxLOG_Trace) );
315
316 wxLog::RemoveTraceMask(TEST_MASK);
317 m_log->Clear();
318
319 TraceTest("Not shown again");
320 CPPUNIT_ASSERT_EQUAL( "", m_log->GetLog(wxLOG_Trace) );
321 }
322
323 #endif // wxDEBUG_LEVEL
324
325 #if WXWIN_COMPATIBILITY_2_8
326
CompatLogger()327 void LogTestCase::CompatLogger()
328 {
329 CompatTestLog log;
330 wxLog * const logOld = wxLog::SetActiveTarget(&log);
331 wxON_BLOCK_EXIT1( wxLog::SetActiveTarget, logOld );
332
333 wxLogError("Old error");
334 CPPUNIT_ASSERT_EQUAL( "Old error", log.GetLog(wxLOG_Error) );
335 }
336
CompatLogger2()337 void LogTestCase::CompatLogger2()
338 {
339 CompatTestLog2 log;
340 wxLog * const logOld = wxLog::SetActiveTarget(&log);
341 wxON_BLOCK_EXIT1( wxLog::SetActiveTarget, logOld );
342
343 wxLogWarning("Old warning");
344 CPPUNIT_ASSERT_EQUAL( "Old warning", log.Get() );
345 }
346
347 #endif // WXWIN_COMPATIBILITY_2_8
348
SysError()349 void LogTestCase::SysError()
350 {
351 wxString s;
352
353 wxLogSysError(17, "Error");
354 CPPUNIT_ASSERT( m_log->GetLog(wxLOG_Error).StartsWith("Error (", &s) );
355 WX_ASSERT_MESSAGE( ("Error message is \"(%s\"", s), s.StartsWith("error 17") );
356
357 // Try to ensure that the system error is 0.
358 #ifdef __WINDOWS__
359 ::SetLastError(0);
360 #else
361 errno = 0;
362 #endif
363
364 wxLogSysError("Success");
365 CPPUNIT_ASSERT( m_log->GetLog(wxLOG_Error).StartsWith("Success (", &s) );
366 WX_ASSERT_MESSAGE( ("Error message is \"(%s\"", s), s.StartsWith("error 0") );
367
368 wxOpen("no-such-file", 0, 0);
369 wxLogSysError("Not found");
370 CPPUNIT_ASSERT( m_log->GetLog(wxLOG_Error).StartsWith("Not found (", &s) );
371 WX_ASSERT_MESSAGE( ("Error message is \"(%s\"", s), s.StartsWith("error 2") );
372 }
373
NoWarnings()374 void LogTestCase::NoWarnings()
375 {
376 // Check that "else" branch is [not] taken as expected and that this code
377 // compiles without warnings (which used to not be the case).
378
379 bool b = wxFalse;
380 if ( b )
381 wxLogError("Not logged");
382 else
383 b = !b;
384
385 CPPUNIT_ASSERT( b );
386
387 if ( b )
388 wxLogError("If");
389 else
390 CPPUNIT_FAIL("Should not be taken");
391
392 CPPUNIT_ASSERT_EQUAL( "If", m_log->GetLog(wxLOG_Error) );
393 }
394