Merge "Add some more UUIDs to log files"
diff --git a/aos/containers/BUILD b/aos/containers/BUILD
index 8277212..9e527cd 100644
--- a/aos/containers/BUILD
+++ b/aos/containers/BUILD
@@ -66,3 +66,15 @@
         "@com_github_google_glog//:glog",
     ],
 )
+
+cc_test(
+    name = "resizeable_buffer_test",
+    srcs = [
+        "resizeable_buffer_test.cc",
+    ],
+    deps = [
+        ":resizeable_buffer",
+        "//aos/testing:googletest",
+        "@com_google_absl//absl/types:span",
+    ],
+)
diff --git a/aos/containers/resizeable_buffer_test.cc b/aos/containers/resizeable_buffer_test.cc
new file mode 100644
index 0000000..1d27a39
--- /dev/null
+++ b/aos/containers/resizeable_buffer_test.cc
@@ -0,0 +1,95 @@
+#include "aos/containers/resizeable_buffer.h"
+
+#include <numeric>
+
+#include "absl/types/span.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace aos::testing {
+
+// Tests using resize to do some stuff with a ResizeableBuffer.
+TEST(ResizeableBufferTest, Resize) {
+  ResizeableBuffer buffer;
+  EXPECT_EQ(buffer.size(), 0u);
+  EXPECT_EQ(buffer.capacity(), 0u);
+
+  buffer.resize(3);
+  EXPECT_EQ(buffer.size(), 3u);
+  EXPECT_GE(buffer.capacity(), 3u);
+  EXPECT_EQ(buffer.begin() + 3, buffer.end());
+
+  buffer.resize(5);
+  EXPECT_EQ(buffer.size(), 5u);
+  EXPECT_GE(buffer.capacity(), 5u);
+  EXPECT_EQ(buffer.begin() + 5, buffer.end());
+
+  buffer.resize(2);
+  EXPECT_EQ(buffer.size(), 2u);
+  EXPECT_GE(buffer.capacity(), 2u);
+  EXPECT_EQ(buffer.begin() + 2, buffer.end());
+}
+
+// Tests using erase_front on a ResizeableBuffer.
+TEST(ResizeableBufferTest, EraseFront) {
+  ResizeableBuffer buffer;
+  EXPECT_EQ(buffer.size(), 0u);
+  EXPECT_EQ(buffer.capacity(), 0u);
+
+  buffer.resize(5);
+  for (int i = 0; i < 5; ++i) {
+    buffer.begin()[i] = '1' + i;
+  }
+  EXPECT_THAT(absl::Span<uint8_t>(buffer.begin(), buffer.size()),
+              ::testing::ElementsAre('1', '2', '3', '4', '5'));
+  buffer.erase_front(2);
+  EXPECT_THAT(absl::Span<uint8_t>(buffer.begin(), buffer.size()),
+              ::testing::ElementsAre('3', '4', '5'));
+}
+
+// Tests using push_back starting from an empty ResizeableBuffer.
+TEST(ResizeableBufferTest, PushBackEmpty) {
+  ResizeableBuffer buffer;
+  buffer.push_back('1');
+  buffer.push_back('2');
+  buffer.push_back('3');
+  EXPECT_THAT(absl::Span<uint8_t>(buffer.begin(), buffer.size()),
+              ::testing::ElementsAre('1', '2', '3'));
+}
+
+// Tests using push_back starting from a non-empty ResizeableBuffer.
+TEST(ResizeableBufferTest, PushBackNonEmpty) {
+  ResizeableBuffer buffer;
+  EXPECT_EQ(buffer.size(), 0u);
+  EXPECT_EQ(buffer.capacity(), 0u);
+
+  buffer.resize(2);
+  for (int i = 0; i < 2; ++i) {
+    buffer.begin()[i] = '1' + i;
+  }
+  buffer.push_back('3');
+  buffer.push_back('4');
+  buffer.push_back('5');
+  EXPECT_THAT(absl::Span<uint8_t>(buffer.begin(), buffer.size()),
+              ::testing::ElementsAre('1', '2', '3', '4', '5'));
+}
+
+// Tests using push_back starting from a large non-empty ResizeableBuffer.
+TEST(ResizeableBufferTest, PushBackLargeNonEmpty) {
+  ResizeableBuffer buffer;
+  EXPECT_EQ(buffer.size(), 0u);
+  EXPECT_EQ(buffer.capacity(), 0u);
+
+  buffer.resize(27);
+  for (int i = 0; i < 27; ++i) {
+    buffer.begin()[i] = '1' + i;
+  }
+  buffer.push_back('1' + 27);
+  buffer.push_back('1' + 28);
+  std::vector<char> expected(29);
+  std::iota(expected.begin(), expected.end(), '1');
+  EXPECT_THAT(absl::Span<uint8_t>(buffer.begin(), buffer.size()),
+              ::testing::ElementsAreArray(expected));
+}
+
+}  // namespace aos::testing
diff --git a/aos/flatbuffer_introspection.cc b/aos/flatbuffer_introspection.cc
index 0fc37a7..5f6ca45 100644
--- a/aos/flatbuffer_introspection.cc
+++ b/aos/flatbuffer_introspection.cc
@@ -76,12 +76,8 @@
     int64_t enum_value,
     const flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>>
         *values) {
-  auto result = std::find_if(values->begin(), values->end(),
-                             [enum_value](const reflection::EnumVal *a) {
-                               return a->value() == enum_value;
-                             });
-  return result != values->end() ? result->name()->string_view()
-                                 : std::string_view();
+  auto search = values->LookupByKey(enum_value);
+  return search != nullptr ? search->name()->string_view() : std::string_view();
 }
 
 // Convert integer to string, checking if it is an enum.
diff --git a/frc971/codelab/README.md b/frc971/codelab/README.md
index e274f24..2fdf08c 100644
--- a/frc971/codelab/README.md
+++ b/frc971/codelab/README.md
@@ -1,5 +1,12 @@
 # FRC971 "Codelab"
 
+## Flatbuffers tutorial
+
+Flatbuffers has pretty good [tutorials](https://google.github.io/flatbuffers/flatbuffers_guide_tutorial.html) for how to use them.  We recommend
+going through them for more information.
+
+## Basic control loop
+
 Welcome! This folder contains a "codelab" where you can go through the process
 of fleshing out a basic control-loop using the same infrastructure as we do for
 the control loops that normally run on our robots. Currently, this just consists
diff --git a/frc971/codelab/basic.cc b/frc971/codelab/basic.cc
index 36e64c5..6144fed 100644
--- a/frc971/codelab/basic.cc
+++ b/frc971/codelab/basic.cc
@@ -30,7 +30,8 @@
     Status::Builder builder = status->MakeBuilder<Status>();
     // TODO(you): Fill out the Status message! In order to populate fields, use
     // the add_field_name() method on the builder, just like we do with the
-    // Output message above.
+    // Output message above.  Look at the definition of Status in
+    // basic_status.fbs and populate the field according to the comments there.
 
     status->Send(builder.Finish());
   }
diff --git a/frc971/codelab/basic.h b/frc971/codelab/basic.h
index 944048f..b75a87f 100644
--- a/frc971/codelab/basic.h
+++ b/frc971/codelab/basic.h
@@ -15,6 +15,9 @@
 // This codelab helps build basic knowledge of how to use 971 control loop
 // primatives.
 //
+// For flatbuffers background, we recommend checking out
+// https://google.github.io/flatbuffers/flatbuffers_guide_tutorial.html
+//
 // The meat of the task is to make the tests pass.
 //
 // Run the tests with: