blob: a971d82434a25ed330eb7c425b56b8002385db13 [file] [log] [blame]
James Kuszmaulf5eb4682023-09-22 17:16:59 -07001#include "aos/flatbuffers/static_flatbuffers.h"
2
Stephan Pleines6191f1d2024-05-30 20:44:45 -07003#include <stdint.h>
4#include <string.h>
5
6#include <algorithm>
7#include <iostream>
8#include <iterator>
9#include <memory>
10#include <span>
11#include <type_traits>
12#include <utility>
13#include <vector>
14
James Kuszmaulf5eb4682023-09-22 17:16:59 -070015#include "absl/strings/str_format.h"
16#include "absl/strings/str_join.h"
Stephan Pleines6191f1d2024-05-30 20:44:45 -070017#include "absl/types/span.h"
James Kuszmaulf5eb4682023-09-22 17:16:59 -070018#include "external/com_github_google_flatbuffers/src/annotated_binary_text_gen.h"
19#include "external/com_github_google_flatbuffers/src/binary_annotator.h"
Stephan Pleines6191f1d2024-05-30 20:44:45 -070020#include "flatbuffers/base.h"
21#include "flatbuffers/buffer.h"
22#include "flatbuffers/flatbuffer_builder.h"
23#include "flatbuffers/stl_emulation.h"
24#include "flatbuffers/string.h"
25#include "flatbuffers/vector.h"
26#include "glog/logging.h"
James Kuszmaulf5eb4682023-09-22 17:16:59 -070027#include "gtest/gtest.h"
28
29#include "aos/flatbuffers.h"
Stephan Pleines6191f1d2024-05-30 20:44:45 -070030#include "aos/flatbuffers/base.h"
James Kuszmaulf5eb4682023-09-22 17:16:59 -070031#include "aos/flatbuffers/builder.h"
32#include "aos/flatbuffers/interesting_schemas.h"
Stephan Pleines6191f1d2024-05-30 20:44:45 -070033#include "aos/flatbuffers/static_vector.h"
34#include "aos/flatbuffers/test_dir/include_generated.h"
James Kuszmaul1e57af92023-12-20 15:34:54 -080035#include "aos/flatbuffers/test_dir/include_reflection_static.h"
Stephan Pleines6191f1d2024-05-30 20:44:45 -070036#include "aos/flatbuffers/test_dir/include_static.h"
37#include "aos/flatbuffers/test_dir/type_coverage_generated.h"
James Kuszmaulf5eb4682023-09-22 17:16:59 -070038#include "aos/flatbuffers/test_dir/type_coverage_static.h"
Stephan Pleines6191f1d2024-05-30 20:44:45 -070039#include "aos/flatbuffers/test_generated.h"
James Kuszmaulf5eb4682023-09-22 17:16:59 -070040#include "aos/flatbuffers/test_schema.h"
41#include "aos/flatbuffers/test_static.h"
42#include "aos/json_to_flatbuffer.h"
43#include "aos/testing/path.h"
44#include "aos/testing/tmpdir.h"
45#include "aos/util/file.h"
46
47namespace aos::fbs::testing {
48
49namespace {
50// Uses the binary schema to annotate a provided flatbuffer. Returns the
51// annotated flatbuffer.
52std::string AnnotateBinaries(
53 const aos::NonSizePrefixedFlatbuffer<reflection::Schema> &schema,
54 flatbuffers::span<uint8_t> binary_data) {
55 flatbuffers::BinaryAnnotator binary_annotator(
56 schema.span().data(), schema.span().size(), binary_data.data(),
57 binary_data.size());
58
59 auto annotations = binary_annotator.Annotate();
60 const std::string schema_filename =
61 aos::testing::TestTmpDir() + "/schema.bfbs";
62
63 aos::WriteFlatbufferToFile(schema_filename, schema);
64
65 flatbuffers::AnnotatedBinaryTextGenerator text_generator(
66 flatbuffers::AnnotatedBinaryTextGenerator::Options{}, annotations,
67 binary_data.data(), binary_data.size());
68
69 text_generator.Generate(aos::testing::TestTmpDir() + "/foo.bfbs",
70 schema_filename);
71
72 return aos::util::ReadFileToStringOrDie(aos::testing::TestTmpDir() +
73 "/foo.afb");
74}
75const reflection::Object *GetObjectByName(const reflection::Schema *schema,
76 std::string_view name) {
77 for (const reflection::Object *object : *schema->objects()) {
78 if (object->name()->string_view() == name) {
79 return object;
80 }
81 }
82 return nullptr;
83}
James Kuszmaul1c9693f2023-12-08 09:45:26 -080084
85// Accesses all the values in the supplied span. Used to ensure that memory
86// sanitizers can observe uninitialized memory.
87void TestMemory(std::span<uint8_t> memory) {
88 std::stringstream str;
89 internal::DebugBytes(memory, str);
90 EXPECT_LT(0u, str.view().size());
91}
James Kuszmaulf5eb4682023-09-22 17:16:59 -070092} // namespace
93
94class StaticFlatbuffersTest : public ::testing::Test {
95 protected:
96 template <typename T>
97 void VerifyJson(const std::string_view data) {
98 Builder<T> json_builder = aos::JsonToStaticFlatbuffer<T>(data);
99
100 EXPECT_EQ(data, aos::FlatbufferToJson(json_builder.AsFlatbufferSpan(),
101 {.multi_line = true}));
102 }
103 aos::FlatbufferSpan<reflection::Schema> test_schema_{TestTableSchema()};
104 aos::FlatbufferSpan<reflection::Schema> interesting_schemas_{
105 UnsupportedSchema()};
106};
107
108// Test that compiles the same code that is used by an example in
109// //aos/documentation/aos/docs/flatbuffers.md.
110TEST_F(StaticFlatbuffersTest, DocumentationExample) {
111 aos::fbs::VectorAllocator allocator;
112 Builder<TestTableStatic> builder(&allocator);
113 TestTableStatic *object = builder.get();
114 object->set_scalar(123);
115 {
116 auto vector = object->add_vector_of_scalars();
117 CHECK(vector->emplace_back(4));
118 CHECK(vector->emplace_back(5));
119 }
120 {
121 auto string = object->add_string();
122 string->SetString("Hello, World!");
123 }
124 {
125 auto vector_of_strings = object->add_vector_of_strings();
126 auto sub_string = CHECK_NOTNULL(vector_of_strings->emplace_back());
127 CHECK(sub_string->emplace_back('D'));
128 }
129 { object->set_substruct({971, 254}); }
130 {
131 auto subtable = object->add_subtable();
132 subtable->set_foo(1234);
133 }
134 {
135 auto vector = object->add_vector_of_structs();
136 CHECK(vector->emplace_back({48, 67}));
137 CHECK(vector->emplace_back({118, 148}));
138 CHECK(vector->emplace_back({971, 973}));
139 // Max vector size is three; this should fail.
140 CHECK(!vector->emplace_back({1114, 2056}));
141 }
142 {
143 auto vector = object->add_vector_of_tables();
144 auto subobject = vector->emplace_back();
145 subobject->set_foo(222);
146 }
147 {
148 auto subtable = object->add_included_table();
149 subtable->set_foo(included::TestEnum::B);
150 }
151 ASSERT_TRUE(builder.AsFlatbufferSpan().Verify());
152 LOG(INFO) << aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
153 {.multi_line = true});
154 LOG(INFO) << AnnotateBinaries(test_schema_, builder.buffer());
155}
156
157// Test that compiles the same code that is used by an example in
158// //aos/documentation/aos/docs/flatbuffers.md showing how to convert a
159// Populate*() method for adding a subtable to a flatbuffer.
160namespace {
161flatbuffers::Offset<SubTable> PopulateOld(flatbuffers::FlatBufferBuilder *fbb) {
162 SubTable::Builder builder(*fbb);
163 builder.add_foo(1234);
164 return builder.Finish();
165}
166void PopulateStatic(SubTableStatic *subtable) { subtable->set_foo(1234); }
167} // namespace
168TEST_F(StaticFlatbuffersTest, PopulateMethodConversionExample) {
169 // Using a FlatBufferBuilder:
170 flatbuffers::FlatBufferBuilder fbb;
171 // Note: the PopulateOld() *must* be called prior to creating the builder.
172 const flatbuffers::Offset<SubTable> subtable_offset = PopulateOld(&fbb);
173 TestTable::Builder testtable_builder(fbb);
174 testtable_builder.add_subtable(subtable_offset);
175 fbb.Finish(testtable_builder.Finish());
176 aos::FlatbufferDetachedBuffer<TestTable> fbb_finished = fbb.Release();
177
178 // Using the static flatbuffer API.
179 aos::fbs::VectorAllocator allocator;
180 Builder<TestTableStatic> static_builder(&allocator);
181 PopulateStatic(CHECK_NOTNULL(static_builder.get()->add_subtable()));
182
183 // And confirm that they both contain the expected flatbuffer:
184 const std::string expected = R"json({ "subtable": { "foo": 1234 } })json";
185 EXPECT_EQ(expected, aos::FlatbufferToJson(fbb_finished));
186 EXPECT_EQ(expected, aos::FlatbufferToJson(static_builder.AsFlatbufferSpan()));
187}
188
189TEST_F(StaticFlatbuffersTest, UnsupportedSchema) {
190 const reflection::Schema *schema = &interesting_schemas_.message();
191 EXPECT_DEATH(
192 GenerateCodeForObject(
193 schema, GetObjectByName(schema, "aos.fbs.testing.TableWithUnion")),
194 "Union not supported");
195 GenerateCodeForObject(
196 schema, GetObjectByName(schema, "aos.fbs.testing.MissingVectorLength"));
197 EXPECT_DEATH(
198 GenerateCodeForObject(
199 schema,
200 GetObjectByName(schema, "aos.fbs.testing.NonIntegerVectorLength")),
201 "vector_badlength must specify a positive integer for the "
202 "static_length attribute.");
203 EXPECT_DEATH(GenerateCodeForObject(
204 schema, GetObjectByName(
205 schema, "aos.fbs.testing.NegativeVectorLength")),
206 "Field vector_badlength must have a non-negative "
207 "static_length.");
208 GenerateCodeForObject(
209 schema, GetObjectByName(schema, "aos.fbs.testing.ZeroVectorLength"));
210 GenerateCodeForObject(
211 schema, GetObjectByName(schema, "aos.fbs.testing.MissingStringLength"));
212 GenerateCodeForObject(
213 schema,
214 GetObjectByName(schema, "aos.fbs.testing.MissingSubStringLength"));
215}
216
217// Tests that we can go through and manually build up a big flatbuffer and that
218// it stays valid at all points.
219TEST_F(StaticFlatbuffersTest, ManuallyConstructFlatbuffer) {
220 {
221 aos::fbs::VectorAllocator allocator;
222 Builder<SubTableStatic> builder(&allocator);
223 SubTableStatic *object = builder.get();
224 if (!builder.AsFlatbufferSpan().Verify()) {
225 LOG(ERROR) << object->SerializationDebugString() << "\nRoot table offset "
226 << *reinterpret_cast<const uoffset_t *>(
227 builder.buffer().data())
228 << "\nraw bytes\n";
229 aos::fbs::internal::DebugBytes(builder.buffer(), std::cerr);
230 FAIL();
231 return;
232 }
233 EXPECT_EQ("{ }", aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
234 object->set_foo(123);
235 object->set_baz(971);
236 CHECK(builder.AsFlatbufferSpan().Verify());
237 EXPECT_EQ(123, object->AsFlatbuffer().foo());
238 EXPECT_EQ(971, object->AsFlatbuffer().baz());
James Kuszmaul98c798d2024-04-24 15:58:09 -0700239 EXPECT_EQ(R"json({ "foo": 123, "baz": 971 })json",
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700240 aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
James Kuszmaul1c9693f2023-12-08 09:45:26 -0800241 TestMemory(builder.buffer());
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700242 }
243 {
Maxwell Hendersonfb1e3bc2024-02-04 13:55:22 -0800244 // aos::FixedAllocator
245 // allocator(TestTableStatic::kUnalignedBufferSize);
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700246 aos::fbs::VectorAllocator allocator;
247 Builder<TestTableStatic> builder(&allocator);
248 TestTableStatic *object = builder.get();
249 const aos::fbs::testing::TestTable &fbs = object->AsFlatbuffer();
250 VLOG(1) << object->SerializationDebugString();
251 CHECK(builder.AsFlatbufferSpan().Verify());
252 EXPECT_EQ("{ }", aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
253 {
254 ASSERT_FALSE(object->has_scalar());
255 object->set_scalar(123);
256 EXPECT_TRUE(fbs.has_scalar());
257 EXPECT_EQ(123, fbs.scalar());
258 }
259 EXPECT_EQ(R"json({ "scalar": 123 })json",
260 aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
261 {
262 ASSERT_FALSE(object->has_vector_of_scalars());
263 auto vector = object->add_vector_of_scalars();
264 ASSERT_TRUE(vector->emplace_back(4));
265 ASSERT_TRUE(vector->emplace_back(5));
266 ASSERT_TRUE(object->has_vector_of_scalars());
267 ASSERT_TRUE(fbs.has_vector_of_scalars());
268 VLOG(1) << vector->SerializationDebugString();
269 EXPECT_TRUE(fbs.has_vector_of_scalars());
270 EXPECT_EQ(2u, fbs.vector_of_scalars()->size());
271 EXPECT_EQ(4, fbs.vector_of_scalars()->Get(0));
272 EXPECT_EQ(5, fbs.vector_of_scalars()->Get(1));
273 }
274 EXPECT_EQ(R"json({ "scalar": 123, "vector_of_scalars": [ 4, 5 ] })json",
275 aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
276 {
277 EXPECT_FALSE(object->has_string());
278 auto string = object->add_string();
279 EXPECT_TRUE(object->has_string());
280 string->SetString("Hello, World!");
281 EXPECT_EQ(13u, object->string()->size());
282 ASSERT_TRUE(fbs.has_string());
283 ASSERT_EQ(13u, fbs.string()->size());
284 EXPECT_EQ("Hello, World!", fbs.string()->string_view());
285 // Check that we null-terminated correctly.
286 EXPECT_EQ(13u, strnlen(fbs.string()->c_str(), 20));
287 }
288 EXPECT_EQ(
289 R"json({ "scalar": 123, "vector_of_scalars": [ 4, 5 ], "string": "Hello, World!" })json",
290 aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
291 {
292 EXPECT_FALSE(object->has_vector_of_strings());
293 auto vector_of_strings = object->add_vector_of_strings();
294 EXPECT_TRUE(object->has_vector_of_strings());
295 auto sub_string = CHECK_NOTNULL(vector_of_strings->emplace_back());
296 ASSERT_TRUE(sub_string->emplace_back('D'));
297 EXPECT_TRUE(fbs.has_vector_of_strings());
298 ASSERT_EQ(1u, fbs.vector_of_strings()->size());
299 ASSERT_EQ(1u, fbs.vector_of_strings()->Get(0)->size());
300 EXPECT_EQ('D', fbs.vector_of_strings()->Get(0)->Get(0));
301 }
302 EXPECT_EQ(
303 R"json({
304 "scalar": 123,
305 "vector_of_scalars": [
306 4,
307 5
308 ],
309 "string": "Hello, World!",
310 "vector_of_strings": [
311 "D"
312 ]
313})json",
314 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
315 {.multi_line = true}));
316 {
317 EXPECT_FALSE(object->has_substruct());
318 object->set_substruct({971, 254});
319 EXPECT_TRUE(object->has_substruct());
320 EXPECT_TRUE(fbs.has_substruct());
321 EXPECT_EQ(971, fbs.substruct()->x());
322 EXPECT_EQ(254, fbs.substruct()->y());
323 }
324 EXPECT_EQ(
325 R"json({
326 "scalar": 123,
327 "vector_of_scalars": [
328 4,
329 5
330 ],
331 "string": "Hello, World!",
332 "vector_of_strings": [
333 "D"
334 ],
335 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700336 "x": 971,
337 "y": 254
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700338 }
339})json",
340 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
341 {.multi_line = true}));
342 {
343 auto subtable = object->add_subtable();
344 subtable->set_foo(1234);
345 EXPECT_TRUE(fbs.has_subtable());
346 EXPECT_EQ(1234, fbs.subtable()->foo());
347 EXPECT_FALSE(fbs.subtable()->has_baz());
348 }
349 EXPECT_EQ(
350 R"json({
351 "scalar": 123,
352 "vector_of_scalars": [
353 4,
354 5
355 ],
356 "string": "Hello, World!",
357 "vector_of_strings": [
358 "D"
359 ],
360 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700361 "x": 971,
362 "y": 254
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700363 },
364 "subtable": {
365 "foo": 1234
366 }
367})json",
368 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
369 {.multi_line = true}));
370 {
371 auto vector = object->add_vector_of_structs();
372 ASSERT_TRUE(vector->emplace_back({48, 67}));
373 ASSERT_TRUE(vector->emplace_back({118, 148}));
374 ASSERT_TRUE(vector->emplace_back({971, 973}));
375 ASSERT_FALSE(vector->emplace_back({1114, 2056}));
376 EXPECT_TRUE(fbs.has_vector_of_structs());
377 EXPECT_EQ(3u, fbs.vector_of_structs()->size());
378 EXPECT_EQ(48, fbs.vector_of_structs()->Get(0)->x());
379 EXPECT_EQ(67, fbs.vector_of_structs()->Get(0)->y());
380 EXPECT_EQ(118, fbs.vector_of_structs()->Get(1)->x());
381 EXPECT_EQ(object->vector_of_structs()->at(1).x(),
382 fbs.vector_of_structs()->Get(1)->x());
383 EXPECT_EQ((*object->vector_of_structs())[1].x(),
384 fbs.vector_of_structs()->Get(1)->x());
385 EXPECT_EQ(148, fbs.vector_of_structs()->Get(1)->y());
386 EXPECT_EQ(971, fbs.vector_of_structs()->Get(2)->x());
387 EXPECT_EQ(973, fbs.vector_of_structs()->Get(2)->y());
388 }
389 EXPECT_EQ(
390 R"json({
391 "scalar": 123,
392 "vector_of_scalars": [
393 4,
394 5
395 ],
396 "string": "Hello, World!",
397 "vector_of_strings": [
398 "D"
399 ],
400 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700401 "x": 971,
402 "y": 254
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700403 },
404 "subtable": {
405 "foo": 1234
406 },
407 "vector_of_structs": [
408 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700409 "x": 48,
410 "y": 67
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700411 },
412 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700413 "x": 118,
414 "y": 148
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700415 },
416 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700417 "x": 971,
418 "y": 973
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700419 }
420 ]
421})json",
422 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
423 {.multi_line = true}));
424 {
425 EXPECT_FALSE(object->has_vector_of_tables());
426 auto vector = object->add_vector_of_tables();
427 EXPECT_TRUE(object->has_vector_of_tables());
428 auto subobject = vector->emplace_back();
429 subobject->set_foo(222);
430 EXPECT_TRUE(fbs.has_vector_of_tables());
431 EXPECT_EQ(1u, fbs.vector_of_tables()->size());
432 EXPECT_EQ(222, fbs.vector_of_tables()->Get(0)->foo());
433 EXPECT_EQ(object->vector_of_tables()->at(0).foo(),
434 fbs.vector_of_tables()->Get(0)->foo());
435 }
436 EXPECT_EQ(
437 R"json({
438 "scalar": 123,
439 "vector_of_scalars": [
440 4,
441 5
442 ],
443 "string": "Hello, World!",
444 "vector_of_strings": [
445 "D"
446 ],
447 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700448 "x": 971,
449 "y": 254
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700450 },
451 "subtable": {
452 "foo": 1234
453 },
454 "vector_of_structs": [
455 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700456 "x": 48,
457 "y": 67
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700458 },
459 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700460 "x": 118,
461 "y": 148
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700462 },
463 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700464 "x": 971,
465 "y": 973
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700466 }
467 ],
468 "vector_of_tables": [
469 {
470 "foo": 222
471 }
472 ]
473})json",
474 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
475 {.multi_line = true}));
476 {
477 EXPECT_FALSE(object->has_included_table());
478 auto subtable = object->add_included_table();
479 EXPECT_TRUE(object->has_included_table());
480 subtable->set_foo(included::TestEnum::B);
481 ASSERT_TRUE(fbs.has_included_table());
482 ASSERT_TRUE(fbs.included_table()->has_foo());
483 EXPECT_EQ(included::TestEnum::B, fbs.included_table()->foo());
484 }
485 EXPECT_EQ(
486 R"json({
487 "scalar": 123,
488 "vector_of_scalars": [
489 4,
490 5
491 ],
492 "string": "Hello, World!",
493 "vector_of_strings": [
494 "D"
495 ],
496 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700497 "x": 971,
498 "y": 254
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700499 },
500 "subtable": {
501 "foo": 1234
502 },
503 "vector_of_structs": [
504 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700505 "x": 48,
506 "y": 67
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700507 },
508 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700509 "x": 118,
510 "y": 148
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700511 },
512 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700513 "x": 971,
514 "y": 973
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700515 }
516 ],
517 "vector_of_tables": [
518 {
519 "foo": 222
520 }
521 ],
522 "included_table": {
523 "foo": "B"
524 }
525})json",
526 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
527 {.multi_line = true}));
528 {
529 auto aligned_vector = object->add_vector_aligned();
530 ASSERT_EQ(64,
531 std::remove_reference<decltype(*aligned_vector)>::type::kAlign);
532 ASSERT_EQ(64, TestTableStatic::kAlign);
533 ASSERT_TRUE(aligned_vector->emplace_back(444));
534 EXPECT_TRUE(fbs.has_vector_aligned());
535 EXPECT_EQ(1u, fbs.vector_aligned()->size());
536 EXPECT_EQ(0u,
537 reinterpret_cast<size_t>(fbs.vector_aligned()->data()) % 64);
538 EXPECT_EQ(444, fbs.vector_aligned()->Get(0));
539 }
540 VLOG(1) << object->SerializationDebugString();
541 CHECK(builder.AsFlatbufferSpan().Verify());
542 const std::string expected_contents =
543 R"json({
544 "scalar": 123,
545 "vector_of_scalars": [
546 4,
547 5
548 ],
549 "string": "Hello, World!",
550 "vector_of_strings": [
551 "D"
552 ],
553 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700554 "x": 971,
555 "y": 254
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700556 },
557 "subtable": {
558 "foo": 1234
559 },
560 "vector_aligned": [
561 444
562 ],
563 "vector_of_structs": [
564 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700565 "x": 48,
566 "y": 67
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700567 },
568 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700569 "x": 118,
570 "y": 148
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700571 },
572 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700573 "x": 971,
574 "y": 973
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700575 }
576 ],
577 "vector_of_tables": [
578 {
579 "foo": 222
580 }
581 ],
582 "included_table": {
583 "foo": "B"
584 }
585})json";
586 EXPECT_EQ(expected_contents,
587 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
588 {.multi_line = true}));
589 VLOG(1) << AnnotateBinaries(test_schema_, builder.buffer());
590 VerifyJson<TestTableStatic>(expected_contents);
591 {
592 auto aligned_vector = object->mutable_vector_aligned();
593 ASSERT_TRUE(aligned_vector->reserve(100));
594 EXPECT_EQ(100, aligned_vector->capacity());
595 ASSERT_TRUE(builder.AsFlatbufferSpan().Verify())
596 << aligned_vector->SerializationDebugString();
597 EXPECT_EQ(expected_contents,
598 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
599 {.multi_line = true}));
600 std::vector<int> scalars;
601 scalars.push_back(aligned_vector->at(0));
602 while (aligned_vector->size() < 100u) {
603 scalars.push_back(aligned_vector->size());
604 CHECK(aligned_vector->emplace_back(aligned_vector->size()));
605 }
606 VLOG(1) << aligned_vector->SerializationDebugString();
607 VLOG(1) << AnnotateBinaries(test_schema_, builder.buffer());
608 EXPECT_EQ(absl::StrFormat(
609 R"json({
610 "scalar": 123,
611 "vector_of_scalars": [
612 4,
613 5
614 ],
615 "string": "Hello, World!",
616 "vector_of_strings": [
617 "D"
618 ],
619 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700620 "x": 971,
621 "y": 254
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700622 },
623 "subtable": {
624 "foo": 1234
625 },
626 "vector_aligned": [
627 %s
628 ],
629 "vector_of_structs": [
630 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700631 "x": 48,
632 "y": 67
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700633 },
634 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700635 "x": 118,
636 "y": 148
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700637 },
638 {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700639 "x": 971,
640 "y": 973
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700641 }
642 ],
643 "vector_of_tables": [
644 {
645 "foo": 222
646 }
647 ],
648 "included_table": {
649 "foo": "B"
650 }
651})json",
652 absl::StrJoin(scalars, ",\n ")),
653 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
654 {.multi_line = true}));
655 }
656
657 {
658 auto unspecified_vector = object->add_unspecified_length_vector();
659 ASSERT_NE(nullptr, unspecified_vector);
660 ASSERT_EQ(0, unspecified_vector->capacity());
661 ASSERT_FALSE(unspecified_vector->emplace_back(0));
662 ASSERT_TRUE(unspecified_vector->reserve(2));
663 ASSERT_TRUE(unspecified_vector->emplace_back(1));
664 ASSERT_TRUE(unspecified_vector->emplace_back(2));
665 ASSERT_FALSE(unspecified_vector->emplace_back(3));
666 ASSERT_TRUE(builder.AsFlatbufferSpan().Verify());
667 }
James Kuszmaul1c9693f2023-12-08 09:45:26 -0800668 TestMemory(builder.buffer());
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700669 }
670}
671
672// Tests that field clearing (and subsequent resetting) works properly.
673TEST_F(StaticFlatbuffersTest, ClearFields) {
674 aos::fbs::VectorAllocator allocator;
675 Builder<TestTableStatic> builder(&allocator);
676 TestTableStatic *object = builder.get();
677 // For each field, we will confirm the following:
678 // * Clearing a non-existent field causes no issues.
679 // * We can set a field, clear it, and have it not be present.
680 // * We can set the field again afterwards.
681 {
682 object->clear_scalar();
683 ASSERT_TRUE(builder.Verify());
684 object->set_scalar(123);
685 EXPECT_EQ(123, object->AsFlatbuffer().scalar());
686 object->clear_scalar();
687 ASSERT_TRUE(builder.Verify());
688 EXPECT_FALSE(object->has_scalar());
689 object->set_scalar(456);
690 EXPECT_EQ(456, object->AsFlatbuffer().scalar());
691 }
692 {
693 object->clear_vector_of_scalars();
694 ASSERT_TRUE(builder.Verify());
695 EXPECT_FALSE(object->has_vector_of_scalars());
696 auto vector = object->add_vector_of_scalars();
697 ASSERT_TRUE(vector->emplace_back(4));
698 ASSERT_TRUE(vector->emplace_back(5));
699 ASSERT_TRUE(vector->emplace_back(6));
700 // Deliberately force a resize of the vector to ensure that we can exercise
701 // what happens if we clear a non-standard size field.
702 ASSERT_FALSE(vector->emplace_back(7));
703 ASSERT_TRUE(vector->reserve(4));
704 ASSERT_TRUE(vector->emplace_back(7));
705 EXPECT_EQ(
706 R"json({
707 "scalar": 456,
708 "vector_of_scalars": [
709 4,
710 5,
711 6,
712 7
713 ]
714})json",
715 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
716 {.multi_line = true}));
717 ASSERT_TRUE(builder.Verify());
718 object->clear_vector_of_scalars();
719 ASSERT_TRUE(builder.Verify());
720 ASSERT_FALSE(object->has_vector_of_scalars())
721 << aos::FlatbufferToJson(builder.AsFlatbufferSpan());
722 vector = CHECK_NOTNULL(object->add_vector_of_scalars());
723 ASSERT_TRUE(builder.Verify());
724 EXPECT_EQ(0u, object->AsFlatbuffer().vector_of_scalars()->size());
725 ASSERT_TRUE(vector->emplace_back(9));
726 ASSERT_TRUE(vector->emplace_back(7));
727 ASSERT_TRUE(vector->emplace_back(1));
728 // This vector has no knowledge of the past resizing; it should fail to add
729 // an extra number.
730 ASSERT_FALSE(vector->emplace_back(7));
731 }
732 {
733 object->clear_substruct();
734 ASSERT_TRUE(builder.Verify());
735 EXPECT_FALSE(object->has_substruct());
736 object->set_substruct(SubStruct{2, 3});
737 EXPECT_EQ(
738 R"json({
739 "scalar": 456,
740 "vector_of_scalars": [
741 9,
742 7,
743 1
744 ],
745 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700746 "x": 2,
747 "y": 3
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700748 }
749})json",
750 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
751 {.multi_line = true}));
752 object->clear_substruct();
753 ASSERT_TRUE(builder.Verify());
754 EXPECT_FALSE(object->has_substruct());
755 object->set_substruct(SubStruct{4, 5});
756 EXPECT_EQ(
757 R"json({
758 "scalar": 456,
759 "vector_of_scalars": [
760 9,
761 7,
762 1
763 ],
764 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700765 "x": 4,
766 "y": 5
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700767 }
768})json",
769 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
770 {.multi_line = true}));
771 }
772 {
773 object->clear_subtable();
774 ASSERT_TRUE(builder.Verify());
775 EXPECT_FALSE(object->has_subtable());
776 auto subtable = CHECK_NOTNULL(object->add_subtable());
777 subtable->set_baz(9.71);
778 EXPECT_EQ(
779 R"json({
780 "scalar": 456,
781 "vector_of_scalars": [
782 9,
783 7,
784 1
785 ],
786 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700787 "x": 4,
788 "y": 5
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700789 },
790 "subtable": {
791 "baz": 9.71
792 }
793})json",
794 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
795 {.multi_line = true}));
796 object->clear_subtable();
797 ASSERT_TRUE(builder.Verify());
798 EXPECT_FALSE(object->has_subtable());
799 subtable = CHECK_NOTNULL(object->add_subtable());
800 subtable->set_baz(16.78);
801 EXPECT_EQ(
802 R"json({
803 "scalar": 456,
804 "vector_of_scalars": [
805 9,
806 7,
807 1
808 ],
809 "substruct": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700810 "x": 4,
811 "y": 5
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700812 },
813 "subtable": {
James Kuszmaul98c798d2024-04-24 15:58:09 -0700814 "baz": 16.78
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700815 }
816})json",
817 aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
818 {.multi_line = true}));
819 }
James Kuszmaul1c9693f2023-12-08 09:45:26 -0800820 TestMemory(builder.buffer());
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700821}
822
823// Try to cover ~all supported scalar/flatbuffer types using JSON convenience
824// functions.
825TEST_F(StaticFlatbuffersTest, FlatbufferTypeCoverage) {
Stephan Pleines9e40c8e2024-02-07 20:58:28 -0800826 VerifyJson<aos::testing::ConfigurationStatic>("{\n\n}");
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700827 std::string populated_config =
828 aos::util::ReadFileToStringOrDie(aos::testing::ArtifactPath(
829 "aos/flatbuffers/test_dir/type_coverage.json"));
830 // Get rid of a pesky new line.
831 populated_config = populated_config.substr(0, populated_config.size() - 1);
Stephan Pleines9e40c8e2024-02-07 20:58:28 -0800832 VerifyJson<aos::testing::ConfigurationStatic>(populated_config);
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700833
834 // And now play around with mutating the buffer.
Stephan Pleines9e40c8e2024-02-07 20:58:28 -0800835 Builder<aos::testing::ConfigurationStatic> builder =
836 aos::JsonToStaticFlatbuffer<aos::testing::ConfigurationStatic>(
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700837 populated_config);
838 ASSERT_TRUE(builder.Verify());
839 builder.get()->clear_foo_float();
840 ASSERT_TRUE(builder.Verify());
841 ASSERT_FALSE(builder.get()->AsFlatbuffer().has_foo_float());
842 builder.get()->set_foo_float(1.111);
843 ASSERT_TRUE(builder.Verify());
844 ASSERT_FLOAT_EQ(1.111, builder.get()->AsFlatbuffer().foo_float());
James Kuszmaul1c9693f2023-12-08 09:45:26 -0800845 TestMemory(builder.buffer());
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700846}
847
James Kuszmaula75cd7c2023-12-07 15:52:51 -0800848TEST_F(StaticFlatbuffersTest, MinimallyAlignedTable) {
849 VerifyJson<MinimallyAlignedTableStatic>("{\n \"field\": 123\n}");
850 static_assert(4u == alignof(uoffset_t),
851 "The alignment of a uoffset_t is expected to be 4.");
852 ASSERT_EQ(alignof(uoffset_t), MinimallyAlignedTableStatic::kAlign)
853 << "No table should have an alignment of less than the alignment of the "
854 "table's root offset.";
855}
856
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700857// Confirm that we can use the SpanAllocator with a span that provides exactly
858// the required buffer size.
859TEST_F(StaticFlatbuffersTest, ExactSizeSpanAllocator) {
James Kuszmaul1c9693f2023-12-08 09:45:26 -0800860 uint8_t buffer[Builder<TestTableStatic>::kBufferSize];
861 aos::fbs::SpanAllocator allocator({buffer, sizeof(buffer)});
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700862 Builder<TestTableStatic> builder(&allocator);
863 TestTableStatic *object = builder.get();
864 object->set_scalar(123);
865 {
866 auto vector = object->add_vector_of_scalars();
867 ASSERT_TRUE(vector->emplace_back(4));
868 ASSERT_TRUE(vector->emplace_back(5));
869 }
870 {
871 auto string = object->add_string();
872 string->SetString("Hello, World!");
873 }
874 {
875 auto vector_of_strings = object->add_vector_of_strings();
876 auto sub_string = CHECK_NOTNULL(vector_of_strings->emplace_back());
877 ASSERT_TRUE(sub_string->emplace_back('D'));
878 }
879 { object->set_substruct({971, 254}); }
880 {
881 auto subtable = object->add_subtable();
882 subtable->set_foo(1234);
883 }
884 {
885 auto vector = object->add_vector_of_structs();
886 ASSERT_TRUE(vector->emplace_back({48, 67}));
887 ASSERT_TRUE(vector->emplace_back({118, 148}));
888 ASSERT_TRUE(vector->emplace_back({971, 973}));
889 // Max vector size is three; this should fail.
890 ASSERT_FALSE(vector->emplace_back({1114, 2056}));
891 // We don't have any extra space available.
892 ASSERT_FALSE(vector->reserve(4));
893 ASSERT_FALSE(vector->emplace_back({1114, 2056}));
894 }
895 {
896 auto vector = object->add_vector_of_tables();
897 auto subobject = vector->emplace_back();
898 subobject->set_foo(222);
899 }
900 {
901 auto subtable = object->add_included_table();
902 subtable->set_foo(included::TestEnum::B);
903 }
904 ASSERT_TRUE(builder.AsFlatbufferSpan().Verify());
905 VLOG(1) << aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
906 {.multi_line = true});
907 VLOG(1) << AnnotateBinaries(test_schema_, builder.buffer());
James Kuszmaul1c9693f2023-12-08 09:45:26 -0800908 TestMemory(builder.buffer());
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700909}
910
911// Test that when we provide too small of a span to the Builder that it
912// correctly fails.
913TEST_F(StaticFlatbuffersTest, TooSmallSpanAllocator) {
914 std::vector<uint8_t> buffer;
915 buffer.resize(10, 0);
916 aos::fbs::SpanAllocator allocator({buffer.data(), buffer.size()});
917 EXPECT_DEATH(Builder<TestTableStatic>{&allocator}, "Failed to allocate");
918}
919
920// Verify that if we create a span with extra headroom that that lets us
921// dynamically alter the size of vectors in the flatbuffers.
922TEST_F(StaticFlatbuffersTest, ExtraLargeSpanAllocator) {
James Kuszmaul1c9693f2023-12-08 09:45:26 -0800923 uint8_t buffer[Builder<TestTableStatic>::kBufferSize + 10000];
924 aos::fbs::SpanAllocator allocator({buffer, sizeof(buffer)});
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700925 Builder<TestTableStatic> builder(&allocator);
926 TestTableStatic *object = builder.get();
927 {
928 auto vector = object->add_unspecified_length_vector();
929 // Confirm that the vector does indeed start out at zero length.
930 ASSERT_FALSE(vector->emplace_back(4));
931 ASSERT_TRUE(vector->reserve(9000));
932 vector->resize(256);
933 for (size_t index = 0; index < 256; ++index) {
934 vector->at(index) = static_cast<uint8_t>(index);
935 }
936 }
937 ASSERT_EQ(256, object->AsFlatbuffer().unspecified_length_vector()->size());
938 size_t expected = 0;
939 for (const uint8_t value :
940 *object->AsFlatbuffer().unspecified_length_vector()) {
941 EXPECT_EQ(expected++, value);
942 }
James Kuszmaul22448052023-12-14 15:55:14 -0800943 expected = 0;
944 for (const uint8_t value : *object->unspecified_length_vector()) {
945 EXPECT_EQ(expected++, value);
946 }
James Kuszmaul1c9693f2023-12-08 09:45:26 -0800947 TestMemory(builder.buffer());
James Kuszmaulf5eb4682023-09-22 17:16:59 -0700948}
James Kuszmaul22448052023-12-14 15:55:14 -0800949
950// Tests that the iterators on the Vector type work.
951TEST_F(StaticFlatbuffersTest, IteratorTest) {
952 Builder<TestTableStatic> builder(std::make_unique<VectorAllocator>());
953 {
954 auto vector = builder->add_unspecified_length_vector();
955 ASSERT_TRUE(vector->reserve(9000));
956 vector->resize(256);
957 uint8_t set_value = 0;
958 for (uint8_t &destination : *vector) {
959 destination = set_value;
960 ++set_value;
961 }
962 uint8_t expected = 0;
963 for (const uint8_t value : *builder->unspecified_length_vector()) {
964 EXPECT_EQ(expected, value);
965 ++expected;
966 }
967 // Exercise some of the random access iterator functionality to ensure that
968 // we have it implemented.
969 auto begin_it = vector->begin();
970 EXPECT_EQ(begin_it + 256, vector->end());
971 EXPECT_EQ(7, *(begin_it + 7));
972 EXPECT_EQ(255, *(vector->end() - 1));
973 EXPECT_EQ(256, vector->end() - vector->begin());
974 EXPECT_EQ(-256, vector->begin() - vector->end());
975 static_assert(std::random_access_iterator<decltype(vector->begin())>,
976 "The vector iterator does not meet the requirements of a "
977 "random access iterator.");
978 }
979 {
980 auto vector = builder->add_vector_of_structs();
981 vector->resize(3);
982 double set_value = 0;
983 for (SubStruct &destination : *vector) {
984 destination.mutate_x(set_value);
985 destination.mutate_y(-set_value);
986 set_value += 1.0;
987 }
988 double expected = 0;
989 for (const SubStruct &value : *builder->vector_of_structs()) {
990 EXPECT_EQ(expected, value.x());
991 EXPECT_EQ(-expected, value.y());
992 expected += 1.0;
993 }
994 static_assert(std::random_access_iterator<decltype(vector->begin())>,
995 "The vector iterator does not meet the requirements of a "
996 "random access iterator.");
997 }
998 {
999 auto vector = builder->add_vector_of_tables();
1000 vector->resize(3);
1001 int set_value = 0;
1002 for (SubTableStatic &destination : *vector) {
1003 destination.set_foo(set_value);
1004 set_value += 1;
1005 }
1006 int expected = 0;
1007 for (const SubTableStatic &value : *builder->vector_of_tables()) {
1008 EXPECT_EQ(expected, value.foo());
1009 EXPECT_FALSE(value.has_baz());
1010 expected += 1;
1011 }
1012 static_assert(std::random_access_iterator<decltype(vector->begin())>,
1013 "The vector iterator does not meet the requirements of a "
1014 "random access iterator.");
1015 }
1016}
Maxwell Hendersonfb1e3bc2024-02-04 13:55:22 -08001017
1018// Confirm that we can use the FixedStackAllocator
1019TEST_F(StaticFlatbuffersTest, FixedStackAllocator) {
1020 aos::fbs::FixedStackAllocator<Builder<TestTableStatic>::kBufferSize>
1021 allocator;
1022 Builder<TestTableStatic> builder(&allocator);
1023 TestTableStatic *object = builder.get();
1024 object->set_scalar(123);
1025 {
1026 auto vector = object->add_vector_of_scalars();
1027 ASSERT_TRUE(vector->emplace_back(4));
1028 ASSERT_TRUE(vector->emplace_back(5));
1029 }
1030 {
1031 auto string = object->add_string();
1032 string->SetString("Hello, World!");
1033 }
1034 {
1035 auto vector_of_strings = object->add_vector_of_strings();
1036 auto sub_string = CHECK_NOTNULL(vector_of_strings->emplace_back());
1037 ASSERT_TRUE(sub_string->emplace_back('D'));
1038 }
1039 { object->set_substruct({971, 254}); }
1040 {
1041 auto subtable = object->add_subtable();
1042 subtable->set_foo(1234);
1043 }
1044 {
1045 auto vector = object->add_vector_of_structs();
1046 ASSERT_TRUE(vector->emplace_back({48, 67}));
1047 ASSERT_TRUE(vector->emplace_back({118, 148}));
1048 ASSERT_TRUE(vector->emplace_back({971, 973}));
1049 // Max vector size is three; this should fail.
1050 ASSERT_FALSE(vector->emplace_back({1114, 2056}));
1051 // We don't have any extra space available.
1052 ASSERT_FALSE(vector->reserve(4));
1053 ASSERT_FALSE(vector->emplace_back({1114, 2056}));
1054 }
1055 {
1056 auto vector = object->add_vector_of_tables();
1057 auto subobject = vector->emplace_back();
1058 subobject->set_foo(222);
1059 }
1060 {
1061 auto subtable = object->add_included_table();
1062 subtable->set_foo(included::TestEnum::B);
1063 }
1064 ASSERT_TRUE(builder.AsFlatbufferSpan().Verify());
1065 VLOG(1) << aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
1066 {.multi_line = true});
1067 VLOG(1) << AnnotateBinaries(test_schema_, builder.buffer());
1068 TestMemory(builder.buffer());
1069}
1070
James Kuszmaul6be41022023-12-20 11:55:28 -08001071// Uses a small example to manually verify that we can copy from the flatbuffer
1072// object API.
1073TEST_F(StaticFlatbuffersTest, ObjectApiCopy) {
1074 aos::fbs::testing::TestTableT object_t;
1075 object_t.scalar = 971;
1076 object_t.vector_of_strings.push_back("971");
1077 object_t.vector_of_structs.push_back({1, 2});
1078 object_t.subtable = std::make_unique<SubTableT>();
1079 aos::fbs::VectorAllocator allocator;
1080 Builder<TestTableStatic> builder(&allocator);
1081 ASSERT_TRUE(builder->FromFlatbuffer(object_t));
1082 ASSERT_TRUE(builder.AsFlatbufferSpan().Verify());
1083 // Note that vectors and strings get set to zero-length, but present, values.
1084 EXPECT_EQ(
1085 "{ \"scalar\": 971, \"vector_of_scalars\": [ ], \"string\": \"\", "
1086 "\"vector_of_strings\": [ \"971\" ], \"subtable\": { \"foo\": 0, "
James Kuszmaul98c798d2024-04-24 15:58:09 -07001087 "\"baz\": 0 }, \"vector_aligned\": [ ], \"vector_of_structs\": [ { "
1088 "\"x\": 1, \"y\": 2 } ], \"vector_of_tables\": [ ], "
James Kuszmaul6be41022023-12-20 11:55:28 -08001089 "\"unspecified_length_vector\": [ ], \"unspecified_length_string\": "
1090 "\"\", \"unspecified_length_vector_of_strings\": [ ] }",
1091 aos::FlatbufferToJson(builder.AsFlatbufferSpan()));
1092}
1093
1094// More completely covers our object API copying by comparing the flatbuffer
1095// Pack() methods to our FromFlatbuffer() methods.
1096TEST_F(StaticFlatbuffersTest, FlatbufferObjectTypeCoverage) {
1097 VerifyJson<aos::testing::ConfigurationStatic>("{\n\n}");
1098 std::string populated_config =
1099 aos::util::ReadFileToStringOrDie(aos::testing::ArtifactPath(
1100 "aos/flatbuffers/test_dir/type_coverage.json"));
1101 Builder<aos::testing::ConfigurationStatic> json_builder =
1102 aos::JsonToStaticFlatbuffer<aos::testing::ConfigurationStatic>(
1103 populated_config);
1104 aos::testing::ConfigurationT object_t;
1105 json_builder->AsFlatbuffer().UnPackTo(&object_t);
1106
1107 Builder<aos::testing::ConfigurationStatic> from_object_static;
1108 ASSERT_TRUE(from_object_static->FromFlatbuffer(object_t));
1109 flatbuffers::FlatBufferBuilder fbb;
1110 fbb.Finish(aos::testing::Configuration::Pack(fbb, &object_t));
1111 aos::FlatbufferDetachedBuffer<aos::testing::Configuration> from_object_raw =
1112 fbb.Release();
1113 EXPECT_EQ(aos::FlatbufferToJson(from_object_raw, {.multi_line = true}),
1114 aos::FlatbufferToJson(from_object_static, {.multi_line = true}));
1115}
1116
James Kuszmaul1e57af92023-12-20 15:34:54 -08001117// Tests that we can build code that uses the reflection types.
1118TEST_F(StaticFlatbuffersTest, IncludeReflectionTypes) {
1119 VerifyJson<::aos::testing::UseSchemaStatic>("{\n\n}");
1120}
1121
James Kuszmauld4b4f1d2024-03-13 15:57:35 -07001122// Tests that we can use the move constructor on a Builder.
1123TEST_F(StaticFlatbuffersTest, BuilderMoveConstructor) {
1124 uint8_t buffer[Builder<TestTableStatic>::kBufferSize];
1125 aos::fbs::SpanAllocator allocator({buffer, sizeof(buffer)});
1126 Builder<TestTableStatic> builder_from(&allocator);
1127 Builder<TestTableStatic> builder(std::move(builder_from));
1128 TestTableStatic *object = builder.get();
1129 object->set_scalar(123);
1130 {
1131 auto vector = object->add_vector_of_scalars();
1132 ASSERT_TRUE(vector->emplace_back(4));
1133 ASSERT_TRUE(vector->emplace_back(5));
1134 }
1135 {
1136 auto string = object->add_string();
1137 string->SetString("Hello, World!");
1138 }
1139 {
1140 auto vector_of_strings = object->add_vector_of_strings();
1141 auto sub_string = CHECK_NOTNULL(vector_of_strings->emplace_back());
1142 ASSERT_TRUE(sub_string->emplace_back('D'));
1143 }
1144 { object->set_substruct({971, 254}); }
1145 {
1146 auto subtable = object->add_subtable();
1147 subtable->set_foo(1234);
1148 }
1149 {
1150 auto vector = object->add_vector_of_structs();
1151 ASSERT_TRUE(vector->emplace_back({48, 67}));
1152 ASSERT_TRUE(vector->emplace_back({118, 148}));
1153 ASSERT_TRUE(vector->emplace_back({971, 973}));
1154 // Max vector size is three; this should fail.
1155 ASSERT_FALSE(vector->emplace_back({1114, 2056}));
1156 // We don't have any extra space available.
1157 ASSERT_FALSE(vector->reserve(4));
1158 ASSERT_FALSE(vector->emplace_back({1114, 2056}));
1159 }
1160 {
1161 auto vector = object->add_vector_of_tables();
1162 auto subobject = vector->emplace_back();
1163 subobject->set_foo(222);
1164 }
1165 {
1166 auto subtable = object->add_included_table();
1167 subtable->set_foo(included::TestEnum::B);
1168 }
1169 ASSERT_TRUE(builder.AsFlatbufferSpan().Verify());
1170 VLOG(1) << aos::FlatbufferToJson(builder.AsFlatbufferSpan(),
1171 {.multi_line = true});
1172 VLOG(1) << AnnotateBinaries(test_schema_, builder.buffer());
1173 TestMemory(builder.buffer());
1174}
1175
James Kuszmaulf5eb4682023-09-22 17:16:59 -07001176} // namespace aos::fbs::testing