diff options
Diffstat (limited to 'linden/indra/test/llerror_tut.cpp')
-rw-r--r-- | linden/indra/test/llerror_tut.cpp | 767 |
1 files changed, 767 insertions, 0 deletions
diff --git a/linden/indra/test/llerror_tut.cpp b/linden/indra/test/llerror_tut.cpp new file mode 100644 index 0000000..a4b4258 --- /dev/null +++ b/linden/indra/test/llerror_tut.cpp | |||
@@ -0,0 +1,767 @@ | |||
1 | /** | ||
2 | * @file llerror_tut.cpp | ||
3 | * @date December 2006 | ||
4 | * @brief error unit tests | ||
5 | * | ||
6 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | #include "llerror.h" | ||
30 | namespace | ||
31 | { | ||
32 | void test_that_error_h_includes_enough_things_to_compile_a_message() | ||
33 | { | ||
34 | llinfos << "!" << llendl; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | #include <tut/tut.h> | ||
39 | #include "lltut.h" | ||
40 | |||
41 | #include <vector> | ||
42 | |||
43 | #include "llerrorcontrol.h" | ||
44 | #include "llsd.h" | ||
45 | |||
46 | namespace | ||
47 | { | ||
48 | static bool fatalWasCalled; | ||
49 | void fatalCall(const std::string&) { fatalWasCalled = true; } | ||
50 | |||
51 | class TestRecorder : public LLError::Recorder | ||
52 | { | ||
53 | public: | ||
54 | TestRecorder() : mWantsTime(false) { } | ||
55 | ~TestRecorder() { LLError::removeRecorder(this); } | ||
56 | |||
57 | void recordMessage(LLError::ELevel level, | ||
58 | const std::string& message) | ||
59 | { | ||
60 | mMessages.push_back(message); | ||
61 | } | ||
62 | |||
63 | int countMessages() { return (int) mMessages.size(); } | ||
64 | void clearMessages() { mMessages.clear(); } | ||
65 | |||
66 | void setWantsTime(bool t) { mWantsTime = t; } | ||
67 | bool wantsTime() { return mWantsTime; } | ||
68 | |||
69 | std::string message(int n) | ||
70 | { | ||
71 | std::ostringstream test_name; | ||
72 | test_name << "testing message " << n << ", not enough messages"; | ||
73 | |||
74 | tut::ensure(test_name.str(), n < countMessages()); | ||
75 | return mMessages[n]; | ||
76 | } | ||
77 | |||
78 | private: | ||
79 | typedef std::vector<std::string> MessageVector; | ||
80 | MessageVector mMessages; | ||
81 | |||
82 | bool mWantsTime; | ||
83 | }; | ||
84 | } | ||
85 | |||
86 | namespace tut | ||
87 | { | ||
88 | struct ErrorTestData | ||
89 | { | ||
90 | TestRecorder mRecorder; | ||
91 | LLError::Settings* mPriorErrorSettings; | ||
92 | |||
93 | ErrorTestData() | ||
94 | { | ||
95 | fatalWasCalled = false; | ||
96 | |||
97 | mPriorErrorSettings = LLError::saveAndResetSettings(); | ||
98 | LLError::setDefaultLevel(LLError::LEVEL_DEBUG); | ||
99 | LLError::setFatalFunction(fatalCall); | ||
100 | LLError::addRecorder(&mRecorder); | ||
101 | } | ||
102 | |||
103 | ~ErrorTestData() | ||
104 | { | ||
105 | LLError::removeRecorder(&mRecorder); | ||
106 | LLError::restoreSettings(mPriorErrorSettings); | ||
107 | } | ||
108 | |||
109 | void ensure_message_count(int expectedCount) | ||
110 | { | ||
111 | ensure_equals("message count", mRecorder.countMessages(), expectedCount); | ||
112 | } | ||
113 | |||
114 | void ensure_message_contains(int n, const std::string& expectedText) | ||
115 | { | ||
116 | std::ostringstream test_name; | ||
117 | test_name << "testing message " << n; | ||
118 | |||
119 | ensure_contains(test_name.str(), mRecorder.message(n), expectedText); | ||
120 | } | ||
121 | |||
122 | void ensure_message_does_not_contain(int n, const std::string& expectedText) | ||
123 | { | ||
124 | std::ostringstream test_name; | ||
125 | test_name << "testing message " << n; | ||
126 | |||
127 | ensure_does_not_contain(test_name.str(), mRecorder.message(n), expectedText); | ||
128 | } | ||
129 | }; | ||
130 | |||
131 | typedef test_group<ErrorTestData> ErrorTestGroup; | ||
132 | typedef ErrorTestGroup::object ErrorTestObject; | ||
133 | |||
134 | ErrorTestGroup errorTestGroup("error"); | ||
135 | |||
136 | template<> template<> | ||
137 | void ErrorTestObject::test<1>() | ||
138 | // basic test of output | ||
139 | { | ||
140 | llinfos << "test" << llendl; | ||
141 | llinfos << "bob" << llendl; | ||
142 | |||
143 | ensure_message_contains(0, "test"); | ||
144 | ensure_message_contains(1, "bob"); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | namespace | ||
149 | { | ||
150 | void writeSome() | ||
151 | { | ||
152 | lldebugs << "one" << llendl; | ||
153 | llinfos << "two" << llendl; | ||
154 | llwarns << "three" << llendl; | ||
155 | llerrs << "four" << llendl; | ||
156 | // fatal messages write out and addtional "error" message | ||
157 | } | ||
158 | }; | ||
159 | |||
160 | namespace tut | ||
161 | { | ||
162 | template<> template<> | ||
163 | void ErrorTestObject::test<2>() | ||
164 | // messages are filtered based on default level | ||
165 | { | ||
166 | LLError::setDefaultLevel(LLError::LEVEL_DEBUG); | ||
167 | writeSome(); | ||
168 | ensure_message_contains(0, "one"); | ||
169 | ensure_message_contains(1, "two"); | ||
170 | ensure_message_contains(2, "three"); | ||
171 | ensure_message_contains(3, "error"); | ||
172 | ensure_message_contains(4, "four"); | ||
173 | ensure_message_count(5); | ||
174 | |||
175 | LLError::setDefaultLevel(LLError::LEVEL_INFO); | ||
176 | writeSome(); | ||
177 | ensure_message_contains(5, "two"); | ||
178 | ensure_message_contains(6, "three"); | ||
179 | ensure_message_contains(7, "error"); | ||
180 | ensure_message_contains(8, "four"); | ||
181 | ensure_message_count(9); | ||
182 | |||
183 | LLError::setDefaultLevel(LLError::LEVEL_WARN); | ||
184 | writeSome(); | ||
185 | ensure_message_contains(9, "three"); | ||
186 | ensure_message_contains(10, "error"); | ||
187 | ensure_message_contains(11, "four"); | ||
188 | ensure_message_count(12); | ||
189 | |||
190 | LLError::setDefaultLevel(LLError::LEVEL_ERROR); | ||
191 | writeSome(); | ||
192 | ensure_message_contains(12, "error"); | ||
193 | ensure_message_contains(13, "four"); | ||
194 | ensure_message_count(14); | ||
195 | |||
196 | LLError::setDefaultLevel(LLError::LEVEL_NONE); | ||
197 | writeSome(); | ||
198 | ensure_message_count(14); | ||
199 | } | ||
200 | |||
201 | template<> template<> | ||
202 | void ErrorTestObject::test<3>() | ||
203 | // error type string in output | ||
204 | { | ||
205 | writeSome(); | ||
206 | ensure_message_contains(0, "DEBUG: "); | ||
207 | ensure_message_contains(1, "INFO: "); | ||
208 | ensure_message_contains(2, "WARNING: "); | ||
209 | ensure_message_does_not_contain(3, "ERROR"); | ||
210 | ensure_message_contains(4, "ERROR: "); | ||
211 | ensure_message_count(5); | ||
212 | } | ||
213 | |||
214 | template<> template<> | ||
215 | void ErrorTestObject::test<4>() | ||
216 | // file abbreviation | ||
217 | { | ||
218 | std::string thisFile = __FILE__; | ||
219 | std::string abbreviateFile = LLError::abbreviateFile(thisFile); | ||
220 | |||
221 | ensure_ends_with("file name abbreviation", | ||
222 | abbreviateFile, | ||
223 | "test/llerror_tut.cpp" | ||
224 | ); | ||
225 | ensure_does_not_contain("file name abbreviation", | ||
226 | abbreviateFile, "indra"); | ||
227 | |||
228 | std::string someFile = | ||
229 | #if LL_WINDOWS | ||
230 | "C:/amy/bob/cam.cpp" | ||
231 | #else | ||
232 | "/amy/bob/cam.cpp" | ||
233 | #endif | ||
234 | ; | ||
235 | std::string someAbbreviation = LLError::abbreviateFile(someFile); | ||
236 | |||
237 | ensure_equals("non-indra file abbreviation", | ||
238 | someAbbreviation, someFile); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | namespace | ||
243 | { | ||
244 | std::string locationString(int line) | ||
245 | { | ||
246 | std::ostringstream location; | ||
247 | location << LLError::abbreviateFile(__FILE__) | ||
248 | << "(" << line << ") : "; | ||
249 | |||
250 | return location.str(); | ||
251 | } | ||
252 | |||
253 | std::string writeReturningLocation() | ||
254 | { | ||
255 | llinfos << "apple" << llendl; int this_line = __LINE__; | ||
256 | return locationString(this_line); | ||
257 | } | ||
258 | |||
259 | std::string writeReturningLocationAndFunction() | ||
260 | { | ||
261 | llinfos << "apple" << llendl; int this_line = __LINE__; | ||
262 | return locationString(this_line) + __FUNCTION__; | ||
263 | } | ||
264 | |||
265 | std::string errorReturningLocation() | ||
266 | { | ||
267 | llerrs << "die" << llendl; int this_line = __LINE__; | ||
268 | return locationString(this_line); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | namespace tut | ||
273 | { | ||
274 | template<> template<> | ||
275 | void ErrorTestObject::test<5>() | ||
276 | // file and line information in log messages | ||
277 | { | ||
278 | std::string location = writeReturningLocation(); | ||
279 | // expecting default to not print location information | ||
280 | |||
281 | LLError::setPrintLocation(true); | ||
282 | writeReturningLocation(); | ||
283 | |||
284 | LLError::setPrintLocation(false); | ||
285 | writeReturningLocation(); | ||
286 | |||
287 | ensure_message_does_not_contain(0, location); | ||
288 | ensure_message_contains(1, location); | ||
289 | ensure_message_does_not_contain(2, location); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | /* The following helper functions and class members all log a simple message | ||
294 | from some particular function scope. Each function takes a bool argument | ||
295 | that indicates if it should log its own name or not (in the manner that | ||
296 | existing log messages often do.) The functions all return their C++ | ||
297 | name so that test can be substantial mechanized. | ||
298 | */ | ||
299 | |||
300 | std::string logFromGlobal(bool id) | ||
301 | { | ||
302 | llinfos << (id ? "logFromGlobal: " : "") << "hi" << llendl; | ||
303 | return "logFromGlobal"; | ||
304 | } | ||
305 | |||
306 | static std::string logFromStatic(bool id) | ||
307 | { | ||
308 | llinfos << (id ? "logFromStatic: " : "") << "hi" << llendl; | ||
309 | return "logFromStatic"; | ||
310 | } | ||
311 | |||
312 | namespace | ||
313 | { | ||
314 | std::string logFromAnon(bool id) | ||
315 | { | ||
316 | llinfos << (id ? "logFromAnon: " : "") << "hi" << llendl; | ||
317 | return "logFromAnon"; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | namespace Foo { | ||
322 | std::string logFromNamespace(bool id) | ||
323 | { | ||
324 | llinfos << (id ? "Foo::logFromNamespace: " : "") << "hi" << llendl; | ||
325 | //return "Foo::logFromNamespace"; | ||
326 | // there is no standard way to get the namespace name, hence | ||
327 | // we won't be testing for it | ||
328 | return "logFromNamespace"; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | namespace | ||
333 | { | ||
334 | class ClassWithNoLogType { | ||
335 | public: | ||
336 | std::string logFromMember(bool id) | ||
337 | { | ||
338 | llinfos << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << llendl; | ||
339 | return "ClassWithNoLogType::logFromMember"; | ||
340 | } | ||
341 | static std::string logFromStatic(bool id) | ||
342 | { | ||
343 | llinfos << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << llendl; | ||
344 | return "ClassWithNoLogType::logFromStatic"; | ||
345 | } | ||
346 | }; | ||
347 | |||
348 | class ClassWithLogType { | ||
349 | LOG_CLASS(ClassWithLogType); | ||
350 | public: | ||
351 | std::string logFromMember(bool id) | ||
352 | { | ||
353 | llinfos << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << llendl; | ||
354 | return "ClassWithLogType::logFromMember"; | ||
355 | } | ||
356 | static std::string logFromStatic(bool id) | ||
357 | { | ||
358 | llinfos << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << llendl; | ||
359 | return "ClassWithLogType::logFromStatic"; | ||
360 | } | ||
361 | }; | ||
362 | |||
363 | std::string logFromNamespace(bool id) { return Foo::logFromNamespace(id); } | ||
364 | std::string logFromClassWithNoLogTypeMember(bool id) { ClassWithNoLogType c; return c.logFromMember(id); } | ||
365 | std::string logFromClassWithNoLogTypeStatic(bool id) { return ClassWithNoLogType::logFromStatic(id); } | ||
366 | std::string logFromClassWithLogTypeMember(bool id) { ClassWithLogType c; return c.logFromMember(id); } | ||
367 | std::string logFromClassWithLogTypeStatic(bool id) { return ClassWithLogType::logFromStatic(id); } | ||
368 | |||
369 | void ensure_has_once(const std::string& message, | ||
370 | const std::string& actual, const std::string& expected) | ||
371 | { | ||
372 | std::string::size_type n1 = actual.find(expected); | ||
373 | std::string::size_type n2 = std::string::npos; | ||
374 | if (n1 != std::string::npos) | ||
375 | { | ||
376 | n2 = std::string(actual, n1 + expected.size()).find(expected); | ||
377 | } | ||
378 | |||
379 | if (n1 == std::string::npos || n2 != std::string::npos) | ||
380 | { | ||
381 | std::stringstream ss; | ||
382 | ss << message << ": " << "expected to find one copy of " << expected | ||
383 | << " in actual " << actual; | ||
384 | throw tut::failure(ss.str().c_str()); | ||
385 | } | ||
386 | } | ||
387 | |||
388 | typedef std::string (*LogFromFunction)(bool); | ||
389 | void testLogNameOnce(TestRecorder& recorder, LogFromFunction f, | ||
390 | const std::string& class_name = "") | ||
391 | { | ||
392 | recorder.clearMessages(); | ||
393 | std::string name = f(false); | ||
394 | f(true); | ||
395 | |||
396 | std::string messageWithoutName = recorder.message(0); | ||
397 | std::string messageWithName = recorder.message(1); | ||
398 | |||
399 | ensure_has_once(name + " logged without name", | ||
400 | messageWithoutName, name); | ||
401 | ensure_has_once(name + " logged with name", | ||
402 | messageWithName, name); | ||
403 | |||
404 | if (!class_name.empty()) | ||
405 | { | ||
406 | ensure_has_once(name + "logged without name", | ||
407 | messageWithoutName, class_name); | ||
408 | ensure_has_once(name + "logged with name", | ||
409 | messageWithName, class_name); | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | namespace tut | ||
415 | { | ||
416 | template<> template<> | ||
417 | // class/function information in output | ||
418 | void ErrorTestObject::test<6>() | ||
419 | { | ||
420 | testLogNameOnce(mRecorder, logFromGlobal); | ||
421 | testLogNameOnce(mRecorder, logFromStatic); | ||
422 | testLogNameOnce(mRecorder, logFromAnon); | ||
423 | testLogNameOnce(mRecorder, logFromNamespace); | ||
424 | //testLogNameOnce(mRecorder, logFromClassWithNoLogTypeMember, "ClassWithNoLogType"); | ||
425 | //testLogNameOnce(mRecorder, logFromClassWithNoLogTypeStatic, "ClassWithNoLogType"); | ||
426 | // XXX: figure out what the exepcted response is for these | ||
427 | testLogNameOnce(mRecorder, logFromClassWithLogTypeMember, "ClassWithLogType"); | ||
428 | testLogNameOnce(mRecorder, logFromClassWithLogTypeStatic, "ClassWithLogType"); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | namespace | ||
433 | { | ||
434 | std::string innerLogger() | ||
435 | { | ||
436 | llinfos << "inside" << llendl; | ||
437 | return "moo"; | ||
438 | } | ||
439 | |||
440 | std::string outerLogger() | ||
441 | { | ||
442 | llinfos << "outside(" << innerLogger() << ")" << llendl; | ||
443 | return "bar"; | ||
444 | } | ||
445 | |||
446 | void uberLogger() | ||
447 | { | ||
448 | llinfos << "uber(" << outerLogger() << "," << innerLogger() << ")" << llendl; | ||
449 | } | ||
450 | |||
451 | class LogWhileLogging | ||
452 | { | ||
453 | public: | ||
454 | void print(std::ostream& out) const | ||
455 | { | ||
456 | llinfos << "logging" << llendl; | ||
457 | out << "baz"; | ||
458 | } | ||
459 | }; | ||
460 | |||
461 | std::ostream& operator<<(std::ostream& out, const LogWhileLogging& l) | ||
462 | { l.print(out); return out; } | ||
463 | |||
464 | void metaLogger() | ||
465 | { | ||
466 | LogWhileLogging l; | ||
467 | llinfos << "meta(" << l << ")" << llendl; | ||
468 | } | ||
469 | |||
470 | } | ||
471 | |||
472 | namespace tut | ||
473 | { | ||
474 | template<> template<> | ||
475 | // handle nested logging | ||
476 | void ErrorTestObject::test<7>() | ||
477 | { | ||
478 | outerLogger(); | ||
479 | ensure_message_contains(0, "inside"); | ||
480 | ensure_message_contains(1, "outside(moo)"); | ||
481 | ensure_message_count(2); | ||
482 | |||
483 | uberLogger(); | ||
484 | ensure_message_contains(2, "inside"); | ||
485 | ensure_message_contains(3, "inside"); | ||
486 | ensure_message_contains(4, "outside(moo)"); | ||
487 | ensure_message_contains(5, "uber(bar,moo)"); | ||
488 | ensure_message_count(6); | ||
489 | |||
490 | metaLogger(); | ||
491 | ensure_message_contains(6, "logging"); | ||
492 | ensure_message_contains(7, "meta(baz)"); | ||
493 | ensure_message_count(8); | ||
494 | } | ||
495 | |||
496 | template<> template<> | ||
497 | // special handling of llerrs calls | ||
498 | void ErrorTestObject::test<8>() | ||
499 | { | ||
500 | LLError::setPrintLocation(false); | ||
501 | std::string location = errorReturningLocation(); | ||
502 | |||
503 | ensure_message_contains(0, location + "error"); | ||
504 | ensure_message_contains(1, "die"); | ||
505 | ensure_message_count(2); | ||
506 | |||
507 | ensure("fatal callback called", fatalWasCalled); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | namespace | ||
512 | { | ||
513 | std::string roswell() | ||
514 | { | ||
515 | return "1947-07-08T03:04:05Z"; | ||
516 | } | ||
517 | |||
518 | void ufoSighting() | ||
519 | { | ||
520 | llinfos << "ufo" << llendl; | ||
521 | } | ||
522 | } | ||
523 | |||
524 | namespace tut | ||
525 | { | ||
526 | template<> template<> | ||
527 | // time in output (for recorders that need it) | ||
528 | void ErrorTestObject::test<9>() | ||
529 | { | ||
530 | LLError::setTimeFunction(roswell); | ||
531 | |||
532 | mRecorder.setWantsTime(false); | ||
533 | ufoSighting(); | ||
534 | ensure_message_contains(0, "ufo"); | ||
535 | ensure_message_does_not_contain(0, roswell()); | ||
536 | |||
537 | mRecorder.setWantsTime(true); | ||
538 | ufoSighting(); | ||
539 | ensure_message_contains(1, "ufo"); | ||
540 | ensure_message_contains(1, roswell()); | ||
541 | } | ||
542 | |||
543 | template<> template<> | ||
544 | // output order | ||
545 | void ErrorTestObject::test<10>() | ||
546 | { | ||
547 | LLError::setPrintLocation(true); | ||
548 | LLError::setTimeFunction(roswell); | ||
549 | mRecorder.setWantsTime(true); | ||
550 | std::string locationAndFunction = writeReturningLocationAndFunction(); | ||
551 | |||
552 | ensure_equals("order is time type location function message", | ||
553 | mRecorder.message(0), | ||
554 | roswell() + " INFO: " + locationAndFunction + ": apple"); | ||
555 | } | ||
556 | |||
557 | template<> template<> | ||
558 | // multiple recorders | ||
559 | void ErrorTestObject::test<11>() | ||
560 | { | ||
561 | TestRecorder altRecorder; | ||
562 | LLError::addRecorder(&altRecorder); | ||
563 | |||
564 | llinfos << "boo" << llendl; | ||
565 | |||
566 | ensure_message_contains(0, "boo"); | ||
567 | ensure_equals("alt recorder count", altRecorder.countMessages(), 1); | ||
568 | ensure_contains("alt recorder message 0", altRecorder.message(0), "boo"); | ||
569 | |||
570 | LLError::setTimeFunction(roswell); | ||
571 | |||
572 | TestRecorder anotherRecorder; | ||
573 | anotherRecorder.setWantsTime(true); | ||
574 | LLError::addRecorder(&anotherRecorder); | ||
575 | |||
576 | llinfos << "baz" << llendl; | ||
577 | |||
578 | std::string when = roswell(); | ||
579 | |||
580 | ensure_message_does_not_contain(1, when); | ||
581 | ensure_equals("alt recorder count", altRecorder.countMessages(), 2); | ||
582 | ensure_does_not_contain("alt recorder message 1", altRecorder.message(1), when); | ||
583 | ensure_equals("another recorder count", anotherRecorder.countMessages(), 1); | ||
584 | ensure_contains("another recorder message 0", anotherRecorder.message(0), when); | ||
585 | } | ||
586 | } | ||
587 | |||
588 | class TestAlpha | ||
589 | { | ||
590 | LOG_CLASS(TestAlpha); | ||
591 | public: | ||
592 | static void doDebug() { lldebugs << "add dice" << llendl; } | ||
593 | static void doInfo() { llinfos << "any idea" << llendl; } | ||
594 | static void doWarn() { llwarns << "aim west" << llendl; } | ||
595 | static void doError() { llerrs << "ate eels" << llendl; } | ||
596 | static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } | ||
597 | }; | ||
598 | |||
599 | class TestBeta | ||
600 | { | ||
601 | LOG_CLASS(TestBeta); | ||
602 | public: | ||
603 | static void doDebug() { lldebugs << "bed down" << llendl; } | ||
604 | static void doInfo() { llinfos << "buy iron" << llendl; } | ||
605 | static void doWarn() { llwarns << "bad word" << llendl; } | ||
606 | static void doError() { llerrs << "big easy" << llendl; } | ||
607 | static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } | ||
608 | }; | ||
609 | |||
610 | namespace tut | ||
611 | { | ||
612 | template<> template<> | ||
613 | // filtering by class | ||
614 | void ErrorTestObject::test<12>() | ||
615 | { | ||
616 | LLError::setDefaultLevel(LLError::LEVEL_WARN); | ||
617 | LLError::setClassLevel("TestBeta", LLError::LEVEL_INFO); | ||
618 | |||
619 | TestAlpha::doAll(); | ||
620 | TestBeta::doAll(); | ||
621 | |||
622 | ensure_message_contains(0, "aim west"); | ||
623 | ensure_message_contains(1, "error"); | ||
624 | ensure_message_contains(2, "ate eels"); | ||
625 | ensure_message_contains(3, "buy iron"); | ||
626 | ensure_message_contains(4, "bad word"); | ||
627 | ensure_message_contains(5, "error"); | ||
628 | ensure_message_contains(6, "big easy"); | ||
629 | ensure_message_count(7); | ||
630 | } | ||
631 | |||
632 | template<> template<> | ||
633 | // filtering by function, and that it will override class filtering | ||
634 | void ErrorTestObject::test<13>() | ||
635 | { | ||
636 | LLError::setDefaultLevel(LLError::LEVEL_DEBUG); | ||
637 | LLError::setClassLevel("TestBeta", LLError::LEVEL_WARN); | ||
638 | LLError::setFunctionLevel("TestBeta::doInfo", LLError::LEVEL_DEBUG); | ||
639 | LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE); | ||
640 | |||
641 | TestBeta::doAll(); | ||
642 | ensure_message_contains(0, "buy iron"); | ||
643 | ensure_message_contains(1, "bad word"); | ||
644 | ensure_message_count(2); | ||
645 | } | ||
646 | |||
647 | template<> template<> | ||
648 | // filtering by file | ||
649 | // and that it is overridden by both class and function filtering | ||
650 | void ErrorTestObject::test<14>() | ||
651 | { | ||
652 | LLError::setDefaultLevel(LLError::LEVEL_DEBUG); | ||
653 | LLError::setFileLevel(LLError::abbreviateFile(__FILE__), | ||
654 | LLError::LEVEL_WARN); | ||
655 | LLError::setClassLevel("TestAlpha", LLError::LEVEL_INFO); | ||
656 | LLError::setFunctionLevel("TestAlpha::doError", | ||
657 | LLError::LEVEL_NONE); | ||
658 | LLError::setFunctionLevel("TestBeta::doError", | ||
659 | LLError::LEVEL_NONE); | ||
660 | |||
661 | TestAlpha::doAll(); | ||
662 | TestBeta::doAll(); | ||
663 | ensure_message_contains(0, "any idea"); | ||
664 | ensure_message_contains(1, "aim west"); | ||
665 | ensure_message_contains(2, "bad word"); | ||
666 | ensure_message_count(3); | ||
667 | } | ||
668 | |||
669 | template<> template<> | ||
670 | // proper cached, efficient lookup of filtering | ||
671 | void ErrorTestObject::test<15>() | ||
672 | { | ||
673 | LLError::setDefaultLevel(LLError::LEVEL_NONE); | ||
674 | |||
675 | TestAlpha::doInfo(); | ||
676 | ensure_message_count(0); | ||
677 | ensure_equals("first check", LLError::shouldLogCallCount(), 1); | ||
678 | TestAlpha::doInfo(); | ||
679 | ensure_message_count(0); | ||
680 | ensure_equals("second check", LLError::shouldLogCallCount(), 1); | ||
681 | |||
682 | LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG); | ||
683 | TestAlpha::doInfo(); | ||
684 | ensure_message_count(1); | ||
685 | ensure_equals("third check", LLError::shouldLogCallCount(), 2); | ||
686 | TestAlpha::doInfo(); | ||
687 | ensure_message_count(2); | ||
688 | ensure_equals("fourth check", LLError::shouldLogCallCount(), 2); | ||
689 | |||
690 | LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN); | ||
691 | TestAlpha::doInfo(); | ||
692 | ensure_message_count(2); | ||
693 | ensure_equals("fifth check", LLError::shouldLogCallCount(), 3); | ||
694 | TestAlpha::doInfo(); | ||
695 | ensure_message_count(2); | ||
696 | ensure_equals("sixth check", LLError::shouldLogCallCount(), 3); | ||
697 | } | ||
698 | |||
699 | template<> template<> | ||
700 | // configuration from LLSD | ||
701 | void ErrorTestObject::test<16>() | ||
702 | { | ||
703 | std::string this_file = LLError::abbreviateFile(__FILE__); | ||
704 | LLSD config; | ||
705 | config["print-location"] = true; | ||
706 | config["default-level"] = "DEBUG"; | ||
707 | |||
708 | LLSD set1; | ||
709 | set1["level"] = "WARN"; | ||
710 | set1["files"][0] = this_file; | ||
711 | |||
712 | LLSD set2; | ||
713 | set2["level"] = "INFO"; | ||
714 | set2["classes"][0] = "TestAlpha"; | ||
715 | |||
716 | LLSD set3; | ||
717 | set3["level"] = "NONE"; | ||
718 | set3["functions"][0] = "TestAlpha::doError"; | ||
719 | set3["functions"][1] = "TestBeta::doError"; | ||
720 | |||
721 | config["settings"][0] = set1; | ||
722 | config["settings"][1] = set2; | ||
723 | config["settings"][2] = set3; | ||
724 | |||
725 | LLError::configure(config); | ||
726 | |||
727 | TestAlpha::doAll(); | ||
728 | TestBeta::doAll(); | ||
729 | ensure_message_contains(0, "any idea"); | ||
730 | ensure_message_contains(0, this_file); | ||
731 | ensure_message_contains(1, "aim west"); | ||
732 | ensure_message_contains(2, "bad word"); | ||
733 | ensure_message_count(3); | ||
734 | |||
735 | // make sure reconfiguring works | ||
736 | LLSD config2; | ||
737 | config2["default-level"] = "WARN"; | ||
738 | |||
739 | LLError::configure(config2); | ||
740 | |||
741 | TestAlpha::doAll(); | ||
742 | TestBeta::doAll(); | ||
743 | ensure_message_contains(3, "aim west"); | ||
744 | ensure_message_does_not_contain(3, this_file); | ||
745 | ensure_message_contains(4, "error"); | ||
746 | ensure_message_contains(5, "ate eels"); | ||
747 | ensure_message_contains(6, "bad word"); | ||
748 | ensure_message_contains(7, "error"); | ||
749 | ensure_message_contains(8, "big easy"); | ||
750 | ensure_message_count(9); | ||
751 | } | ||
752 | } | ||
753 | |||
754 | /* Tests left: | ||
755 | handling of classes without LOG_CLASS | ||
756 | |||
757 | live update of filtering from file | ||
758 | |||
759 | syslog recorder | ||
760 | file recorder | ||
761 | cerr/stderr recorder | ||
762 | fixed buffer recorder | ||
763 | windows recorder | ||
764 | |||
765 | mutex use when logging (?) | ||
766 | strange careful about to crash handling (?) | ||
767 | */ | ||