PageRenderTime 36ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llcommon/tests/llerror_test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 762 lines | 576 code | 114 blank | 72 comment | 3 complexity | 3927d0e4bc6a41f3336f016e5702b3d5 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llerror_test.cpp
  3. * @date December 2006
  4. * @brief error unit tests
  5. *
  6. * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  7. * Second Life Viewer Source Code
  8. * Copyright (C) 2010, Linden Research, Inc.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation;
  13. * version 2.1 of the License only.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  25. * $/LicenseInfo$
  26. */
  27. #include <vector>
  28. #include "linden_common.h"
  29. #include "../llerror.h"
  30. #include "../llerrorcontrol.h"
  31. #include "../llsd.h"
  32. #include "../test/lltut.h"
  33. namespace
  34. {
  35. void test_that_error_h_includes_enough_things_to_compile_a_message()
  36. {
  37. llinfos << "!" << llendl;
  38. }
  39. }
  40. namespace
  41. {
  42. static bool fatalWasCalled;
  43. void fatalCall(const std::string&) { fatalWasCalled = true; }
  44. }
  45. namespace tut
  46. {
  47. class TestRecorder : public LLError::Recorder
  48. {
  49. public:
  50. TestRecorder() : mWantsTime(false) { }
  51. ~TestRecorder() { LLError::removeRecorder(this); }
  52. void recordMessage(LLError::ELevel level,
  53. const std::string& message)
  54. {
  55. mMessages.push_back(message);
  56. }
  57. int countMessages() { return (int) mMessages.size(); }
  58. void clearMessages() { mMessages.clear(); }
  59. void setWantsTime(bool t) { mWantsTime = t; }
  60. bool wantsTime() { return mWantsTime; }
  61. std::string message(int n)
  62. {
  63. std::ostringstream test_name;
  64. test_name << "testing message " << n << ", not enough messages";
  65. tut::ensure(test_name.str(), n < countMessages());
  66. return mMessages[n];
  67. }
  68. private:
  69. typedef std::vector<std::string> MessageVector;
  70. MessageVector mMessages;
  71. bool mWantsTime;
  72. };
  73. struct ErrorTestData
  74. {
  75. TestRecorder mRecorder;
  76. LLError::Settings* mPriorErrorSettings;
  77. ErrorTestData()
  78. {
  79. fatalWasCalled = false;
  80. mPriorErrorSettings = LLError::saveAndResetSettings();
  81. LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
  82. LLError::setFatalFunction(fatalCall);
  83. LLError::addRecorder(&mRecorder);
  84. }
  85. ~ErrorTestData()
  86. {
  87. LLError::removeRecorder(&mRecorder);
  88. LLError::restoreSettings(mPriorErrorSettings);
  89. }
  90. void ensure_message_count(int expectedCount)
  91. {
  92. ensure_equals("message count", mRecorder.countMessages(), expectedCount);
  93. }
  94. void ensure_message_contains(int n, const std::string& expectedText)
  95. {
  96. std::ostringstream test_name;
  97. test_name << "testing message " << n;
  98. ensure_contains(test_name.str(), mRecorder.message(n), expectedText);
  99. }
  100. void ensure_message_does_not_contain(int n, const std::string& expectedText)
  101. {
  102. std::ostringstream test_name;
  103. test_name << "testing message " << n;
  104. ensure_does_not_contain(test_name.str(), mRecorder.message(n), expectedText);
  105. }
  106. };
  107. typedef test_group<ErrorTestData> ErrorTestGroup;
  108. typedef ErrorTestGroup::object ErrorTestObject;
  109. ErrorTestGroup errorTestGroup("error");
  110. template<> template<>
  111. void ErrorTestObject::test<1>()
  112. // basic test of output
  113. {
  114. llinfos << "test" << llendl;
  115. llinfos << "bob" << llendl;
  116. ensure_message_contains(0, "test");
  117. ensure_message_contains(1, "bob");
  118. }
  119. }
  120. namespace
  121. {
  122. void writeSome()
  123. {
  124. lldebugs << "one" << llendl;
  125. llinfos << "two" << llendl;
  126. llwarns << "three" << llendl;
  127. llerrs << "four" << llendl;
  128. // fatal messages write out and addtional "error" message
  129. }
  130. };
  131. namespace tut
  132. {
  133. template<> template<>
  134. void ErrorTestObject::test<2>()
  135. // messages are filtered based on default level
  136. {
  137. LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
  138. writeSome();
  139. ensure_message_contains(0, "one");
  140. ensure_message_contains(1, "two");
  141. ensure_message_contains(2, "three");
  142. ensure_message_contains(3, "error");
  143. ensure_message_contains(4, "four");
  144. ensure_message_count(5);
  145. LLError::setDefaultLevel(LLError::LEVEL_INFO);
  146. writeSome();
  147. ensure_message_contains(5, "two");
  148. ensure_message_contains(6, "three");
  149. ensure_message_contains(7, "error");
  150. ensure_message_contains(8, "four");
  151. ensure_message_count(9);
  152. LLError::setDefaultLevel(LLError::LEVEL_WARN);
  153. writeSome();
  154. ensure_message_contains(9, "three");
  155. ensure_message_contains(10, "error");
  156. ensure_message_contains(11, "four");
  157. ensure_message_count(12);
  158. LLError::setDefaultLevel(LLError::LEVEL_ERROR);
  159. writeSome();
  160. ensure_message_contains(12, "error");
  161. ensure_message_contains(13, "four");
  162. ensure_message_count(14);
  163. LLError::setDefaultLevel(LLError::LEVEL_NONE);
  164. writeSome();
  165. ensure_message_count(14);
  166. }
  167. template<> template<>
  168. void ErrorTestObject::test<3>()
  169. // error type string in output
  170. {
  171. writeSome();
  172. ensure_message_contains(0, "DEBUG: ");
  173. ensure_message_contains(1, "INFO: ");
  174. ensure_message_contains(2, "WARNING: ");
  175. ensure_message_does_not_contain(3, "ERROR");
  176. ensure_message_contains(4, "ERROR: ");
  177. ensure_message_count(5);
  178. }
  179. template<> template<>
  180. void ErrorTestObject::test<4>()
  181. // file abbreviation
  182. {
  183. std::string thisFile = __FILE__;
  184. std::string abbreviateFile = LLError::abbreviateFile(thisFile);
  185. ensure_ends_with("file name abbreviation",
  186. abbreviateFile,
  187. "llcommon/tests/llerror_test.cpp"
  188. );
  189. ensure_does_not_contain("file name abbreviation",
  190. abbreviateFile, "indra");
  191. std::string someFile =
  192. #if LL_WINDOWS
  193. "C:/amy/bob/cam.cpp"
  194. #else
  195. "/amy/bob/cam.cpp"
  196. #endif
  197. ;
  198. std::string someAbbreviation = LLError::abbreviateFile(someFile);
  199. ensure_equals("non-indra file abbreviation",
  200. someAbbreviation, someFile);
  201. }
  202. }
  203. namespace
  204. {
  205. std::string locationString(int line)
  206. {
  207. std::ostringstream location;
  208. location << LLError::abbreviateFile(__FILE__)
  209. << "(" << line << ") : ";
  210. return location.str();
  211. }
  212. std::string writeReturningLocation()
  213. {
  214. llinfos << "apple" << llendl; int this_line = __LINE__;
  215. return locationString(this_line);
  216. }
  217. std::string writeReturningLocationAndFunction()
  218. {
  219. llinfos << "apple" << llendl; int this_line = __LINE__;
  220. return locationString(this_line) + __FUNCTION__;
  221. }
  222. std::string errorReturningLocation()
  223. {
  224. llerrs << "die" << llendl; int this_line = __LINE__;
  225. return locationString(this_line);
  226. }
  227. }
  228. namespace tut
  229. {
  230. template<> template<>
  231. void ErrorTestObject::test<5>()
  232. // file and line information in log messages
  233. {
  234. std::string location = writeReturningLocation();
  235. // expecting default to not print location information
  236. LLError::setPrintLocation(true);
  237. writeReturningLocation();
  238. LLError::setPrintLocation(false);
  239. writeReturningLocation();
  240. ensure_message_does_not_contain(0, location);
  241. ensure_message_contains(1, location);
  242. ensure_message_does_not_contain(2, location);
  243. }
  244. }
  245. /* The following helper functions and class members all log a simple message
  246. from some particular function scope. Each function takes a bool argument
  247. that indicates if it should log its own name or not (in the manner that
  248. existing log messages often do.) The functions all return their C++
  249. name so that test can be substantial mechanized.
  250. */
  251. std::string logFromGlobal(bool id)
  252. {
  253. llinfos << (id ? "logFromGlobal: " : "") << "hi" << llendl;
  254. return "logFromGlobal";
  255. }
  256. static std::string logFromStatic(bool id)
  257. {
  258. llinfos << (id ? "logFromStatic: " : "") << "hi" << llendl;
  259. return "logFromStatic";
  260. }
  261. namespace
  262. {
  263. std::string logFromAnon(bool id)
  264. {
  265. llinfos << (id ? "logFromAnon: " : "") << "hi" << llendl;
  266. return "logFromAnon";
  267. }
  268. }
  269. namespace Foo {
  270. std::string logFromNamespace(bool id)
  271. {
  272. llinfos << (id ? "Foo::logFromNamespace: " : "") << "hi" << llendl;
  273. //return "Foo::logFromNamespace";
  274. // there is no standard way to get the namespace name, hence
  275. // we won't be testing for it
  276. return "logFromNamespace";
  277. }
  278. }
  279. namespace
  280. {
  281. class ClassWithNoLogType {
  282. public:
  283. std::string logFromMember(bool id)
  284. {
  285. llinfos << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << llendl;
  286. return "ClassWithNoLogType::logFromMember";
  287. }
  288. static std::string logFromStatic(bool id)
  289. {
  290. llinfos << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << llendl;
  291. return "ClassWithNoLogType::logFromStatic";
  292. }
  293. };
  294. class ClassWithLogType {
  295. LOG_CLASS(ClassWithLogType);
  296. public:
  297. std::string logFromMember(bool id)
  298. {
  299. llinfos << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << llendl;
  300. return "ClassWithLogType::logFromMember";
  301. }
  302. static std::string logFromStatic(bool id)
  303. {
  304. llinfos << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << llendl;
  305. return "ClassWithLogType::logFromStatic";
  306. }
  307. };
  308. std::string logFromNamespace(bool id) { return Foo::logFromNamespace(id); }
  309. std::string logFromClassWithNoLogTypeMember(bool id) { ClassWithNoLogType c; return c.logFromMember(id); }
  310. std::string logFromClassWithNoLogTypeStatic(bool id) { return ClassWithNoLogType::logFromStatic(id); }
  311. std::string logFromClassWithLogTypeMember(bool id) { ClassWithLogType c; return c.logFromMember(id); }
  312. std::string logFromClassWithLogTypeStatic(bool id) { return ClassWithLogType::logFromStatic(id); }
  313. void ensure_has(const std::string& message,
  314. const std::string& actual, const std::string& expected)
  315. {
  316. std::string::size_type n1 = actual.find(expected);
  317. if (n1 == std::string::npos)
  318. {
  319. std::stringstream ss;
  320. ss << message << ": " << "expected to find a copy of " << expected
  321. << " in actual " << actual;
  322. throw tut::failure(ss.str().c_str());
  323. }
  324. }
  325. typedef std::string (*LogFromFunction)(bool);
  326. void testLogName(tut::TestRecorder& recorder, LogFromFunction f,
  327. const std::string& class_name = "")
  328. {
  329. recorder.clearMessages();
  330. std::string name = f(false);
  331. f(true);
  332. std::string messageWithoutName = recorder.message(0);
  333. std::string messageWithName = recorder.message(1);
  334. ensure_has(name + " logged without name",
  335. messageWithoutName, name);
  336. ensure_has(name + " logged with name",
  337. messageWithName, name);
  338. if (!class_name.empty())
  339. {
  340. ensure_has(name + "logged without name",
  341. messageWithoutName, class_name);
  342. ensure_has(name + "logged with name",
  343. messageWithName, class_name);
  344. }
  345. }
  346. }
  347. namespace tut
  348. {
  349. template<> template<>
  350. // class/function information in output
  351. void ErrorTestObject::test<6>()
  352. {
  353. testLogName(mRecorder, logFromGlobal);
  354. testLogName(mRecorder, logFromStatic);
  355. testLogName(mRecorder, logFromAnon);
  356. testLogName(mRecorder, logFromNamespace);
  357. //testLogName(mRecorder, logFromClassWithNoLogTypeMember, "ClassWithNoLogType");
  358. //testLogName(mRecorder, logFromClassWithNoLogTypeStatic, "ClassWithNoLogType");
  359. // XXX: figure out what the exepcted response is for these
  360. testLogName(mRecorder, logFromClassWithLogTypeMember, "ClassWithLogType");
  361. testLogName(mRecorder, logFromClassWithLogTypeStatic, "ClassWithLogType");
  362. }
  363. }
  364. namespace
  365. {
  366. std::string innerLogger()
  367. {
  368. llinfos << "inside" << llendl;
  369. return "moo";
  370. }
  371. std::string outerLogger()
  372. {
  373. llinfos << "outside(" << innerLogger() << ")" << llendl;
  374. return "bar";
  375. }
  376. void uberLogger()
  377. {
  378. llinfos << "uber(" << outerLogger() << "," << innerLogger() << ")" << llendl;
  379. }
  380. class LogWhileLogging
  381. {
  382. public:
  383. void print(std::ostream& out) const
  384. {
  385. llinfos << "logging" << llendl;
  386. out << "baz";
  387. }
  388. };
  389. std::ostream& operator<<(std::ostream& out, const LogWhileLogging& l)
  390. { l.print(out); return out; }
  391. void metaLogger()
  392. {
  393. LogWhileLogging l;
  394. llinfos << "meta(" << l << ")" << llendl;
  395. }
  396. }
  397. namespace tut
  398. {
  399. template<> template<>
  400. // handle nested logging
  401. void ErrorTestObject::test<7>()
  402. {
  403. outerLogger();
  404. ensure_message_contains(0, "inside");
  405. ensure_message_contains(1, "outside(moo)");
  406. ensure_message_count(2);
  407. uberLogger();
  408. ensure_message_contains(2, "inside");
  409. ensure_message_contains(3, "inside");
  410. ensure_message_contains(4, "outside(moo)");
  411. ensure_message_contains(5, "uber(bar,moo)");
  412. ensure_message_count(6);
  413. metaLogger();
  414. ensure_message_contains(6, "logging");
  415. ensure_message_contains(7, "meta(baz)");
  416. ensure_message_count(8);
  417. }
  418. template<> template<>
  419. // special handling of llerrs calls
  420. void ErrorTestObject::test<8>()
  421. {
  422. LLError::setPrintLocation(false);
  423. std::string location = errorReturningLocation();
  424. ensure_message_contains(0, location + "error");
  425. ensure_message_contains(1, "die");
  426. ensure_message_count(2);
  427. ensure("fatal callback called", fatalWasCalled);
  428. }
  429. }
  430. namespace
  431. {
  432. std::string roswell()
  433. {
  434. return "1947-07-08T03:04:05Z";
  435. }
  436. void ufoSighting()
  437. {
  438. llinfos << "ufo" << llendl;
  439. }
  440. }
  441. namespace tut
  442. {
  443. template<> template<>
  444. // time in output (for recorders that need it)
  445. void ErrorTestObject::test<9>()
  446. {
  447. LLError::setTimeFunction(roswell);
  448. mRecorder.setWantsTime(false);
  449. ufoSighting();
  450. ensure_message_contains(0, "ufo");
  451. ensure_message_does_not_contain(0, roswell());
  452. mRecorder.setWantsTime(true);
  453. ufoSighting();
  454. ensure_message_contains(1, "ufo");
  455. ensure_message_contains(1, roswell());
  456. }
  457. template<> template<>
  458. // output order
  459. void ErrorTestObject::test<10>()
  460. {
  461. LLError::setPrintLocation(true);
  462. LLError::setTimeFunction(roswell);
  463. mRecorder.setWantsTime(true);
  464. std::string locationAndFunction = writeReturningLocationAndFunction();
  465. ensure_equals("order is time type location function message",
  466. mRecorder.message(0),
  467. roswell() + " INFO: " + locationAndFunction + ": apple");
  468. }
  469. template<> template<>
  470. // multiple recorders
  471. void ErrorTestObject::test<11>()
  472. {
  473. TestRecorder altRecorder;
  474. LLError::addRecorder(&altRecorder);
  475. llinfos << "boo" << llendl;
  476. ensure_message_contains(0, "boo");
  477. ensure_equals("alt recorder count", altRecorder.countMessages(), 1);
  478. ensure_contains("alt recorder message 0", altRecorder.message(0), "boo");
  479. LLError::setTimeFunction(roswell);
  480. TestRecorder anotherRecorder;
  481. anotherRecorder.setWantsTime(true);
  482. LLError::addRecorder(&anotherRecorder);
  483. llinfos << "baz" << llendl;
  484. std::string when = roswell();
  485. ensure_message_does_not_contain(1, when);
  486. ensure_equals("alt recorder count", altRecorder.countMessages(), 2);
  487. ensure_does_not_contain("alt recorder message 1", altRecorder.message(1), when);
  488. ensure_equals("another recorder count", anotherRecorder.countMessages(), 1);
  489. ensure_contains("another recorder message 0", anotherRecorder.message(0), when);
  490. }
  491. }
  492. class TestAlpha
  493. {
  494. LOG_CLASS(TestAlpha);
  495. public:
  496. static void doDebug() { lldebugs << "add dice" << llendl; }
  497. static void doInfo() { llinfos << "any idea" << llendl; }
  498. static void doWarn() { llwarns << "aim west" << llendl; }
  499. static void doError() { llerrs << "ate eels" << llendl; }
  500. static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }
  501. };
  502. class TestBeta
  503. {
  504. LOG_CLASS(TestBeta);
  505. public:
  506. static void doDebug() { lldebugs << "bed down" << llendl; }
  507. static void doInfo() { llinfos << "buy iron" << llendl; }
  508. static void doWarn() { llwarns << "bad word" << llendl; }
  509. static void doError() { llerrs << "big easy" << llendl; }
  510. static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }
  511. };
  512. namespace tut
  513. {
  514. template<> template<>
  515. // filtering by class
  516. void ErrorTestObject::test<12>()
  517. {
  518. LLError::setDefaultLevel(LLError::LEVEL_WARN);
  519. LLError::setClassLevel("TestBeta", LLError::LEVEL_INFO);
  520. TestAlpha::doAll();
  521. TestBeta::doAll();
  522. ensure_message_contains(0, "aim west");
  523. ensure_message_contains(1, "error");
  524. ensure_message_contains(2, "ate eels");
  525. ensure_message_contains(3, "buy iron");
  526. ensure_message_contains(4, "bad word");
  527. ensure_message_contains(5, "error");
  528. ensure_message_contains(6, "big easy");
  529. ensure_message_count(7);
  530. }
  531. template<> template<>
  532. // filtering by function, and that it will override class filtering
  533. void ErrorTestObject::test<13>()
  534. {
  535. LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
  536. LLError::setClassLevel("TestBeta", LLError::LEVEL_WARN);
  537. LLError::setFunctionLevel("TestBeta::doInfo", LLError::LEVEL_DEBUG);
  538. LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE);
  539. TestBeta::doAll();
  540. ensure_message_contains(0, "buy iron");
  541. ensure_message_contains(1, "bad word");
  542. ensure_message_count(2);
  543. }
  544. template<> template<>
  545. // filtering by file
  546. // and that it is overridden by both class and function filtering
  547. void ErrorTestObject::test<14>()
  548. {
  549. LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
  550. LLError::setFileLevel(LLError::abbreviateFile(__FILE__),
  551. LLError::LEVEL_WARN);
  552. LLError::setClassLevel("TestAlpha", LLError::LEVEL_INFO);
  553. LLError::setFunctionLevel("TestAlpha::doError",
  554. LLError::LEVEL_NONE);
  555. LLError::setFunctionLevel("TestBeta::doError",
  556. LLError::LEVEL_NONE);
  557. TestAlpha::doAll();
  558. TestBeta::doAll();
  559. ensure_message_contains(0, "any idea");
  560. ensure_message_contains(1, "aim west");
  561. ensure_message_contains(2, "bad word");
  562. ensure_message_count(3);
  563. }
  564. template<> template<>
  565. // proper cached, efficient lookup of filtering
  566. void ErrorTestObject::test<15>()
  567. {
  568. LLError::setDefaultLevel(LLError::LEVEL_NONE);
  569. TestAlpha::doInfo();
  570. ensure_message_count(0);
  571. ensure_equals("first check", LLError::shouldLogCallCount(), 1);
  572. TestAlpha::doInfo();
  573. ensure_message_count(0);
  574. ensure_equals("second check", LLError::shouldLogCallCount(), 1);
  575. LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG);
  576. TestAlpha::doInfo();
  577. ensure_message_count(1);
  578. ensure_equals("third check", LLError::shouldLogCallCount(), 2);
  579. TestAlpha::doInfo();
  580. ensure_message_count(2);
  581. ensure_equals("fourth check", LLError::shouldLogCallCount(), 2);
  582. LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN);
  583. TestAlpha::doInfo();
  584. ensure_message_count(2);
  585. ensure_equals("fifth check", LLError::shouldLogCallCount(), 3);
  586. TestAlpha::doInfo();
  587. ensure_message_count(2);
  588. ensure_equals("sixth check", LLError::shouldLogCallCount(), 3);
  589. }
  590. template<> template<>
  591. // configuration from LLSD
  592. void ErrorTestObject::test<16>()
  593. {
  594. std::string this_file = LLError::abbreviateFile(__FILE__);
  595. LLSD config;
  596. config["print-location"] = true;
  597. config["default-level"] = "DEBUG";
  598. LLSD set1;
  599. set1["level"] = "WARN";
  600. set1["files"][0] = this_file;
  601. LLSD set2;
  602. set2["level"] = "INFO";
  603. set2["classes"][0] = "TestAlpha";
  604. LLSD set3;
  605. set3["level"] = "NONE";
  606. set3["functions"][0] = "TestAlpha::doError";
  607. set3["functions"][1] = "TestBeta::doError";
  608. config["settings"][0] = set1;
  609. config["settings"][1] = set2;
  610. config["settings"][2] = set3;
  611. LLError::configure(config);
  612. TestAlpha::doAll();
  613. TestBeta::doAll();
  614. ensure_message_contains(0, "any idea");
  615. ensure_message_contains(0, this_file);
  616. ensure_message_contains(1, "aim west");
  617. ensure_message_contains(2, "bad word");
  618. ensure_message_count(3);
  619. // make sure reconfiguring works
  620. LLSD config2;
  621. config2["default-level"] = "WARN";
  622. LLError::configure(config2);
  623. TestAlpha::doAll();
  624. TestBeta::doAll();
  625. ensure_message_contains(3, "aim west");
  626. ensure_message_does_not_contain(3, this_file);
  627. ensure_message_contains(4, "error");
  628. ensure_message_contains(5, "ate eels");
  629. ensure_message_contains(6, "bad word");
  630. ensure_message_contains(7, "error");
  631. ensure_message_contains(8, "big easy");
  632. ensure_message_count(9);
  633. }
  634. }
  635. /* Tests left:
  636. handling of classes without LOG_CLASS
  637. live update of filtering from file
  638. syslog recorder
  639. file recorder
  640. cerr/stderr recorder
  641. fixed buffer recorder
  642. windows recorder
  643. mutex use when logging (?)
  644. strange careful about to crash handling (?)
  645. */