pw_unit_test: Make simple runner look like GTest

This makes these changes to the unit test framework:

(1) Makes the simple test runner output match GTest
(2) Adds a new RunAllTestsStart() and RunAllTestsEnd() event
(3) Adds an intentionally-failing expectation to the sample test

Example output:

[==========] Running all tests.
[ RUN      ] PigweedTest.ExpectBool
[       OK ] PigweedTest.ExpectBool
[ RUN      ] PigweedTest.ExpectBasicComparisons
[       OK ] PigweedTest.ExpectBasicComparisons
[ RUN      ] PigweedTest.ExpectStringEquality
[       OK ] PigweedTest.ExpectStringEquality
[ RUN      ] PigweedTest.NonCopyableType
[       OK ] PigweedTest.NonCopyableType
[ RUN      ] PigweedTest.MacroArgumentsOnlyAreEvaluatedOnce
[       OK ] PigweedTest.MacroArgumentsOnlyAreEvaluatedOnce
[ RUN      ] FixtureTest.CustomFixture
[       OK ] FixtureTest.CustomFixture
[ RUN      ] PigweedTestFixture.TheNumberIs35
[       OK ] PigweedTestFixture.TheNumberIs35
[ RUN      ] PigweedTestFixture.YupTheNumberIs35
[       OK ] PigweedTestFixture.YupTheNumberIs35
[ RUN      ] PigweedTestFixture.MissingExpectations
../pw_unit_test/framework_test.cc:156: Failure
      Expected: missed_expectations == 200
[  FAILED  ] PigweedTestFixture.MissingExpectations
[==========] Done running all tests.
[  PASSED  ] 8 test(s).
[  FAILED  ] 1 test(s).

Change-Id: I813096a9d62423e256993ae03724337d52702297
diff --git a/pw_build/BUILD.gn b/pw_build/BUILD.gn
index ebe935d..75003fa 100644
--- a/pw_build/BUILD.gn
+++ b/pw_build/BUILD.gn
@@ -27,6 +27,9 @@
   cflags = [
     "-Wall",
     "-Wextra",
+
+    # Warn when a switch on an enum does not cover all the cases.
+    "-Wswitch",
   ]
 }
 
diff --git a/pw_unit_test/framework.cc b/pw_unit_test/framework.cc
index 24fbb7c..b89a4b2 100644
--- a/pw_unit_test/framework.cc
+++ b/pw_unit_test/framework.cc
@@ -38,9 +38,18 @@
 }
 
 int Framework::RunAllTests() {
+  run_tests_summary_.passed_tests = 0;
+  run_tests_summary_.failed_tests = 0;
+
+  if (event_handler_ != nullptr) {
+    event_handler_->RunAllTestsStart();
+  }
   for (TestInfo* test = tests_; test != nullptr; test = test->next) {
     test->run();
   }
+  if (event_handler_ != nullptr) {
+    event_handler_->RunAllTestsEnd(run_tests_summary_);
+  }
   return exit_status_;
 }
 
