| #include <functional> |
| #include <span> |
| #include <string> |
| #include <string_view> |
| #include <vector> |
| |
| #include "absl/strings/str_join.h" |
| #include "gtest/gtest.h" |
| |
| #include "aos/flatbuffers/builder.h" |
| #include "aos/flatbuffers/test_static.h" |
| #include "aos/json_to_flatbuffer.h" |
| |
| namespace aos::fbs::testing { |
| |
| class StaticFlatbuffersFuzzTest : public ::testing::Test { |
| protected: |
| template <typename T> |
| void VerifyJson(const std::string_view data) { |
| Builder<T> json_builder = aos::JsonToStaticFlatbuffer<T>(data); |
| |
| EXPECT_EQ(data, aos::FlatbufferToJson(json_builder.AsFlatbufferSpan(), |
| {.multi_line = true})); |
| } |
| }; |
| |
| namespace { |
| void Combine(const std::span<const std::vector<std::string_view>> &strings, |
| std::function<void(const std::vector<std::string_view> &)> handler, |
| const std::vector<std::string_view> ¤t_combination) { |
| if (strings.empty()) { |
| handler(current_combination); |
| return; |
| } |
| for (const std::string_view &str : strings.front()) { |
| std::vector<std::string_view> combination = current_combination; |
| combination.push_back(str); |
| Combine(strings.subspan(1), handler, combination); |
| } |
| } |
| void Combine( |
| const std::vector<std::vector<std::string_view>> &strings, |
| std::function<void(const std::vector<std::string_view> &)> handler) { |
| Combine(std::span<const std::vector<std::string_view>>{strings.data(), |
| strings.size()}, |
| handler, {}); |
| } |
| } // namespace |
| |
| // Iterate over lots of variations of different flatbuffers to try to see if we |
| // can exercise weird corner-cases. |
| TEST_F(StaticFlatbuffersFuzzTest, JsonFuzzing) { |
| std::vector<std::vector<std::string_view>> stanzas{ |
| {"", "\"scalar\": 1323"}, |
| {"", "\"vector_of_scalars\": [\n \n ]", |
| "\"vector_of_scalars\": [\n 123\n ]", |
| "\"vector_of_scalars\": [\n 123,\n 456\n ]"}, |
| {"", "\"string\": \"\"", "\"string\": \"abcdef\"", |
| "\"string\": \"abcdefghijklmnopqrstuvwxyz\""}, |
| { |
| "", |
| "\"vector_of_strings\": [\n \n ]", |
| "\"vector_of_strings\": [\n \"\",\n \"abcdef\"\n ]", |
| "\"vector_of_strings\": [\n \"\",\n \"abcdef\",\n " |
| "\"abcdefghijklmnopqrstuvwxyz\"\n ]", |
| "\"vector_of_strings\": [\n \"\",\n \"abcdef\",\n \"971\",\n " |
| "\"abcdefghijklmnopqrstuvwxyz\"\n ]", |
| "\"vector_of_strings\": [\n \"\",\n \"abcdef\",\n " |
| "\"abcdefghijklmnopqrstuvwxyz\",\n \"971\",\n \"123\"\n ]", |
| "\"vector_of_strings\": [\n \"\",\n \"abcdef\",\n \"xyz\",\n " |
| "\"971\",\n \"123\"\n ]", |
| }, |
| { |
| "", |
| "\"substruct\": {\n \"x\": 971,\n \"y\": 123\n }", |
| }, |
| { |
| "", |
| "\"subtable\": {\n\n }", |
| "\"subtable\": {\n \"baz\": 1.23\n }", |
| "\"subtable\": {\n \"foo\": 123,\n \"baz\": 1.23\n }", |
| }, |
| { |
| "", |
| "\"vector_aligned\": [\n \n ]", |
| "\"vector_aligned\": [\n 678\n ]", |
| "\"vector_aligned\": [\n 678,\n 456\n ]", |
| "\"vector_aligned\": [\n 7,\n 6,\n 5,\n 4,\n 3,\n 2,\n 1,\n " |
| "0\n ]", |
| }, |
| { |
| "", |
| "\"vector_of_structs\": [\n \n ]", |
| R"json("vector_of_structs": [ |
| { |
| "x": 1, |
| "y": 2 |
| } |
| ])json", |
| R"json("vector_of_structs": [ |
| { |
| "x": 1, |
| "y": 2 |
| }, |
| { |
| "x": 3, |
| "y": 4 |
| }, |
| { |
| "x": 5, |
| "y": 6 |
| } |
| ])json", |
| R"json("vector_of_structs": [ |
| { |
| "x": 1, |
| "y": 2 |
| }, |
| { |
| "x": 3, |
| "y": 4 |
| }, |
| { |
| "x": 5, |
| "y": 6 |
| }, |
| { |
| "x": 7, |
| "y": 8 |
| }, |
| { |
| "x": 9, |
| "y": 10 |
| } |
| ])json", |
| }, |
| { |
| "", |
| "\"vector_of_tables\": [\n \n ]", |
| R"json("vector_of_tables": [ |
| { |
| |
| } |
| ])json", |
| R"json("vector_of_tables": [ |
| { |
| "foo": 1 |
| } |
| ])json", |
| R"json("vector_of_tables": [ |
| { |
| "foo": 1 |
| }, |
| { |
| "foo": 2 |
| }, |
| { |
| "foo": 3 |
| }, |
| { |
| "foo": 4 |
| }, |
| { |
| "foo": 5 |
| }, |
| { |
| "foo": 6 |
| } |
| ])json", |
| }, |
| { |
| "", |
| "\"included_table\": {\n\n }", |
| "\"included_table\": {\n \"foo\": \"A\"\n }", |
| }, |
| { |
| "", |
| "\"unspecified_length_vector\": [\n \n ]", |
| "\"unspecified_length_vector\": [\n 123\n ]", |
| "\"unspecified_length_vector\": [\n 123,\n 100\n ]", |
| }, |
| { |
| "", |
| "\"unspecified_length_string\": \"\"", |
| "\"unspecified_length_string\": \"Hello, World!\"", |
| }, |
| { |
| "", |
| "\"unspecified_length_vector_of_strings\": [\n \n ]", |
| "\"unspecified_length_vector_of_strings\": [\n \"\"\n ]", |
| "\"unspecified_length_vector_of_strings\": [\n \"Goodbye, \",\n " |
| "\"World!\"\n ]", |
| }, |
| }; |
| Combine(stanzas, [this](const std::vector<std::string_view> &strings) { |
| std::vector<std::string_view> no_empty_strings; |
| for (const std::string_view &str : strings) { |
| if (!str.empty()) { |
| no_empty_strings.push_back(str); |
| } |
| } |
| if (no_empty_strings.empty()) { |
| VerifyJson<TestTableStatic>("{\n\n}"); |
| } else { |
| VerifyJson<TestTableStatic>( |
| "{\n " + absl::StrJoin(no_empty_strings, ",\n ") + "\n}"); |
| } |
| }); |
| } |
| } // namespace aos::fbs::testing |