Add a InterpolatedTimeConverter to wrap time conversion

This gives us an interface that we can use in EventScheduler to query
the current time, and helpers to interpolate time from a list of points.

Change-Id: I44bd5f0f795604c63a29cb1e3f65815b790edb6a
diff --git a/aos/network/testing_time_converter.cc b/aos/network/testing_time_converter.cc
new file mode 100644
index 0000000..0dd0cb3
--- /dev/null
+++ b/aos/network/testing_time_converter.cc
@@ -0,0 +1,105 @@
+#include "aos/network/testing_time_converter.h"
+
+#include <chrono>
+#include <deque>
+#include <optional>
+#include <tuple>
+
+#include "aos/events/event_scheduler.h"
+#include "aos/network/multinode_timestamp_filter.h"
+#include "aos/time/time.h"
+
+namespace aos {
+namespace message_bridge {
+
+namespace chrono = std::chrono;
+
+TestingTimeConverter ::TestingTimeConverter(size_t node_count)
+    : InterpolatedTimeConverter(node_count),
+      last_monotonic_(node_count, monotonic_clock::epoch()) {
+  CHECK_GE(node_count, 1u);
+}
+
+TestingTimeConverter::~TestingTimeConverter() {
+  if (at_end_) {
+    CHECK(!NextTimestamp()) << ": At the end but there is more data.";
+  }
+}
+
+void TestingTimeConverter::StartEqual() {
+  CHECK(first_);
+  first_ = false;
+  ts_.emplace_back(std::make_tuple(last_distributed_, last_monotonic_));
+}
+
+chrono::nanoseconds TestingTimeConverter::AddMonotonic(
+    std::vector<monotonic_clock::duration> times) {
+  CHECK_EQ(times.size(), last_monotonic_.size());
+  for (size_t i = 0; i < times.size(); ++i) {
+    CHECK_GT(times[i].count(), 0);
+    last_monotonic_[i] += times[i];
+  }
+  chrono::nanoseconds dt(0);
+  if (!first_) {
+    dt = *std::max_element(times.begin(), times.end());
+    last_distributed_ += dt;
+  } else {
+    first_ = false;
+  }
+  ts_.emplace_back(std::make_tuple(last_distributed_, last_monotonic_));
+  return dt;
+}
+
+chrono::nanoseconds TestingTimeConverter::AddMonotonic(
+    std::vector<monotonic_clock::time_point> times) {
+  CHECK_EQ(times.size(), last_monotonic_.size());
+  chrono::nanoseconds dt(0);
+  if (!first_) {
+    dt = times[0] - last_monotonic_[0];
+    for (size_t i = 0; i < times.size(); ++i) {
+      CHECK_GT(times[i], last_monotonic_[i]);
+      dt = std::max(dt, times[i] - times[0]);
+    }
+    last_distributed_ += dt;
+    last_monotonic_ = times;
+  } else {
+    first_ = false;
+    last_monotonic_ = times;
+  }
+  ts_.emplace_back(std::make_tuple(last_distributed_, std::move(times)));
+  return dt;
+}
+
+void TestingTimeConverter::AddNextTimestamp(
+    distributed_clock::time_point time,
+    std::vector<monotonic_clock::time_point> times) {
+  CHECK_EQ(times.size(), last_monotonic_.size());
+  if (!first_) {
+    CHECK_GT(time, last_distributed_);
+    for (size_t i = 0; i < times.size(); ++i) {
+      CHECK_GT(times[i], last_monotonic_[i]);
+    }
+  } else {
+    first_ = false;
+  }
+  last_distributed_ = time;
+  last_monotonic_ = times;
+
+  ts_.emplace_back(std::make_tuple(time, std::move(times)));
+}
+
+std::optional<std::tuple<distributed_clock::time_point,
+                         std::vector<monotonic_clock::time_point>>>
+TestingTimeConverter::NextTimestamp() {
+  CHECK(!first_) << ": Tried to pull a timestamp before one was added.  This "
+                    "is unlikely to be what you want.";
+  if (ts_.empty()) {
+    return std::nullopt;
+  }
+  auto result = ts_.front();
+  ts_.pop_front();
+  return result;
+}
+
+}  // namespace message_bridge
+}  // namespace aos