@@ -64,6 +73,14 @@
 
 void Framework::EndTest(Test* test) {
   current_test_ = nullptr;
+  switch (current_result_) {
+    case TestResult::kSuccess:
+      run_tests_summary_.passed_tests++;
+      break;
+    case TestResult::kFailure:
+      run_tests_summary_.failed_tests++;
+      break;
+  }
 
   if (event_handler_ == nullptr) {
     return;
diff --git a/pw_unit_test/public/pw_unit_test/event_handler.h b/pw_unit_test/public/pw_unit_test/event_handler.h
index 8a8338b..4fd9ca4 100644
--- a/pw_unit_test/public/pw_unit_test/event_handler.h
+++ b/pw_unit_test/public/pw_unit_test/event_handler.h
@@ -75,11 +75,25 @@
   bool success;
 };
 
+struct RunTestsSummary {
+  // The number of passed tests among the run tests.
+  int passed_tests;
+
+  // The number of passed tests among the run tests.
+  int failed_tests;
+};
+
 // An event handler is responsible for collecting and processing the results of
 // a unit test run. Its interface is called by the unit test framework as tests
 // are executed and various test events occur.
 class EventHandler {
  public:
+  // Called before all tests are run.
+  virtual void RunAllTestsStart() = 0;
+
+  // Called after all tests are run.
+  virtual void RunAllTestsEnd(const RunTestsSummary& run_tests_summary) = 0;
+
   // Called when a new test case is started.
   virtual void TestCaseStart(const TestCase& test_case) = 0;
 
diff --git a/pw_unit_test/public/pw_unit_test/framework.h b/pw_unit_test/public/pw_unit_test/framework.h
index 111b892..d633dfa 100644
--- a/pw_unit_test/public/pw_unit_test/framework.h
+++ b/pw_unit_test/public/pw_unit_test/framework.h
@@ -91,6 +91,7 @@
   constexpr Framework()
       : current_test_(nullptr),
         current_result_(TestResult::kSuccess),
+        run_tests_summary_{.passed_tests = 0, .failed_tests = 0},
         exit_status_(0),
         event_handler_(nullptr),
         memory_pool_() {}
@@ -178,6 +179,9 @@
   // Overall result of the current test case (pass/fail).
   TestResult current_result_;
 
+  // Overall result of the ongoing test run, which covers multiple tests.
+  RunTestsSummary run_tests_summary_;
+
   // Program exit status returned by RunAllTests for Googletest compatibility.
   int exit_status_;
 
diff --git a/pw_unit_test/public/pw_unit_test/simple_printing_event_handler.h b/pw_unit_test/public/pw_unit_test/simple_printing_event_handler.h
index 25c1568..f777568 100644
--- a/pw_unit_test/public/pw_unit_test/simple_printing_event_handler.h
+++ b/pw_unit_test/public/pw_unit_test/simple_printing_event_handler.h
@@ -41,6 +41,8 @@
   SimplePrintingEventHandler(WriteFunction write_function, bool verbose = false)
       : write_(write_function), verbose_(verbose) {}
 
+  void RunAllTestsStart() override;
+  void RunAllTestsEnd(const RunTestsSummary& run_tests_summary) override;
   void TestCaseStart(const TestCase& test_case) override;
   void TestCaseEnd(const TestCase& test_case, TestResult result) override;
   void TestCaseExpect(const TestCase& test_case,
diff --git a/pw_unit_test/simple_printing_event_handler.cc b/pw_unit_test/simple_printing_event_handler.cc
index 1ae5d29..9024158 100644
--- a/pw_unit_test/simple_printing_event_handler.cc
+++ b/pw_unit_test/simple_printing_event_handler.cc
@@ -19,16 +19,39 @@
 
 namespace pw::unit_test {
 
+void SimplePrintingEventHandler::RunAllTestsStart() {
+  WriteAndFlush("[==========] Running all tests.\n");
+}
+
+void SimplePrintingEventHandler::RunAllTestsEnd(
+    const RunTestsSummary& run_tests_summary) {
+  WriteAndFlush("[==========] Done running all tests.\n");
+  WriteAndFlush(
+      "[  PASSED  ] %d test(s).\n", run_tests_summary.passed_tests);
+  if (run_tests_summary.failed_tests) {
+    WriteAndFlush(
+        "[  FAILED  ] %d test(s).\n", run_tests_summary.failed_tests);
+  }
+}
+
 void SimplePrintingEventHandler::TestCaseStart(const TestCase& test_case) {
   WriteAndFlush(
-      ">>> Running %s.%s\n", test_case.suite_name, test_case.test_name);
+      "[ RUN      ] %s.%s\n", test_case.suite_name, test_case.test_name);
 }
 
 void SimplePrintingEventHandler::TestCaseEnd(const TestCase& test_case,
                                              TestResult result) {
-  const char* status = result == TestResult::kSuccess ? "succeeded" : "failed";
-  WriteAndFlush(
-      "<<< Test %s.%s %s\n", test_case.suite_name, test_case.test_name, status);
+  // Use a switch with no default to detect changes in the test result enum.
+  switch (result) {
+    case TestResult::kSuccess:
+      WriteAndFlush(
+          "[       OK ] %s.%s\n", test_case.suite_name, test_case.test_name);
+      break;
+    case TestResult::kFailure:
+      WriteAndFlush(
+          "[  FAILED  ] %s.%s\n", test_case.suite_name, test_case.test_name);
+      break;
+  }
 }
 
 void SimplePrintingEventHandler::TestCaseExpect(
@@ -37,9 +60,10 @@
     return;
   }
 
-  const char* result = expectation.success ? "SUCCESS" : "FAILURE";
-  WriteAndFlush("[%s] %s\n", result, expectation.expression);
-  WriteAndFlush("  at %s:%d\n", test_case.file_name, expectation.line_number);
+  const char* result = expectation.success ? "Success" : "Failure";
+  WriteAndFlush(
+      "%s:%d: %s\n", test_case.file_name, expectation.line_number, result);
+  WriteAndFlush("      Expected: %s\n", expectation.expression);
 }
 
 int SimplePrintingEventHandler::WriteAndFlush(const char* format, ...) {