blob: fb1b3e13f6eed255ac5fd26f4d176063113a68c3 [file] [log] [blame]
James Kuszmaulf5eb4682023-09-22 17:16:59 -07001#include "absl/strings/str_format.h"
2#include "absl/strings/str_join.h"
3#include "gmock/gmock.h"
4#include "gtest/gtest.h"
5
6#include "aos/flatbuffers.h"
7#include "aos/flatbuffers/builder.h"
8#include "aos/flatbuffers/static_flatbuffers.h"
9#include "aos/flatbuffers/test_dir/type_coverage_static.h"
10#include "aos/flatbuffers/test_static.h"
11#include "aos/json_to_flatbuffer.h"
12#include "aos/testing/path.h"
13#include "aos/testing/tmpdir.h"
14#include "aos/util/file.h"
15
16namespace aos::fbs::testing {
17
18class StaticFlatbuffersFuzzTest : public ::testing::Test {
19 protected:
20 template <typename T>
21 void VerifyJson(const std::string_view data) {
22 Builder<T> json_builder = aos::JsonToStaticFlatbuffer<T>(data);
23
24 EXPECT_EQ(data, aos::FlatbufferToJson(json_builder.AsFlatbufferSpan(),
25 {.multi_line = true}));
26 }
27};
28
29namespace {
30void Combine(const std::span<const std::vector<std::string_view>> &strings,
31 std::function<void(const std::vector<std::string_view> &)> handler,
32 const std::vector<std::string_view> &current_combination) {
33 if (strings.empty()) {
34 handler(current_combination);
35 return;
36 }
37 for (const std::string_view &str : strings.front()) {
38 std::vector<std::string_view> combination = current_combination;
39 combination.push_back(str);
40 Combine(strings.subspan(1), handler, combination);
41 }
42}
43void Combine(
44 const std::vector<std::vector<std::string_view>> &strings,
45 std::function<void(const std::vector<std::string_view> &)> handler) {
46 Combine(std::span<const std::vector<std::string_view>>{strings.data(),
47 strings.size()},
48 handler, {});
49}
50} // namespace
51
52// Iterate over lots of variations of different flatbuffers to try to see if we
53// can exercise weird corner-cases.
54TEST_F(StaticFlatbuffersFuzzTest, JsonFuzzing) {
55 std::vector<std::vector<std::string_view>> stanzas{
56 {"", "\"scalar\": 1323"},
57 {"", "\"vector_of_scalars\": [\n \n ]",
58 "\"vector_of_scalars\": [\n 123\n ]",
59 "\"vector_of_scalars\": [\n 123,\n 456\n ]"},
60 {"", "\"string\": \"\"", "\"string\": \"abcdef\"",
61 "\"string\": \"abcdefghijklmnopqrstuvwxyz\""},
62 {
63 "",
64 "\"vector_of_strings\": [\n \n ]",
65 "\"vector_of_strings\": [\n \"\",\n \"abcdef\"\n ]",
66 "\"vector_of_strings\": [\n \"\",\n \"abcdef\",\n "
67 "\"abcdefghijklmnopqrstuvwxyz\"\n ]",
68 "\"vector_of_strings\": [\n \"\",\n \"abcdef\",\n \"971\",\n "
69 "\"abcdefghijklmnopqrstuvwxyz\"\n ]",
70 "\"vector_of_strings\": [\n \"\",\n \"abcdef\",\n "
71 "\"abcdefghijklmnopqrstuvwxyz\",\n \"971\",\n \"123\"\n ]",
72 "\"vector_of_strings\": [\n \"\",\n \"abcdef\",\n \"xyz\",\n "
73 "\"971\",\n \"123\"\n ]",
74 },
75 {
76 "",
77 "\"substruct\": {\n \"x\": 971.0,\n \"y\": 123.0\n }",
78 },
79 {
80 "",
81 "\"subtable\": {\n\n }",
82 "\"subtable\": {\n \"baz\": 1.23\n }",
83 "\"subtable\": {\n \"foo\": 123,\n \"baz\": 1.23\n }",
84 },
85 {
86 "",
87 "\"vector_aligned\": [\n \n ]",
88 "\"vector_aligned\": [\n 678\n ]",
89 "\"vector_aligned\": [\n 678,\n 456\n ]",
90 "\"vector_aligned\": [\n 7,\n 6,\n 5,\n 4,\n 3,\n 2,\n 1,\n "
91 "0\n ]",
92 },
93 {
94 "",
95 "\"vector_of_structs\": [\n \n ]",
96 R"json("vector_of_structs": [
97 {
98 "x": 1.0,
99 "y": 2.0
100 }
101 ])json",
102 R"json("vector_of_structs": [
103 {
104 "x": 1.0,
105 "y": 2.0
106 },
107 {
108 "x": 3.0,
109 "y": 4.0
110 },
111 {
112 "x": 5.0,
113 "y": 6.0
114 }
115 ])json",
116 R"json("vector_of_structs": [
117 {
118 "x": 1.0,
119 "y": 2.0
120 },
121 {
122 "x": 3.0,
123 "y": 4.0
124 },
125 {
126 "x": 5.0,
127 "y": 6.0
128 },
129 {
130 "x": 7.0,
131 "y": 8.0
132 },
133 {
134 "x": 9.0,
135 "y": 10.0
136 }
137 ])json",
138 },
139 {
140 "",
141 "\"vector_of_tables\": [\n \n ]",
142 R"json("vector_of_tables": [
143 {
144
145 }
146 ])json",
147 R"json("vector_of_tables": [
148 {
149 "foo": 1
150 }
151 ])json",
152 R"json("vector_of_tables": [
153 {
154 "foo": 1
155 },
156 {
157 "foo": 2
158 },
159 {
160 "foo": 3
161 },
162 {
163 "foo": 4
164 },
165 {
166 "foo": 5
167 },
168 {
169 "foo": 6
170 }
171 ])json",
172 },
173 {
174 "",
175 "\"included_table\": {\n\n }",
176 "\"included_table\": {\n \"foo\": \"A\"\n }",
177 },
178 {
179 "",
180 "\"unspecified_length_vector\": [\n \n ]",
181 "\"unspecified_length_vector\": [\n 123\n ]",
182 "\"unspecified_length_vector\": [\n 123,\n 100\n ]",
183 },
184 {
185 "",
186 "\"unspecified_length_string\": \"\"",
187 "\"unspecified_length_string\": \"Hello, World!\"",
188 },
189 {
190 "",
191 "\"unspecified_length_vector_of_strings\": [\n \n ]",
192 "\"unspecified_length_vector_of_strings\": [\n \"\"\n ]",
193 "\"unspecified_length_vector_of_strings\": [\n \"Goodbye, \",\n "
194 "\"World!\"\n ]",
195 },
196 };
197 Combine(stanzas, [this](const std::vector<std::string_view> &strings) {
198 std::vector<std::string_view> no_empty_strings;
199 for (const std::string_view &str : strings) {
200 if (!str.empty()) {
201 no_empty_strings.push_back(str);
202 }
203 }
204 if (no_empty_strings.empty()) {
205 VerifyJson<TestTableStatic>("{\n\n}");
206 } else {
207 VerifyJson<TestTableStatic>(
208 "{\n " + absl::StrJoin(no_empty_strings, ",\n ") + "\n}");
209 }
210 });
211}
212} // namespace aos::fbs::testing