libwreport  3.42
utils/tests.h
1 #ifndef WREPORT_TESTS_H
2 #define WREPORT_TESTS_H
3 
13 #include <cstdint>
14 #include <exception>
15 #include <filesystem>
16 #include <functional>
17 #include <sstream>
18 #include <string>
19 #include <vector>
20 
21 namespace wreport::tests {
22 struct LocationInfo;
23 } // namespace wreport::tests
24 
25 /*
26  * These global arguments will be shadowed by local variables in functions that
27  * implement tests.
28  *
29  * They are here to act as default root nodes to fulfill method signatures when
30  * tests are called from outside other tests.
31  */
32 extern const wreport::tests::LocationInfo wreport_test_location_info;
33 
34 namespace wreport::tests {
35 
53 struct LocationInfo : public std::stringstream
54 {
55  LocationInfo() {}
56 
61  std::ostream& operator()();
62 };
63 
66 {
67  const char* file;
68  int line;
69  const char* call;
70  std::string local_info;
71 
72  TestStackFrame(const char* file_, int line_, const char* call_)
73  : file(file_), line(line_), call(call_)
74  {
75  }
76 
77  TestStackFrame(const char* file_, int line_, const char* call_,
78  const LocationInfo& local_info_)
79  : file(file_), line(line_), call(call_), local_info(local_info_.str())
80  {
81  }
82 
83  std::string format() const;
84 
85  void format(std::ostream& out) const;
86 };
87 
88 struct TestStack : public std::vector<TestStackFrame>
89 {
90  using vector::vector;
91 
93  std::string backtrace() const;
94 
96  void backtrace(std::ostream& out) const;
97 };
98 
103 struct TestFailed : public std::exception
104 {
105  std::string message;
106  TestStack stack;
107 
108  explicit TestFailed(const std::exception& e);
109 
110  template <typename... Args>
111  TestFailed(const std::exception& e, Args&&... args) : TestFailed(e)
112  {
113  add_stack_info(std::forward<Args>(args)...);
114  }
115 
116  explicit TestFailed(const std::string& message_) : message(message_) {}
117 
118  template <typename... Args>
119  TestFailed(const std::string& message_, Args&&... args)
120  : TestFailed(message_)
121  {
122  add_stack_info(std::forward<Args>(args)...);
123  }
124 
125  const char* what() const noexcept override { return message.c_str(); }
126 
127  template <typename... Args> void add_stack_info(Args&&... args)
128  {
129  stack.emplace_back(std::forward<Args>(args)...);
130  }
131 };
132 
136 struct TestSkipped : public std::exception
137 {
138  std::string reason;
139 
140  TestSkipped();
141  explicit TestSkipped(const std::string& reason);
142 };
143 
148 #define WREPORT_TEST_INFO(name) \
149  wreport::tests::LocationInfo wreport_test_location_info; \
150  wreport::tests::LocationInfo& name = wreport_test_location_info
151 
159 template <typename A> void assert_true(const A& actual)
161 {
162  if (actual)
163  return;
164  std::stringstream ss;
165  ss << "actual value " << actual << " is not true";
166  throw TestFailed(ss.str());
167 }
168 
169 [[noreturn]] void assert_true(std::nullptr_t actual);
170 
172 template <typename A> void assert_false(const A& actual)
173 {
174  if (!actual)
175  return;
176  std::stringstream ss;
177  ss << "actual value " << actual << " is not false";
178  throw TestFailed(ss.str());
179 }
180 
181 void assert_false(std::nullptr_t actual);
182 
183 template <typename LIST>
184 static inline void _format_list(std::ostream& o, const LIST& list)
185 {
186  bool first = true;
187  o << "[";
188  for (const auto& v : list)
189  {
190  if (first)
191  first = false;
192  else
193  o << ", ";
194  o << v;
195  }
196  o << "]";
197 }
198 
199 template <typename T>
200 void assert_equal(const std::vector<T>& actual, const std::vector<T>& expected)
201 {
202  if (actual == expected)
203  return;
204  std::stringstream ss;
205  ss << "value ";
206  _format_list(ss, actual);
207  ss << " is different than the expected ";
208  _format_list(ss, expected);
209  throw TestFailed(ss.str());
210 }
211 
212 template <typename T>
213 void assert_equal(const std::vector<T>& actual,
214  const std::initializer_list<T>& expected)
215 {
216  if (actual == expected)
217  return;
218  std::stringstream ss;
219  ss << "value ";
220  _format_list(ss, actual);
221  ss << " is different than the expected ";
222  _format_list(ss, expected);
223  throw TestFailed(ss.str());
224 }
225 
230 template <typename A, typename E>
231 void assert_equal(const A& actual, const E& expected)
232 {
233  if (actual == expected)
234  return;
235  std::stringstream ss;
236  ss << "value '" << actual << "' is different than the expected '"
237  << expected << "'";
238  throw TestFailed(ss.str());
239 }
240 
245 template <typename A, typename E>
246 void assert_not_equal(const A& actual, const E& expected)
247 {
248  if (actual != expected)
249  return;
250  std::stringstream ss;
251  ss << "value '" << actual << "' is not different than the expected '"
252  << expected << "'";
253  throw TestFailed(ss.str());
254 }
255 
257 template <typename A, typename E>
258 void assert_less(const A& actual, const E& expected)
259 {
260  if (actual < expected)
261  return;
262  std::stringstream ss;
263  ss << "value '" << actual << "' is not less than the expected '" << expected
264  << "'";
265  throw TestFailed(ss.str());
266 }
267 
269 template <typename A, typename E>
270 void assert_less_equal(const A& actual, const E& expected)
271 {
272  if (actual <= expected)
273  return;
274  std::stringstream ss;
275  ss << "value '" << actual
276  << "' is not less than or equals to the expected '" << expected << "'";
277  throw TestFailed(ss.str());
278 }
279 
281 template <typename A, typename E>
282 void assert_greater(const A& actual, const E& expected)
283 {
284  if (actual > expected)
285  return;
286  std::stringstream ss;
287  ss << "value '" << actual << "' is not greater than the expected '"
288  << expected << "'";
289  throw TestFailed(ss.str());
290 }
291 
293 template <typename A, typename E>
294 void assert_greater_equal(const A& actual, const E& expected)
295 {
296  if (actual >= expected)
297  return;
298  std::stringstream ss;
299  ss << "value '" << actual
300  << "' is not greater than or equals to the expected '" << expected
301  << "'";
302  throw TestFailed(ss.str());
303 }
304 
306 void assert_startswith(const std::string& actual, const std::string& expected);
307 
309 void assert_endswith(const std::string& actual, const std::string& expected);
310 
312 void assert_contains(const std::string& actual, const std::string& expected);
313 
315 void assert_not_contains(const std::string& actual,
316  const std::string& expected);
317 
324 void assert_re_matches(const std::string& actual, const std::string& expected);
325 
332 void assert_not_re_matches(const std::string& actual,
333  const std::string& expected);
334 
335 template <class A> struct Actual
336 {
337  A _actual;
338  Actual(const A& actual) : _actual(actual) {}
339  Actual(const Actual&) = default;
340  Actual(Actual&&) = default;
341  ~Actual() = default;
342  Actual& operator=(const Actual&) = delete;
343  Actual& operator=(Actual&&) = delete;
344 
345  void istrue() const { assert_true(_actual); }
346  void isfalse() const { assert_false(_actual); }
347  template <typename E> void operator==(const E& expected) const
348  {
349  assert_equal(_actual, expected);
350  }
351  template <typename E> void operator!=(const E& expected) const
352  {
353  assert_not_equal(_actual, expected);
354  }
355  template <typename E> void operator<(const E& expected) const
356  {
357  return assert_less(_actual, expected);
358  }
359  template <typename E> void operator<=(const E& expected) const
360  {
361  return assert_less_equal(_actual, expected);
362  }
363  template <typename E> void operator>(const E& expected) const
364  {
365  return assert_greater(_actual, expected);
366  }
367  template <typename E> void operator>=(const E& expected) const
368  {
369  return assert_greater_equal(_actual, expected);
370  }
371 };
372 
373 template <typename T> inline Actual<int> actual_int(const T& value)
374 {
375  return Actual<int>(value);
376 }
377 template <typename T> inline Actual<unsigned> actual_unsigned(const T& value)
378 {
379  return Actual<unsigned>(value);
380 }
381 template <typename T> inline Actual<double> actual_double(const T& value)
382 {
383  return Actual<double>(value);
384 }
385 
387 {
388  const char* _actual;
389  ActualCString(const char* s) : _actual(s) {}
390 
391  void istrue() const { return assert_true(_actual); }
392  void isfalse() const { return assert_false(_actual); }
393  void operator==(const char* expected) const;
394  void operator==(const std::string& expected) const;
395  void operator!=(const char* expected) const;
396  void operator!=(const std::string& expected) const;
397  void operator<(const std::string& expected) const;
398  void operator<=(const std::string& expected) const;
399  void operator>(const std::string& expected) const;
400  void operator>=(const std::string& expected) const;
401  void startswith(const std::string& expected) const;
402  void endswith(const std::string& expected) const;
403  void contains(const std::string& expected) const;
404  void not_contains(const std::string& expected) const;
405  void matches(const std::string& re) const;
406  void not_matches(const std::string& re) const;
407 };
408 
409 struct ActualStdString : public Actual<std::string>
410 {
411  explicit ActualStdString(const std::string& s) : Actual<std::string>(s) {}
412 
414  void operator==(const std::vector<uint8_t>& expected) const;
416  void operator!=(const std::vector<uint8_t>& expected) const;
417  void startswith(const std::string& expected) const;
418  void endswith(const std::string& expected) const;
419  void contains(const std::string& expected) const;
420  void not_contains(const std::string& expected) const;
421  void matches(const std::string& re) const;
422  void not_matches(const std::string& re) const;
423 };
424 
425 struct ActualPath : public Actual<std::filesystem::path>
426 {
427  explicit ActualPath(const std::filesystem::path& p)
429  {
430  }
431 
434 
435  // Check if the normalized paths match
436  void is(const std::filesystem::path& expected) const;
437  [[deprecated("Use path_startswith")]] void
438  startswith(const std::string& data) const;
439 
440  void path_startswith(const std::filesystem::path& expected) const;
441  void path_endswith(const std::filesystem::path& expected) const;
442  void path_contains(const std::filesystem::path& expected) const;
443  void path_not_contains(const std::filesystem::path& expected) const;
444 
445  void exists() const;
446  void not_exists() const;
447  void empty() const;
448  void not_empty() const;
449 
450  void contents_startwith(const std::string& data) const;
451  void contents_equal(const std::string& data) const;
452  void contents_equal(const std::vector<uint8_t>& data) const;
453  void contents_equal(const std::initializer_list<std::string>& lines) const;
454  void contents_match(const std::string& data_re) const;
455  void
456  contents_match(const std::initializer_list<std::string>& lines_re) const;
457 };
458 
459 struct ActualDouble : public Actual<double>
460 {
461  using Actual::Actual;
462 
463  void almost_equal(double expected, unsigned places) const;
464  void not_almost_equal(double expected, unsigned places) const;
465 };
466 
467 template <typename A> inline Actual<A> actual(const A& actual)
468 {
469  return Actual<A>(actual);
470 }
471 inline ActualCString actual(const char* actual)
472 {
473  return ActualCString(actual);
474 }
475 inline ActualCString actual(char* actual) { return ActualCString(actual); }
476 inline ActualStdString actual(const std::string& actual)
477 {
478  return ActualStdString(actual);
479 }
480 inline ActualStdString actual(const std::vector<uint8_t>& actual)
481 {
482  return ActualStdString(std::string(actual.begin(), actual.end()));
483 }
484 inline ActualPath actual(const std::filesystem::path& actual)
485 {
486  return ActualPath(actual);
487 }
488 inline ActualDouble actual(double actual) { return ActualDouble(actual); }
489 
490 struct ActualFunction : public Actual<std::function<void()>>
491 {
492  using Actual::Actual;
493 
494  void throws(const std::string& what_match) const;
495 };
496 
497 inline ActualFunction actual_function(std::function<void()> actual)
498 {
499  return ActualFunction(actual);
500 }
501 
502 inline ActualPath actual_path(const char* pathname)
503 {
504  return ActualPath(pathname);
505 }
506 inline ActualPath actual_path(const std::string& pathname)
507 {
508  return ActualPath(pathname);
509 }
510 inline ActualPath actual_file(const char* pathname)
511 {
512  return ActualPath(pathname);
513 }
514 inline ActualPath actual_file(const std::string& pathname)
515 {
516  return ActualPath(pathname);
517 }
518 
519 template <typename T> struct ActualVector : public Actual<std::vector<T>>
520 {
521  explicit ActualVector(const std::vector<T>& v) : Actual<std::vector<T>>(v)
522  {
523  }
524 
525  void _print_vector(std::ostream& o, const std::vector<T>& value) const
526  {
527  o << "[";
528  bool first = true;
529  for (const auto& el : value)
530  {
531  if (first)
532  first = false;
533  else
534  o << ", ";
535  o << el;
536  }
537  o << "]";
538  }
539 
540  void operator==(const std::vector<T>& expected)
541  {
542  if (expected == this->_actual)
543  return;
544  std::stringstream ss;
545  ss << "Vector ";
546  _print_vector(ss, this->_actual);
547  ss << " is not the same as expected ";
548  _print_vector(ss, expected);
549  throw TestFailed(ss.str());
550  }
551 
552  void operator!=(const std::vector<T>& expected)
553  {
554  if (expected != this->_actual)
555  return;
556  std::stringstream ss;
557  ss << "Vector ";
558  _print_vector(ss, this->_actual);
559  ss << " unexpectedly matches the value provided";
560  throw TestFailed(ss.str());
561  }
562 };
563 
564 template <typename T>
565 inline ActualVector<T> actual(const std::vector<T>& actual)
566 {
567  return ActualVector(actual);
568 }
569 
577 #define wassert(...) \
578  do \
579  { \
580  try \
581  { \
582  __VA_ARGS__; \
583  } \
584  catch (wreport::tests::TestFailed & e1) \
585  { \
586  e1.add_stack_info(__FILE__, __LINE__, #__VA_ARGS__, \
587  wreport_test_location_info); \
588  throw; \
589  } \
590  catch (std::exception & e2) \
591  { \
592  throw wreport::tests::TestFailed(e2, __FILE__, __LINE__, \
593  #__VA_ARGS__, \
594  wreport_test_location_info); \
595  } \
596  } while (0)
597 
599 #define wassert_true(...) wassert(actual(__VA_ARGS__).istrue())
600 
602 #define wassert_false(...) wassert(actual(__VA_ARGS__).isfalse())
603 
609 #define wassert_throws(exc, ...) \
610  [&]() { \
611  try \
612  { \
613  __VA_ARGS__; \
614  wfail_test(#__VA_ARGS__ " did not throw " #exc); \
615  } \
616  catch (TestFailed & e1) \
617  { \
618  throw; \
619  } \
620  catch (exc & e2) \
621  { \
622  return e2; \
623  } \
624  catch (std::exception & e3) \
625  { \
626  std::string msg(#__VA_ARGS__ " did not throw " #exc \
627  " but threw "); \
628  msg += typeid(e3).name(); \
629  msg += " instead"; \
630  wfail_test(msg); \
631  } \
632  }()
633 
641 #define wcallchecked(func) \
642  [&]() { \
643  try \
644  { \
645  return func; \
646  } \
647  catch (wreport::tests::TestFailed & e) \
648  { \
649  e.add_stack_info(__FILE__, __LINE__, #func, \
650  wreport_test_location_info); \
651  throw; \
652  } \
653  catch (std::exception & e) \
654  { \
655  throw wreport::tests::TestFailed(e, __FILE__, __LINE__, #func, \
656  wreport_test_location_info); \
657  } \
658  }()
659 
663 #define wfail_test(msg) wassert(throw wreport::tests::TestFailed((msg)))
664 
665 struct TestCase;
666 struct TestController;
667 struct TestRegistry;
668 struct TestCaseResult;
669 struct TestMethod;
670 struct TestMethodResult;
671 
676 {
678  std::string name;
679 
681  std::string doc;
682 
688  std::function<void()> test_function;
689 
690  TestMethod(const std::string& name_) : name(name_), test_function() {}
691 
692  TestMethod(const std::string& name_, std::function<void()> test_function_)
693  : name(name_), test_function(test_function_)
694  {
695  }
696 };
697 
702 struct TestCase
703 {
705  std::string name;
706 
708  std::vector<TestMethod> methods;
709 
711  bool tests_registered = false;
712 
713  TestCase(const std::string& name);
714  virtual ~TestCase() {}
715 
719  void register_tests_once();
720 
728  virtual void register_tests() = 0;
729 
733  virtual void setup() {}
734 
738  virtual void teardown() {}
739 
743  virtual void test_setup() {}
744 
748  virtual void test_teardown() {}
749 
754 
759 
767  virtual TestCaseResult run_tests(TestController& controller);
768 
781  virtual TestMethodResult run_test(TestController& controller,
782  TestMethod& method);
783 
788  TestMethod& add_method(const std::string& name_)
789  {
790  methods.emplace_back(name_);
791  return methods.back();
792  }
793 
797  template <typename... Args>
798  TestMethod& add_method(const std::string& name_,
799  std::function<void()> test_function)
800  {
801  methods.emplace_back(name_, test_function);
802  return methods.back();
803  }
804 
808  template <typename... Args>
809  TestMethod& add_method(const std::string& name_, const std::string& doc,
810  std::function<void()> test_function)
811  {
812  methods.emplace_back(name_, test_function);
813  methods.back().doc = doc;
814  return methods.back();
815  }
816 };
817 
828 struct Fixture
829 {
830  // Called before each test
831  void test_setup() {}
832 
833  // Called after each test
834  void test_teardown() {}
835 };
836 
837 template <typename Fixture, typename... Args>
838 static inline Fixture* fixture_factory(Args... args)
839 {
840  return new Fixture(args...);
841 }
842 
846 template <typename FIXTURE> class FixtureTestCase : public TestCase
847 {
848 public:
849  typedef FIXTURE Fixture;
850 
851  Fixture* fixture = nullptr;
852  std::function<Fixture*()> make_fixture;
853 
854  template <typename... Args>
855  FixtureTestCase(const std::string& name_, Args... args) : TestCase(name_)
856  {
857  make_fixture = std::bind(fixture_factory<FIXTURE, Args...>, args...);
858  }
859  FixtureTestCase(const FixtureTestCase&) = delete;
860  FixtureTestCase(FixtureTestCase&&) = delete;
861  FixtureTestCase& operator=(const FixtureTestCase&) = delete;
862  FixtureTestCase& operator=(FixtureTestCase&) = delete;
863 
864  void setup() override
865  {
866  TestCase::setup();
867  fixture = make_fixture();
868  }
869 
870  void teardown() override
871  {
872  delete fixture;
873  fixture = nullptr;
875  }
876 
877  void method_setup(TestMethodResult& mr) override
878  {
880  if (fixture)
881  fixture->test_setup();
882  }
883 
885  {
886  if (fixture)
887  fixture->test_teardown();
889  }
890 
895  template <typename... Args>
896  TestMethod& add_method(const std::string& name_,
897  std::function<void(FIXTURE&)> test_function)
898  {
899  return TestCase::add_method(name_, [=]() { test_function(*fixture); });
900  }
901 
906  template <typename... Args>
907  TestMethod& add_method(const std::string& name_, const std::string& doc,
908  std::function<void(FIXTURE&)> test_function)
909  {
910  return TestCase::add_method(name_, doc,
911  [=]() { test_function(*fixture); });
912  }
913 };
914 
915 } // namespace wreport::tests
916 #endif
Utility functions for the unit tests.
Definition: tests.h:38
virtual TestCaseResult run_tests(TestController &controller)
Call setup(), run all the tests that have been registered, then call teardown().
Result of running a whole test case.
Definition: testrunner.h:90
Test case collecting several test methods, and self-registering with the singleton instance of TestRe...
Definition: utils/tests.h:702
std::string name
Name of the test case.
Definition: utils/tests.h:705
Information about one stack frame in the test execution stack.
Definition: utils/tests.h:65
Add information to the test backtrace for the tests run in the current scope.
Definition: utils/tests.h:53
void assert_not_re_matches(const std::string &actual, const std::string &expected)
Ensure that the string actual does not match the extended regular expression expected.
Exception thrown when a test or a test case needs to be skipped.
Definition: utils/tests.h:136
Definition: utils/tests.h:519
void assert_endswith(const std::string &actual, const std::string &expected)
Ensure that the string actual ends with expected.
virtual void method_setup(TestMethodResult &)
Set up before the test method is run.
Definition: utils/tests.h:753
void register_tests_once()
Idempotent wrapper for register_tests()
virtual void test_teardown()
Clean up after each test method is run.
Definition: utils/tests.h:748
bool tests_registered
Set to true the first time register_tests_once is run.
Definition: utils/tests.h:711
Abstract interface for the objects that supervise test execution.
Definition: testrunner.h:155
void assert_true(const A &actual)
The following assert_* functions throw TestFailed without capturing file/line numbers, and need to be used inside wassert to give good error messages.
Definition: utils/tests.h:160
void assert_not_contains(const std::string &actual, const std::string &expected)
Ensure that the string actual does not contain expected.
Definition: utils/tests.h:335
virtual void test_setup()
Set up before each test method is run.
Definition: utils/tests.h:743
virtual TestMethodResult run_test(TestController &controller, TestMethod &method)
Run a test method.
void teardown() override
Clean up after the test case is run.
Definition: utils/tests.h:870
Exception thrown when a test assertion fails, normally by Location::fail_test.
Definition: utils/tests.h:103
Definition: utils/tests.h:425
void method_teardown(TestMethodResult &mr) override
Clean up after the test method is run.
Definition: utils/tests.h:884
std::vector< TestMethod > methods
All registered test methods.
Definition: utils/tests.h:708
std::string backtrace() const
Return the formatted backtrace for this location.
TestMethod & add_method(const std::string &name_, const std::string &doc, std::function< void()> test_function)
Register a new test method, including documentation.
Definition: utils/tests.h:809
Definition: utils/tests.h:88
virtual void setup()
Set up the test case before it is run.
Definition: utils/tests.h:733
Definition: utils/tests.h:386
std::string doc
Documentation attached to this test method.
Definition: utils/tests.h:681
Definition: utils/tests.h:490
Definition: utils/tests.h:459
Result of running a test method.
Definition: testrunner.h:23
TestMethod & add_method(const std::string &name_, const std::string &doc, std::function< void(FIXTURE &)> test_function)
Register a new test method that takes a reference to the fixture as argument, including documentation...
Definition: utils/tests.h:907
void setup() override
Set up the test case before it is run.
Definition: utils/tests.h:864
std::function< void()> test_function
Main body of the test method.
Definition: utils/tests.h:688
void method_setup(TestMethodResult &mr) override
Set up before the test method is run.
Definition: utils/tests.h:877
Definition: utils/tests.h:409
virtual void register_tests()=0
This will be called before running the test case, to populate it with its test methods.
TestMethod & add_method(const std::string &name_)
Register a new test method, with the actual test function to be added later.
Definition: utils/tests.h:788
void assert_greater_equal(const A &actual, const E &expected)
Ensure that the actual value is greather or equal than the reference value.
Definition: utils/tests.h:294
void assert_contains(const std::string &actual, const std::string &expected)
Ensure that the string actual contains expected.
void assert_not_equal(const A &actual, const E &expected)
Test function that ensures that the actual value is different than a reference one.
Definition: utils/tests.h:246
Test case that includes a fixture.
Definition: utils/tests.h:846
void assert_re_matches(const std::string &actual, const std::string &expected)
Ensure that the string actual matches the extended regular expression expected.
TestMethod & add_method(const std::string &name_, std::function< void()> test_function)
Register a new test method.
Definition: utils/tests.h:798
Test method information.
Definition: utils/tests.h:675
void assert_greater(const A &actual, const E &expected)
Ensure that the actual value is greater than the reference value.
Definition: utils/tests.h:282
virtual void method_teardown(TestMethodResult &)
Clean up after the test method is run.
Definition: utils/tests.h:758
void assert_false(const A &actual)
Test function that ensures that the actual value is false.
Definition: utils/tests.h:172
virtual void teardown()
Clean up after the test case is run.
Definition: utils/tests.h:738
TestMethod & add_method(const std::string &name_, std::function< void(FIXTURE &)> test_function)
Register a new test method that takes a reference to the fixture as argument.
Definition: utils/tests.h:896
void assert_less_equal(const A &actual, const E &expected)
Ensure that the actual value is less or equal than the reference value.
Definition: utils/tests.h:270
std::string name
Name of the test method.
Definition: utils/tests.h:678
Base class for test fixtures.
Definition: utils/tests.h:828
void assert_less(const A &actual, const E &expected)
Ensure that the actual value is less than the reference value.
Definition: utils/tests.h:258
std::ostream & operator()()
Clear the current information and return the output stream to which new information can be sent...
void assert_startswith(const std::string &actual, const std::string &expected)
Ensure that the string actual starts with expected.