1 /*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <stdint.h>
17
18 #include <cmath>
19 #include <limits>
20 #include <memory>
21 #include <string>
22
23 #if defined(__ANDROID__)
24 #define INCLUDE_64_BIT_TESTS 0
25 #else
26 #define INCLUDE_64_BIT_TESTS 1
27 #endif
28
29 #include "alignment_test.h"
30 #include "evolution_test.h"
31 #include "flatbuffers/flatbuffers.h"
32 #include "flatbuffers/idl.h"
33 #include "flatbuffers/minireflect.h"
34 #include "flatbuffers/reflection_generated.h"
35 #include "flatbuffers/registry.h"
36 #include "flatbuffers/util.h"
37 #include "fuzz_test.h"
38 #include "json_test.h"
39 #include "key_field_test.h"
40 #include "monster_test.h"
41 #include "monster_test_generated.h"
42 #include "native_inline_table_test_generated.h"
43 #include "optional_scalars_test.h"
44 #include "parser_test.h"
45 #include "proto_test.h"
46 #include "reflection_test.h"
47 #include "tests/union_vector/union_vector_generated.h"
48 #include "union_underlying_type_test_generated.h"
49 #if !defined(_MSC_VER) || _MSC_VER >= 1700
50 # include "tests/arrays_test_generated.h"
51 #endif
52 #if INCLUDE_64_BIT_TESTS
53 #include "tests/64bit/offset64_test.h"
54 #endif
55 #include "flexbuffers_test.h"
56 #include "is_quiet_nan.h"
57 #include "monster_test_bfbs_generated.h" // Generated using --bfbs-comments --bfbs-builtins --cpp --bfbs-gen-embed
58 #include "native_type_test_generated.h"
59 #include "test_assert.h"
60 #include "util_test.h"
61
62 void FlatBufferBuilderTest();
63
64 namespace flatbuffers {
65 namespace tests {
66 namespace {
67
68 // clang-format off
69 // Check that char* and uint8_t* are interoperable types.
70 // The reinterpret_cast<> between the pointers are used to simplify data loading.
71 static_assert(flatbuffers::is_same<uint8_t, char>::value ||
72 flatbuffers::is_same<uint8_t, unsigned char>::value,
73 "unexpected uint8_t type");
74
75 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
76 // Ensure IEEE-754 support if tests of floats with NaN/Inf will run.
77 static_assert(std::numeric_limits<float>::is_iec559 &&
78 std::numeric_limits<double>::is_iec559,
79 "IEC-559 (IEEE-754) standard required");
80 #endif
81 // clang-format on
82
83 using namespace MyGame::Example;
84
TriviallyCopyableTest()85 void TriviallyCopyableTest() {
86 // clang-format off
87 #if __GNUG__ && __GNUC__ < 5 && \
88 !(defined(__clang__) && __clang_major__ >= 16)
89 TEST_EQ(__is_trivially_copyable(Vec3), true);
90 #else
91 #if __cplusplus >= 201103L
92 TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
93 #endif
94 #endif
95 // clang-format on
96 }
97
98 // Guard against -Wunused-function on platforms without file tests.
99 #ifndef FLATBUFFERS_NO_FILE_TESTS
GenerateTableTextTest(const std::string & tests_data_path)100 void GenerateTableTextTest(const std::string &tests_data_path) {
101 std::string schemafile;
102 std::string jsonfile;
103 bool ok =
104 flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(),
105 false, &schemafile) &&
106 flatbuffers::LoadFile((tests_data_path + "monsterdata_test.json").c_str(),
107 false, &jsonfile);
108 TEST_EQ(ok, true);
109 auto include_test_path =
110 flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
111 const char *include_directories[] = { tests_data_path.c_str(),
112 include_test_path.c_str(), nullptr };
113 flatbuffers::IDLOptions opt;
114 opt.indent_step = -1;
115 flatbuffers::Parser parser(opt);
116 ok = parser.Parse(schemafile.c_str(), include_directories) &&
117 parser.Parse(jsonfile.c_str(), include_directories);
118 TEST_EQ(ok, true);
119 // Test root table
120 const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
121 const auto abilities = monster->testarrayofsortedstruct();
122 TEST_EQ(abilities->size(), 3);
123 TEST_EQ(abilities->Get(0)->id(), 0);
124 TEST_EQ(abilities->Get(0)->distance(), 45);
125 TEST_EQ(abilities->Get(1)->id(), 1);
126 TEST_EQ(abilities->Get(1)->distance(), 21);
127 TEST_EQ(abilities->Get(2)->id(), 5);
128 TEST_EQ(abilities->Get(2)->distance(), 12);
129
130 std::string jsongen;
131 auto result = GenTextFromTable(parser, monster, "MyGame.Example.Monster",
132 &jsongen);
133 TEST_NULL(result);
134 // Test sub table
135 const Vec3 *pos = monster->pos();
136 jsongen.clear();
137 result = GenTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
138 TEST_NULL(result);
139 TEST_EQ_STR(
140 jsongen.c_str(),
141 "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
142 const Test &test3 = pos->test3();
143 jsongen.clear();
144 result =
145 GenTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
146 TEST_NULL(result);
147 TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
148 const Test *test4 = monster->test4()->Get(0);
149 jsongen.clear();
150 result =
151 GenTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
152 TEST_NULL(result);
153 TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
154 }
155
MultiFileNameClashTest(const std::string & tests_data_path)156 void MultiFileNameClashTest(const std::string &tests_data_path) {
157 const auto name_clash_path =
158 flatbuffers::ConCatPathFileName(tests_data_path, "name_clash_test");
159 const char *include_directories[] = { name_clash_path.c_str() };
160
161 // Load valid 2 file Flatbuffer schema
162 const auto valid_path =
163 flatbuffers::ConCatPathFileName(name_clash_path, "valid_test1.fbs");
164 std::string valid_schema;
165 TEST_ASSERT(flatbuffers::LoadFile(valid_path.c_str(), false, &valid_schema));
166 // Clashing table and union names in different namespaces must be parsable
167 TEST_ASSERT(
168 flatbuffers::Parser().Parse(valid_schema.c_str(), include_directories));
169
170 flatbuffers::Parser p;
171 TEST_ASSERT(p.Parse(valid_schema.c_str(), include_directories));
172
173 // Load invalid 2 file Flatbuffer schema
174 const auto invalid_path =
175 flatbuffers::ConCatPathFileName(name_clash_path, "invalid_test1.fbs");
176 std::string invalid_schema;
177 TEST_ASSERT(
178 flatbuffers::LoadFile(invalid_path.c_str(), false, &invalid_schema));
179 // Clashing table and union names in same namespace must fail to parse
180 TEST_EQ(
181 flatbuffers::Parser().Parse(invalid_schema.c_str(), include_directories),
182 false);
183 }
184
InvalidNestedFlatbufferTest(const std::string & tests_data_path)185 void InvalidNestedFlatbufferTest(const std::string &tests_data_path) {
186 // First, load and parse FlatBuffer schema (.fbs)
187 std::string schemafile;
188 TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(),
189 false, &schemafile),
190 true);
191 auto include_test_path =
192 flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
193 const char *include_directories[] = { tests_data_path.c_str(),
194 include_test_path.c_str(), nullptr };
195 flatbuffers::Parser parser1;
196 TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
197
198 // "color" inside nested flatbuffer contains invalid enum value
199 TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
200 "\"Leela\", color: \"nonexistent\"}}"),
201 false);
202 }
203
UnionVectorTest(const std::string & tests_data_path)204 void UnionVectorTest(const std::string &tests_data_path) {
205 // load FlatBuffer fbs schema and json.
206 std::string schemafile, jsonfile;
207 TEST_EQ(flatbuffers::LoadFile(
208 (tests_data_path + "union_vector/union_vector.fbs").c_str(),
209 false, &schemafile),
210 true);
211 TEST_EQ(flatbuffers::LoadFile(
212 (tests_data_path + "union_vector/union_vector.json").c_str(),
213 false, &jsonfile),
214 true);
215
216 // parse schema.
217 flatbuffers::IDLOptions idl_opts;
218 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
219 flatbuffers::Parser parser(idl_opts);
220 TEST_EQ(parser.Parse(schemafile.c_str()), true);
221
222 flatbuffers::FlatBufferBuilder fbb;
223
224 // union types.
225 std::vector<uint8_t> types;
226 types.push_back(static_cast<uint8_t>(Character_Belle));
227 types.push_back(static_cast<uint8_t>(Character_MuLan));
228 types.push_back(static_cast<uint8_t>(Character_BookFan));
229 types.push_back(static_cast<uint8_t>(Character_Other));
230 types.push_back(static_cast<uint8_t>(Character_Unused));
231
232 // union values.
233 std::vector<flatbuffers::Offset<void>> characters;
234 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
235 characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
236 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
237 characters.push_back(fbb.CreateString("Other").Union());
238 characters.push_back(fbb.CreateString("Unused").Union());
239
240 // create Movie.
241 const auto movie_offset =
242 CreateMovie(fbb, Character_Rapunzel,
243 fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
244 fbb.CreateVector(types), fbb.CreateVector(characters));
245 FinishMovieBuffer(fbb, movie_offset);
246
247 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
248 TEST_EQ(VerifyMovieBuffer(verifier), true);
249
250 auto flat_movie = GetMovie(fbb.GetBufferPointer());
251
252 auto TestMovie = [](const Movie *movie) {
253 TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
254
255 auto cts = movie->characters_type();
256 TEST_EQ(movie->characters_type()->size(), 5);
257 TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
258 TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
259 TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
260 TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
261 TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
262
263 auto rapunzel = movie->main_character_as_Rapunzel();
264 TEST_NOTNULL(rapunzel);
265 TEST_EQ(rapunzel->hair_length(), 6);
266
267 auto cs = movie->characters();
268 TEST_EQ(cs->size(), 5);
269 auto belle = cs->GetAs<BookReader>(0);
270 TEST_EQ(belle->books_read(), 7);
271 auto mu_lan = cs->GetAs<Attacker>(1);
272 TEST_EQ(mu_lan->sword_attack_damage(), 5);
273 auto book_fan = cs->GetAs<BookReader>(2);
274 TEST_EQ(book_fan->books_read(), 2);
275 auto other = cs->GetAsString(3);
276 TEST_EQ_STR(other->c_str(), "Other");
277 auto unused = cs->GetAsString(4);
278 TEST_EQ_STR(unused->c_str(), "Unused");
279 };
280
281 TestMovie(flat_movie);
282
283 // Also test the JSON we loaded above.
284 TEST_EQ(parser.Parse(jsonfile.c_str()), true);
285 auto jbuf = parser.builder_.GetBufferPointer();
286 flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
287 TEST_EQ(VerifyMovieBuffer(jverifier), true);
288 TestMovie(GetMovie(jbuf));
289
290 auto movie_object = flat_movie->UnPack();
291 TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
292 TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
293 TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
294 TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
295 TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
296 TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
297
298 fbb.Clear();
299 fbb.Finish(Movie::Pack(fbb, movie_object));
300
301 delete movie_object;
302
303 auto repacked_movie = GetMovie(fbb.GetBufferPointer());
304
305 TestMovie(repacked_movie);
306
307 // Generate text using mini-reflection.
308 auto s =
309 flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
310 TEST_EQ_STR(
311 s.c_str(),
312 "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
313 "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
314 "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
315 "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
316
317 flatbuffers::ToStringVisitor visitor("\n", true, " ");
318 IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
319 TEST_EQ_STR(visitor.s.c_str(),
320 "{\n"
321 " \"main_character_type\": \"Rapunzel\",\n"
322 " \"main_character\": {\n"
323 " \"hair_length\": 6\n"
324 " },\n"
325 " \"characters_type\": [\n"
326 " \"Belle\",\n"
327 " \"MuLan\",\n"
328 " \"BookFan\",\n"
329 " \"Other\",\n"
330 " \"Unused\"\n"
331 " ],\n"
332 " \"characters\": [\n"
333 " {\n"
334 " \"books_read\": 7\n"
335 " },\n"
336 " {\n"
337 " \"sword_attack_damage\": 5\n"
338 " },\n"
339 " {\n"
340 " \"books_read\": 2\n"
341 " },\n"
342 " \"Other\",\n"
343 " \"Unused\"\n"
344 " ]\n"
345 "}");
346
347 // Generate text using parsed schema.
348 std::string jsongen;
349 auto result = GenText(parser, fbb.GetBufferPointer(), &jsongen);
350 TEST_NULL(result);
351 TEST_EQ_STR(jsongen.c_str(),
352 "{\n"
353 " main_character_type: \"Rapunzel\",\n"
354 " main_character: {\n"
355 " hair_length: 6\n"
356 " },\n"
357 " characters_type: [\n"
358 " \"Belle\",\n"
359 " \"MuLan\",\n"
360 " \"BookFan\",\n"
361 " \"Other\",\n"
362 " \"Unused\"\n"
363 " ],\n"
364 " characters: [\n"
365 " {\n"
366 " books_read: 7\n"
367 " },\n"
368 " {\n"
369 " sword_attack_damage: 5\n"
370 " },\n"
371 " {\n"
372 " books_read: 2\n"
373 " },\n"
374 " \"Other\",\n"
375 " \"Unused\"\n"
376 " ]\n"
377 "}\n");
378
379 // Simple test with reflection.
380 parser.Serialize();
381 auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
382 auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
383 fbb.GetBufferPointer(), fbb.GetSize());
384 TEST_EQ(ok, true);
385
386 flatbuffers::Parser parser2(idl_opts);
387 TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
388 "union Any { Bool }"
389 "table Root { a:Any; }"
390 "root_type Root;"),
391 true);
392 TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
393 }
394 #endif
395
EndianSwapTest()396 void EndianSwapTest() {
397 TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
398 TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
399 0x78563412);
400 TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
401 0xEFCDAB9078563412);
402 TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
403 }
404
UninitializedVectorTest()405 void UninitializedVectorTest() {
406 flatbuffers::FlatBufferBuilder builder;
407
408 Test *buf = nullptr;
409 auto vector_offset =
410 builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
411 TEST_NOTNULL(buf);
412 buf[0] = Test(10, 20);
413 buf[1] = Test(30, 40);
414
415 auto required_name = builder.CreateString("myMonster");
416 auto monster_builder = MonsterBuilder(builder);
417 monster_builder.add_name(
418 required_name); // required field mandated for monster.
419 monster_builder.add_test4(vector_offset);
420 builder.Finish(monster_builder.Finish());
421
422 auto p = builder.GetBufferPointer();
423 auto uvt = flatbuffers::GetRoot<Monster>(p);
424 TEST_NOTNULL(uvt);
425 auto vec = uvt->test4();
426 TEST_NOTNULL(vec);
427 auto test_0 = vec->Get(0);
428 auto test_1 = vec->Get(1);
429 TEST_EQ(test_0->a(), 10);
430 TEST_EQ(test_0->b(), 20);
431 TEST_EQ(test_1->a(), 30);
432 TEST_EQ(test_1->b(), 40);
433 }
434
EqualOperatorTest()435 void EqualOperatorTest() {
436 MonsterT a;
437 MonsterT b;
438 // We have to reset the fields that are NaN to zero to allow the equality
439 // to evaluate to true.
440 TEST_EQ(std::isnan(a.nan_default), true);
441 TEST_EQ(std::isnan(b.nan_default), true);
442 a.nan_default = 0;
443 b.nan_default = 0;
444 TEST_EQ(b == a, true);
445 TEST_EQ(b != a, false);
446
447 b.mana = 33;
448 TEST_EQ(b == a, false);
449 TEST_EQ(b != a, true);
450 b.mana = 150;
451 TEST_EQ(b == a, true);
452 TEST_EQ(b != a, false);
453
454 b.inventory.push_back(3);
455 TEST_EQ(b == a, false);
456 TEST_EQ(b != a, true);
457 b.inventory.clear();
458 TEST_EQ(b == a, true);
459 TEST_EQ(b != a, false);
460
461 a.enemy.reset(new MonsterT());
462 a.enemy->nan_default = 0;
463 TEST_EQ(b != a, true);
464 a.enemy->mana = 33;
465 TEST_EQ(b == a, false);
466 TEST_EQ(b != a, true);
467
468 b.enemy.reset(new MonsterT());
469 b.enemy->nan_default = 0;
470 TEST_EQ(b == a, false);
471 TEST_EQ(b != a, true);
472 b.enemy->mana = 33;
473 TEST_EQ(b == a, true);
474 TEST_EQ(b != a, false);
475
476 a.enemy.reset(nullptr);
477 TEST_EQ(b == a, false);
478 TEST_EQ(b != a, true);
479 b.enemy->mana = 150;
480 TEST_EQ(b == a, false);
481 TEST_EQ(b != a, true);
482 a.enemy.reset(new MonsterT());
483 a.enemy->nan_default = 0;
484 TEST_EQ(b == a, true);
485 TEST_EQ(b != a, false);
486
487 b.enemy.reset(nullptr);
488
489 b.test.type = Any_Monster;
490 TEST_EQ(b == a, false);
491 TEST_EQ(b != a, true);
492
493 // Test that vector of tables are compared by value and not by reference.
494 {
495 // Two tables are equal by default.
496 MonsterT a, b;
497 a.nan_default = 0;
498 b.nan_default = 0;
499 TEST_EQ(a == b, true);
500
501 // Adding only a table to one of the monster vectors should make it not
502 // equal (due to size mistmatch).
503 a.testarrayoftables.push_back(
504 flatbuffers::unique_ptr<MonsterT>(new MonsterT));
505 a.testarrayoftables.back()->nan_default = 0;
506 TEST_EQ(a == b, false);
507
508 // Adding an equalivant table to the other monster vector should make it
509 // equal again.
510 b.testarrayoftables.push_back(
511 flatbuffers::unique_ptr<MonsterT>(new MonsterT));
512 b.testarrayoftables.back()->nan_default = 0;
513 TEST_EQ(a == b, true);
514
515 // Create two new monsters that are different.
516 auto c = flatbuffers::unique_ptr<MonsterT>(new MonsterT);
517 auto d = flatbuffers::unique_ptr<MonsterT>(new MonsterT);
518 c->nan_default = 0;
519 d->nan_default = 0;
520 c->hp = 1;
521 d->hp = 2;
522 TEST_EQ(c == d, false);
523
524 // Adding them to the original monsters should also make them different.
525 a.testarrayoftables.push_back(std::move(c));
526 b.testarrayoftables.push_back(std::move(d));
527 TEST_EQ(a == b, false);
528
529 // Remove the mismatching monsters to get back to equality
530 a.testarrayoftables.pop_back();
531 b.testarrayoftables.pop_back();
532 TEST_EQ(a == b, true);
533
534 // Check that nullptr are OK.
535 a.testarrayoftables.push_back(nullptr);
536 b.testarrayoftables.push_back(
537 flatbuffers::unique_ptr<MonsterT>(new MonsterT));
538 TEST_EQ(a == b, false);
539 }
540 }
541
CreateSharedStringTest()542 void CreateSharedStringTest() {
543 flatbuffers::FlatBufferBuilder builder;
544 const auto one1 = builder.CreateSharedString("one");
545 const auto two = builder.CreateSharedString("two");
546 const auto one2 = builder.CreateSharedString("one");
547 TEST_EQ(one1.o, one2.o);
548 const auto onetwo = builder.CreateSharedString("onetwo");
549 TEST_EQ(onetwo.o != one1.o, true);
550 TEST_EQ(onetwo.o != two.o, true);
551
552 // Support for embedded nulls
553 const char chars_b[] = { 'a', '\0', 'b' };
554 const char chars_c[] = { 'a', '\0', 'c' };
555 const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
556 const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
557 const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
558 TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
559 TEST_EQ(null_b1.o, null_b2.o);
560
561 // Put the strings into an array for round trip verification.
562 std::array<flatbuffers::Offset<flatbuffers::String>, 7> array = {
563 one1, two, one2, onetwo, null_b1, null_c, null_b2
564 };
565 const auto vector_offset =
566 builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(array);
567 MonsterBuilder monster_builder(builder);
568 monster_builder.add_name(two);
569 monster_builder.add_testarrayofstring(vector_offset);
570 builder.Finish(monster_builder.Finish());
571
572 // Read the Monster back.
573 const auto *monster =
574 flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
575 TEST_EQ_STR(monster->name()->c_str(), "two");
576 const auto *testarrayofstring = monster->testarrayofstring();
577 TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
578 const auto &a = *testarrayofstring;
579 TEST_EQ_STR(a[0]->c_str(), "one");
580 TEST_EQ_STR(a[1]->c_str(), "two");
581 TEST_EQ_STR(a[2]->c_str(), "one");
582 TEST_EQ_STR(a[3]->c_str(), "onetwo");
583 TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
584 TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
585 TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
586
587 // Make sure String::operator< works, too, since it is related to
588 // StringOffsetCompare.
589 TEST_EQ((*a[0]) < (*a[1]), true);
590 TEST_EQ((*a[1]) < (*a[0]), false);
591 TEST_EQ((*a[1]) < (*a[2]), false);
592 TEST_EQ((*a[2]) < (*a[1]), true);
593 TEST_EQ((*a[4]) < (*a[3]), true);
594 TEST_EQ((*a[5]) < (*a[4]), false);
595 TEST_EQ((*a[5]) < (*a[4]), false);
596 TEST_EQ((*a[6]) < (*a[5]), true);
597 }
598
599 #if !defined(FLATBUFFERS_USE_STD_SPAN) && !defined(FLATBUFFERS_SPAN_MINIMAL)
FlatbuffersSpanTest()600 void FlatbuffersSpanTest() {
601 // Compile-time checking of non-const [] to const [] conversions.
602 using flatbuffers::internal::is_span_convertible;
603 (void)is_span_convertible<int, 1, int, 1>::type(123);
604 (void)is_span_convertible<const int, 1, int, 1>::type(123);
605 (void)is_span_convertible<const int64_t, 1, int64_t, 1>::type(123);
606 (void)is_span_convertible<const uint64_t, 1, uint64_t, 1>::type(123);
607 (void)is_span_convertible<const int, 1, const int, 1>::type(123);
608 (void)is_span_convertible<const int64_t, 1, const int64_t, 1>::type(123);
609 (void)is_span_convertible<const uint64_t, 1, const uint64_t, 1>::type(123);
610
611 using flatbuffers::span;
612 span<char, 0> c1;
613 TEST_EQ(c1.size(), 0);
614 span<char, flatbuffers::dynamic_extent> c2;
615 TEST_EQ(c2.size(), 0);
616 span<char> c3;
617 TEST_EQ(c3.size(), 0);
618 TEST_ASSERT(c1.empty() && c2.empty() && c3.empty());
619
620 int i_data7[7] = { 0, 1, 2, 3, 4, 5, 6 };
621 span<int, 7> i1(&i_data7[0], 7);
622 span<int> i2(i1); // make dynamic from static
623 TEST_EQ(i1.size(), 7);
624 TEST_EQ(i1.empty(), false);
625 TEST_EQ(i1.size(), i2.size());
626 TEST_EQ(i1.data(), i_data7);
627 TEST_EQ(i1[2], 2);
628 // Make const span from a non-const one.
629 span<const int, 7> i3(i1);
630 // Construct from a C-array.
631 span<int, 7> i4(i_data7);
632 span<const int, 7> i5(i_data7);
633 span<int> i6(i_data7);
634 span<const int> i7(i_data7);
635 TEST_EQ(i7.size(), 7);
636 // Check construction from a const array.
637 const int i_cdata5[5] = { 4, 3, 2, 1, 0 };
638 span<const int, 5> i8(i_cdata5);
639 span<const int> i9(i_cdata5);
640 TEST_EQ(i9.size(), 5);
641 // Construction from a (ptr, size) pair.
642 span<int, 7> i10(i_data7, 7);
643 span<int> i11(i_data7, 7);
644 TEST_EQ(i11.size(), 7);
645 span<const int, 5> i12(i_cdata5, 5);
646 span<const int> i13(i_cdata5, 5);
647 TEST_EQ(i13.size(), 5);
648 // Construction from std::array.
649 std::array<int, 6> i_arr6 = { { 0, 1, 2, 3, 4, 5 } };
650 span<int, 6> i14(i_arr6);
651 span<const int, 6> i15(i_arr6);
652 span<int> i16(i_arr6);
653 span<const int> i17(i_arr6);
654 TEST_EQ(i17.size(), 6);
655 const std::array<int, 8> i_carr8 = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
656 span<const int, 8> i18(i_carr8);
657 span<const int> i19(i_carr8);
658 TEST_EQ(i18.size(), 8);
659 TEST_EQ(i19.size(), 8);
660 TEST_EQ(i19[7], 7);
661 // Check compatibility with flatbuffers::Array.
662 int fbs_int3_underlaying[3] = { 0 };
663 int fbs_int3_data[3] = { 1, 2, 3 };
664 auto &fbs_int3 = flatbuffers::CastToArray(fbs_int3_underlaying);
665 fbs_int3.CopyFromSpan(fbs_int3_data);
666 TEST_EQ(fbs_int3.Get(1), 2);
667 const int fbs_cint3_data[3] = { 2, 3, 4 };
668 fbs_int3.CopyFromSpan(fbs_cint3_data);
669 TEST_EQ(fbs_int3.Get(1), 3);
670 // Check with Array<Enum, N>
671 enum class Dummy : uint16_t { Zero = 0, One, Two };
672 Dummy fbs_dummy3_underlaying[3] = {};
673 Dummy fbs_dummy3_data[3] = { Dummy::One, Dummy::Two, Dummy::Two };
674 auto &fbs_dummy3 = flatbuffers::CastToArray(fbs_dummy3_underlaying);
675 fbs_dummy3.CopyFromSpan(fbs_dummy3_data);
676 TEST_EQ(fbs_dummy3.Get(1), Dummy::Two);
677 }
678 #else
FlatbuffersSpanTest()679 void FlatbuffersSpanTest() {}
680 #endif
681
682 // VS10 does not support typed enums, exclude from tests
683 #if !defined(_MSC_VER) || _MSC_VER >= 1700
FixedLengthArrayTest()684 void FixedLengthArrayTest() {
685 // Generate an ArrayTable containing one ArrayStruct.
686 flatbuffers::FlatBufferBuilder fbb;
687 MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
688 TEST_NOTNULL(nStruct0.mutable_a());
689 nStruct0.mutable_a()->Mutate(0, 1);
690 nStruct0.mutable_a()->Mutate(1, 2);
691 TEST_NOTNULL(nStruct0.mutable_c());
692 nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
693 nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
694 TEST_NOTNULL(nStruct0.mutable_d());
695 nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
696 nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
697 MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
698 TEST_NOTNULL(nStruct1.mutable_a());
699 nStruct1.mutable_a()->Mutate(0, 3);
700 nStruct1.mutable_a()->Mutate(1, 4);
701 TEST_NOTNULL(nStruct1.mutable_c());
702 nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
703 nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
704 TEST_NOTNULL(nStruct1.mutable_d());
705 nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
706 nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
707 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
708 TEST_NOTNULL(aStruct.b());
709 TEST_NOTNULL(aStruct.mutable_b());
710 TEST_NOTNULL(aStruct.mutable_d());
711 TEST_NOTNULL(aStruct.mutable_f());
712 for (int i = 0; i < aStruct.b()->size(); i++)
713 aStruct.mutable_b()->Mutate(i, i + 1);
714 aStruct.mutable_d()->Mutate(0, nStruct0);
715 aStruct.mutable_d()->Mutate(1, nStruct1);
716 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
717 MyGame::Example::FinishArrayTableBuffer(fbb, aTable);
718 // Verify correctness of the ArrayTable.
719 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
720 TEST_ASSERT(MyGame::Example::VerifyArrayTableBuffer(verifier));
721 // Do test.
722 auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
723 auto mArStruct = p->mutable_a();
724 TEST_NOTNULL(mArStruct);
725 TEST_NOTNULL(mArStruct->b());
726 TEST_NOTNULL(mArStruct->d());
727 TEST_NOTNULL(mArStruct->f());
728 TEST_NOTNULL(mArStruct->mutable_b());
729 TEST_NOTNULL(mArStruct->mutable_d());
730 TEST_NOTNULL(mArStruct->mutable_f());
731 TEST_EQ(mArStruct->a(), 2);
732 TEST_EQ(mArStruct->b()->size(), 15);
733 mArStruct->mutable_b()->Mutate(14, -14);
734 TEST_EQ(mArStruct->b()->Get(14), -14);
735 TEST_EQ(mArStruct->c(), 12);
736 TEST_NOTNULL(mArStruct->d()->Get(0));
737 TEST_NOTNULL(mArStruct->d()->Get(0)->a());
738 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
739 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
740 TEST_NOTNULL(mArStruct->d()->Get(1));
741 TEST_NOTNULL(mArStruct->d()->Get(1)->a());
742 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
743 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
744 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
745 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
746 mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
747 TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
748 TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
749 TEST_NOTNULL(mArStruct->d()->Get(0)->c());
750 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
751 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
752 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
753 mArStruct->d()->Get(0)->d()->Get(0));
754 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
755 mArStruct->d()->Get(0)->d()->Get(1));
756 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
757 TEST_NOTNULL(mArStruct->d()->Get(1)->c());
758 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
759 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
760 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
761 mArStruct->d()->Get(1)->d()->Get(0));
762 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
763 mArStruct->d()->Get(1)->d()->Get(1));
764 for (int i = 0; i < mArStruct->b()->size() - 1; i++)
765 TEST_EQ(mArStruct->b()->Get(i), i + 1);
766 // Check alignment
767 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
768 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
769
770 // Check if default constructor set all memory zero
771 const size_t arr_size = sizeof(MyGame::Example::ArrayStruct);
772 char non_zero_memory[arr_size];
773 // set memory chunk of size ArrayStruct to 1's
774 std::memset(static_cast<void *>(non_zero_memory), 1, arr_size);
775 // after placement-new it should be all 0's
776 # if defined(_MSC_VER) && defined(_DEBUG)
777 # undef new
778 # endif
779 MyGame::Example::ArrayStruct *ap =
780 new (non_zero_memory) MyGame::Example::ArrayStruct;
781 # if defined(_MSC_VER) && defined(_DEBUG)
782 # define new DEBUG_NEW
783 # endif
784 (void)ap;
785 for (size_t i = 0; i < arr_size; ++i) { TEST_EQ(non_zero_memory[i], 0); }
786 }
787 #else
FixedLengthArrayTest()788 void FixedLengthArrayTest() {}
789 #endif // !defined(_MSC_VER) || _MSC_VER >= 1700
790
791 #if !defined(FLATBUFFERS_SPAN_MINIMAL) && \
792 (!defined(_MSC_VER) || _MSC_VER >= 1700)
FixedLengthArrayConstructorTest()793 void FixedLengthArrayConstructorTest() {
794 const int32_t nested_a[2] = { 1, 2 };
795 MyGame::Example::TestEnum nested_c[2] = { MyGame::Example::TestEnum::A,
796 MyGame::Example::TestEnum::B };
797 const int64_t int64_2[2] = { -2, -1 };
798
799 std::array<MyGame::Example::NestedStruct, 2> init_d = {
800 { MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
801 nested_c, int64_2),
802 MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::A,
803 nested_c,
804 std::array<int64_t, 2>{ { 12, 13 } }) }
805 };
806
807 MyGame::Example::ArrayStruct arr_struct(
808 8.125,
809 std::array<int32_t, 0xF>{
810 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
811 -17, init_d, 10, int64_2);
812 TEST_EQ(arr_struct.a(), 8.125);
813 TEST_EQ(arr_struct.b()->Get(2), 3);
814 TEST_EQ(arr_struct.c(), -17);
815
816 TEST_NOTNULL(arr_struct.d());
817 const auto &arr_d_0 = *arr_struct.d()->Get(0);
818 TEST_EQ(arr_d_0.a()->Get(0), 1);
819 TEST_EQ(arr_d_0.a()->Get(1), 2);
820 TEST_EQ(arr_d_0.b(), MyGame::Example::TestEnum::B);
821 TEST_EQ(arr_d_0.c()->Get(0), MyGame::Example::TestEnum::A);
822 TEST_EQ(arr_d_0.c()->Get(1), MyGame::Example::TestEnum::B);
823 TEST_EQ(arr_d_0.d()->Get(0), -2);
824 TEST_EQ(arr_d_0.d()->Get(1), -1);
825 const auto &arr_d_1 = *arr_struct.d()->Get(1);
826 TEST_EQ(arr_d_1.a()->Get(0), 1);
827 TEST_EQ(arr_d_1.a()->Get(1), 2);
828 TEST_EQ(arr_d_1.b(), MyGame::Example::TestEnum::A);
829 TEST_EQ(arr_d_1.c()->Get(0), MyGame::Example::TestEnum::A);
830 TEST_EQ(arr_d_1.c()->Get(1), MyGame::Example::TestEnum::B);
831 TEST_EQ(arr_d_1.d()->Get(0), 12);
832 TEST_EQ(arr_d_1.d()->Get(1), 13);
833
834 TEST_EQ(arr_struct.e(), 10);
835 TEST_EQ(arr_struct.f()->Get(0), -2);
836 TEST_EQ(arr_struct.f()->Get(1), -1);
837 }
838 #else
FixedLengthArrayConstructorTest()839 void FixedLengthArrayConstructorTest() {}
840 #endif
841
FixedLengthArrayOperatorEqualTest()842 void FixedLengthArrayOperatorEqualTest() {
843 const int32_t nested_a[2] = { 1, 2 };
844 MyGame::Example::TestEnum nested_c[2] = { MyGame::Example::TestEnum::A,
845 MyGame::Example::TestEnum::B };
846
847 MyGame::Example::TestEnum nested_cc[2] = { MyGame::Example::TestEnum::A,
848 MyGame::Example::TestEnum::C };
849 const int64_t int64_2[2] = { -2, -1 };
850
851 std::array<MyGame::Example::NestedStruct, 2> init_d = {
852 { MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
853 nested_c, int64_2),
854 MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
855 nested_c,
856 std::array<int64_t, 2>{ { -2, -1 } }) }
857 };
858
859 auto different = MyGame::Example::NestedStruct(
860 nested_a, MyGame::Example::TestEnum::B, nested_cc,
861 std::array<int64_t, 2>{ { -2, -1 } });
862
863 TEST_ASSERT(init_d[0] == init_d[1]);
864 TEST_ASSERT(init_d[0] != different);
865
866 std::array<MyGame::Example::ArrayStruct, 3> arr_struct = {
867 MyGame::Example::ArrayStruct(
868 8.125,
869 std::array<int32_t, 0xF>{
870 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
871 -17, init_d, 10, int64_2),
872
873 MyGame::Example::ArrayStruct(
874 8.125,
875 std::array<int32_t, 0xF>{
876 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
877 -17, init_d, 10, int64_2),
878
879 MyGame::Example::ArrayStruct(
880 8.125,
881 std::array<int32_t, 0xF>{
882 { 1000, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
883 -17, init_d, 10, int64_2)
884 };
885
886 TEST_ASSERT(arr_struct[0] == arr_struct[1]);
887 TEST_ASSERT(arr_struct[1] != arr_struct[2]);
888 }
889
NativeTypeTest()890 void NativeTypeTest() {
891 const int N = 3;
892
893 Geometry::ApplicationDataT src_data;
894 src_data.vectors.reserve(N);
895 src_data.vectors_alt.reserve(N);
896
897 for (int i = 0; i < N; ++i) {
898 src_data.vectors.push_back(
899 Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
900 src_data.vectors_alt.push_back(
901 Native::Vector3D(20 * i + 0.1f, 20 * i + 0.2f, 20 * i + 0.3f));
902 }
903
904 flatbuffers::FlatBufferBuilder fbb;
905 fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
906
907 auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
908
909 for (int i = 0; i < N; ++i) {
910 const Native::Vector3D &v = dstDataT->vectors[i];
911 TEST_EQ(v.x, 10 * i + 0.1f);
912 TEST_EQ(v.y, 10 * i + 0.2f);
913 TEST_EQ(v.z, 10 * i + 0.3f);
914
915 const Native::Vector3D &v2 = dstDataT->vectors_alt[i];
916 TEST_EQ(v2.x, 20 * i + 0.1f);
917 TEST_EQ(v2.y, 20 * i + 0.2f);
918 TEST_EQ(v2.z, 20 * i + 0.3f);
919 }
920 }
921
922 // Guard against -Wunused-function on platforms without file tests.
923 #ifndef FLATBUFFERS_NO_FILE_TESTS
924 // VS10 does not support typed enums, exclude from tests
925 # if !defined(_MSC_VER) || _MSC_VER >= 1700
FixedLengthArrayJsonTest(const std::string & tests_data_path,bool binary)926 void FixedLengthArrayJsonTest(const std::string &tests_data_path, bool binary) {
927 // load FlatBuffer schema (.fbs) and JSON from disk
928 std::string schemafile;
929 std::string jsonfile;
930 TEST_EQ(flatbuffers::LoadFile(
931 (tests_data_path + "arrays_test." + (binary ? "bfbs" : "fbs"))
932 .c_str(),
933 binary, &schemafile),
934 true);
935 TEST_EQ(
936 flatbuffers::LoadFile((tests_data_path + "arrays_test.golden").c_str(),
937 false, &jsonfile),
938 true);
939
940 // parse schema first, so we can use it to parse the data after
941 flatbuffers::Parser parserOrg, parserGen;
942 if (binary) {
943 flatbuffers::Verifier verifier(
944 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
945 schemafile.size());
946 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
947 TEST_EQ(parserOrg.Deserialize(
948 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
949 schemafile.size()),
950 true);
951 TEST_EQ(parserGen.Deserialize(
952 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
953 schemafile.size()),
954 true);
955 } else {
956 TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
957 TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
958 }
959 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
960
961 // First, verify it, just in case:
962 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
963 parserOrg.builder_.GetSize());
964 TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
965
966 // Export to JSON
967 std::string jsonGen;
968 TEST_NULL(
969 GenText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen));
970
971 // Import from JSON
972 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
973
974 // Verify buffer from generated JSON
975 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
976 parserGen.builder_.GetSize());
977 TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
978
979 // Compare generated buffer to original
980 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
981 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
982 parserGen.builder_.GetBufferPointer(),
983 parserOrg.builder_.GetSize()),
984 0);
985 }
986
FixedLengthArraySpanTest(const std::string & tests_data_path)987 void FixedLengthArraySpanTest(const std::string &tests_data_path) {
988 // load FlatBuffer schema (.fbs) and JSON from disk
989 std::string schemafile;
990 std::string jsonfile;
991 TEST_EQ(flatbuffers::LoadFile((tests_data_path + "arrays_test.fbs").c_str(),
992 false, &schemafile),
993 true);
994 TEST_EQ(
995 flatbuffers::LoadFile((tests_data_path + "arrays_test.golden").c_str(),
996 false, &jsonfile),
997 true);
998
999 // parse schema first, so we can use it to parse the data after
1000 flatbuffers::Parser parser;
1001 TEST_EQ(parser.Parse(schemafile.c_str()), true);
1002 TEST_EQ(parser.Parse(jsonfile.c_str()), true);
1003 auto &fbb = parser.builder_;
1004 auto verifier = flatbuffers::Verifier(fbb.GetBufferPointer(), fbb.GetSize());
1005 TEST_EQ(true, VerifyArrayTableBuffer(verifier));
1006
1007 auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
1008 TEST_NOTNULL(p);
1009 auto table_struct = p->mutable_a();
1010 TEST_NOTNULL(table_struct);
1011 TEST_EQ(2, table_struct->d()->size());
1012 TEST_NOTNULL(table_struct->d());
1013 TEST_NOTNULL(table_struct->mutable_d());
1014 // test array of structs
1015 auto const_d = flatbuffers::make_span(*table_struct->d());
1016 auto mutable_d = flatbuffers::make_span(*table_struct->mutable_d());
1017 TEST_EQ(2, const_d.size());
1018 TEST_EQ(2, mutable_d.size());
1019 TEST_ASSERT(const_d[0] == mutable_d[0]);
1020 TEST_ASSERT(const_d[1] == mutable_d[1]);
1021 mutable_d[0] = const_d[0]; // mutate
1022 // test scalars
1023 auto &const_nested = const_d[0];
1024 auto &mutable_nested = mutable_d[0];
1025 static_assert(sizeof(MyGame::Example::TestEnum) == sizeof(uint8_t),
1026 "TestEnum's underlaying type must by byte");
1027 TEST_NOTNULL(const_nested.d());
1028 TEST_NOTNULL(mutable_nested.d());
1029 {
1030 flatbuffers::span<const MyGame::Example::TestEnum, 2> const_d_c =
1031 flatbuffers::make_span(*const_nested.c());
1032 auto mutable_d_c = flatbuffers::make_span(*mutable_nested.mutable_c());
1033 TEST_EQ(2, const_d_c.size());
1034 TEST_EQ(2, mutable_d_c.size());
1035 TEST_EQ(MyGame::Example::TestEnum::C, const_d_c[0]);
1036 TEST_EQ(MyGame::Example::TestEnum::B, const_d_c[1]);
1037 TEST_ASSERT(mutable_d_c.end() == std::copy(const_d_c.begin(),
1038 const_d_c.end(),
1039 mutable_d_c.begin()));
1040 TEST_ASSERT(
1041 std::equal(const_d_c.begin(), const_d_c.end(), mutable_d_c.begin()));
1042 }
1043 // test little endian array of int32
1044 # if FLATBUFFERS_LITTLEENDIAN
1045 {
1046 flatbuffers::span<const int32_t, 2> const_d_a =
1047 flatbuffers::make_span(*const_nested.a());
1048 auto mutable_d_a = flatbuffers::make_span(*mutable_nested.mutable_a());
1049 TEST_EQ(2, const_d_a.size());
1050 TEST_EQ(2, mutable_d_a.size());
1051 TEST_EQ(-1, const_d_a[0]);
1052 TEST_EQ(2, const_d_a[1]);
1053 TEST_ASSERT(mutable_d_a.end() == std::copy(const_d_a.begin(),
1054 const_d_a.end(),
1055 mutable_d_a.begin()));
1056 TEST_ASSERT(
1057 std::equal(const_d_a.begin(), const_d_a.end(), mutable_d_a.begin()));
1058 }
1059 # endif
1060 }
1061 # else
FixedLengthArrayJsonTest(bool)1062 void FixedLengthArrayJsonTest(bool /*binary*/) {}
FixedLengthArraySpanTest()1063 void FixedLengthArraySpanTest() {}
1064 # endif
1065
TestEmbeddedBinarySchema(const std::string & tests_data_path)1066 void TestEmbeddedBinarySchema(const std::string &tests_data_path) {
1067 // load JSON from disk
1068 std::string jsonfile;
1069 TEST_EQ(flatbuffers::LoadFile(
1070 (tests_data_path + "monsterdata_test.golden").c_str(), false,
1071 &jsonfile),
1072 true);
1073
1074 // parse schema first, so we can use it to parse the data after
1075 flatbuffers::Parser parserOrg, parserGen;
1076 flatbuffers::Verifier verifier(MyGame::Example::MonsterBinarySchema::data(),
1077 MyGame::Example::MonsterBinarySchema::size());
1078 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
1079 TEST_EQ(parserOrg.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
1080 MyGame::Example::MonsterBinarySchema::size()),
1081 true);
1082 TEST_EQ(parserGen.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
1083 MyGame::Example::MonsterBinarySchema::size()),
1084 true);
1085 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
1086
1087 // First, verify it, just in case:
1088 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
1089 parserOrg.builder_.GetSize());
1090 TEST_EQ(VerifyMonsterBuffer(verifierOrg), true);
1091
1092 // Export to JSON
1093 std::string jsonGen;
1094 TEST_NULL(
1095 GenText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen));
1096
1097 // Import from JSON
1098 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
1099
1100 // Verify buffer from generated JSON
1101 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
1102 parserGen.builder_.GetSize());
1103 TEST_EQ(VerifyMonsterBuffer(verifierGen), true);
1104
1105 // Compare generated buffer to original
1106 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
1107 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
1108 parserGen.builder_.GetBufferPointer(),
1109 parserOrg.builder_.GetSize()),
1110 0);
1111 }
1112 #endif
1113
EmbeddedSchemaAccessByType()1114 template<typename T> void EmbeddedSchemaAccessByType() {
1115 // Get the binary schema from the Type itself.
1116 // Verify the schema is OK.
1117 flatbuffers::Verifier verifierEmbeddedSchema(
1118 T::TableType::BinarySchema::data(), T::TableType::BinarySchema::size());
1119 TEST_EQ(reflection::VerifySchemaBuffer(verifierEmbeddedSchema), true);
1120
1121 // Reflect it.
1122 auto schema = reflection::GetSchema(T::TableType::BinarySchema::data());
1123
1124 // This should equal the expected root table.
1125 TEST_EQ_STR(schema->root_table()->name()->c_str(), "MyGame.Example.Monster");
1126 }
1127
EmbeddedSchemaAccess()1128 void EmbeddedSchemaAccess() {
1129 // Get the binary schema for the monster.
1130 // Verify the schema is OK.
1131 flatbuffers::Verifier verifierEmbeddedSchema(Monster::BinarySchema::data(),
1132 Monster::BinarySchema::size());
1133 TEST_EQ(reflection::VerifySchemaBuffer(verifierEmbeddedSchema), true);
1134
1135 // Reflect it.
1136 auto schema = reflection::GetSchema(Monster::BinarySchema::data());
1137
1138 // This should equal the expected root table.
1139 TEST_EQ_STR(schema->root_table()->name()->c_str(), "MyGame.Example.Monster");
1140
1141 // Repeat above, but do so through a template parameter:
1142 EmbeddedSchemaAccessByType<StatT>();
1143 }
1144
NestedVerifierTest()1145 void NestedVerifierTest() {
1146 // Create a nested monster.
1147 flatbuffers::FlatBufferBuilder nested_builder;
1148 FinishMonsterBuffer(
1149 nested_builder,
1150 CreateMonster(nested_builder, nullptr, 0, 0,
1151 nested_builder.CreateString("NestedMonster")));
1152
1153 // Verify the nested monster
1154 flatbuffers::Verifier verifier(nested_builder.GetBufferPointer(),
1155 nested_builder.GetSize());
1156 TEST_EQ(true, VerifyMonsterBuffer(verifier));
1157
1158 {
1159 // Create the outer monster.
1160 flatbuffers::FlatBufferBuilder builder;
1161
1162 // Add the nested monster as a vector of bytes.
1163 auto nested_monster_bytes = builder.CreateVector(
1164 nested_builder.GetBufferPointer(), nested_builder.GetSize());
1165
1166 auto name = builder.CreateString("OuterMonster");
1167
1168 MonsterBuilder mon_builder(builder);
1169 mon_builder.add_name(name);
1170 mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
1171 FinishMonsterBuffer(builder, mon_builder.Finish());
1172
1173 // Verify the root monster, which includes verifing the nested monster
1174 flatbuffers::Verifier verifier(builder.GetBufferPointer(),
1175 builder.GetSize());
1176 TEST_EQ(true, VerifyMonsterBuffer(verifier));
1177 }
1178
1179 {
1180 // Create the outer monster.
1181 flatbuffers::FlatBufferBuilder builder;
1182
1183 // Purposely invalidate the nested flatbuffer setting its length to 1, an
1184 // invalid length.
1185 uint8_t invalid_nested_buffer[1];
1186 auto nested_monster_bytes = builder.CreateVector(invalid_nested_buffer, 1);
1187
1188 auto name = builder.CreateString("OuterMonster");
1189
1190 MonsterBuilder mon_builder(builder);
1191 mon_builder.add_name(name);
1192 mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
1193 FinishMonsterBuffer(builder, mon_builder.Finish());
1194
1195 // Verify the root monster fails, since the included nested monster fails.
1196 flatbuffers::Verifier verifier(builder.GetBufferPointer(),
1197 builder.GetSize());
1198 TEST_EQ(false, VerifyMonsterBuffer(verifier));
1199
1200 // Verify the root monster succeeds, since we've disabled checking nested
1201 // flatbuffers
1202 flatbuffers::Verifier::Options options;
1203 options.check_nested_flatbuffers = false;
1204 flatbuffers::Verifier no_check_nested(builder.GetBufferPointer(),
1205 builder.GetSize(), options);
1206 TEST_EQ(true, VerifyMonsterBuffer(no_check_nested));
1207 }
1208
1209 {
1210 // Create the outer monster.
1211 flatbuffers::FlatBufferBuilder builder;
1212
1213 // Purposely invalidate the nested flatbuffer setting its length to 0, an
1214 // invalid length.
1215 uint8_t *invalid_nested_buffer = nullptr;
1216 auto nested_monster_bytes = builder.CreateVector(invalid_nested_buffer, 0);
1217
1218 auto name = builder.CreateString("OuterMonster");
1219
1220 MonsterBuilder mon_builder(builder);
1221 mon_builder.add_name(name);
1222 mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
1223 FinishMonsterBuffer(builder, mon_builder.Finish());
1224
1225 // Verify the root monster fails, since the included nested monster fails.
1226 flatbuffers::Verifier verifier(builder.GetBufferPointer(),
1227 builder.GetSize());
1228 TEST_EQ(false, VerifyMonsterBuffer(verifier));
1229 }
1230 }
1231
1232 template<class T, class Container>
TestIterators(const std::vector<T> & expected,const Container & tested)1233 void TestIterators(const std::vector<T> &expected, const Container &tested) {
1234 TEST_ASSERT(tested.rbegin().base() == tested.end());
1235 TEST_ASSERT(tested.crbegin().base() == tested.cend());
1236 TEST_ASSERT(tested.rend().base() == tested.begin());
1237 TEST_ASSERT(tested.crend().base() == tested.cbegin());
1238
1239 size_t k = 0;
1240 for (auto it = tested.begin(); it != tested.end(); ++it, ++k) {
1241 const auto &e = expected.at(k);
1242 TEST_EQ(*it, e);
1243 }
1244 TEST_EQ(k, expected.size());
1245
1246 k = expected.size();
1247 for (auto it = tested.rbegin(); it != tested.rend(); ++it, --k) {
1248 const auto &e = expected.at(k - 1);
1249 TEST_EQ(*it, e);
1250 }
1251 TEST_EQ(k, 0);
1252 }
1253
FlatbuffersIteratorsTest()1254 void FlatbuffersIteratorsTest() {
1255 {
1256 flatbuffers::FlatBufferBuilder fbb;
1257 const std::vector<unsigned char> inv_data = { 1, 2, 3 };
1258 {
1259 auto mon_name = fbb.CreateString("MyMonster"); // key, mandatory
1260 auto inv_vec = fbb.CreateVector(inv_data);
1261 auto empty_i64_vec =
1262 fbb.CreateVector(static_cast<const int64_t *>(nullptr), 0);
1263 MonsterBuilder mb(fbb);
1264 mb.add_name(mon_name);
1265 mb.add_inventory(inv_vec);
1266 mb.add_vector_of_longs(empty_i64_vec);
1267 FinishMonsterBuffer(fbb, mb.Finish());
1268 }
1269 const auto &mon = *flatbuffers::GetRoot<Monster>(fbb.GetBufferPointer());
1270
1271 TEST_EQ_STR("MyMonster", mon.name()->c_str());
1272 TEST_ASSERT(mon.inventory());
1273 TEST_ASSERT(mon.vector_of_longs());
1274 TestIterators(inv_data, *mon.inventory());
1275 TestIterators(std::vector<int64_t>(), *mon.vector_of_longs());
1276 }
1277
1278 {
1279 flatbuffers::FlatBufferBuilder fbb;
1280 MyGame::Example::ArrayStruct aStruct;
1281 MyGame::Example::FinishArrayTableBuffer(
1282 fbb, MyGame::Example::CreateArrayTable(fbb, &aStruct));
1283 const auto &array_table =
1284 *flatbuffers::GetRoot<ArrayTable>(fbb.GetBufferPointer());
1285 TEST_ASSERT(array_table.a());
1286 auto &int_15 = *array_table.a()->b();
1287 TestIterators(std::vector<int>(15, 0), int_15);
1288 }
1289 }
1290
PrivateAnnotationsLeaks()1291 void PrivateAnnotationsLeaks() {
1292 // Simple schemas and a "has optional scalar" sentinal.
1293 std::vector<std::string> schemas;
1294 std::vector<std::string> failure_schemas;
1295
1296 // (private) (table/struct)
1297 schemas.push_back(
1298 "table Monster (private) { mana: int; }"
1299 "struct ABC (private) { mana: int; }");
1300
1301 // (public) (table/struct)
1302 schemas.push_back(
1303 "table Monster { mana: int; }"
1304 "struct ABC { mana: int; }");
1305
1306 // (private) (union) containing (private) (table/struct)
1307 schemas.push_back(
1308 "table Monster (private) { mana: int; } "
1309 "struct ABC (private) { mana: int; } "
1310 "union Any (private) { Monster, ABC } ");
1311
1312 // (public) (union) containing (public) (table/struct)
1313 schemas.push_back(
1314 "table Monster { mana: int; }"
1315 "struct ABC { mana: int; }"
1316 "union Any { Monster, ABC }");
1317
1318 // (private) (table/struct/enum)
1319 schemas.push_back(
1320 "table Monster (private) { mana: int; }"
1321 "struct ABC (private) { mana: int; }"
1322 "enum Race:byte (private) { None = -1, Human = 0, }");
1323
1324 // (public) (table/struct/enum)
1325 schemas.push_back(
1326 "table Monster { mana: int; }"
1327 "struct ABC { mana: int; }"
1328 "enum Race:byte { None = -1, Human = 0, }");
1329
1330 // (private) (union) containing (private) (table/struct)
1331 schemas.push_back(
1332 "table Monster (private) { mana: int; }"
1333 "struct ABC (private) { mana: int; }"
1334 "enum Race:byte (private) { None = -1, Human = 0, }"
1335 "union Any (private) { Monster, ABC }");
1336
1337 // (public) (union) containing (public) (table/struct)
1338 schemas.push_back(
1339 "table Monster { mana: int; }"
1340 "struct ABC { mana: int; }"
1341 "enum Race:byte { None = -1, Human = 0, }"
1342 "union Any { Monster, ABC }");
1343
1344 // (private) (table), (public struct)
1345 schemas.push_back(
1346 "table Monster (private) { mana: int; }"
1347 "struct ABC { mana: int; }");
1348
1349 // (private) (table), (public) (struct/enum)
1350 schemas.push_back(
1351 "table Monster (private) { mana: int; }"
1352 "struct ABC { mana: int; }"
1353 "enum Race:byte { None = -1, Human = 0, }");
1354
1355 // (public) (struct) containing (public) (enum)
1356 schemas.push_back(
1357 "enum Race:byte { None = -1, Human = 0, }"
1358 "table Monster { mana: int; }"
1359 "struct ABC { mana: int; type: Race; }");
1360
1361 // (public) (union) containing (private) (table) & (public) (struct)
1362 failure_schemas.push_back(
1363 "table Monster (private) { mana: int; }"
1364 "struct ABC { mana: int; }"
1365 "union Any { Monster, ABC }");
1366
1367 // (public) (union) containing (private) (table/struct)
1368 failure_schemas.push_back(
1369 "table Monster (private) { mana: int; }"
1370 "struct ABC (private) { mana: int; }"
1371 "enum Race:byte { None = -1, Human = 0, }"
1372 "union Any { Monster, ABC }");
1373
1374 // (public) (table) containing (private) (struct)
1375 failure_schemas.push_back(
1376 "table Monster { mana: int; ab: ABC; }"
1377 "struct ABC (private) { mana: int; }");
1378
1379 // (public) (struct) containing (private) (enum)
1380 failure_schemas.push_back(
1381 "enum Race:byte (private) { None = -1, Human = 0, }"
1382 "table Monster { mana: int; }"
1383 "struct ABC { mana: int; type: Race; }");
1384
1385 flatbuffers::IDLOptions opts;
1386 opts.lang_to_generate = flatbuffers::IDLOptions::Language::kSwift;
1387 opts.no_leak_private_annotations = true;
1388
1389 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
1390 flatbuffers::Parser parser(opts);
1391 TEST_ASSERT(parser.Parse(schema->c_str()));
1392 }
1393
1394 for (auto schema = failure_schemas.begin(); schema < failure_schemas.end();
1395 schema++) {
1396 flatbuffers::Parser parser(opts);
1397 TEST_EQ(false, parser.Parse(schema->c_str()));
1398 }
1399
1400 opts.no_leak_private_annotations = false;
1401
1402 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
1403 flatbuffers::Parser parser(opts);
1404 TEST_ASSERT(parser.Parse(schema->c_str()));
1405 }
1406
1407 for (auto schema = failure_schemas.begin(); schema < failure_schemas.end();
1408 schema++) {
1409 flatbuffers::Parser parser(opts);
1410 TEST_ASSERT(parser.Parse(schema->c_str()));
1411 }
1412 }
1413
VectorSpanTest()1414 void VectorSpanTest() {
1415 flatbuffers::FlatBufferBuilder builder;
1416
1417 auto mloc = CreateMonster(
1418 builder, nullptr, 0, 0, builder.CreateString("Monster"),
1419 builder.CreateVector<uint8_t>({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }));
1420
1421 FinishMonsterBuffer(builder, mloc);
1422
1423 auto monster = GetMonster(builder.GetBufferPointer());
1424 auto mutable_monster = GetMutableMonster(builder.GetBufferPointer());
1425
1426 { // using references
1427 TEST_NOTNULL(monster->inventory());
1428
1429 flatbuffers::span<const uint8_t> const_inventory =
1430 flatbuffers::make_span(*monster->inventory());
1431 TEST_EQ(const_inventory.size(), 10);
1432 TEST_EQ(const_inventory[0], 0);
1433 TEST_EQ(const_inventory[9], 9);
1434
1435 flatbuffers::span<uint8_t> mutable_inventory =
1436 flatbuffers::make_span(*mutable_monster->mutable_inventory());
1437 TEST_EQ(mutable_inventory.size(), 10);
1438 TEST_EQ(mutable_inventory[0], 0);
1439 TEST_EQ(mutable_inventory[9], 9);
1440
1441 mutable_inventory[0] = 42;
1442 TEST_EQ(mutable_inventory[0], 42);
1443
1444 mutable_inventory[0] = 0;
1445 TEST_EQ(mutable_inventory[0], 0);
1446 }
1447
1448 { // using pointers
1449 TEST_EQ(flatbuffers::VectorLength(monster->inventory()), 10);
1450
1451 flatbuffers::span<const uint8_t> const_inventory =
1452 flatbuffers::make_span(monster->inventory());
1453 TEST_EQ(const_inventory.size(), 10);
1454 TEST_EQ(const_inventory[0], 0);
1455 TEST_EQ(const_inventory[9], 9);
1456
1457 flatbuffers::span<uint8_t> mutable_inventory =
1458 flatbuffers::make_span(mutable_monster->mutable_inventory());
1459 TEST_EQ(mutable_inventory.size(), 10);
1460 TEST_EQ(mutable_inventory[0], 0);
1461 TEST_EQ(mutable_inventory[9], 9);
1462
1463 mutable_inventory[0] = 42;
1464 TEST_EQ(mutable_inventory[0], 42);
1465
1466 mutable_inventory[0] = 0;
1467 TEST_EQ(mutable_inventory[0], 0);
1468 }
1469
1470 {
1471 TEST_ASSERT(nullptr == monster->testnestedflatbuffer());
1472
1473 TEST_EQ(flatbuffers::VectorLength(monster->testnestedflatbuffer()), 0);
1474
1475 flatbuffers::span<const uint8_t> const_nested =
1476 flatbuffers::make_span(monster->testnestedflatbuffer());
1477 TEST_ASSERT(const_nested.empty());
1478
1479 flatbuffers::span<uint8_t> mutable_nested =
1480 flatbuffers::make_span(mutable_monster->mutable_testnestedflatbuffer());
1481 TEST_ASSERT(mutable_nested.empty());
1482 }
1483 }
1484
NativeInlineTableVectorTest()1485 void NativeInlineTableVectorTest() {
1486 TestNativeInlineTableT test;
1487 for (int i = 0; i < 10; ++i) {
1488 NativeInlineTableT t;
1489 t.a = i;
1490 test.t.push_back(t);
1491 }
1492
1493 flatbuffers::FlatBufferBuilder fbb;
1494 auto offset = TestNativeInlineTable::Pack(fbb, &test);
1495 fbb.Finish(offset);
1496
1497 auto *root =
1498 flatbuffers::GetRoot<TestNativeInlineTable>(fbb.GetBufferPointer());
1499 TestNativeInlineTableT unpacked;
1500 root->UnPackTo(&unpacked);
1501
1502 for (int i = 0; i < 10; ++i) { TEST_ASSERT(unpacked.t[i] == test.t[i]); }
1503
1504 TEST_ASSERT(unpacked.t == test.t);
1505 }
1506
1507 // Guard against -Wunused-function on platforms without file tests.
1508 #ifndef FLATBUFFERS_NO_FILE_TESTS
DoNotRequireEofTest(const std::string & tests_data_path)1509 void DoNotRequireEofTest(const std::string &tests_data_path) {
1510 std::string schemafile;
1511 bool ok = flatbuffers::LoadFile(
1512 (tests_data_path + "monster_test.fbs").c_str(), false, &schemafile);
1513 TEST_EQ(ok, true);
1514 auto include_test_path =
1515 flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
1516 const char *include_directories[] = { tests_data_path.c_str(),
1517 include_test_path.c_str(), nullptr };
1518 flatbuffers::IDLOptions opt;
1519 opt.require_json_eof = false;
1520 flatbuffers::Parser parser(opt);
1521 ok = parser.Parse(schemafile.c_str(), include_directories);
1522 TEST_EQ(ok, true);
1523
1524 const char *str = R"(Some text at the beginning. {
1525 "name": "Blob",
1526 "hp": 5
1527 }{
1528 "name": "Imp",
1529 "hp": 10
1530 }
1531 Some extra text at the end too.
1532 )";
1533 const char *tableStart = std::strchr(str, '{');
1534 ok = parser.ParseJson(tableStart);
1535 TEST_EQ(ok, true);
1536
1537 const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
1538 TEST_EQ_STR(monster->name()->c_str(), "Blob");
1539 TEST_EQ(monster->hp(), 5);
1540
1541 tableStart += parser.BytesConsumed();
1542
1543 ok = parser.ParseJson(tableStart);
1544 TEST_EQ(ok, true);
1545
1546 monster = GetMonster(parser.builder_.GetBufferPointer());
1547 TEST_EQ_STR(monster->name()->c_str(), "Imp");
1548 TEST_EQ(monster->hp(), 10);
1549 }
1550 #endif
1551
UnionUnderlyingTypeTest()1552 void UnionUnderlyingTypeTest() {
1553 using namespace UnionUnderlyingType;
1554 TEST_ASSERT(sizeof(ABC) == sizeof(uint32_t));
1555 TEST_ASSERT(static_cast<int32_t>(ABC::A) == 555);
1556 TEST_ASSERT(static_cast<int32_t>(ABC::B) == 666);
1557 TEST_ASSERT(static_cast<int32_t>(ABC::C) == 777);
1558
1559 DT buffer;
1560 AT a;
1561 a.a = 42;
1562 BT b;
1563 b.b = "foo";
1564 CT c;
1565 c.c = true;
1566 buffer.test_union = ABCUnion();
1567 buffer.test_union.Set(a);
1568 buffer.test_vector_of_union.resize(3);
1569 buffer.test_vector_of_union[0].Set(a);
1570 buffer.test_vector_of_union[1].Set(b);
1571 buffer.test_vector_of_union[2].Set(c);
1572
1573 flatbuffers::FlatBufferBuilder fbb;
1574 auto offset = D::Pack(fbb, &buffer);
1575 fbb.Finish(offset);
1576
1577 auto *root =
1578 flatbuffers::GetRoot<D>(fbb.GetBufferPointer());
1579 DT unpacked;
1580 root->UnPackTo(&unpacked);
1581
1582 TEST_ASSERT(unpacked.test_union == buffer.test_union);
1583 TEST_ASSERT(unpacked.test_vector_of_union == buffer.test_vector_of_union);
1584
1585 }
1586
Offset64Tests()1587 static void Offset64Tests() {
1588 #if INCLUDE_64_BIT_TESTS
1589 Offset64Test();
1590 Offset64SerializedFirst();
1591 Offset64NestedFlatBuffer();
1592 Offset64CreateDirect();
1593 Offset64Evolution();
1594 Offset64VectorOfStructs();
1595 Offset64SizePrefix();
1596 Offset64ManyVectors();
1597 Offset64ForceAlign();
1598 #endif
1599 }
1600
FlatBufferTests(const std::string & tests_data_path)1601 int FlatBufferTests(const std::string &tests_data_path) {
1602 // Run our various test suites:
1603
1604 std::string rawbuf;
1605 auto flatbuf1 = CreateFlatBufferTest(rawbuf);
1606 auto flatbuf = std::move(flatbuf1); // Test move assignment.
1607
1608 AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
1609 rawbuf.length());
1610 AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
1611
1612 MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
1613
1614 ObjectFlatBuffersTest(flatbuf.data());
1615 UnPackTo(flatbuf.data());
1616
1617 MiniReflectFlatBuffersTest(flatbuf.data());
1618 MiniReflectFixedLengthArrayTest();
1619
1620 SizePrefixedTest();
1621
1622 AlignmentTest();
1623
1624 #ifndef FLATBUFFERS_NO_FILE_TESTS
1625 ParseAndGenerateTextTest(tests_data_path, false);
1626 ParseAndGenerateTextTest(tests_data_path, true);
1627 FixedLengthArrayJsonTest(tests_data_path, false);
1628 FixedLengthArrayJsonTest(tests_data_path, true);
1629 ReflectionTest(tests_data_path, flatbuf.data(), flatbuf.size());
1630 ParseProtoTest(tests_data_path);
1631 EvolutionTest(tests_data_path);
1632 UnionDeprecationTest(tests_data_path);
1633 UnionVectorTest(tests_data_path);
1634 GenerateTableTextTest(tests_data_path);
1635 TestEmbeddedBinarySchema(tests_data_path);
1636 JsonOptionalTest(tests_data_path, false);
1637 JsonOptionalTest(tests_data_path, true);
1638 MultiFileNameClashTest(tests_data_path);
1639 InvalidNestedFlatbufferTest(tests_data_path);
1640 JsonDefaultTest(tests_data_path);
1641 JsonEnumsTest(tests_data_path);
1642 TestMonsterExtraFloats(tests_data_path);
1643 ParseIncorrectMonsterJsonTest(tests_data_path);
1644 FixedLengthArraySpanTest(tests_data_path);
1645 DoNotRequireEofTest(tests_data_path);
1646 JsonUnionStructTest();
1647 #else
1648 // Guard against -Wunused-parameter.
1649 (void)tests_data_path;
1650 #endif
1651
1652 UtilConvertCase();
1653
1654 FuzzTest1();
1655 FuzzTest2();
1656
1657 TriviallyCopyableTest();
1658 ErrorTest();
1659 ValueTest();
1660 EnumValueTest();
1661 NestedListTest();
1662 EnumStringsTest();
1663 EnumNamesTest();
1664 EnumOutOfRangeTest();
1665 IntegerOutOfRangeTest();
1666 IntegerBoundaryTest();
1667 UnicodeTest();
1668 UnicodeTestAllowNonUTF8();
1669 UnicodeTestGenerateTextFailsOnNonUTF8();
1670 UnicodeSurrogatesTest();
1671 UnicodeInvalidSurrogatesTest();
1672 InvalidUTF8Test();
1673 UnknownFieldsTest();
1674 ParseUnionTest();
1675 ValidSameNameDifferentNamespaceTest();
1676 ConformTest();
1677 ParseProtoBufAsciiTest();
1678 TypeAliasesTest();
1679 EndianSwapTest();
1680 CreateSharedStringTest();
1681 FlexBuffersTest();
1682 FlexBuffersReuseBugTest();
1683 FlexBuffersDeprecatedTest();
1684 UninitializedVectorTest();
1685 EqualOperatorTest();
1686 NumericUtilsTest();
1687 IsAsciiUtilsTest();
1688 ValidFloatTest();
1689 InvalidFloatTest();
1690 FixedLengthArrayTest();
1691 NativeTypeTest();
1692 OptionalScalarsTest();
1693 ParseFlexbuffersFromJsonWithNullTest();
1694 FlatbuffersSpanTest();
1695 FixedLengthArrayConstructorTest();
1696 FixedLengthArrayOperatorEqualTest();
1697 FieldIdentifierTest();
1698 StringVectorDefaultsTest();
1699 FlexBuffersFloatingPointTest();
1700 FlatbuffersIteratorsTest();
1701 WarningsAsErrorsTest();
1702 NestedVerifierTest();
1703 PrivateAnnotationsLeaks();
1704 JsonUnsortedArrayTest();
1705 VectorSpanTest();
1706 NativeInlineTableVectorTest();
1707 FixedSizedScalarKeyInStructTest();
1708 StructKeyInStructTest();
1709 NestedStructKeyInStructTest();
1710 FixedSizedStructArrayKeyInStructTest();
1711 EmbeddedSchemaAccess();
1712 Offset64Tests();
1713 UnionUnderlyingTypeTest();
1714 return 0;
1715 }
1716 } // namespace
1717 } // namespace tests
1718 } // namespace flatbuffers
1719
main(int argc,const char * argv[])1720 int main(int argc, const char *argv[]) {
1721 std::string tests_data_path = "tests/";
1722
1723 for (int argi = 1; argi < argc; argi++) {
1724 std::string arg = argv[argi];
1725 if (arg == "--test_path") {
1726 if (++argi >= argc) {
1727 fprintf(stderr, "error: missing path following: %s\n", arg.c_str());
1728 exit(1);
1729 }
1730 // Override default path if provided one.
1731 tests_data_path = argv[argi];
1732
1733 } else {
1734 fprintf(stderr, "error: Unknown argument: %s\n", arg.c_str());
1735 exit(1);
1736 }
1737 }
1738
1739 InitTestEngine();
1740
1741 std::string req_locale;
1742 if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
1743 &req_locale)) {
1744 TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
1745 req_locale.c_str());
1746 req_locale = flatbuffers::RemoveStringQuotes(req_locale);
1747 std::string the_locale;
1748 TEST_ASSERT_FUNC(
1749 flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
1750 TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
1751 }
1752
1753 #ifdef FLATBUFFERS_TEST_PATH_PREFIX
1754 tests_data_path =
1755 FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) + tests_data_path;
1756 #endif
1757
1758 flatbuffers::tests::FlatBufferTests(tests_data_path);
1759 FlatBufferBuilderTest();
1760
1761 if (!testing_fails) {
1762 TEST_OUTPUT_LINE("ALL TESTS PASSED");
1763 } else {
1764 TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
1765 }
1766 return CloseTestEngine();
1767 }
1768