copying branch over from other 2013 repo
diff --git a/aos/common/logging/logging_impl_test.cc b/aos/common/logging/logging_impl_test.cc
new file mode 100644
index 0000000..bc411ce
--- /dev/null
+++ b/aos/common/logging/logging_impl_test.cc
@@ -0,0 +1,176 @@
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "aos/common/logging/logging_impl.h"
+#include "aos/common/time.h"
+#include "aos/common/die.h"
+#include "aos/common/inttypes.h"
+
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+using ::testing::AssertionFailure;
+
+namespace aos {
+namespace logging {
+namespace testing {
+
+class TestLogImplementation : public LogImplementation {
+  virtual void DoLog(log_level level, const char *format, va_list ap) {
+    internal::FillInMessage(level, format, ap, &message_);
+
+    used_ = true;
+  }
+
+  LogMessage message_;
+
+ public:
+  const LogMessage &message() { return message_; }
+  bool used() { return used_; }
+  void reset_used() { used_ = false; }
+
+  TestLogImplementation() : used_(false) {}
+
+  bool used_;
+};
+class LoggingTest : public ::testing::Test {
+ protected:
+  AssertionResult WasAnythingLogged() {
+    if (log_implementation->used()) {
+      return AssertionSuccess() << "read message '" <<
+          log_implementation->message().message << "'";
+    }
+    return AssertionFailure();
+  }
+  AssertionResult WasLogged(log_level level, const std::string message) {
+    if (!log_implementation->used()) {
+      return AssertionFailure() << "nothing was logged";
+    }
+    if (log_implementation->message().level != level) {
+      return AssertionFailure() << "a message with level " <<
+          log_str(log_implementation->message().level) <<
+          " was logged instead of " << log_str(level);
+    }
+    internal::Context *context = internal::Context::Get();
+    if (log_implementation->message().source != context->source) {
+      Die("got a message from %"PRIu32", but we're %"PRIu32"\n",
+          static_cast<uint32_t>(log_implementation->message().source),
+          static_cast<uint32_t>(context->source));
+    }
+    if (strcmp(log_implementation->message().name, context->name) != 0) {
+      Die("got a message from %s, but we're %s\n",
+          log_implementation->message().name, context->name);
+    }
+    if (strstr(log_implementation->message().message, message.c_str())
+        == NULL) {
+      return AssertionFailure() << "got a message of '" <<
+          log_implementation->message().message <<
+          "' but expected it to contain '" << message << "'";
+    }
+
+    return AssertionSuccess() << log_implementation->message().message;
+  }
+
+ private:
+  virtual void SetUp() {
+    static bool first = true;
+    if (first) {
+      first = false;
+
+      Init();
+      // We'll end up with several of them stacked up, but it really doesn't
+      // matter.
+      AddImplementation(log_implementation = new TestLogImplementation());
+    }
+
+    log_implementation->reset_used();
+  }
+  virtual void TearDown() {
+    Cleanup();
+  }
+
+  static TestLogImplementation *log_implementation;
+};
+TestLogImplementation *LoggingTest::log_implementation(NULL);
+typedef LoggingTest LoggingDeathTest;
+
+// Tests both basic logging functionality and that the test setup works
+// correctly.
+TEST_F(LoggingTest, Basic) {
+  EXPECT_FALSE(WasAnythingLogged());
+  LOG(INFO, "test log 1\n");
+  EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
+  LOG(INFO, "test log 1.5\n");
+  // there's a subtle typo on purpose...
+  EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
+  LOG(ERROR, "test log 2=%d\n", 55);
+  EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
+  LOG(ERROR, "test log 3\n");
+  EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
+  LOG(WARNING, "test log 4\n");
+  EXPECT_TRUE(WasAnythingLogged());
+}
+TEST_F(LoggingTest, Cork) {
+  static const int begin_line = __LINE__;
+  LOG_CORK("first part ");
+  LOG_CORK("second part (=%d) ", 19);
+  EXPECT_FALSE(WasAnythingLogged());
+  LOG_CORK("third part ");
+  static const int end_line = __LINE__;
+  LOG_UNCORK(WARNING, "last part %d\n", 5);
+  std::stringstream expected;
+  expected << "logging_impl_test.cc: ";
+  expected << (begin_line + 1);
+  expected << "-";
+  expected << (end_line + 1);
+  expected << ": ";
+  expected << __PRETTY_FUNCTION__;
+  expected << ": first part second part (=19) third part last part 5\n";
+  EXPECT_TRUE(WasLogged(WARNING, expected.str()));
+}
+
+#ifndef __VXWORKS__
+TEST_F(LoggingDeathTest, Fatal) {
+  ASSERT_EXIT(LOG(FATAL, "this should crash it\n"),
+              ::testing::KilledBySignal(SIGABRT),
+              "this should crash it");
+}
+#endif
+
+TEST_F(LoggingTest, PrintfDirectives) {
+  LOG(INFO, "test log %%1 %%d\n");
+  EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
+  LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
+  EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
+  LOG_CORK("log 3 part %%1 %%d ");
+  LOG_UNCORK(DEBUG, "log 3 part %%2 %%f\n");
+  EXPECT_TRUE(WasLogged(DEBUG, "log 3 part %1 %d log 3 part %2 %f\n"));
+}
+
+TEST_F(LoggingTest, Timing) {
+  // For writing only.
+  //static const long kTimingCycles = 5000000;
+  static const long kTimingCycles = 5000;
+
+  time::Time start = time::Time::Now();
+  for (long i = 0; i < kTimingCycles; ++i) {
+    LOG(INFO, "a\n");
+  }
+  time::Time end = time::Time::Now();
+  time::Time diff = end - start;
+  printf("short message took %lld nsec for %ld\n",
+         diff.ToNSec(), kTimingCycles);
+
+  start = time::Time::Now();
+  for (long i = 0; i < kTimingCycles; ++i) {
+    LOG(INFO, "something longer than just \"a\" to log to test timing\n");
+  }
+  end = time::Time::Now();
+  diff = end - start;
+  printf("long message took %lld nsec for %ld\n",
+         diff.ToNSec(), kTimingCycles);
+}
+
+}  // namespace testing
+}  // namespace logging
+}  // namespace aos