Refactor & test foxglove image converter

Add a simple test to confirm that it actually produces useful images.

Trying to get a start on better testing for the infrastructure
associated with various calibration stuff, and figured I'd actually add
tests for the code that I added...

Change-Id: I4ac485b1c199f5412c9c6f41a9dd93639ce8f1a1
Signed-off-by: James Kuszmaul <jabukuszmaul@gmail.com>
diff --git a/frc971/vision/foxglove_image_converter_test.cc b/frc971/vision/foxglove_image_converter_test.cc
new file mode 100644
index 0000000..65b3b6b
--- /dev/null
+++ b/frc971/vision/foxglove_image_converter_test.cc
@@ -0,0 +1,68 @@
+#include "frc971/vision/foxglove_image_converter.h"
+
+#include "aos/events/simulated_event_loop.h"
+#include "aos/json_to_flatbuffer.h"
+#include "aos/testing/path.h"
+#include "aos/testing/tmpdir.h"
+#include "gtest/gtest.h"
+
+namespace frc971::vision {
+std::ostream &operator<<(std::ostream &os, ImageCompression compression) {
+  os << ExtensionForCompression(compression);
+  return os;
+}
+namespace testing {
+class ImageConverterTest : public ::testing::TestWithParam<ImageCompression> {
+ protected:
+  ImageConverterTest()
+      : config_(aos::configuration::ReadConfig(
+            aos::testing::ArtifactPath("frc971/vision/converter_config.json"))),
+        factory_(&config_.message()),
+        camera_image_(
+            aos::FileToFlatbuffer<CameraImage>(aos::testing::ArtifactPath(
+                "external/april_tag_test_image/test.bfbs"))),
+        node_(aos::configuration::GetNode(&config_.message(), "test")),
+        test_event_loop_(factory_.MakeEventLoop("test", node_)),
+        image_sender_(test_event_loop_->MakeSender<CameraImage>("/camera")),
+        converter_event_loop_(factory_.MakeEventLoop("converter", node_)),
+        converter_(converter_event_loop_.get(), "/camera", "/visualize",
+                   GetParam()),
+        output_path_(absl::StrCat(aos::testing::TestTmpDir(), "/test.",
+                                  ExtensionForCompression(GetParam()))) {
+    test_event_loop_->OnRun(
+        [this]() { image_sender_.CheckOk(image_sender_.Send(camera_image_)); });
+    test_event_loop_->MakeWatcher(
+        "/visualize", [this](const foxglove::CompressedImage &image) {
+          ASSERT_TRUE(image.has_data());
+          std::string expected_contents =
+              aos::util::ReadFileToStringOrDie(aos::testing::ArtifactPath(
+                  absl::StrCat("external/april_tag_test_image/expected.",
+                               ExtensionForCompression(GetParam()))));
+          std::string_view data(
+              reinterpret_cast<const char *>(image.data()->data()),
+              image.data()->size());
+          EXPECT_EQ(expected_contents, data);
+          aos::util::WriteStringToFileOrDie(output_path_, data);
+          factory_.Exit();
+        });
+  }
+
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
+  aos::SimulatedEventLoopFactory factory_;
+  aos::FlatbufferVector<CameraImage> camera_image_;
+  const aos::Node *const node_;
+  std::unique_ptr<aos::EventLoop> test_event_loop_;
+  aos::Sender<CameraImage> image_sender_;
+  std::unique_ptr<aos::EventLoop> converter_event_loop_;
+  FoxgloveImageConverter converter_;
+  std::string output_path_;
+};
+
+TEST_P(ImageConverterTest, ImageToFoxglove) { factory_.Run(); }
+
+INSTANTIATE_TEST_SUITE_P(CompressionOptions, ImageConverterTest,
+                         ::testing::Values(ImageCompression::kJpeg,
+                                           ImageCompression::kPng));
+
+}  // namespace testing
+}  // namespace frc971::vision