Add log-related command-line options to unit tests.

You can now specify the following when running a unit test:
  -p, --print-logs
      Print the log messages as they are being generated.
  -o, --log-file=FILE
      Print all log messages to FILE instead of standard output

Also, when a test fails the messages no longer get dumped to standard
output. They only get dumped when specifying --print-logs.

Change-Id: Icc265734f302c27c24829409ca6f7c8fce2979d4
diff --git a/aos/build/externals.gyp b/aos/build/externals.gyp
index e72f4f7..315f0bf 100644
--- a/aos/build/externals.gyp
+++ b/aos/build/externals.gyp
@@ -129,16 +129,18 @@
       'type': 'static_library',
       'sources': [
         '<(externals)/gtest-<(gtest_version)/src/gtest-all.cc',
-            '<(externals)/gtest-<(gtest_version)/fused-src/gtest/gtest_main.cc',
+        '<(AOS)/externals/gtest/gtest_main.cc',
       ],
       'include_dirs': [
         '<(externals)/gtest-<(gtest_version)',
       ],
       'dependencies': [
         'gtest_prod',
+        '<(AOS)/common/common.gyp:queue_testutils',
       ],
       'export_dependent_settings': [
         'gtest_prod',
+        '<(AOS)/common/common.gyp:queue_testutils',
       ],
       'cflags!': ['-Werror'],
       'direct_dependent_settings': {
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index 5264dab..a0750fe 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -20,7 +20,6 @@
       'dependencies': [
         '<(AOS)/build/aos.gyp:logging',
         'once',
-        '<(EXTERNALS):gtest',
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:shared_mem',
       ],
       'export_dependent_settings': [
diff --git a/aos/common/queue_testutils.cc b/aos/common/queue_testutils.cc
index 824cb89..d71d023 100644
--- a/aos/common/queue_testutils.cc
+++ b/aos/common/queue_testutils.cc
@@ -41,22 +41,41 @@
     }
   }
 
+  void SetOutputFile(const char *filename) {
+    if (strcmp("-", filename) != 0) {
+      FILE *newfile = fopen(filename, "w");
+
+      if (newfile) {
+        output_file_ = newfile;
+      }
+    }
+  }
+
+  void PrintMessagesAsTheyComeIn() { print_as_messages_come_in_ = true; }
+
  private:
   TestLogImplementation() {}
+  ~TestLogImplementation() {
+    if (output_file_ != stdout) {
+      fclose(output_file_);
+    }
+  }
 
   static TestLogImplementation *CreateInstance() {
     return new TestLogImplementation();
   }
 
   virtual void HandleMessage(const LogMessage &message) override {
-    if (message.level == FATAL) {
-      logging::internal::PrintMessage(stdout, message);
+    if (message.level == FATAL || print_as_messages_come_in_) {
+      logging::internal::PrintMessage(output_file_, message);
     }
 
     messages_.push_back(message);
   }
 
   ::std::vector<LogMessage> messages_;
+  bool print_as_messages_come_in_ = false;
+  FILE *output_file_ = stdout;
 };
 
 class MyTestEventListener : public ::testing::EmptyTestEventListener {
@@ -65,13 +84,8 @@
   }
   virtual void OnTestEnd(const ::testing::TestInfo &test_info) {
     if (test_info.result()->Failed()) {
-      printf("Test %s failed. Printing out all log messages.\n",
+      printf("Test %s failed. Use '--print-logs' to see all log messages.\n",
              test_info.name());
-      fputs("\tThis will include already printed WARNING and up messages.\n",
-            stdout);
-      fputs("\tIt will also include duplicates of all gtest failures.\n",
-            stdout);
-      TestLogImplementation::GetInstance()->PrintAllMessages();
     }
   }
 
@@ -145,6 +159,14 @@
   CHECK_EQ(atexit(TerminateExitHandler), 0);
 }
 
+void SetLogFileName(const char* filename) {
+  TestLogImplementation::GetInstance()->SetOutputFile(filename);
+}
+
+void ForcePrintLogsDuringTests() {
+  TestLogImplementation::GetInstance()->PrintMessagesAsTheyComeIn();
+}
+
 }  // namespace testing
 }  // namespace common
 }  // namespace aos
diff --git a/aos/common/queue_testutils.h b/aos/common/queue_testutils.h
index 3c7a0a4..fb0ffcd 100644
--- a/aos/common/queue_testutils.h
+++ b/aos/common/queue_testutils.h
@@ -35,6 +35,16 @@
 // being run.
 void PreventExit();
 
+// Redirect the messages enabled by EnableTestLogging() function to a file.
+// By default the messages are printed to standard output.
+void SetLogFileName(const char* filename);
+
+// Force the messages to be printed as they are handled by the logging
+// framework. This can be useful for tests that hang where no messages would
+// otherwise be printed. This is also useful for tests that do pass, but where
+// we want to use graphing tools to verify what's happening.
+void ForcePrintLogsDuringTests();
+
 }  // namespace testing
 }  // namespace common
 }  // namespace aos
diff --git a/aos/externals/gtest/gtest_main.cc b/aos/externals/gtest/gtest_main.cc
new file mode 100644
index 0000000..024c502
--- /dev/null
+++ b/aos/externals/gtest/gtest_main.cc
@@ -0,0 +1,52 @@
+#include <iostream>
+#include <getopt.h>
+
+#include "gtest/gtest.h"
+#include "aos/common/queue_testutils.h"
+
+GTEST_API_ int main(int argc, char **argv) {
+  static const struct option long_options[] = {
+      {"help", no_argument, 0, 'h'},
+      {"print-logs", no_argument, 0, 'p'},
+      {"log-file", required_argument, 0, 'o'},
+      {0, 0, 0, 0},
+  };
+
+  testing::InitGoogleTest(&argc, argv);
+
+  // The gtest library modifies argc and argv to remove all of its own command
+  // line switches etc. So after calling InitGoogleTest() we can parse our own
+  // command line options.
+  while (true) {
+    int c = getopt_long(argc, argv, "po:", long_options, nullptr);
+
+    if (c == -1) {
+      break;
+    }
+
+    switch (c) {
+      case 'h':
+        printf(
+            "\nFRC971 options:\n"
+            "  -p, --print-logs\n"
+            "      Print the log messages as they are being generated.\n"
+            "  -o, --log-file=FILE\n"
+            "      Print all log messages to FILE instead of standard output\n"
+            );
+        break;
+
+      case 'p':
+        aos::common::testing::ForcePrintLogsDuringTests();
+        break;
+
+      case 'o':
+        aos::common::testing::SetLogFileName(optarg);
+        break;
+
+      case '?':
+        abort();
+    }
+  }
+
+  return RUN_ALL_TESTS();
+}