Add gmock matcher support for comparing flatbuffers
This makes it easier to compare flatbuffers in tests.
Change-Id: Iabd1038f7ce9dfc3edf1162f2d7b0485cdda3b90
diff --git a/aos/BUILD b/aos/BUILD
index 86aa433..790f845 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -463,6 +463,7 @@
target_compatible_with = ["@platforms//os:linux"],
deps = [
":configuration",
+ "//aos/testing:flatbuffer_eq",
"//aos/testing:googletest",
"//aos/testing:test_logging",
],
diff --git a/aos/configuration_test.cc b/aos/configuration_test.cc
index a5b3b59..e0c4dc3 100644
--- a/aos/configuration_test.cc
+++ b/aos/configuration_test.cc
@@ -2,12 +2,13 @@
#include "absl/strings/strip.h"
#include "aos/json_to_flatbuffer.h"
+#include "aos/testing/flatbuffer_eq.h"
#include "aos/testing/test_logging.h"
#include "aos/util/file.h"
#include "flatbuffers/reflection.h"
#include "glog/logging.h"
-#include "gtest/gtest.h"
#include "gmock/gmock.h"
+#include "gtest/gtest.h"
namespace aos {
namespace configuration {
@@ -23,12 +24,17 @@
typedef ConfigurationTest ConfigurationDeathTest;
// *the* expected location for all working tests.
-const char *kExpectedLocation =
- "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }";
+aos::FlatbufferDetachedBuffer<Channel> ExpectedLocation() {
+ return JsonToFlatbuffer<Channel>(
+ "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }");
+}
+
// And for multinode setups
-const char *kExpectedMultinodeLocation =
- "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
- "\"source_node\": \"pi1\" }";
+aos::FlatbufferDetachedBuffer<Channel> ExpectedMultinodeLocation() {
+ return JsonToFlatbuffer<Channel>(
+ "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
+ "\"source_node\": \"pi1\" }");
+}
// Tests that we can read and merge a configuration.
TEST_F(ConfigurationTest, ConfigMerge) {
@@ -143,9 +149,8 @@
ReadConfig(kConfigPrefix + "config1.json");
// Test a basic lookup first.
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr)),
- kExpectedLocation);
+ EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr),
+ aos::testing::FlatbufferEq(ExpectedLocation()));
// Test that an invalid name results in nullptr back.
EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
@@ -153,22 +158,18 @@
// Tests that a root map/rename works. And that they get processed from the
// bottom up.
- EXPECT_EQ(FlatbufferToJson(
- GetChannel(config, "/batman", ".aos.bar", "app1", nullptr)),
- kExpectedLocation);
+ EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", nullptr),
+ aos::testing::FlatbufferEq(ExpectedLocation()));
// And then test that an application specific map/rename works.
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr)),
- kExpectedLocation);
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr)),
- kExpectedLocation);
+ EXPECT_THAT(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr),
+ aos::testing::FlatbufferEq(ExpectedLocation()));
+ EXPECT_THAT(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr),
+ aos::testing::FlatbufferEq(ExpectedLocation()));
// And then test that an invalid application name gets properly ignored.
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr)),
- kExpectedLocation);
+ EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr),
+ aos::testing::FlatbufferEq(ExpectedLocation()));
}
// Tests that we can lookup a location with node specific maps.
@@ -179,29 +180,24 @@
const Node *pi2 = GetNode(&config.message(), "pi2");
// Test a basic lookup first.
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi1)),
- kExpectedMultinodeLocation);
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi2)),
- kExpectedMultinodeLocation);
+ EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi1),
+ aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
+ EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi2),
+ aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
// Tests that a root map/rename works with a node specific map.
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
- kExpectedMultinodeLocation);
+ EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
+ aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
// Tests that a root map/rename fails with a node specific map for the wrong
// node.
EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
// And then test that an application specific map/rename works.
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1)),
- kExpectedMultinodeLocation);
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1)),
- kExpectedMultinodeLocation);
+ EXPECT_THAT(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1),
+ aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
+ EXPECT_THAT(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1),
+ aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
// And then that it fails when the node changes.
EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
@@ -214,9 +210,8 @@
const Node *pi1 = GetNode(&config.message(), "pi1");
// Test a basic lookup first.
- EXPECT_EQ(
- FlatbufferToJson(GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
- kExpectedMultinodeLocation);
+ EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
+ aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
// Now confirm that a second message on the same name doesn't get remapped.
const char *kExpectedBazMultinodeLocation =
@@ -234,12 +229,8 @@
const Node *pi1 = GetNode(&config.message(), "pi1");
// Confirm that a glob with nothing after it matches.
- const char *kExpectedMultinodeLocation =
- "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
- "\"source_node\": \"pi1\" }";
- EXPECT_EQ(FlatbufferToJson(
- GetChannel(config, "/magic/string", ".aos.bar", "app7", pi1)),
- kExpectedMultinodeLocation);
+ EXPECT_THAT(GetChannel(config, "/magic/string", ".aos.bar", "app7", pi1),
+ aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
// Now confirm that glob with something following it matches and renames
// correctly.
diff --git a/aos/testing/BUILD b/aos/testing/BUILD
index 116acc0..d3287e3 100644
--- a/aos/testing/BUILD
+++ b/aos/testing/BUILD
@@ -102,3 +102,18 @@
target_compatible_with = ["@platforms//os:linux"],
visibility = ["//visibility:public"],
)
+
+cc_library(
+ name = "flatbuffer_eq",
+ testonly = True,
+ hdrs = [
+ "flatbuffer_eq.h",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//aos:flatbuffer_merge",
+ "//aos:flatbuffers",
+ "//aos:json_to_flatbuffer",
+ "@com_google_googletest//:gtest",
+ ],
+)
diff --git a/aos/testing/flatbuffer_eq.h b/aos/testing/flatbuffer_eq.h
new file mode 100644
index 0000000..03f3241
--- /dev/null
+++ b/aos/testing/flatbuffer_eq.h
@@ -0,0 +1,57 @@
+#ifndef AOS_TESTING_FLATBUFFER_EQ_H_
+#define AOS_TESTING_FLATBUFFER_EQ_H_
+
+#include "aos/flatbuffer_merge.h"
+#include "aos/flatbuffers.h"
+#include "aos/json_to_flatbuffer.h"
+#include "gmock/gmock.h"
+
+namespace aos {
+namespace testing {
+
+// Use FlatbufferEq to instantiate this.
+template <typename T>
+class FlatbufferEqMatcher {
+ public:
+ FlatbufferEqMatcher(aos::FlatbufferString<T> expected)
+ : expected_(std::move(expected)) {}
+
+ bool MatchAndExplain(const T *t,
+ ::testing::MatchResultListener *listener) const {
+ *listener << "is " << aos::FlatbufferToJson(t);
+ return aos::CompareFlatBuffer(t, &expected_.message());
+ }
+
+ bool MatchAndExplain(const aos::Flatbuffer<T> &t,
+ ::testing::MatchResultListener *listener) const {
+ return MatchAndExplain(&t.message(), listener);
+ }
+
+ void DescribeTo(std::ostream *os) const {
+ *os << "is equal to " << aos::FlatbufferToJson(&expected_.message());
+ }
+
+ void DescribeNegationTo(std::ostream *os) const {
+ *os << "is not equal to " << aos::FlatbufferToJson(&expected_.message());
+ }
+
+ private:
+ const aos::FlatbufferString<T> expected_;
+};
+
+// Returns a googlemock matcher which will compare a `const T *` or a `const
+// aos::Flatbuffer<T> &` against expected. This will automatically give nice
+// error messages if they don't match.
+//
+// T must be a flatbuffer table type.
+template <typename T>
+::testing::PolymorphicMatcher<FlatbufferEqMatcher<T>> FlatbufferEq(
+ const aos::NonSizePrefixedFlatbuffer<T> &expected) {
+ return ::testing::MakePolymorphicMatcher(
+ FlatbufferEqMatcher(aos::FlatbufferString<T>(expected)));
+}
+
+} // namespace testing
+} // namespace aos
+
+#endif // AOS_TESTING_FLATBUFFER_EQ_H_