2 * Copyright 2014 Google Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "flatbuffers/flatbuffers.h"
19 #include "flatbuffers/idl.h"
20 #include "flatbuffers/minireflect.h"
21 #include "flatbuffers/registry.h"
22 #include "flatbuffers/util.h"
25 #ifdef FLATBUFFERS_CPP98_STL
27 using flatbuffers::unique_ptr;
32 #include "monster_test_generated.h"
33 #include "namespace_test/namespace_test1_generated.h"
34 #include "namespace_test/namespace_test2_generated.h"
35 #include "union_vector/union_vector_generated.h"
36 #include "optional_scalars_generated.h"
37 #if !defined(_MSC_VER) || _MSC_VER >= 1700
38 # include "monster_extra_generated.h"
39 # include "arrays_test_generated.h"
40 # include "evolution_test/evolution_v1_generated.h"
41 # include "evolution_test/evolution_v2_generated.h"
44 #include "native_type_test_generated.h"
45 #include "test_assert.h"
47 #include "flatbuffers/flexbuffers.h"
48 #include "monster_test_bfbs_generated.h" // Generated using --bfbs-comments --bfbs-builtins --cpp --bfbs-gen-embed
51 // Check that char* and uint8_t* are interoperable types.
52 // The reinterpret_cast<> between the pointers are used to simplify data loading.
53 static_assert(flatbuffers::is_same<uint8_t, char>::value ||
54 flatbuffers::is_same<uint8_t, unsigned char>::value,
55 "unexpected uint8_t type");
57 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
58 // Ensure IEEE-754 support if tests of floats with NaN/Inf will run.
59 static_assert(std::numeric_limits<float>::is_iec559 &&
60 std::numeric_limits<double>::is_iec559,
61 "IEC-559 (IEEE-754) standard required");
65 // Shortcuts for the infinity.
66 static const auto infinity_f = std::numeric_limits<float>::infinity();
67 static const auto infinity_d = std::numeric_limits<double>::infinity();
69 using namespace MyGame::Example;
71 void FlatBufferBuilderTest();
73 // Include simple random number generator to ensure results will be the
74 // same cross platform.
75 // http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
76 uint32_t lcg_seed = 48271;
79 (static_cast<uint64_t>(lcg_seed) * 279470273UL) % 4294967291UL;
81 void lcg_reset() { lcg_seed = 48271; }
83 std::string test_data_path =
84 #ifdef BAZEL_TEST_DATA_PATH
85 "../com_github_google_flatbuffers/tests/";
90 // example of how to build up a serialized buffer algorithmically:
91 flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) {
92 flatbuffers::FlatBufferBuilder builder;
94 auto vec = Vec3(1, 2, 3, 0, Color_Red, Test(10, 20));
96 auto name = builder.CreateString("MyMonster");
98 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
99 auto inventory = builder.CreateVector(inv_data, 10);
101 // Alternatively, create the vector first, and fill in data later:
102 // unsigned char *inv_buf = nullptr;
103 // auto inventory = builder.CreateUninitializedVector<unsigned char>(
105 // memcpy(inv_buf, inv_data, 10);
107 Test tests[] = { Test(10, 20), Test(30, 40) };
108 auto testv = builder.CreateVectorOfStructs(tests, 2);
111 #ifndef FLATBUFFERS_CPP98_STL
112 // Create a vector of structures from a lambda.
113 auto testv2 = builder.CreateVectorOfStructs<Test>(
114 2, [&](size_t i, Test* s) -> void {
118 // Create a vector of structures using a plain old C++ function.
119 auto testv2 = builder.CreateVectorOfStructs<Test>(
120 2, [](size_t i, Test* s, void *state) -> void {
121 *s = (reinterpret_cast<Test*>(state))[i];
123 #endif // FLATBUFFERS_CPP98_STL
126 // create monster with very few fields set:
127 // (same functionality as CreateMonster below, but sets fields manually)
128 flatbuffers::Offset<Monster> mlocs[3];
129 auto fred = builder.CreateString("Fred");
130 auto barney = builder.CreateString("Barney");
131 auto wilma = builder.CreateString("Wilma");
132 MonsterBuilder mb1(builder);
134 mlocs[0] = mb1.Finish();
135 MonsterBuilder mb2(builder);
136 mb2.add_name(barney);
138 mlocs[1] = mb2.Finish();
139 MonsterBuilder mb3(builder);
141 mlocs[2] = mb3.Finish();
143 // Create an array of strings. Also test string pooling, and lambdas.
145 builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(
147 [](size_t i, flatbuffers::FlatBufferBuilder *b)
148 -> flatbuffers::Offset<flatbuffers::String> {
149 static const char *names[] = { "bob", "fred", "bob", "fred" };
150 return b->CreateSharedString(names[i]);
154 // Creating vectors of strings in one convenient call.
155 std::vector<std::string> names2;
156 names2.push_back("jane");
157 names2.push_back("mary");
158 auto vecofstrings2 = builder.CreateVectorOfStrings(names2);
160 // Create an array of sorted tables, can be used with binary search when read:
161 auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3);
163 // Create an array of sorted structs,
164 // can be used with binary search when read:
165 std::vector<Ability> abilities;
166 abilities.push_back(Ability(4, 40));
167 abilities.push_back(Ability(3, 30));
168 abilities.push_back(Ability(2, 20));
169 abilities.push_back(Ability(0, 0));
170 auto vecofstructs = builder.CreateVectorOfSortedStructs(&abilities);
172 flatbuffers::Offset<Stat> mlocs_stats[1];
173 auto miss = builder.CreateString("miss");
174 StatBuilder mb_miss(builder);
175 mb_miss.add_id(miss);
177 mb_miss.add_count(0); // key
178 mlocs_stats[0] = mb_miss.Finish();
179 auto vec_of_stats = builder.CreateVectorOfSortedTables(mlocs_stats, 1);
181 // Create a nested FlatBuffer.
182 // Nested FlatBuffers are stored in a ubyte vector, which can be convenient
183 // since they can be memcpy'd around much easier than other FlatBuffer
184 // values. They have little overhead compared to storing the table directly.
185 // As a test, create a mostly empty Monster buffer:
186 flatbuffers::FlatBufferBuilder nested_builder;
187 auto nmloc = CreateMonster(nested_builder, nullptr, 0, 0,
188 nested_builder.CreateString("NestedMonster"));
189 FinishMonsterBuffer(nested_builder, nmloc);
190 // Now we can store the buffer in the parent. Note that by default, vectors
191 // are only aligned to their elements or size field, so in this case if the
192 // buffer contains 64-bit elements, they may not be correctly aligned. We fix
194 builder.ForceVectorAlignment(nested_builder.GetSize(), sizeof(uint8_t),
195 nested_builder.GetBufferMinAlignment());
196 // If for whatever reason you don't have the nested_builder available, you
197 // can substitute flatbuffers::largest_scalar_t (64-bit) for the alignment, or
198 // the largest force_align value in your schema if you're using it.
199 auto nested_flatbuffer_vector = builder.CreateVector(
200 nested_builder.GetBufferPointer(), nested_builder.GetSize());
202 // Test a nested FlexBuffer:
203 flexbuffers::Builder flexbuild;
206 auto flex = builder.CreateVector(flexbuild.GetBuffer());
208 // Test vector of enums.
209 Color colors[] = { Color_Blue, Color_Green };
210 // We use this special creation function because we have an array of
211 // pre-C++11 (enum class) enums whose size likely is int, yet its declared
212 // type in the schema is byte.
213 auto vecofcolors = builder.CreateVectorScalarCast<uint8_t, Color>(colors, 2);
215 // shortcut for creating monster with all fields set:
216 auto mloc = CreateMonster(
217 builder, &vec, 150, 80, name, inventory, Color_Blue, Any_Monster,
218 mlocs[1].Union(), // Store a union.
219 testv, vecofstrings, vecoftables, 0, nested_flatbuffer_vector, 0, false,
220 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f, vecofstrings2,
221 vecofstructs, flex, testv2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
222 AnyUniqueAliases_NONE, 0, AnyAmbiguousAliases_NONE, 0, vecofcolors,
223 MyGame::Example::Race_None, 0, vec_of_stats);
225 FinishMonsterBuffer(builder, mloc);
228 #ifdef FLATBUFFERS_TEST_VERBOSE
229 // print byte data for debugging:
230 auto p = builder.GetBufferPointer();
231 for (flatbuffers::uoffset_t i = 0; i < builder.GetSize(); i++)
236 // return the buffer for the caller to use.
238 reinterpret_cast<const char *>(builder.GetBufferPointer());
239 buffer.assign(bufferpointer, bufferpointer + builder.GetSize());
241 return builder.Release();
244 // example of accessing a buffer loaded in memory:
245 void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
246 bool pooled = true) {
247 // First, verify the buffers integrity (optional)
248 flatbuffers::Verifier verifier(flatbuf, length);
249 TEST_EQ(VerifyMonsterBuffer(verifier), true);
252 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
253 std::vector<uint8_t> test_buff;
254 test_buff.resize(length * 2);
255 std::memcpy(&test_buff[0], flatbuf, length);
256 std::memcpy(&test_buff[length], flatbuf, length);
258 flatbuffers::Verifier verifier1(&test_buff[0], length);
259 TEST_EQ(VerifyMonsterBuffer(verifier1), true);
260 TEST_EQ(verifier1.GetComputedSize(), length);
262 flatbuffers::Verifier verifier2(&test_buff[length], length);
263 TEST_EQ(VerifyMonsterBuffer(verifier2), true);
264 TEST_EQ(verifier2.GetComputedSize(), length);
268 TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0);
269 TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true);
270 TEST_EQ(strcmp(MonsterExtension(), "mon"), 0);
272 // Access the buffer from the root.
273 auto monster = GetMonster(flatbuf);
275 TEST_EQ(monster->hp(), 80);
276 TEST_EQ(monster->mana(), 150); // default
277 TEST_EQ_STR(monster->name()->c_str(), "MyMonster");
278 // Can't access the following field, it is deprecated in the schema,
279 // which means accessors are not generated:
280 // monster.friendly()
282 auto pos = monster->pos();
284 TEST_EQ(pos->z(), 3);
285 TEST_EQ(pos->test3().a(), 10);
286 TEST_EQ(pos->test3().b(), 20);
288 auto inventory = monster->inventory();
289 TEST_EQ(VectorLength(inventory), 10UL); // Works even if inventory is null.
290 TEST_NOTNULL(inventory);
291 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
292 // Check compatibilty of iterators with STL.
293 std::vector<unsigned char> inv_vec(inventory->begin(), inventory->end());
295 for (auto it = inventory->begin(); it != inventory->end(); ++it, ++n) {
296 auto indx = it - inventory->begin();
297 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
298 TEST_EQ(*it, inv_data[indx]);
300 TEST_EQ(n, inv_vec.size());
303 for (auto it = inventory->cbegin(); it != inventory->cend(); ++it, ++n) {
304 auto indx = it - inventory->cbegin();
305 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
306 TEST_EQ(*it, inv_data[indx]);
308 TEST_EQ(n, inv_vec.size());
311 for (auto it = inventory->rbegin(); it != inventory->rend(); ++it, ++n) {
312 auto indx = inventory->rend() - it - 1;
313 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
314 TEST_EQ(*it, inv_data[indx]);
316 TEST_EQ(n, inv_vec.size());
319 for (auto it = inventory->crbegin(); it != inventory->crend(); ++it, ++n) {
320 auto indx = inventory->crend() - it - 1;
321 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
322 TEST_EQ(*it, inv_data[indx]);
324 TEST_EQ(n, inv_vec.size());
326 TEST_EQ(monster->color(), Color_Blue);
328 // Example of accessing a union:
329 TEST_EQ(monster->test_type(), Any_Monster); // First make sure which it is.
330 auto monster2 = reinterpret_cast<const Monster *>(monster->test());
331 TEST_NOTNULL(monster2);
332 TEST_EQ_STR(monster2->name()->c_str(), "Fred");
334 // Example of accessing a vector of strings:
335 auto vecofstrings = monster->testarrayofstring();
336 TEST_EQ(vecofstrings->size(), 4U);
337 TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
338 TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
340 // These should have pointer equality because of string pooling.
341 TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
342 TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
345 auto vecofstrings2 = monster->testarrayofstring2();
347 TEST_EQ(vecofstrings2->size(), 2U);
348 TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
349 TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
352 // Example of accessing a vector of tables:
353 auto vecoftables = monster->testarrayoftables();
354 TEST_EQ(vecoftables->size(), 3U);
355 for (auto it = vecoftables->begin(); it != vecoftables->end(); ++it) {
356 TEST_EQ(strlen(it->name()->c_str()) >= 4, true);
358 TEST_EQ_STR(vecoftables->Get(0)->name()->c_str(), "Barney");
359 TEST_EQ(vecoftables->Get(0)->hp(), 1000);
360 TEST_EQ_STR(vecoftables->Get(1)->name()->c_str(), "Fred");
361 TEST_EQ_STR(vecoftables->Get(2)->name()->c_str(), "Wilma");
362 TEST_NOTNULL(vecoftables->LookupByKey("Barney"));
363 TEST_NOTNULL(vecoftables->LookupByKey("Fred"));
364 TEST_NOTNULL(vecoftables->LookupByKey("Wilma"));
366 // Test accessing a vector of sorted structs
367 auto vecofstructs = monster->testarrayofsortedstruct();
368 if (vecofstructs) { // not filled in monster_test.bfbs
369 for (flatbuffers::uoffset_t i = 0; i < vecofstructs->size() - 1; i++) {
370 auto left = vecofstructs->Get(i);
371 auto right = vecofstructs->Get(i + 1);
372 TEST_EQ(true, (left->KeyCompareLessThan(right)));
374 TEST_NOTNULL(vecofstructs->LookupByKey(0)); // test default value
375 TEST_NOTNULL(vecofstructs->LookupByKey(3));
376 TEST_EQ(static_cast<const Ability *>(nullptr),
377 vecofstructs->LookupByKey(5));
380 if (auto vec_of_stat = monster->scalar_key_sorted_tables()) {
381 auto stat_0 = vec_of_stat->LookupByKey(static_cast<uint16_t>(0u));
382 TEST_NOTNULL(stat_0);
383 TEST_NOTNULL(stat_0->id());
384 TEST_EQ(0, stat_0->count());
385 TEST_EQ_STR("miss", stat_0->id()->c_str());
388 // Test nested FlatBuffers if available:
389 auto nested_buffer = monster->testnestedflatbuffer();
391 // nested_buffer is a vector of bytes you can memcpy. However, if you
392 // actually want to access the nested data, this is a convenient
393 // accessor that directly gives you the root table:
394 auto nested_monster = monster->testnestedflatbuffer_nested_root();
395 TEST_EQ_STR(nested_monster->name()->c_str(), "NestedMonster");
398 // Test flexbuffer if available:
399 auto flex = monster->flex();
400 // flex is a vector of bytes you can memcpy etc.
401 TEST_EQ(flex->size(), 4); // Encoded FlexBuffer bytes.
402 // However, if you actually want to access the nested data, this is a
403 // convenient accessor that directly gives you the root value:
404 TEST_EQ(monster->flex_flexbuffer_root().AsInt16(), 1234);
406 // Test vector of enums:
407 auto colors = monster->vector_of_enums();
409 TEST_EQ(colors->size(), 2);
410 TEST_EQ(colors->Get(0), Color_Blue);
411 TEST_EQ(colors->Get(1), Color_Green);
414 // Since Flatbuffers uses explicit mechanisms to override the default
415 // compiler alignment, double check that the compiler indeed obeys them:
416 // (Test consists of a short and byte):
417 TEST_EQ(flatbuffers::AlignOf<Test>(), 2UL);
418 TEST_EQ(sizeof(Test), 4UL);
420 const flatbuffers::Vector<const Test *> *tests_array[] = {
424 for (size_t i = 0; i < sizeof(tests_array) / sizeof(tests_array[0]); ++i) {
425 auto tests = tests_array[i];
427 auto test_0 = tests->Get(0);
428 auto test_1 = tests->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 for (auto it = tests->begin(); it != tests->end(); ++it) {
434 TEST_EQ(it->a() == 10 || it->a() == 30, true); // Just testing iterators.
438 // Checking for presence of fields:
439 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
440 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
442 // Obtaining a buffer from a root:
443 TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
446 // Change a FlatBuffer in-place, after it has been constructed.
447 void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
448 // Get non-const pointer to root.
449 auto monster = GetMutableMonster(flatbuf);
451 // Each of these tests mutates, then tests, then set back to the original,
452 // so we can test that the buffer in the end still passes our original test.
453 auto hp_ok = monster->mutate_hp(10);
454 TEST_EQ(hp_ok, true); // Field was present.
455 TEST_EQ(monster->hp(), 10);
456 // Mutate to default value
457 auto hp_ok_default = monster->mutate_hp(100);
458 TEST_EQ(hp_ok_default, true); // Field was present.
459 TEST_EQ(monster->hp(), 100);
460 // Test that mutate to default above keeps field valid for further mutations
461 auto hp_ok_2 = monster->mutate_hp(20);
462 TEST_EQ(hp_ok_2, true);
463 TEST_EQ(monster->hp(), 20);
464 monster->mutate_hp(80);
466 // Monster originally at 150 mana (default value)
467 auto mana_default_ok = monster->mutate_mana(150); // Mutate to default value.
468 TEST_EQ(mana_default_ok,
469 true); // Mutation should succeed, because default value.
470 TEST_EQ(monster->mana(), 150);
471 auto mana_ok = monster->mutate_mana(10);
472 TEST_EQ(mana_ok, false); // Field was NOT present, because default value.
473 TEST_EQ(monster->mana(), 150);
476 auto pos = monster->mutable_pos();
477 auto test3 = pos->mutable_test3(); // Struct inside a struct.
478 test3.mutate_a(50); // Struct fields never fail.
479 TEST_EQ(test3.a(), 50);
483 auto inventory = monster->mutable_inventory();
484 inventory->Mutate(9, 100);
485 TEST_EQ(inventory->Get(9), 100);
486 inventory->Mutate(9, 9);
488 auto tables = monster->mutable_testarrayoftables();
489 auto first = tables->GetMutableObject(0);
490 TEST_EQ(first->hp(), 1000);
492 TEST_EQ(first->hp(), 0);
493 first->mutate_hp(1000);
495 // Run the verifier and the regular test to make sure we didn't trample on
497 AccessFlatBufferTest(flatbuf, length);
500 // Unpack a FlatBuffer into objects.
501 void ObjectFlatBuffersTest(uint8_t *flatbuf) {
502 // Optional: we can specify resolver and rehasher functions to turn hashed
503 // strings into object pointers and back, to implement remote references
505 auto resolver = flatbuffers::resolver_function_t(
506 [](void **pointer_adr, flatbuffers::hash_value_t hash) {
509 // Don't actually do anything, leave variable null.
511 auto rehasher = flatbuffers::rehasher_function_t(
512 [](void *pointer) -> flatbuffers::hash_value_t {
517 // Turn a buffer into C++ objects.
518 auto monster1 = UnPackMonster(flatbuf, &resolver);
520 // Re-serialize the data.
521 flatbuffers::FlatBufferBuilder fbb1;
522 fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
523 MonsterIdentifier());
525 // Unpack again, and re-serialize again.
526 auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
527 flatbuffers::FlatBufferBuilder fbb2;
528 fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
529 MonsterIdentifier());
531 // Now we've gone full round-trip, the two buffers should match.
532 auto len1 = fbb1.GetSize();
533 auto len2 = fbb2.GetSize();
535 TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), len1), 0);
537 // Test it with the original buffer test to make sure all data survived.
538 AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
540 // Test accessing fields, similar to AccessFlatBufferTest above.
541 TEST_EQ(monster2->hp, 80);
542 TEST_EQ(monster2->mana, 150); // default
543 TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
545 auto &pos = monster2->pos;
547 TEST_EQ(pos->z(), 3);
548 TEST_EQ(pos->test3().a(), 10);
549 TEST_EQ(pos->test3().b(), 20);
551 auto &inventory = monster2->inventory;
552 TEST_EQ(inventory.size(), 10UL);
553 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
554 for (auto it = inventory.begin(); it != inventory.end(); ++it)
555 TEST_EQ(*it, inv_data[it - inventory.begin()]);
557 TEST_EQ(monster2->color, Color_Blue);
559 auto monster3 = monster2->test.AsMonster();
560 TEST_NOTNULL(monster3);
561 TEST_EQ_STR(monster3->name.c_str(), "Fred");
563 auto &vecofstrings = monster2->testarrayofstring;
564 TEST_EQ(vecofstrings.size(), 4U);
565 TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
566 TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
568 auto &vecofstrings2 = monster2->testarrayofstring2;
569 TEST_EQ(vecofstrings2.size(), 2U);
570 TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
571 TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
573 auto &vecoftables = monster2->testarrayoftables;
574 TEST_EQ(vecoftables.size(), 3U);
575 TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
576 TEST_EQ(vecoftables[0]->hp, 1000);
577 TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
578 TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
580 auto &tests = monster2->test4;
581 TEST_EQ(tests[0].a(), 10);
582 TEST_EQ(tests[0].b(), 20);
583 TEST_EQ(tests[1].a(), 30);
584 TEST_EQ(tests[1].b(), 40);
587 // Prefix a FlatBuffer with a size field.
588 void SizePrefixedTest() {
589 // Create size prefixed buffer.
590 flatbuffers::FlatBufferBuilder fbb;
591 FinishSizePrefixedMonsterBuffer(
592 fbb, CreateMonster(fbb, 0, 200, 300, fbb.CreateString("bob")));
595 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
596 TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier), true);
599 auto m = GetSizePrefixedMonster(fbb.GetBufferPointer());
600 TEST_EQ(m->mana(), 200);
601 TEST_EQ(m->hp(), 300);
602 TEST_EQ_STR(m->name()->c_str(), "bob");
605 void TriviallyCopyableTest() {
607 #if __GNUG__ && __GNUC__ < 5
608 TEST_EQ(__has_trivial_copy(Vec3), true);
610 #if __cplusplus >= 201103L
611 TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
617 // Check stringify of an default enum value to json
618 void JsonDefaultTest() {
619 // load FlatBuffer schema (.fbs) from disk
620 std::string schemafile;
621 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
624 // parse schema first, so we can use it to parse the data after
625 flatbuffers::Parser parser;
626 auto include_test_path =
627 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
628 const char *include_directories[] = { test_data_path.c_str(),
629 include_test_path.c_str(), nullptr };
631 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
632 // create incomplete monster and store to json
633 parser.opts.output_default_scalars_in_json = true;
634 parser.opts.output_enum_identifiers = true;
635 flatbuffers::FlatBufferBuilder builder;
636 auto name = builder.CreateString("default_enum");
637 MonsterBuilder color_monster(builder);
638 color_monster.add_name(name);
639 FinishMonsterBuffer(builder, color_monster.Finish());
641 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
642 TEST_EQ(result, true);
643 // default value of the "color" field is Blue
644 TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true);
645 // default value of the "testf" field is 3.14159
646 TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true);
649 void JsonEnumsTest() {
650 // load FlatBuffer schema (.fbs) from disk
651 std::string schemafile;
652 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
655 // parse schema first, so we can use it to parse the data after
656 flatbuffers::Parser parser;
657 auto include_test_path =
658 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
659 const char *include_directories[] = { test_data_path.c_str(),
660 include_test_path.c_str(), nullptr };
661 parser.opts.output_enum_identifiers = true;
662 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
663 flatbuffers::FlatBufferBuilder builder;
664 auto name = builder.CreateString("bitflag_enum");
665 MonsterBuilder color_monster(builder);
666 color_monster.add_name(name);
667 color_monster.add_color(Color(Color_Blue | Color_Red));
668 FinishMonsterBuffer(builder, color_monster.Finish());
670 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
671 TEST_EQ(result, true);
672 TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true);
673 // Test forward compatibility with 'output_enum_identifiers = true'.
674 // Current Color doesn't have '(1u << 2)' field, let's add it.
676 std::string future_json;
677 auto future_name = builder.CreateString("future bitflag_enum");
678 MonsterBuilder future_color(builder);
679 future_color.add_name(future_name);
680 future_color.add_color(
681 static_cast<Color>((1u << 2) | Color_Blue | Color_Red));
682 FinishMonsterBuffer(builder, future_color.Finish());
683 result = GenerateText(parser, builder.GetBufferPointer(), &future_json);
684 TEST_EQ(result, true);
685 TEST_EQ(std::string::npos != future_json.find("color: 13"), true);
688 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
689 // The IEEE-754 quiet_NaN is not simple binary constant.
690 // All binary NaN bit strings have all the bits of the biased exponent field E
691 // set to 1. A quiet NaN bit string should be encoded with the first bit d[1]
692 // of the trailing significand field T being 1 (d[0] is implicit bit).
693 // It is assumed that endianness of floating-point is same as integer.
694 template<typename T, typename U, U qnan_base> bool is_quiet_nan_impl(T v) {
695 static_assert(sizeof(T) == sizeof(U), "unexpected");
697 std::memcpy(&b, &v, sizeof(T));
698 return ((b & qnan_base) == qnan_base);
700 # if defined(__mips__) || defined(__hppa__)
701 static bool is_quiet_nan(float v) {
702 return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v) ||
703 is_quiet_nan_impl<float, uint32_t, 0x7FBFFFFFu>(v);
705 static bool is_quiet_nan(double v) {
706 return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v) ||
707 is_quiet_nan_impl<double, uint64_t, 0x7FF7FFFFFFFFFFFFu>(v);
710 static bool is_quiet_nan(float v) {
711 return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v);
713 static bool is_quiet_nan(double v) {
714 return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v);
718 void TestMonsterExtraFloats() {
719 TEST_EQ(is_quiet_nan(1.0), false);
720 TEST_EQ(is_quiet_nan(infinity_d), false);
721 TEST_EQ(is_quiet_nan(-infinity_f), false);
722 TEST_EQ(is_quiet_nan(std::numeric_limits<float>::quiet_NaN()), true);
723 TEST_EQ(is_quiet_nan(std::numeric_limits<double>::quiet_NaN()), true);
725 using namespace flatbuffers;
726 using namespace MyGame;
727 // Load FlatBuffer schema (.fbs) from disk.
728 std::string schemafile;
729 TEST_EQ(LoadFile((test_data_path + "monster_extra.fbs").c_str(), false,
732 // Parse schema first, so we can use it to parse the data after.
734 auto include_test_path = ConCatPathFileName(test_data_path, "include_test");
735 const char *include_directories[] = { test_data_path.c_str(),
736 include_test_path.c_str(), nullptr };
737 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
738 // Create empty extra and store to json.
739 parser.opts.output_default_scalars_in_json = true;
740 parser.opts.output_enum_identifiers = true;
741 FlatBufferBuilder builder;
742 const auto def_root = MonsterExtraBuilder(builder).Finish();
743 FinishMonsterExtraBuffer(builder, def_root);
744 const auto def_obj = builder.GetBufferPointer();
745 const auto def_extra = GetMonsterExtra(def_obj);
746 TEST_NOTNULL(def_extra);
747 TEST_EQ(is_quiet_nan(def_extra->f0()), true);
748 TEST_EQ(is_quiet_nan(def_extra->f1()), true);
749 TEST_EQ(def_extra->f2(), +infinity_f);
750 TEST_EQ(def_extra->f3(), -infinity_f);
751 TEST_EQ(is_quiet_nan(def_extra->d0()), true);
752 TEST_EQ(is_quiet_nan(def_extra->d1()), true);
753 TEST_EQ(def_extra->d2(), +infinity_d);
754 TEST_EQ(def_extra->d3(), -infinity_d);
756 auto result = GenerateText(parser, def_obj, &jsongen);
757 TEST_EQ(result, true);
758 // Check expected default values.
759 TEST_EQ(std::string::npos != jsongen.find("f0: nan"), true);
760 TEST_EQ(std::string::npos != jsongen.find("f1: nan"), true);
761 TEST_EQ(std::string::npos != jsongen.find("f2: inf"), true);
762 TEST_EQ(std::string::npos != jsongen.find("f3: -inf"), true);
763 TEST_EQ(std::string::npos != jsongen.find("d0: nan"), true);
764 TEST_EQ(std::string::npos != jsongen.find("d1: nan"), true);
765 TEST_EQ(std::string::npos != jsongen.find("d2: inf"), true);
766 TEST_EQ(std::string::npos != jsongen.find("d3: -inf"), true);
767 // Parse 'mosterdata_extra.json'.
768 const auto extra_base = test_data_path + "monsterdata_extra";
770 TEST_EQ(LoadFile((extra_base + ".json").c_str(), false, &jsongen), true);
771 TEST_EQ(parser.Parse(jsongen.c_str()), true);
772 const auto test_file = parser.builder_.GetBufferPointer();
773 const auto test_size = parser.builder_.GetSize();
774 Verifier verifier(test_file, test_size);
775 TEST_ASSERT(VerifyMonsterExtraBuffer(verifier));
776 const auto extra = GetMonsterExtra(test_file);
778 TEST_EQ(is_quiet_nan(extra->f0()), true);
779 TEST_EQ(is_quiet_nan(extra->f1()), true);
780 TEST_EQ(extra->f2(), +infinity_f);
781 TEST_EQ(extra->f3(), -infinity_f);
782 TEST_EQ(is_quiet_nan(extra->d0()), true);
783 TEST_EQ(extra->d1(), +infinity_d);
784 TEST_EQ(extra->d2(), -infinity_d);
785 TEST_EQ(is_quiet_nan(extra->d3()), true);
786 TEST_NOTNULL(extra->fvec());
787 TEST_EQ(extra->fvec()->size(), 4);
788 TEST_EQ(extra->fvec()->Get(0), 1.0f);
789 TEST_EQ(extra->fvec()->Get(1), -infinity_f);
790 TEST_EQ(extra->fvec()->Get(2), +infinity_f);
791 TEST_EQ(is_quiet_nan(extra->fvec()->Get(3)), true);
792 TEST_NOTNULL(extra->dvec());
793 TEST_EQ(extra->dvec()->size(), 4);
794 TEST_EQ(extra->dvec()->Get(0), 2.0);
795 TEST_EQ(extra->dvec()->Get(1), +infinity_d);
796 TEST_EQ(extra->dvec()->Get(2), -infinity_d);
797 TEST_EQ(is_quiet_nan(extra->dvec()->Get(3)), true);
800 void TestMonsterExtraFloats() {}
803 // example of parsing text straight into a buffer, and generating
804 // text back from it:
805 void ParseAndGenerateTextTest(bool binary) {
806 // load FlatBuffer schema (.fbs) and JSON from disk
807 std::string schemafile;
808 std::string jsonfile;
809 TEST_EQ(flatbuffers::LoadFile(
810 (test_data_path + "monster_test." + (binary ? "bfbs" : "fbs"))
812 binary, &schemafile),
814 TEST_EQ(flatbuffers::LoadFile(
815 (test_data_path + "monsterdata_test.golden").c_str(), false,
819 auto include_test_path =
820 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
821 const char *include_directories[] = { test_data_path.c_str(),
822 include_test_path.c_str(), nullptr };
824 // parse schema first, so we can use it to parse the data after
825 flatbuffers::Parser parser;
827 flatbuffers::Verifier verifier(
828 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
830 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
831 // auto schema = reflection::GetSchema(schemafile.c_str());
832 TEST_EQ(parser.Deserialize((const uint8_t *)schemafile.c_str(),
836 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
838 TEST_EQ(parser.ParseJson(jsonfile.c_str()), true);
840 // here, parser.builder_ contains a binary buffer that is the parsed data.
842 // First, verify it, just in case:
843 flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
844 parser.builder_.GetSize());
845 TEST_EQ(VerifyMonsterBuffer(verifier), true);
847 AccessFlatBufferTest(parser.builder_.GetBufferPointer(),
848 parser.builder_.GetSize(), false);
850 // to ensure it is correct, we now generate text back from the binary,
851 // and compare the two:
854 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
855 TEST_EQ(result, true);
856 TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
858 // We can also do the above using the convenient Registry that knows about
859 // a set of file_identifiers mapped to schemas.
860 flatbuffers::Registry registry;
861 // Make sure schemas can find their includes.
862 registry.AddIncludeDirectory(test_data_path.c_str());
863 registry.AddIncludeDirectory(include_test_path.c_str());
864 // Call this with many schemas if possible.
865 registry.Register(MonsterIdentifier(),
866 (test_data_path + "monster_test.fbs").c_str());
867 // Now we got this set up, we can parse by just specifying the identifier,
868 // the correct schema will be loaded on the fly:
869 auto buf = registry.TextToFlatBuffer(jsonfile.c_str(), MonsterIdentifier());
870 // If this fails, check registry.lasterror_.
871 TEST_NOTNULL(buf.data());
872 // Test the buffer, to be sure:
873 AccessFlatBufferTest(buf.data(), buf.size(), false);
874 // We can use the registry to turn this back into text, in this case it
875 // will get the file_identifier from the binary:
877 auto ok = registry.FlatBufferToText(buf.data(), buf.size(), &text);
878 // If this fails, check registry.lasterror_.
880 TEST_EQ_STR(text.c_str(), jsonfile.c_str());
882 // Generate text for UTF-8 strings without escapes.
883 std::string jsonfile_utf8;
884 TEST_EQ(flatbuffers::LoadFile((test_data_path + "unicode_test.json").c_str(),
885 false, &jsonfile_utf8),
887 TEST_EQ(parser.Parse(jsonfile_utf8.c_str(), include_directories), true);
888 // To ensure it is correct, generate utf-8 text back from the binary.
889 std::string jsongen_utf8;
890 // request natural printing for utf-8 strings
891 parser.opts.natural_utf8 = true;
892 parser.opts.strict_json = true;
894 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen_utf8),
896 TEST_EQ_STR(jsongen_utf8.c_str(), jsonfile_utf8.c_str());
899 void ReflectionTest(uint8_t *flatbuf, size_t length) {
900 // Load a binary schema.
901 std::string bfbsfile;
902 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.bfbs").c_str(),
906 // Verify it, just in case:
907 flatbuffers::Verifier verifier(
908 reinterpret_cast<const uint8_t *>(bfbsfile.c_str()), bfbsfile.length());
909 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
911 // Make sure the schema is what we expect it to be.
912 auto &schema = *reflection::GetSchema(bfbsfile.c_str());
913 auto root_table = schema.root_table();
914 TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
915 auto fields = root_table->fields();
916 auto hp_field_ptr = fields->LookupByKey("hp");
917 TEST_NOTNULL(hp_field_ptr);
918 auto &hp_field = *hp_field_ptr;
919 TEST_EQ_STR(hp_field.name()->c_str(), "hp");
920 TEST_EQ(hp_field.id(), 2);
921 TEST_EQ(hp_field.type()->base_type(), reflection::Short);
923 auto friendly_field_ptr = fields->LookupByKey("friendly");
924 TEST_NOTNULL(friendly_field_ptr);
925 TEST_NOTNULL(friendly_field_ptr->attributes());
926 TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
928 // Make sure the table index is what we expect it to be.
929 auto pos_field_ptr = fields->LookupByKey("pos");
930 TEST_NOTNULL(pos_field_ptr);
931 TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
932 auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
933 TEST_NOTNULL(pos_table_ptr);
934 TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
936 // Test nullability of fields: hp is a 0-default scalar, pos is a struct =>
937 // optional, and name is a required string => not optional.
938 TEST_EQ(hp_field.optional(), false);
939 TEST_EQ(pos_field_ptr->optional(), true);
940 TEST_EQ(fields->LookupByKey("name")->optional(), false);
942 // Now use it to dynamically access a buffer.
943 auto &root = *flatbuffers::GetAnyRoot(flatbuf);
945 // Verify the buffer first using reflection based verification
946 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
949 auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
952 // Rather than needing to know the type, we can also get the value of
953 // any field as an int64_t/double/string, regardless of what it actually is.
954 auto hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
955 TEST_EQ(hp_int64, 80);
956 auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
957 TEST_EQ(hp_double, 80.0);
958 auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
959 TEST_EQ_STR(hp_string.c_str(), "80");
961 // Get struct field through reflection
962 auto pos_struct = flatbuffers::GetFieldStruct(root, *pos_field_ptr);
963 TEST_NOTNULL(pos_struct);
964 TEST_EQ(flatbuffers::GetAnyFieldF(*pos_struct,
965 *pos_table_ptr->fields()->LookupByKey("z")),
968 auto test3_field = pos_table_ptr->fields()->LookupByKey("test3");
969 auto test3_struct = flatbuffers::GetFieldStruct(*pos_struct, *test3_field);
970 TEST_NOTNULL(test3_struct);
971 auto test3_object = schema.objects()->Get(test3_field->type()->index());
973 TEST_EQ(flatbuffers::GetAnyFieldF(*test3_struct,
974 *test3_object->fields()->LookupByKey("a")),
977 // We can also modify it.
978 flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
979 hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
982 // We can also set fields generically:
983 flatbuffers::SetAnyFieldI(&root, hp_field, 300);
984 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
985 TEST_EQ(hp_int64, 300);
986 flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
987 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
988 TEST_EQ(hp_int64, 300);
989 flatbuffers::SetAnyFieldS(&root, hp_field, "300");
990 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
991 TEST_EQ(hp_int64, 300);
993 // Test buffer is valid after the modifications
994 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
997 // Reset it, for further tests.
998 flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
1000 // More advanced functionality: changing the size of items in-line!
1001 // First we put the FlatBuffer inside an std::vector.
1002 std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
1003 // Find the field we want to modify.
1004 auto &name_field = *fields->LookupByKey("name");
1006 // This time we wrap the result from GetAnyRoot in a smartpointer that
1007 // will keep rroot valid as resizingbuf resizes.
1008 auto rroot = flatbuffers::piv(
1009 flatbuffers::GetAnyRoot(flatbuffers::vector_data(resizingbuf)),
1011 SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
1013 // Here resizingbuf has changed, but rroot is still valid.
1014 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
1015 // Now lets extend a vector by 100 elements (10 -> 110).
1016 auto &inventory_field = *fields->LookupByKey("inventory");
1017 auto rinventory = flatbuffers::piv(
1018 flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field), resizingbuf);
1019 flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
1021 // rinventory still valid, so lets read from it.
1022 TEST_EQ(rinventory->Get(10), 50);
1024 // For reflection uses not covered already, there is a more powerful way:
1025 // we can simply generate whatever object we want to add/modify in a
1026 // FlatBuffer of its own, then add that to an existing FlatBuffer:
1027 // As an example, let's add a string to an array of strings.
1028 // First, find our field:
1029 auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
1030 // Find the vector value:
1031 auto rtestarrayofstring = flatbuffers::piv(
1032 flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
1033 **rroot, testarrayofstring_field),
1035 // It's a vector of 2 strings, to which we add one more, initialized to
1037 flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
1038 schema, 3, 0, *rtestarrayofstring, &resizingbuf);
1039 // Here we just create a buffer that contans a single string, but this
1040 // could also be any complex set of tables and other values.
1041 flatbuffers::FlatBufferBuilder stringfbb;
1042 stringfbb.Finish(stringfbb.CreateString("hank"));
1043 // Add the contents of it to our existing FlatBuffer.
1044 // We do this last, so the pointer doesn't get invalidated (since it is
1045 // at the end of the buffer):
1046 auto string_ptr = flatbuffers::AddFlatBuffer(
1047 resizingbuf, stringfbb.GetBufferPointer(), stringfbb.GetSize());
1048 // Finally, set the new value in the vector.
1049 rtestarrayofstring->MutateOffset(2, string_ptr);
1050 TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
1051 TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
1052 // Test integrity of all resize operations above.
1053 flatbuffers::Verifier resize_verifier(
1054 reinterpret_cast<const uint8_t *>(flatbuffers::vector_data(resizingbuf)),
1055 resizingbuf.size());
1056 TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
1058 // Test buffer is valid using reflection as well
1059 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1060 flatbuffers::vector_data(resizingbuf),
1061 resizingbuf.size()),
1064 // As an additional test, also set it on the name field.
1065 // Note: unlike the name change above, this just overwrites the offset,
1066 // rather than changing the string in-place.
1067 SetFieldT(*rroot, name_field, string_ptr);
1068 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
1070 // Using reflection, rather than mutating binary FlatBuffers, we can also copy
1071 // tables and other things out of other FlatBuffers into a FlatBufferBuilder,
1072 // either part or whole.
1073 flatbuffers::FlatBufferBuilder fbb;
1074 auto root_offset = flatbuffers::CopyTable(
1075 fbb, schema, *root_table, *flatbuffers::GetAnyRoot(flatbuf), true);
1076 fbb.Finish(root_offset, MonsterIdentifier());
1077 // Test that it was copied correctly:
1078 AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
1080 // Test buffer is valid using reflection as well
1081 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1082 fbb.GetBufferPointer(), fbb.GetSize()),
1086 void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
1088 flatbuffers::FlatBufferToString(flatbuf, Monster::MiniReflectTypeTable());
1092 "pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
1093 "{ a: 10, b: 20 } }, "
1095 "name: \"MyMonster\", "
1096 "inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
1097 "test_type: Monster, "
1098 "test: { name: \"Fred\" }, "
1099 "test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1100 "testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
1101 "testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" "
1103 "{ name: \"Wilma\" } ], "
1104 // TODO(wvo): should really print this nested buffer correctly.
1105 "testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, "
1107 "4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
1108 "101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
1109 "testarrayofstring2: [ \"jane\", \"mary\" ], "
1110 "testarrayofsortedstruct: [ { id: 0, distance: 0 }, "
1111 "{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
1112 "{ id: 4, distance: 40 } ], "
1113 "flex: [ 210, 4, 5, 2 ], "
1114 "test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1115 "vector_of_enums: [ Blue, Green ], "
1116 "scalar_key_sorted_tables: [ { id: \"miss\" } ] "
1120 Vec3 vec(1, 2, 3, 1.5, Color_Red, test);
1121 flatbuffers::FlatBufferBuilder vec_builder;
1122 vec_builder.Finish(vec_builder.CreateStruct(vec));
1123 auto vec_buffer = vec_builder.Release();
1124 auto vec_str = flatbuffers::FlatBufferToString(vec_buffer.data(),
1125 Vec3::MiniReflectTypeTable());
1126 TEST_EQ_STR(vec_str.c_str(),
1127 "{ x: 1.0, y: 2.0, z: 3.0, test1: 1.5, test2: Red, test3: { a: "
1131 void MiniReflectFixedLengthArrayTest() {
1132 // VS10 does not support typed enums, exclude from tests
1133 #if !defined(_MSC_VER) || _MSC_VER >= 1700
1134 flatbuffers::FlatBufferBuilder fbb;
1135 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
1136 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
1139 auto flatbuf = fbb.Release();
1140 auto s = flatbuffers::FlatBufferToString(
1141 flatbuf.data(), MyGame::Example::ArrayTableTypeTable());
1145 "b: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "
1147 "d: [ { a: [ 0, 0 ], b: A, c: [ A, A ], d: [ 0, 0 ] }, "
1148 "{ a: [ 0, 0 ], b: A, c: [ A, A ], d: [ 0, 0 ] } ], "
1149 "e: 1, f: [ 0, 0 ] } "
1155 // Parse a .proto schema, output as .fbs
1156 void ParseProtoTest() {
1157 // load the .proto and the golden file from disk
1158 std::string protofile;
1159 std::string goldenfile;
1160 std::string goldenunionfile;
1162 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1166 flatbuffers::LoadFile((test_data_path + "prototest/test.golden").c_str(),
1167 false, &goldenfile),
1169 TEST_EQ(flatbuffers::LoadFile(
1170 (test_data_path + "prototest/test_union.golden").c_str(), false,
1174 flatbuffers::IDLOptions opts;
1175 opts.include_dependence_headers = false;
1176 opts.proto_mode = true;
1179 flatbuffers::Parser parser(opts);
1180 auto protopath = test_data_path + "prototest/";
1181 const char *include_directories[] = { protopath.c_str(), nullptr };
1182 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1185 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1187 // Ensure generated file is parsable.
1188 flatbuffers::Parser parser2;
1189 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1190 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1192 // Parse proto with --oneof-union option.
1193 opts.proto_oneof_union = true;
1194 flatbuffers::Parser parser3(opts);
1195 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1198 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1200 // Ensure generated file is parsable.
1201 flatbuffers::Parser parser4;
1202 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1203 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1206 // Parse a .proto schema, output as .fbs
1207 void ParseProtoTestWithSuffix() {
1208 // load the .proto and the golden file from disk
1209 std::string protofile;
1210 std::string goldenfile;
1211 std::string goldenunionfile;
1213 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1216 TEST_EQ(flatbuffers::LoadFile(
1217 (test_data_path + "prototest/test_suffix.golden").c_str(), false,
1220 TEST_EQ(flatbuffers::LoadFile(
1221 (test_data_path + "prototest/test_union_suffix.golden").c_str(),
1222 false, &goldenunionfile),
1225 flatbuffers::IDLOptions opts;
1226 opts.include_dependence_headers = false;
1227 opts.proto_mode = true;
1228 opts.proto_namespace_suffix = "test_namespace_suffix";
1231 flatbuffers::Parser parser(opts);
1232 auto protopath = test_data_path + "prototest/";
1233 const char *include_directories[] = { protopath.c_str(), nullptr };
1234 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1237 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1239 // Ensure generated file is parsable.
1240 flatbuffers::Parser parser2;
1241 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1242 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1244 // Parse proto with --oneof-union option.
1245 opts.proto_oneof_union = true;
1246 flatbuffers::Parser parser3(opts);
1247 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1250 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1252 // Ensure generated file is parsable.
1253 flatbuffers::Parser parser4;
1254 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1255 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1258 // Parse a .proto schema, output as .fbs
1259 void ParseProtoTestWithIncludes() {
1260 // load the .proto and the golden file from disk
1261 std::string protofile;
1262 std::string goldenfile;
1263 std::string goldenunionfile;
1264 std::string importprotofile;
1266 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1269 TEST_EQ(flatbuffers::LoadFile(
1270 (test_data_path + "prototest/imported.proto").c_str(), false,
1273 TEST_EQ(flatbuffers::LoadFile(
1274 (test_data_path + "prototest/test_include.golden").c_str(), false,
1277 TEST_EQ(flatbuffers::LoadFile(
1278 (test_data_path + "prototest/test_union_include.golden").c_str(),
1279 false, &goldenunionfile),
1282 flatbuffers::IDLOptions opts;
1283 opts.include_dependence_headers = true;
1284 opts.proto_mode = true;
1287 flatbuffers::Parser parser(opts);
1288 auto protopath = test_data_path + "prototest/";
1289 const char *include_directories[] = { protopath.c_str(), nullptr };
1290 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1293 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1295 // Generate fbs from import.proto
1296 flatbuffers::Parser import_parser(opts);
1297 TEST_EQ(import_parser.Parse(importprotofile.c_str(), include_directories),
1299 auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test");
1301 // Ensure generated file is parsable.
1302 flatbuffers::Parser parser2;
1304 parser2.Parse(import_fbs.c_str(), include_directories, "imported.fbs"),
1306 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1307 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1309 // Parse proto with --oneof-union option.
1310 opts.proto_oneof_union = true;
1311 flatbuffers::Parser parser3(opts);
1312 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1315 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1317 // Ensure generated file is parsable.
1318 flatbuffers::Parser parser4;
1319 TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, "imported.fbs"), true);
1320 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1321 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1324 template<typename T>
1325 void CompareTableFieldValue(flatbuffers::Table *table,
1326 flatbuffers::voffset_t voffset, T val) {
1327 T read = table->GetField(voffset, static_cast<T>(0));
1331 // Low level stress/fuzz test: serialize/deserialize a variety of
1332 // different kinds of data in different combinations
1334 // Values we're testing against: chosen to ensure no bits get chopped
1335 // off anywhere, and also be different from eachother.
1336 const uint8_t bool_val = true;
1337 const int8_t char_val = -127; // 0x81
1338 const uint8_t uchar_val = 0xFF;
1339 const int16_t short_val = -32222; // 0x8222;
1340 const uint16_t ushort_val = 0xFEEE;
1341 const int32_t int_val = 0x83333333;
1342 const uint32_t uint_val = 0xFDDDDDDD;
1343 const int64_t long_val = 0x8444444444444444LL;
1344 const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
1345 const float float_val = 3.14159f;
1346 const double double_val = 3.14159265359;
1348 const int test_values_max = 11;
1349 const flatbuffers::voffset_t fields_per_object = 4;
1350 const int num_fuzz_objects = 10000; // The higher, the more thorough :)
1352 flatbuffers::FlatBufferBuilder builder;
1354 lcg_reset(); // Keep it deterministic.
1356 flatbuffers::uoffset_t objects[num_fuzz_objects];
1358 // Generate num_fuzz_objects random objects each consisting of
1359 // fields_per_object fields, each of a random type.
1360 for (int i = 0; i < num_fuzz_objects; i++) {
1361 auto start = builder.StartTable();
1362 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1363 int choice = lcg_rand() % test_values_max;
1364 auto off = flatbuffers::FieldIndexToOffset(f);
1366 case 0: builder.AddElement<uint8_t>(off, bool_val, 0); break;
1367 case 1: builder.AddElement<int8_t>(off, char_val, 0); break;
1368 case 2: builder.AddElement<uint8_t>(off, uchar_val, 0); break;
1369 case 3: builder.AddElement<int16_t>(off, short_val, 0); break;
1370 case 4: builder.AddElement<uint16_t>(off, ushort_val, 0); break;
1371 case 5: builder.AddElement<int32_t>(off, int_val, 0); break;
1372 case 6: builder.AddElement<uint32_t>(off, uint_val, 0); break;
1373 case 7: builder.AddElement<int64_t>(off, long_val, 0); break;
1374 case 8: builder.AddElement<uint64_t>(off, ulong_val, 0); break;
1375 case 9: builder.AddElement<float>(off, float_val, 0); break;
1376 case 10: builder.AddElement<double>(off, double_val, 0); break;
1379 objects[i] = builder.EndTable(start);
1381 builder.PreAlign<flatbuffers::largest_scalar_t>(0); // Align whole buffer.
1383 lcg_reset(); // Reset.
1385 uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
1387 // Test that all objects we generated are readable and return the
1388 // expected values. We generate random objects in the same order
1389 // so this is deterministic.
1390 for (int i = 0; i < num_fuzz_objects; i++) {
1391 auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
1392 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1393 int choice = lcg_rand() % test_values_max;
1394 flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
1396 case 0: CompareTableFieldValue(table, off, bool_val); break;
1397 case 1: CompareTableFieldValue(table, off, char_val); break;
1398 case 2: CompareTableFieldValue(table, off, uchar_val); break;
1399 case 3: CompareTableFieldValue(table, off, short_val); break;
1400 case 4: CompareTableFieldValue(table, off, ushort_val); break;
1401 case 5: CompareTableFieldValue(table, off, int_val); break;
1402 case 6: CompareTableFieldValue(table, off, uint_val); break;
1403 case 7: CompareTableFieldValue(table, off, long_val); break;
1404 case 8: CompareTableFieldValue(table, off, ulong_val); break;
1405 case 9: CompareTableFieldValue(table, off, float_val); break;
1406 case 10: CompareTableFieldValue(table, off, double_val); break;
1412 // High level stress/fuzz test: generate a big schema and
1413 // matching json data in random combinations, then parse both,
1414 // generate json back from the binary, and compare with the original.
1416 lcg_reset(); // Keep it deterministic.
1418 const int num_definitions = 30;
1419 const int num_struct_definitions = 5; // Subset of num_definitions.
1420 const int fields_per_definition = 15;
1421 const int instances_per_definition = 5;
1422 const int deprecation_rate = 10; // 1 in deprecation_rate fields will
1425 std::string schema = "namespace test;\n\n";
1428 std::string instances[instances_per_definition];
1430 // Since we're generating schema and corresponding data in tandem,
1431 // this convenience function adds strings to both at once.
1432 static void Add(RndDef (&definitions_l)[num_definitions],
1433 std::string &schema_l, const int instances_per_definition_l,
1434 const char *schema_add, const char *instance_add,
1436 schema_l += schema_add;
1437 for (int i = 0; i < instances_per_definition_l; i++)
1438 definitions_l[definition].instances[i] += instance_add;
1443 #define AddToSchemaAndInstances(schema_add, instance_add) \
1444 RndDef::Add(definitions, schema, instances_per_definition, \
1445 schema_add, instance_add, definition)
1448 RndDef::Add(definitions, schema, instances_per_definition, \
1449 "byte", "1", definition)
1452 RndDef definitions[num_definitions];
1454 // We are going to generate num_definitions, the first
1455 // num_struct_definitions will be structs, the rest tables. For each
1456 // generate random fields, some of which may be struct/table types
1457 // referring to previously generated structs/tables.
1458 // Simultanenously, we generate instances_per_definition JSON data
1459 // definitions, which will have identical structure to the schema
1460 // being generated. We generate multiple instances such that when creating
1461 // hierarchy, we get some variety by picking one randomly.
1462 for (int definition = 0; definition < num_definitions; definition++) {
1463 std::string definition_name = "D" + flatbuffers::NumToString(definition);
1465 bool is_struct = definition < num_struct_definitions;
1467 AddToSchemaAndInstances(
1468 ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
1471 for (int field = 0; field < fields_per_definition; field++) {
1472 const bool is_last_field = field == fields_per_definition - 1;
1474 // Deprecate 1 in deprecation_rate fields. Only table fields can be
1476 // Don't deprecate the last field to avoid dangling commas in JSON.
1477 const bool deprecated =
1478 !is_struct && !is_last_field && (lcg_rand() % deprecation_rate == 0);
1480 std::string field_name = "f" + flatbuffers::NumToString(field);
1481 AddToSchemaAndInstances((" " + field_name + ":").c_str(),
1482 deprecated ? "" : (field_name + ": ").c_str());
1483 // Pick random type:
1484 auto base_type = static_cast<flatbuffers::BaseType>(
1485 lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
1486 switch (base_type) {
1487 case flatbuffers::BASE_TYPE_STRING:
1489 Dummy(); // No strings in structs.
1491 AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
1494 case flatbuffers::BASE_TYPE_VECTOR:
1496 Dummy(); // No vectors in structs.
1498 AddToSchemaAndInstances("[ubyte]",
1499 deprecated ? "" : "[\n0,\n1,\n255\n]");
1502 case flatbuffers::BASE_TYPE_NONE:
1503 case flatbuffers::BASE_TYPE_UTYPE:
1504 case flatbuffers::BASE_TYPE_STRUCT:
1505 case flatbuffers::BASE_TYPE_UNION:
1507 // Pick a random previous definition and random data instance of
1509 int defref = lcg_rand() % definition;
1510 int instance = lcg_rand() % instances_per_definition;
1511 AddToSchemaAndInstances(
1512 ("D" + flatbuffers::NumToString(defref)).c_str(),
1514 : definitions[defref].instances[instance].c_str());
1516 // If this is the first definition, we have no definition we can
1521 case flatbuffers::BASE_TYPE_BOOL:
1522 AddToSchemaAndInstances(
1523 "bool", deprecated ? "" : (lcg_rand() % 2 ? "true" : "false"));
1525 case flatbuffers::BASE_TYPE_ARRAY:
1527 AddToSchemaAndInstances(
1529 deprecated ? "" : "255"); // No fixed-length arrays in tables.
1531 AddToSchemaAndInstances("[int:3]", deprecated ? "" : "[\n,\n,\n]");
1535 // All the scalar types.
1536 schema += flatbuffers::kTypeNames[base_type];
1539 // We want each instance to use its own random value.
1540 for (int inst = 0; inst < instances_per_definition; inst++)
1541 definitions[definition].instances[inst] +=
1542 flatbuffers::IsFloat(base_type)
1543 ? flatbuffers::NumToString<double>(lcg_rand() % 128)
1545 : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
1548 AddToSchemaAndInstances(deprecated ? "(deprecated);\n" : ";\n",
1549 deprecated ? "" : is_last_field ? "\n" : ",\n");
1551 AddToSchemaAndInstances("}\n\n", "}");
1554 schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
1557 flatbuffers::Parser parser;
1559 // Will not compare against the original if we don't write defaults
1560 parser.builder_.ForceDefaults(true);
1562 // Parse the schema, parse the generated data, then generate text back
1563 // from the binary and compare against the original.
1564 TEST_EQ(parser.Parse(schema.c_str()), true);
1566 const std::string &json =
1567 definitions[num_definitions - 1].instances[0] + "\n";
1569 TEST_EQ(parser.Parse(json.c_str()), true);
1571 std::string jsongen;
1572 parser.opts.indent_step = 0;
1574 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
1575 TEST_EQ(result, true);
1577 if (jsongen != json) {
1578 // These strings are larger than a megabyte, so we show the bytes around
1579 // the first bytes that are different rather than the whole string.
1580 size_t len = std::min(json.length(), jsongen.length());
1581 for (size_t i = 0; i < len; i++) {
1582 if (json[i] != jsongen[i]) {
1583 i -= std::min(static_cast<size_t>(10), i); // show some context;
1584 size_t end = std::min(len, i + 20);
1585 for (; i < end; i++)
1586 TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
1587 static_cast<int>(i), jsongen[i], json[i]);
1591 TEST_NOTNULL(nullptr); //-V501 (this comment supresses CWE-570 warning)
1595 #ifdef FLATBUFFERS_TEST_VERBOSE
1596 TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
1597 static_cast<int>(schema.length() / 1024),
1598 static_cast<int>(json.length() / 1024));
1603 // Test that parser errors are actually generated.
1604 void TestError_(const char *src, const char *error_substr, bool strict_json,
1605 const char *file, int line, const char *func) {
1606 flatbuffers::IDLOptions opts;
1607 opts.strict_json = strict_json;
1608 flatbuffers::Parser parser(opts);
1609 if (parser.Parse(src)) {
1610 TestFail("true", "false",
1611 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1613 } else if (!strstr(parser.error_.c_str(), error_substr)) {
1614 TestFail(error_substr, parser.error_.c_str(),
1615 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1620 void TestError_(const char *src, const char *error_substr, const char *file,
1621 int line, const char *func) {
1622 TestError_(src, error_substr, false, file, line, func);
1626 # define TestError(src, ...) \
1627 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
1629 # define TestError(src, ...) \
1630 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1633 // Test that parsing errors occur as we'd expect.
1634 // Also useful for coverage, making sure these paths are run.
1636 // In order they appear in idl_parser.cpp
1637 TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
1638 TestError("\"\0", "illegal");
1639 TestError("\"\\q", "escape code");
1640 TestError("table ///", "documentation");
1641 TestError("@", "illegal");
1642 TestError("table 1", "expecting");
1643 TestError("table X { Y:[[int]]; }", "nested vector");
1644 TestError("table X { Y:1; }", "illegal type");
1645 TestError("table X { Y:int; Y:int; }", "field already");
1646 TestError("table Y {} table X { Y:int; }", "same as table");
1647 TestError("struct X { Y:string; }", "only scalar");
1648 TestError("table X { Y:string = \"\"; }", "default values");
1649 TestError("struct X { a:uint = 42; }", "default values");
1650 TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
1651 TestError("struct X { Y:int (deprecated); }", "deprecate");
1652 TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
1653 "missing type field");
1654 TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
1656 TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
1657 TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
1658 TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
1661 "struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
1664 TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
1665 "unknown enum value");
1666 TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
1667 TestError("enum X:byte { Y } enum X {", "enum already");
1668 TestError("enum X:float {}", "underlying");
1669 TestError("enum X:byte { Y, Y }", "value already");
1670 TestError("enum X:byte { Y=2, Z=2 }", "unique");
1671 TestError("table X { Y:int; } table X {", "datatype already");
1672 TestError("struct X (force_align: 7) { Y:int; }", "force_align");
1673 TestError("struct X {}", "size 0");
1674 TestError("{}", "no root");
1675 TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
1676 TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
1678 TestError("root_type X;", "unknown root");
1679 TestError("struct X { Y:int; } root_type X;", "a table");
1680 TestError("union X { Y }", "referenced");
1681 TestError("union Z { X } struct X { Y:int; }", "only tables");
1682 TestError("table X { Y:[int]; YLength:int; }", "clash");
1683 TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
1684 // float to integer conversion is forbidden
1685 TestError("table X { Y:int; } root_type X; { Y:1.0 }", "float");
1686 TestError("table X { Y:bool; } root_type X; { Y:1.0 }", "float");
1687 TestError("enum X:bool { Y = true }", "must be integral");
1688 // Array of non-scalar
1689 TestError("table X { x:int; } struct Y { y:[X:2]; }",
1690 "may contain only scalar or struct fields");
1691 // Non-snake case field names
1692 TestError("table X { Y: int; } root_type Y: {Y:1.0}", "snake_case");
1695 template<typename T>
1696 T TestValue(const char *json, const char *type_name,
1697 const char *decls = nullptr) {
1698 flatbuffers::Parser parser;
1699 parser.builder_.ForceDefaults(true); // return defaults
1700 auto check_default = json ? false : true;
1701 if (check_default) { parser.opts.output_default_scalars_in_json = true; }
1703 std::string schema = std::string(decls ? decls : "") + "\n" +
1704 "table X { y:" + std::string(type_name) +
1706 auto schema_done = parser.Parse(schema.c_str());
1707 TEST_EQ_STR(parser.error_.c_str(), "");
1708 TEST_EQ(schema_done, true);
1710 auto done = parser.Parse(check_default ? "{}" : json);
1711 TEST_EQ_STR(parser.error_.c_str(), "");
1712 TEST_EQ(done, true);
1714 // Check with print.
1715 std::string print_back;
1716 parser.opts.indent_step = -1;
1717 TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back),
1719 // restore value from its default
1720 if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); }
1722 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
1723 parser.builder_.GetBufferPointer());
1724 return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
1727 bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
1729 // Additional parser testing not covered elsewhere.
1731 // Test scientific notation numbers.
1733 FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
1736 TEST_EQ(FloatCompare(TestValue<float>("{ y:\"0.0314159e+2\" }", "float"),
1740 // Test conversion functions.
1741 TEST_EQ(FloatCompare(TestValue<float>("{ y:cos(rad(180)) }", "float"), -1),
1744 // int embedded to string
1745 TEST_EQ(TestValue<int>("{ y:\"-876\" }", "int=-123"), -876);
1746 TEST_EQ(TestValue<int>("{ y:\"876\" }", "int=-123"), 876);
1748 // Test negative hex constant.
1749 TEST_EQ(TestValue<int>("{ y:-0x8ea0 }", "int=-0x8ea0"), -36512);
1750 TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
1752 // positive hex constant
1753 TEST_EQ(TestValue<int>("{ y:0x1abcdef }", "int=0x1"), 0x1abcdef);
1754 // with optional '+' sign
1755 TEST_EQ(TestValue<int>("{ y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
1757 TEST_EQ(TestValue<int>("{ y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
1759 // Make sure we do unsigned 64bit correctly.
1760 TEST_EQ(TestValue<uint64_t>("{ y:12335089644688340133 }", "ulong"),
1761 12335089644688340133ULL);
1764 TEST_EQ(TestValue<bool>("{ y:\"false\" }", "bool=true"), false);
1765 TEST_EQ(TestValue<bool>("{ y:\"true\" }", "bool=\"true\""), true);
1766 TEST_EQ(TestValue<bool>("{ y:'false' }", "bool=true"), false);
1767 TEST_EQ(TestValue<bool>("{ y:'true' }", "bool=\"true\""), true);
1769 // check comments before and after json object
1770 TEST_EQ(TestValue<int>("/*before*/ { y:1 } /*after*/", "int"), 1);
1771 TEST_EQ(TestValue<int>("//before \n { y:1 } //after", "int"), 1);
1774 void NestedListTest() {
1775 flatbuffers::Parser parser1;
1776 TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
1778 "{ F:[ [10,20], [30,40]] }"),
1782 void EnumStringsTest() {
1783 flatbuffers::Parser parser1;
1784 TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
1786 "{ F:[ A, B, \"C\", \"A B C\" ] }"),
1788 flatbuffers::Parser parser2;
1789 TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
1791 "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"),
1793 // unsigned bit_flags
1794 flatbuffers::Parser parser3;
1796 parser3.Parse("enum E:uint16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }"
1797 " table T { F: E = \"F15 F08\"; }"
1802 void EnumNamesTest() {
1803 TEST_EQ_STR("Red", EnumNameColor(Color_Red));
1804 TEST_EQ_STR("Green", EnumNameColor(Color_Green));
1805 TEST_EQ_STR("Blue", EnumNameColor(Color_Blue));
1806 // Check that Color to string don't crash while decode a mixture of Colors.
1807 // 1) Example::Color enum is enum with unfixed underlying type.
1808 // 2) Valid enum range: [0; 2^(ceil(log2(Color_ANY))) - 1].
1809 // Consequence: A value is out of this range will lead to UB (since C++17).
1810 // For details see C++17 standard or explanation on the SO:
1811 // stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class
1812 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(0)));
1813 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY - 1)));
1814 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY + 1)));
1817 void EnumOutOfRangeTest() {
1818 TestError("enum X:byte { Y = 128 }", "enum value does not fit");
1819 TestError("enum X:byte { Y = -129 }", "enum value does not fit");
1820 TestError("enum X:byte { Y = 126, Z0, Z1 }", "enum value does not fit");
1821 TestError("enum X:ubyte { Y = -1 }", "enum value does not fit");
1822 TestError("enum X:ubyte { Y = 256 }", "enum value does not fit");
1823 TestError("enum X:ubyte { Y = 255, Z }", "enum value does not fit");
1824 TestError("table Y{} union X { Y = -1 }", "enum value does not fit");
1825 TestError("table Y{} union X { Y = 256 }", "enum value does not fit");
1826 TestError("table Y{} union X { Y = 255, Z:Y }", "enum value does not fit");
1827 TestError("enum X:int { Y = -2147483649 }", "enum value does not fit");
1828 TestError("enum X:int { Y = 2147483648 }", "enum value does not fit");
1829 TestError("enum X:uint { Y = -1 }", "enum value does not fit");
1830 TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit");
1831 TestError("enum X:long { Y = 9223372036854775808 }", "does not fit");
1832 TestError("enum X:long { Y = 9223372036854775807, Z }",
1833 "enum value does not fit");
1834 TestError("enum X:ulong { Y = -1 }", "does not fit");
1835 TestError("enum X:ubyte (bit_flags) { Y=8 }", "bit flag out");
1836 TestError("enum X:byte (bit_flags) { Y=7 }", "must be unsigned"); // -128
1837 // bit_flgs out of range
1838 TestError("enum X:ubyte (bit_flags) { Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8 }",
1842 void EnumValueTest() {
1843 // json: "{ Y:0 }", schema: table X { y: "E"}
1844 // 0 in enum (V=0) E then Y=0 is valid.
1845 TEST_EQ(TestValue<int>("{ y:0 }", "E", "enum E:int { V }"), 0);
1846 TEST_EQ(TestValue<int>("{ y:V }", "E", "enum E:int { V }"), 0);
1847 // A default value of Y is 0.
1848 TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
1849 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { V=5 }"), 5);
1850 // Generate json with defaults and check.
1851 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
1853 TEST_EQ(TestValue<int>("{ y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
1854 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
1855 // Generate json with defaults and check.
1856 TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
1857 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
1859 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1860 "enum E:ulong { V = 13835058055282163712 }"),
1861 13835058055282163712ULL);
1862 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1863 "enum E:ulong { V = 18446744073709551615 }"),
1864 18446744073709551615ULL);
1865 // Assign non-enum value to enum field. Is it right?
1866 TEST_EQ(TestValue<int>("{ y:7 }", "E", "enum E:int { V = 0 }"), 7);
1867 // Check that non-ascending values are valid.
1868 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z=10, V=5 }"), 5);
1871 void IntegerOutOfRangeTest() {
1872 TestError("table T { F:byte; } root_type T; { F:128 }",
1873 "constant does not fit");
1874 TestError("table T { F:byte; } root_type T; { F:-129 }",
1875 "constant does not fit");
1876 TestError("table T { F:ubyte; } root_type T; { F:256 }",
1877 "constant does not fit");
1878 TestError("table T { F:ubyte; } root_type T; { F:-1 }",
1879 "constant does not fit");
1880 TestError("table T { F:short; } root_type T; { F:32768 }",
1881 "constant does not fit");
1882 TestError("table T { F:short; } root_type T; { F:-32769 }",
1883 "constant does not fit");
1884 TestError("table T { F:ushort; } root_type T; { F:65536 }",
1885 "constant does not fit");
1886 TestError("table T { F:ushort; } root_type T; { F:-1 }",
1887 "constant does not fit");
1888 TestError("table T { F:int; } root_type T; { F:2147483648 }",
1889 "constant does not fit");
1890 TestError("table T { F:int; } root_type T; { F:-2147483649 }",
1891 "constant does not fit");
1892 TestError("table T { F:uint; } root_type T; { F:4294967296 }",
1893 "constant does not fit");
1894 TestError("table T { F:uint; } root_type T; { F:-1 }",
1895 "constant does not fit");
1896 // Check fixed width aliases
1897 TestError("table X { Y:uint8; } root_type X; { Y: -1 }", "does not fit");
1898 TestError("table X { Y:uint8; } root_type X; { Y: 256 }", "does not fit");
1899 TestError("table X { Y:uint16; } root_type X; { Y: -1 }", "does not fit");
1900 TestError("table X { Y:uint16; } root_type X; { Y: 65536 }", "does not fit");
1901 TestError("table X { Y:uint32; } root_type X; { Y: -1 }", "");
1902 TestError("table X { Y:uint32; } root_type X; { Y: 4294967296 }",
1904 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1905 TestError("table X { Y:uint64; } root_type X; { Y: -9223372036854775809 }",
1907 TestError("table X { Y:uint64; } root_type X; { Y: 18446744073709551616 }",
1910 TestError("table X { Y:int8; } root_type X; { Y: -129 }", "does not fit");
1911 TestError("table X { Y:int8; } root_type X; { Y: 128 }", "does not fit");
1912 TestError("table X { Y:int16; } root_type X; { Y: -32769 }", "does not fit");
1913 TestError("table X { Y:int16; } root_type X; { Y: 32768 }", "does not fit");
1914 TestError("table X { Y:int32; } root_type X; { Y: -2147483649 }", "");
1915 TestError("table X { Y:int32; } root_type X; { Y: 2147483648 }",
1917 TestError("table X { Y:int64; } root_type X; { Y: -9223372036854775809 }",
1919 TestError("table X { Y:int64; } root_type X; { Y: 9223372036854775808 }",
1921 // check out-of-int64 as int8
1922 TestError("table X { Y:int8; } root_type X; { Y: -9223372036854775809 }",
1924 TestError("table X { Y:int8; } root_type X; { Y: 9223372036854775808 }",
1927 // Check default values
1928 TestError("table X { Y:int64=-9223372036854775809; } root_type X; {}",
1930 TestError("table X { Y:int64= 9223372036854775808; } root_type X; {}",
1932 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1933 TestError("table X { Y:uint64=-9223372036854775809; } root_type X; {}",
1935 TestError("table X { Y:uint64= 18446744073709551616; } root_type X; {}",
1939 void IntegerBoundaryTest() {
1940 // Check numerical compatibility with non-C++ languages.
1941 // By the C++ standard, std::numerical_limits<int64_t>::min() ==
1942 // -9223372036854775807 (-2^63+1) or less* The Flatbuffers grammar and most of
1943 // the languages (C#, Java, Rust) expect that minimum values are: -128,
1944 // -32768,.., -9223372036854775808. Since C++20,
1945 // static_cast<int64>(0x8000000000000000ULL) is well-defined two's complement
1946 // cast. Therefore -9223372036854775808 should be valid negative value.
1947 TEST_EQ(flatbuffers::numeric_limits<int8_t>::min(), -128);
1948 TEST_EQ(flatbuffers::numeric_limits<int8_t>::max(), 127);
1949 TEST_EQ(flatbuffers::numeric_limits<int16_t>::min(), -32768);
1950 TEST_EQ(flatbuffers::numeric_limits<int16_t>::max(), 32767);
1951 TEST_EQ(flatbuffers::numeric_limits<int32_t>::min() + 1, -2147483647);
1952 TEST_EQ(flatbuffers::numeric_limits<int32_t>::max(), 2147483647ULL);
1953 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min() + 1LL,
1954 -9223372036854775807LL);
1955 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(), 9223372036854775807ULL);
1956 TEST_EQ(flatbuffers::numeric_limits<uint8_t>::max(), 255);
1957 TEST_EQ(flatbuffers::numeric_limits<uint16_t>::max(), 65535);
1958 TEST_EQ(flatbuffers::numeric_limits<uint32_t>::max(), 4294967295ULL);
1959 TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
1960 18446744073709551615ULL);
1962 TEST_EQ(TestValue<int8_t>("{ y:127 }", "byte"), 127);
1963 TEST_EQ(TestValue<int8_t>("{ y:-128 }", "byte"), -128);
1964 TEST_EQ(TestValue<uint8_t>("{ y:255 }", "ubyte"), 255);
1965 TEST_EQ(TestValue<uint8_t>("{ y:0 }", "ubyte"), 0);
1966 TEST_EQ(TestValue<int16_t>("{ y:32767 }", "short"), 32767);
1967 TEST_EQ(TestValue<int16_t>("{ y:-32768 }", "short"), -32768);
1968 TEST_EQ(TestValue<uint16_t>("{ y:65535 }", "ushort"), 65535);
1969 TEST_EQ(TestValue<uint16_t>("{ y:0 }", "ushort"), 0);
1970 TEST_EQ(TestValue<int32_t>("{ y:2147483647 }", "int"), 2147483647);
1971 TEST_EQ(TestValue<int32_t>("{ y:-2147483648 }", "int") + 1, -2147483647);
1972 TEST_EQ(TestValue<uint32_t>("{ y:4294967295 }", "uint"), 4294967295);
1973 TEST_EQ(TestValue<uint32_t>("{ y:0 }", "uint"), 0);
1974 TEST_EQ(TestValue<int64_t>("{ y:9223372036854775807 }", "long"),
1975 9223372036854775807LL);
1976 TEST_EQ(TestValue<int64_t>("{ y:-9223372036854775808 }", "long") + 1LL,
1977 -9223372036854775807LL);
1978 TEST_EQ(TestValue<uint64_t>("{ y:18446744073709551615 }", "ulong"),
1979 18446744073709551615ULL);
1980 TEST_EQ(TestValue<uint64_t>("{ y:0 }", "ulong"), 0);
1981 TEST_EQ(TestValue<uint64_t>("{ y: 18446744073709551615 }", "uint64"),
1982 18446744073709551615ULL);
1983 // check that the default works
1984 TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
1985 18446744073709551615ULL);
1988 void ValidFloatTest() {
1989 // check rounding to infinity
1990 TEST_EQ(TestValue<float>("{ y:+3.4029e+38 }", "float"), +infinity_f);
1991 TEST_EQ(TestValue<float>("{ y:-3.4029e+38 }", "float"), -infinity_f);
1992 TEST_EQ(TestValue<double>("{ y:+1.7977e+308 }", "double"), +infinity_d);
1993 TEST_EQ(TestValue<double>("{ y:-1.7977e+308 }", "double"), -infinity_d);
1996 FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
1999 TEST_EQ(FloatCompare(TestValue<float>("{ y:\" 0.0314159e+2 \" }", "float"),
2003 TEST_EQ(TestValue<float>("{ y:1 }", "float"), 1.0f);
2004 TEST_EQ(TestValue<float>("{ y:1.0 }", "float"), 1.0f);
2005 TEST_EQ(TestValue<float>("{ y:1. }", "float"), 1.0f);
2006 TEST_EQ(TestValue<float>("{ y:+1. }", "float"), 1.0f);
2007 TEST_EQ(TestValue<float>("{ y:-1. }", "float"), -1.0f);
2008 TEST_EQ(TestValue<float>("{ y:1.e0 }", "float"), 1.0f);
2009 TEST_EQ(TestValue<float>("{ y:1.e+0 }", "float"), 1.0f);
2010 TEST_EQ(TestValue<float>("{ y:1.e-0 }", "float"), 1.0f);
2011 TEST_EQ(TestValue<float>("{ y:0.125 }", "float"), 0.125f);
2012 TEST_EQ(TestValue<float>("{ y:.125 }", "float"), 0.125f);
2013 TEST_EQ(TestValue<float>("{ y:-.125 }", "float"), -0.125f);
2014 TEST_EQ(TestValue<float>("{ y:+.125 }", "float"), +0.125f);
2015 TEST_EQ(TestValue<float>("{ y:5 }", "float"), 5.0f);
2016 TEST_EQ(TestValue<float>("{ y:\"5\" }", "float"), 5.0f);
2018 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
2019 // Old MSVC versions may have problem with this check.
2020 // https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
2021 TEST_EQ(TestValue<double>("{ y:6.9294956446009195e15 }", "double"),
2022 6929495644600920.0);
2024 TEST_EQ(std::isnan(TestValue<double>("{ y:nan }", "double")), true);
2025 TEST_EQ(std::isnan(TestValue<float>("{ y:nan }", "float")), true);
2026 TEST_EQ(std::isnan(TestValue<float>("{ y:\"nan\" }", "float")), true);
2027 TEST_EQ(std::isnan(TestValue<float>("{ y:+nan }", "float")), true);
2028 TEST_EQ(std::isnan(TestValue<float>("{ y:-nan }", "float")), true);
2029 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
2030 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
2032 TEST_EQ(TestValue<float>("{ y:inf }", "float"), infinity_f);
2033 TEST_EQ(TestValue<float>("{ y:\"inf\" }", "float"), infinity_f);
2034 TEST_EQ(TestValue<float>("{ y:+inf }", "float"), infinity_f);
2035 TEST_EQ(TestValue<float>("{ y:-inf }", "float"), -infinity_f);
2036 TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinity_f);
2037 TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinity_f);
2039 "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
2043 "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
2047 // Test binary format of float point.
2048 // https://en.cppreference.com/w/cpp/language/floating_literal
2049 // 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
2050 TEST_EQ(TestValue<double>("{ y:0x12.34p-1 }", "double"), 9.1015625);
2051 // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
2052 TEST_EQ(TestValue<float>("{ y:-0x0.2p0 }", "float"), -0.125f);
2053 TEST_EQ(TestValue<float>("{ y:-0x.2p1 }", "float"), -0.25f);
2054 TEST_EQ(TestValue<float>("{ y:0x1.2p3 }", "float"), 9.0f);
2055 TEST_EQ(TestValue<float>("{ y:0x10.1p0 }", "float"), 16.0625f);
2056 TEST_EQ(TestValue<double>("{ y:0x1.2p3 }", "double"), 9.0);
2057 TEST_EQ(TestValue<double>("{ y:0x10.1p0 }", "double"), 16.0625);
2058 TEST_EQ(TestValue<double>("{ y:0xC.68p+2 }", "double"), 49.625);
2059 TestValue<double>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
2060 TestValue<float>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
2062 #else // FLATBUFFERS_HAS_NEW_STRTOD
2063 TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");
2064 #endif // !FLATBUFFERS_HAS_NEW_STRTOD
2067 void InvalidFloatTest() {
2068 auto invalid_msg = "invalid number";
2069 auto comma_msg = "expecting: ,";
2070 TestError("table T { F:float; } root_type T; { F:1,0 }", "");
2071 TestError("table T { F:float; } root_type T; { F:. }", "");
2072 TestError("table T { F:float; } root_type T; { F:- }", invalid_msg);
2073 TestError("table T { F:float; } root_type T; { F:+ }", invalid_msg);
2074 TestError("table T { F:float; } root_type T; { F:-. }", invalid_msg);
2075 TestError("table T { F:float; } root_type T; { F:+. }", invalid_msg);
2076 TestError("table T { F:float; } root_type T; { F:.e }", "");
2077 TestError("table T { F:float; } root_type T; { F:-e }", invalid_msg);
2078 TestError("table T { F:float; } root_type T; { F:+e }", invalid_msg);
2079 TestError("table T { F:float; } root_type T; { F:-.e }", invalid_msg);
2080 TestError("table T { F:float; } root_type T; { F:+.e }", invalid_msg);
2081 TestError("table T { F:float; } root_type T; { F:-e1 }", invalid_msg);
2082 TestError("table T { F:float; } root_type T; { F:+e1 }", invalid_msg);
2083 TestError("table T { F:float; } root_type T; { F:1.0e+ }", invalid_msg);
2084 TestError("table T { F:float; } root_type T; { F:1.0e- }", invalid_msg);
2085 // exponent pP is mandatory for hex-float
2086 TestError("table T { F:float; } root_type T; { F:0x0 }", invalid_msg);
2087 TestError("table T { F:float; } root_type T; { F:-0x. }", invalid_msg);
2088 TestError("table T { F:float; } root_type T; { F:0x. }", invalid_msg);
2089 TestError("table T { F:float; } root_type T; { F:0Xe }", invalid_msg);
2090 TestError("table T { F:float; } root_type T; { F:\"0Xe\" }", invalid_msg);
2091 TestError("table T { F:float; } root_type T; { F:\"nan(1)\" }", invalid_msg);
2092 // eE not exponent in hex-float!
2093 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
2094 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
2095 TestError("table T { F:float; } root_type T; { F:0x0.0p }", invalid_msg);
2096 TestError("table T { F:float; } root_type T; { F:0x0.0p+ }", invalid_msg);
2097 TestError("table T { F:float; } root_type T; { F:0x0.0p- }", invalid_msg);
2098 TestError("table T { F:float; } root_type T; { F:0x0.0pa1 }", invalid_msg);
2099 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
2100 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
2101 TestError("table T { F:float; } root_type T; { F:0x0.0e+0 }", invalid_msg);
2102 TestError("table T { F:float; } root_type T; { F:0x0.0e-0 }", invalid_msg);
2103 TestError("table T { F:float; } root_type T; { F:0x0.0ep+ }", invalid_msg);
2104 TestError("table T { F:float; } root_type T; { F:0x0.0ep- }", invalid_msg);
2105 TestError("table T { F:float; } root_type T; { F:1.2.3 }", invalid_msg);
2106 TestError("table T { F:float; } root_type T; { F:1.2.e3 }", invalid_msg);
2107 TestError("table T { F:float; } root_type T; { F:1.2e.3 }", invalid_msg);
2108 TestError("table T { F:float; } root_type T; { F:1.2e0.3 }", invalid_msg);
2109 TestError("table T { F:float; } root_type T; { F:1.2e3. }", invalid_msg);
2110 TestError("table T { F:float; } root_type T; { F:1.2e3.0 }", invalid_msg);
2111 TestError("table T { F:float; } root_type T; { F:+-1.0 }", invalid_msg);
2112 TestError("table T { F:float; } root_type T; { F:1.0e+-1 }", invalid_msg);
2113 TestError("table T { F:float; } root_type T; { F:\"1.0e+-1\" }", invalid_msg);
2114 TestError("table T { F:float; } root_type T; { F:1.e0e }", comma_msg);
2115 TestError("table T { F:float; } root_type T; { F:0x1.p0e }", comma_msg);
2116 TestError("table T { F:float; } root_type T; { F:\" 0x10 \" }", invalid_msg);
2118 TestError("table T { F:float; } root_type T; { F:\"1,2.\" }", invalid_msg);
2119 TestError("table T { F:float; } root_type T; { F:\"1.2e3.\" }", invalid_msg);
2120 TestError("table T { F:float; } root_type T; { F:\"0x1.p0e\" }", invalid_msg);
2121 TestError("table T { F:float; } root_type T; { F:\"0x1.0\" }", invalid_msg);
2122 TestError("table T { F:float; } root_type T; { F:\" 0x1.0\" }", invalid_msg);
2123 TestError("table T { F:float; } root_type T; { F:\"+ 0\" }", invalid_msg);
2124 // disable escapes for "number-in-string"
2125 TestError("table T { F:float; } root_type T; { F:\"\\f1.2e3.\" }", "invalid");
2126 TestError("table T { F:float; } root_type T; { F:\"\\t1.2e3.\" }", "invalid");
2127 TestError("table T { F:float; } root_type T; { F:\"\\n1.2e3.\" }", "invalid");
2128 TestError("table T { F:float; } root_type T; { F:\"\\r1.2e3.\" }", "invalid");
2129 TestError("table T { F:float; } root_type T; { F:\"4\\x005\" }", "invalid");
2130 TestError("table T { F:float; } root_type T; { F:\"\'12\'\" }", invalid_msg);
2131 // null is not a number constant!
2132 TestError("table T { F:float; } root_type T; { F:\"null\" }", invalid_msg);
2133 TestError("table T { F:float; } root_type T; { F:null }", invalid_msg);
2136 void GenerateTableTextTest() {
2137 std::string schemafile;
2138 std::string jsonfile;
2140 flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2141 false, &schemafile) &&
2142 flatbuffers::LoadFile((test_data_path + "monsterdata_test.json").c_str(),
2145 auto include_test_path =
2146 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2147 const char *include_directories[] = { test_data_path.c_str(),
2148 include_test_path.c_str(), nullptr };
2149 flatbuffers::IDLOptions opt;
2150 opt.indent_step = -1;
2151 flatbuffers::Parser parser(opt);
2152 ok = parser.Parse(schemafile.c_str(), include_directories) &&
2153 parser.Parse(jsonfile.c_str(), include_directories);
2156 const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
2157 const auto abilities = monster->testarrayofsortedstruct();
2158 TEST_EQ(abilities->size(), 3);
2159 TEST_EQ(abilities->Get(0)->id(), 0);
2160 TEST_EQ(abilities->Get(0)->distance(), 45);
2161 TEST_EQ(abilities->Get(1)->id(), 1);
2162 TEST_EQ(abilities->Get(1)->distance(), 21);
2163 TEST_EQ(abilities->Get(2)->id(), 5);
2164 TEST_EQ(abilities->Get(2)->distance(), 12);
2166 std::string jsongen;
2167 auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster",
2169 TEST_EQ(result, true);
2171 const Vec3 *pos = monster->pos();
2173 result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
2174 TEST_EQ(result, true);
2177 "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
2178 const Test &test3 = pos->test3();
2181 GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
2182 TEST_EQ(result, true);
2183 TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
2184 const Test *test4 = monster->test4()->Get(0);
2187 GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
2188 TEST_EQ(result, true);
2189 TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
2192 template<typename T>
2193 void NumericUtilsTestInteger(const char *lower, const char *upper) {
2195 TEST_EQ(flatbuffers::StringToNumber("1q", &x), false);
2197 TEST_EQ(flatbuffers::StringToNumber(upper, &x), false);
2198 TEST_EQ(x, flatbuffers::numeric_limits<T>::max());
2199 TEST_EQ(flatbuffers::StringToNumber(lower, &x), false);
2200 auto expval = flatbuffers::is_unsigned<T>::value
2201 ? flatbuffers::numeric_limits<T>::max()
2202 : flatbuffers::numeric_limits<T>::lowest();
2206 template<typename T>
2207 void NumericUtilsTestFloat(const char *lower, const char *upper) {
2209 TEST_EQ(flatbuffers::StringToNumber("", &f), false);
2210 TEST_EQ(flatbuffers::StringToNumber("1q", &f), false);
2212 TEST_EQ(flatbuffers::StringToNumber(upper, &f), true);
2213 TEST_EQ(f, +flatbuffers::numeric_limits<T>::infinity());
2214 TEST_EQ(flatbuffers::StringToNumber(lower, &f), true);
2215 TEST_EQ(f, -flatbuffers::numeric_limits<T>::infinity());
2218 void NumericUtilsTest() {
2219 NumericUtilsTestInteger<uint64_t>("-1", "18446744073709551616");
2220 NumericUtilsTestInteger<uint8_t>("-1", "256");
2221 NumericUtilsTestInteger<int64_t>("-9223372036854775809",
2222 "9223372036854775808");
2223 NumericUtilsTestInteger<int8_t>("-129", "128");
2224 NumericUtilsTestFloat<float>("-3.4029e+38", "+3.4029e+38");
2225 NumericUtilsTestFloat<float>("-1.7977e+308", "+1.7977e+308");
2228 void IsAsciiUtilsTest() {
2230 for (int cnt = 0; cnt < 256; cnt++) {
2231 auto alpha = (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
2232 auto dec = (('0' <= c) && (c <= '9'));
2233 auto hex = (('a' <= c) && (c <= 'f')) || (('A' <= c) && (c <= 'F'));
2234 TEST_EQ(flatbuffers::is_alpha(c), alpha);
2235 TEST_EQ(flatbuffers::is_alnum(c), alpha || dec);
2236 TEST_EQ(flatbuffers::is_digit(c), dec);
2237 TEST_EQ(flatbuffers::is_xdigit(c), dec || hex);
2242 void UnicodeTest() {
2243 flatbuffers::Parser parser;
2244 // Without setting allow_non_utf8 = true, we treat \x sequences as byte
2245 // sequences which are then validated as UTF-8.
2246 TEST_EQ(parser.Parse("table T { F:string; }"
2248 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2249 "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD8"
2252 std::string jsongen;
2253 parser.opts.indent_step = -1;
2255 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2256 TEST_EQ(result, true);
2257 TEST_EQ_STR(jsongen.c_str(),
2258 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2259 "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
2262 void UnicodeTestAllowNonUTF8() {
2263 flatbuffers::Parser parser;
2264 parser.opts.allow_non_utf8 = true;
2267 "table T { F:string; }"
2269 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2270 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2272 std::string jsongen;
2273 parser.opts.indent_step = -1;
2275 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2276 TEST_EQ(result, true);
2279 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2280 "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
2283 void UnicodeTestGenerateTextFailsOnNonUTF8() {
2284 flatbuffers::Parser parser;
2285 // Allow non-UTF-8 initially to model what happens when we load a binary
2286 // flatbuffer from disk which contains non-UTF-8 strings.
2287 parser.opts.allow_non_utf8 = true;
2290 "table T { F:string; }"
2292 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2293 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2295 std::string jsongen;
2296 parser.opts.indent_step = -1;
2297 // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates
2299 parser.opts.allow_non_utf8 = false;
2301 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2302 TEST_EQ(result, false);
2305 void UnicodeSurrogatesTest() {
2306 flatbuffers::Parser parser;
2308 TEST_EQ(parser.Parse("table T { F:string (id: 0); }"
2310 "{ F:\"\\uD83D\\uDCA9\"}"),
2312 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
2313 parser.builder_.GetBufferPointer());
2314 auto string = root->GetPointer<flatbuffers::String *>(
2315 flatbuffers::FieldIndexToOffset(0));
2316 TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
2319 void UnicodeInvalidSurrogatesTest() {
2321 "table T { F:string; }"
2324 "unpaired high surrogate");
2326 "table T { F:string; }"
2328 "{ F:\"\\uD800abcd\"}",
2329 "unpaired high surrogate");
2331 "table T { F:string; }"
2333 "{ F:\"\\uD800\\n\"}",
2334 "unpaired high surrogate");
2336 "table T { F:string; }"
2338 "{ F:\"\\uD800\\uD800\"}",
2339 "multiple high surrogates");
2341 "table T { F:string; }"
2344 "unpaired low surrogate");
2347 void InvalidUTF8Test() {
2348 // "1 byte" pattern, under min length of 2 bytes
2350 "table T { F:string; }"
2353 "illegal UTF-8 sequence");
2354 // 2 byte pattern, string too short
2356 "table T { F:string; }"
2359 "illegal UTF-8 sequence");
2360 // 3 byte pattern, string too short
2362 "table T { F:string; }"
2364 "{ F:\"\xEF\xBF\"}",
2365 "illegal UTF-8 sequence");
2366 // 4 byte pattern, string too short
2368 "table T { F:string; }"
2370 "{ F:\"\xF7\xBF\xBF\"}",
2371 "illegal UTF-8 sequence");
2372 // "5 byte" pattern, string too short
2374 "table T { F:string; }"
2376 "{ F:\"\xFB\xBF\xBF\xBF\"}",
2377 "illegal UTF-8 sequence");
2378 // "6 byte" pattern, string too short
2380 "table T { F:string; }"
2382 "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}",
2383 "illegal UTF-8 sequence");
2384 // "7 byte" pattern, string too short
2386 "table T { F:string; }"
2388 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}",
2389 "illegal UTF-8 sequence");
2390 // "5 byte" pattern, over max length of 4 bytes
2392 "table T { F:string; }"
2394 "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}",
2395 "illegal UTF-8 sequence");
2396 // "6 byte" pattern, over max length of 4 bytes
2398 "table T { F:string; }"
2400 "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}",
2401 "illegal UTF-8 sequence");
2402 // "7 byte" pattern, over max length of 4 bytes
2404 "table T { F:string; }"
2406 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}",
2407 "illegal UTF-8 sequence");
2409 // Three invalid encodings for U+000A (\n, aka NEWLINE)
2411 "table T { F:string; }"
2413 "{ F:\"\xC0\x8A\"}",
2414 "illegal UTF-8 sequence");
2416 "table T { F:string; }"
2418 "{ F:\"\xE0\x80\x8A\"}",
2419 "illegal UTF-8 sequence");
2421 "table T { F:string; }"
2423 "{ F:\"\xF0\x80\x80\x8A\"}",
2424 "illegal UTF-8 sequence");
2426 // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
2428 "table T { F:string; }"
2430 "{ F:\"\xE0\x81\xA9\"}",
2431 "illegal UTF-8 sequence");
2433 "table T { F:string; }"
2435 "{ F:\"\xF0\x80\x81\xA9\"}",
2436 "illegal UTF-8 sequence");
2438 // Invalid encoding for U+20AC (EURO SYMBOL)
2440 "table T { F:string; }"
2442 "{ F:\"\xF0\x82\x82\xAC\"}",
2443 "illegal UTF-8 sequence");
2445 // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in
2448 "table T { F:string; }"
2450 // U+10400 "encoded" as U+D801 U+DC00
2451 "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}",
2452 "illegal UTF-8 sequence");
2454 // Check independence of identifier from locale.
2455 std::string locale_ident;
2456 locale_ident += "table T { F";
2457 locale_ident += static_cast<char>(-32); // unsigned 0xE0
2458 locale_ident += " :string; }";
2459 locale_ident += "root_type T;";
2460 locale_ident += "{}";
2461 TestError(locale_ident.c_str(), "");
2464 void UnknownFieldsTest() {
2465 flatbuffers::IDLOptions opts;
2466 opts.skip_unexpected_fields_in_json = true;
2467 flatbuffers::Parser parser(opts);
2469 TEST_EQ(parser.Parse("table T { str:string; i:int;}"
2472 "unknown_string:\"test\","
2473 "\"unknown_string\":\"test\","
2475 "unknown_float:1.0,"
2476 "unknown_array: [ 1, 2, 3, 4],"
2477 "unknown_object: { i: 10 },"
2478 "\"unknown_object\": { \"i\": 10 },"
2482 std::string jsongen;
2483 parser.opts.indent_step = -1;
2485 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2486 TEST_EQ(result, true);
2487 TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
2490 void ParseUnionTest() {
2491 // Unions must be parseable with the type field following the object.
2492 flatbuffers::Parser parser;
2493 TEST_EQ(parser.Parse("table T { A:int; }"
2497 "{ X:{ A:1 }, X_type: T }"),
2499 // Unions must be parsable with prefixed namespace.
2500 flatbuffers::Parser parser2;
2501 TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
2502 "table B { e:U; } root_type B;"
2503 "{ e_type: N_A, e: {} }"),
2507 void InvalidNestedFlatbufferTest() {
2508 // First, load and parse FlatBuffer schema (.fbs)
2509 std::string schemafile;
2510 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2511 false, &schemafile),
2513 auto include_test_path =
2514 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2515 const char *include_directories[] = { test_data_path.c_str(),
2516 include_test_path.c_str(), nullptr };
2517 flatbuffers::Parser parser1;
2518 TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
2520 // "color" inside nested flatbuffer contains invalid enum value
2521 TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
2522 "\"Leela\", color: \"nonexistent\"}}"),
2526 void EvolutionTest() {
2527 // VS10 does not support typed enums, exclude from tests
2528 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2529 const int NUM_VERSIONS = 2;
2530 std::string schemas[NUM_VERSIONS];
2531 std::string jsonfiles[NUM_VERSIONS];
2532 std::vector<uint8_t> binaries[NUM_VERSIONS];
2534 flatbuffers::IDLOptions idl_opts;
2535 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2536 flatbuffers::Parser parser(idl_opts);
2538 // Load all the schema versions and their associated data.
2539 for (int i = 0; i < NUM_VERSIONS; ++i) {
2540 std::string schema = test_data_path + "evolution_test/evolution_v" +
2541 flatbuffers::NumToString(i + 1) + ".fbs";
2542 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2543 std::string json = test_data_path + "evolution_test/evolution_v" +
2544 flatbuffers::NumToString(i + 1) + ".json";
2545 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2547 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2548 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2550 auto bufLen = parser.builder_.GetSize();
2551 auto buf = parser.builder_.GetBufferPointer();
2552 binaries[i].reserve(bufLen);
2553 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2556 // Assert that all the verifiers for the different schema versions properly
2557 // verify any version data.
2558 for (int i = 0; i < NUM_VERSIONS; ++i) {
2559 flatbuffers::Verifier verifier(&binaries[i].front(), binaries[i].size());
2560 TEST_ASSERT(Evolution::V1::VerifyRootBuffer(verifier));
2561 TEST_ASSERT(Evolution::V2::VerifyRootBuffer(verifier));
2564 // Test backwards compatibility by reading old data with an evolved schema.
2565 auto root_v1_viewed_from_v2 = Evolution::V2::GetRoot(&binaries[0].front());
2566 // field 'k' is new in version 2, so it should be null.
2567 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->k());
2568 // field 'l' is new in version 2 with a default of 56.
2569 TEST_EQ(root_v1_viewed_from_v2->l(), 56);
2570 // field 'c' of 'TableA' is new in version 2, so it should be null.
2571 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->e()->c());
2572 // 'TableC' was added to field 'c' union in version 2, so it should be null.
2573 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->c_as_TableC());
2574 // The field 'c' union should be of type 'TableB' regardless of schema version
2575 TEST_ASSERT(root_v1_viewed_from_v2->c_type() == Evolution::V2::Union::TableB);
2576 // The field 'f' was renamed to 'ff' in version 2, it should still be
2578 TEST_EQ(root_v1_viewed_from_v2->ff()->a(), 16);
2580 // Test forwards compatibility by reading new data with an old schema.
2581 auto root_v2_viewed_from_v1 = Evolution::V1::GetRoot(&binaries[1].front());
2582 // The field 'c' union in version 2 is a new table (index = 3) and should
2583 // still be accessible, but not interpretable.
2584 TEST_EQ(static_cast<uint8_t>(root_v2_viewed_from_v1->c_type()), 3);
2585 TEST_NOTNULL(root_v2_viewed_from_v1->c());
2586 // The field 'd' enum in verison 2 has new members and should still be
2587 // accessible, but not interpretable.
2588 TEST_EQ(static_cast<int8_t>(root_v2_viewed_from_v1->d()), 3);
2589 // The field 'a' in version 2 is deprecated and should return the default
2590 // value (0) instead of the value stored in the in the buffer (42).
2591 TEST_EQ(root_v2_viewed_from_v1->a(), 0);
2592 // The field 'ff' was originally named 'f' in version 1, it should still be
2594 TEST_EQ(root_v2_viewed_from_v1->f()->a(), 35);
2598 void UnionDeprecationTest() {
2599 const int NUM_VERSIONS = 2;
2600 std::string schemas[NUM_VERSIONS];
2601 std::string jsonfiles[NUM_VERSIONS];
2602 std::vector<uint8_t> binaries[NUM_VERSIONS];
2604 flatbuffers::IDLOptions idl_opts;
2605 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2606 flatbuffers::Parser parser(idl_opts);
2608 // Load all the schema versions and their associated data.
2609 for (int i = 0; i < NUM_VERSIONS; ++i) {
2610 std::string schema = test_data_path + "evolution_test/evolution_v" +
2611 flatbuffers::NumToString(i + 1) + ".fbs";
2612 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2613 std::string json = test_data_path + "evolution_test/evolution_v" +
2614 flatbuffers::NumToString(i + 1) + ".json";
2615 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2617 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2618 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2620 auto bufLen = parser.builder_.GetSize();
2621 auto buf = parser.builder_.GetBufferPointer();
2622 binaries[i].reserve(bufLen);
2623 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2626 auto v2 = parser.LookupStruct("Evolution.V2.Root");
2628 auto j_type_field = v2->fields.Lookup("j_type");
2629 TEST_NOTNULL(j_type_field);
2630 TEST_ASSERT(j_type_field->deprecated);
2633 void UnionVectorTest() {
2634 // load FlatBuffer fbs schema and json.
2635 std::string schemafile, jsonfile;
2636 TEST_EQ(flatbuffers::LoadFile(
2637 (test_data_path + "union_vector/union_vector.fbs").c_str(), false,
2640 TEST_EQ(flatbuffers::LoadFile(
2641 (test_data_path + "union_vector/union_vector.json").c_str(),
2646 flatbuffers::IDLOptions idl_opts;
2647 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2648 flatbuffers::Parser parser(idl_opts);
2649 TEST_EQ(parser.Parse(schemafile.c_str()), true);
2651 flatbuffers::FlatBufferBuilder fbb;
2654 std::vector<uint8_t> types;
2655 types.push_back(static_cast<uint8_t>(Character_Belle));
2656 types.push_back(static_cast<uint8_t>(Character_MuLan));
2657 types.push_back(static_cast<uint8_t>(Character_BookFan));
2658 types.push_back(static_cast<uint8_t>(Character_Other));
2659 types.push_back(static_cast<uint8_t>(Character_Unused));
2662 std::vector<flatbuffers::Offset<void>> characters;
2663 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
2664 characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
2665 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
2666 characters.push_back(fbb.CreateString("Other").Union());
2667 characters.push_back(fbb.CreateString("Unused").Union());
2670 const auto movie_offset =
2671 CreateMovie(fbb, Character_Rapunzel,
2672 fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
2673 fbb.CreateVector(types), fbb.CreateVector(characters));
2674 FinishMovieBuffer(fbb, movie_offset);
2676 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
2677 TEST_EQ(VerifyMovieBuffer(verifier), true);
2679 auto flat_movie = GetMovie(fbb.GetBufferPointer());
2681 auto TestMovie = [](const Movie *movie) {
2682 TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
2684 auto cts = movie->characters_type();
2685 TEST_EQ(movie->characters_type()->size(), 5);
2686 TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
2687 TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
2688 TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
2689 TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
2690 TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
2692 auto rapunzel = movie->main_character_as_Rapunzel();
2693 TEST_NOTNULL(rapunzel);
2694 TEST_EQ(rapunzel->hair_length(), 6);
2696 auto cs = movie->characters();
2697 TEST_EQ(cs->size(), 5);
2698 auto belle = cs->GetAs<BookReader>(0);
2699 TEST_EQ(belle->books_read(), 7);
2700 auto mu_lan = cs->GetAs<Attacker>(1);
2701 TEST_EQ(mu_lan->sword_attack_damage(), 5);
2702 auto book_fan = cs->GetAs<BookReader>(2);
2703 TEST_EQ(book_fan->books_read(), 2);
2704 auto other = cs->GetAsString(3);
2705 TEST_EQ_STR(other->c_str(), "Other");
2706 auto unused = cs->GetAsString(4);
2707 TEST_EQ_STR(unused->c_str(), "Unused");
2710 TestMovie(flat_movie);
2712 // Also test the JSON we loaded above.
2713 TEST_EQ(parser.Parse(jsonfile.c_str()), true);
2714 auto jbuf = parser.builder_.GetBufferPointer();
2715 flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
2716 TEST_EQ(VerifyMovieBuffer(jverifier), true);
2717 TestMovie(GetMovie(jbuf));
2719 auto movie_object = flat_movie->UnPack();
2720 TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
2721 TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
2722 TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
2723 TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
2724 TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
2725 TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
2728 fbb.Finish(Movie::Pack(fbb, movie_object));
2730 delete movie_object;
2732 auto repacked_movie = GetMovie(fbb.GetBufferPointer());
2734 TestMovie(repacked_movie);
2736 // Generate text using mini-reflection.
2738 flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
2741 "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
2742 "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
2743 "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
2744 "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
2746 flatbuffers::ToStringVisitor visitor("\n", true, " ");
2747 IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
2748 TEST_EQ_STR(visitor.s.c_str(),
2750 " \"main_character_type\": \"Rapunzel\",\n"
2751 " \"main_character\": {\n"
2752 " \"hair_length\": 6\n"
2754 " \"characters_type\": [\n"
2761 " \"characters\": [\n"
2763 " \"books_read\": 7\n"
2766 " \"sword_attack_damage\": 5\n"
2769 " \"books_read\": 2\n"
2776 // Generate text using parsed schema.
2777 std::string jsongen;
2778 auto result = GenerateText(parser, fbb.GetBufferPointer(), &jsongen);
2779 TEST_EQ(result, true);
2780 TEST_EQ_STR(jsongen.c_str(),
2782 " main_character_type: \"Rapunzel\",\n"
2783 " main_character: {\n"
2786 " characters_type: [\n"
2798 " sword_attack_damage: 5\n"
2808 // Simple test with reflection.
2810 auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
2811 auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
2812 fbb.GetBufferPointer(), fbb.GetSize());
2815 flatbuffers::Parser parser2(idl_opts);
2816 TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
2817 "union Any { Bool }"
2818 "table Root { a:Any; }"
2821 TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
2824 void ConformTest() {
2825 flatbuffers::Parser parser;
2826 TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
2828 auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
2829 const char *expected_err) {
2830 flatbuffers::Parser parser2;
2831 TEST_EQ(parser2.Parse(test), true);
2832 auto err = parser2.ConformTo(parser1);
2833 TEST_NOTNULL(strstr(err.c_str(), expected_err));
2836 test_conform(parser, "table T { A:byte; }", "types differ for field");
2837 test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
2838 test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
2839 test_conform(parser, "table T { B:float; }",
2840 "field renamed to different type");
2841 test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
2844 void ParseProtoBufAsciiTest() {
2845 // We can put the parser in a mode where it will accept JSON that looks more
2846 // like Protobuf ASCII, for users that have data in that format.
2847 // This uses no "" for field names (which we already support by default,
2848 // omits `,`, `:` before `{` and a couple of other features.
2849 flatbuffers::Parser parser;
2850 parser.opts.protobuf_ascii_alike = true;
2852 parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
2854 TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
2855 // Similarly, in text output, it should omit these.
2857 auto ok = flatbuffers::GenerateText(
2858 parser, parser.builder_.GetBufferPointer(), &text);
2860 TEST_EQ_STR(text.c_str(),
2861 "{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n");
2864 void FlexBuffersTest() {
2865 flexbuffers::Builder slb(512,
2866 flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
2868 // Write the equivalent of:
2869 // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ],
2870 // foo: 100, bool: true, mymap: { foo: "Fred" } }
2872 #ifndef FLATBUFFERS_CPP98_STL
2873 // It's possible to do this without std::function support as well.
2875 slb.Vector("vec", [&]() {
2876 slb += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2878 slb.IndirectFloat(4.0f);
2879 auto i_f = slb.LastValue();
2880 uint8_t blob[] = { 77 };
2883 slb.ReuseValue(i_f);
2885 int ints[] = { 1, 2, 3 };
2886 slb.Vector("bar", ints, 3);
2887 slb.FixedTypedVector("bar3", ints, 3);
2888 bool bools[] = {true, false, true, false};
2889 slb.Vector("bools", bools, 4);
2890 slb.Bool("bool", true);
2891 slb.Double("foo", 100);
2892 slb.Map("mymap", [&]() {
2893 slb.String("foo", "Fred"); // Testing key and string reuse.
2898 // It's possible to do this without std::function support as well.
2899 slb.Map([](flexbuffers::Builder& slb2) {
2900 slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
2901 slb3 += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2903 slb3.IndirectFloat(4.0f);
2904 auto i_f = slb3.LastValue();
2905 uint8_t blob[] = { 77 };
2908 slb3.ReuseValue(i_f);
2910 int ints[] = { 1, 2, 3 };
2911 slb2.Vector("bar", ints, 3);
2912 slb2.FixedTypedVector("bar3", ints, 3);
2913 slb2.Bool("bool", true);
2914 slb2.Double("foo", 100);
2915 slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
2916 slb3.String("foo", "Fred"); // Testing key and string reuse.
2920 #endif // FLATBUFFERS_CPP98_STL
2922 #ifdef FLATBUFFERS_TEST_VERBOSE
2923 for (size_t i = 0; i < slb.GetBuffer().size(); i++)
2924 printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
2929 auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
2930 TEST_EQ(map.size(), 7);
2931 auto vec = map["vec"].AsVector();
2932 TEST_EQ(vec.size(), 6);
2933 TEST_EQ(vec[0].AsInt64(), -100);
2934 TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
2935 TEST_EQ(vec[1].AsInt64(), 0); // Number parsing failed.
2936 TEST_EQ(vec[2].AsDouble(), 4.0);
2937 TEST_EQ(vec[2].AsString().IsTheEmptyString(), true); // Wrong Type.
2938 TEST_EQ_STR(vec[2].AsString().c_str(), ""); // This still works though.
2939 TEST_EQ_STR(vec[2].ToString().c_str(), "4.0"); // Or have it converted.
2940 // Few tests for templated version of As.
2941 TEST_EQ(vec[0].As<int64_t>(), -100);
2942 TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
2943 TEST_EQ(vec[1].As<int64_t>(), 0); // Number parsing failed.
2944 TEST_EQ(vec[2].As<double>(), 4.0);
2945 // Test that the blob can be accessed.
2946 TEST_EQ(vec[3].IsBlob(), true);
2947 auto blob = vec[3].AsBlob();
2948 TEST_EQ(blob.size(), 1);
2949 TEST_EQ(blob.data()[0], 77);
2950 TEST_EQ(vec[4].IsBool(), true); // Check if type is a bool
2951 TEST_EQ(vec[4].AsBool(), false); // Check if value is false
2952 TEST_EQ(vec[5].AsDouble(), 4.0); // This is shared with vec[2] !
2953 auto tvec = map["bar"].AsTypedVector();
2954 TEST_EQ(tvec.size(), 3);
2955 TEST_EQ(tvec[2].AsInt8(), 3);
2956 auto tvec3 = map["bar3"].AsFixedTypedVector();
2957 TEST_EQ(tvec3.size(), 3);
2958 TEST_EQ(tvec3[2].AsInt8(), 3);
2959 TEST_EQ(map["bool"].AsBool(), true);
2960 auto tvecb = map["bools"].AsTypedVector();
2961 TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
2962 TEST_EQ(map["foo"].AsUInt8(), 100);
2963 TEST_EQ(map["unknown"].IsNull(), true);
2964 auto mymap = map["mymap"].AsMap();
2965 // These should be equal by pointer equality, since key and value are shared.
2966 TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
2967 TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
2968 // We can mutate values in the buffer.
2969 TEST_EQ(vec[0].MutateInt(-99), true);
2970 TEST_EQ(vec[0].AsInt64(), -99);
2971 TEST_EQ(vec[1].MutateString("John"), true); // Size must match.
2972 TEST_EQ_STR(vec[1].AsString().c_str(), "John");
2973 TEST_EQ(vec[1].MutateString("Alfred"), false); // Too long.
2974 TEST_EQ(vec[2].MutateFloat(2.0f), true);
2975 TEST_EQ(vec[2].AsFloat(), 2.0f);
2976 TEST_EQ(vec[2].MutateFloat(3.14159), false); // Double does not fit in float.
2977 TEST_EQ(vec[4].AsBool(), false); // Is false before change
2978 TEST_EQ(vec[4].MutateBool(true), true); // Can change a bool
2979 TEST_EQ(vec[4].AsBool(), true); // Changed bool is now true
2982 flatbuffers::Parser parser;
2984 auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
2985 TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
2986 auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
2987 auto jmap = jroot.AsMap();
2988 auto jvec = jmap["a"].AsVector();
2989 TEST_EQ(jvec[0].AsInt64(), 123);
2990 TEST_EQ(jvec[1].AsDouble(), 456.0);
2991 TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
2992 TEST_EQ(jmap["c"].IsBool(), true); // Parsed correctly to a bool
2993 TEST_EQ(jmap["c"].AsBool(), true); // Parsed correctly to true
2994 TEST_EQ(jmap["d"].IsBool(), true); // Parsed correctly to a bool
2995 TEST_EQ(jmap["d"].AsBool(), false); // Parsed correctly to false
2996 // And from FlexBuffer back to JSON:
2997 auto jsonback = jroot.ToString();
2998 TEST_EQ_STR(jsontest, jsonback.c_str());
3002 for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
3004 for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
3009 TEST_EQ(slb.GetSize(), 664);
3012 void FlexBuffersDeprecatedTest() {
3013 // FlexBuffers as originally designed had a flaw involving the
3014 // FBT_VECTOR_STRING datatype, and this test documents/tests the fix for it.
3015 // Discussion: https://github.com/google/flatbuffers/issues/5627
3016 flexbuffers::Builder slb;
3017 // FBT_VECTOR_* are "typed vectors" where all elements are of the same type.
3018 // Problem is, when storing FBT_STRING elements, it relies on that type to
3019 // get the bit-width for the size field of the string, which in this case
3020 // isn't present, and instead defaults to 8-bit. This means that any strings
3021 // stored inside such a vector, when accessed thru the old API that returns
3022 // a String reference, will appear to be truncated if the string stored is
3023 // actually >=256 bytes.
3024 std::string test_data(300, 'A');
3025 auto start = slb.StartVector();
3026 // This one will have a 16-bit size field.
3027 slb.String(test_data);
3028 // This one will have an 8-bit size field.
3029 slb.String("hello");
3030 // We're asking this to be serialized as a typed vector (true), but not
3031 // fixed size (false). The type will be FBT_VECTOR_STRING with a bit-width
3032 // of whatever the offsets in the vector need, the bit-widths of the strings
3033 // are not stored(!) <- the actual design flaw.
3034 // Note that even in the fixed code, we continue to serialize the elements of
3035 // FBT_VECTOR_STRING as FBT_STRING, since there may be old code out there
3036 // reading new data that we want to continue to function.
3037 // Thus, FBT_VECTOR_STRING, while deprecated, will always be represented the
3038 // same way, the fix lies on the reading side.
3039 slb.EndVector(start, true, false);
3041 // So now lets read this data back.
3042 // For existing data, since we have no way of knowing what the actual
3043 // bit-width of the size field of the string is, we are going to ignore this
3044 // field, and instead treat these strings as FBT_KEY (null-terminated), so we
3045 // can deal with strings of arbitrary length. This of course truncates strings
3046 // with embedded nulls, but we think that that is preferrable over truncating
3047 // strings >= 256 bytes.
3048 auto vec = flexbuffers::GetRoot(slb.GetBuffer()).AsTypedVector();
3049 // Even though this was serialized as FBT_VECTOR_STRING, it is read as
3051 TEST_EQ(vec.ElementType(), flexbuffers::FBT_KEY);
3052 // Access the long string. Previously, this would return a string of size 1,
3053 // since it would read the high-byte of the 16-bit length.
3054 // This should now correctly test the full 300 bytes, using AsKey():
3055 TEST_EQ_STR(vec[0].AsKey(), test_data.c_str());
3056 // Old code that called AsString will continue to work, as the String
3057 // accessor objects now use a cached size that can come from a key as well.
3058 TEST_EQ_STR(vec[0].AsString().c_str(), test_data.c_str());
3059 // Short strings work as before:
3060 TEST_EQ_STR(vec[1].AsKey(), "hello");
3061 TEST_EQ_STR(vec[1].AsString().c_str(), "hello");
3062 // So, while existing code and data mostly "just work" with the fixes applied
3063 // to AsTypedVector and AsString, what do you do going forward?
3064 // Code accessing existing data doesn't necessarily need to change, though
3065 // you could consider using AsKey instead of AsString for a) documenting
3066 // that you are accessing keys, or b) a speedup if you don't actually use
3068 // For new data, or data that doesn't need to be backwards compatible,
3069 // instead serialize as FBT_VECTOR (call EndVector with typed = false, then
3070 // read elements with AsString), or, for maximum compactness, use
3071 // FBT_VECTOR_KEY (call slb.Key above instead, read with AsKey or AsString).
3074 void TypeAliasesTest() {
3075 flatbuffers::FlatBufferBuilder builder;
3077 builder.Finish(CreateTypeAliases(
3078 builder, flatbuffers::numeric_limits<int8_t>::min(),
3079 flatbuffers::numeric_limits<uint8_t>::max(),
3080 flatbuffers::numeric_limits<int16_t>::min(),
3081 flatbuffers::numeric_limits<uint16_t>::max(),
3082 flatbuffers::numeric_limits<int32_t>::min(),
3083 flatbuffers::numeric_limits<uint32_t>::max(),
3084 flatbuffers::numeric_limits<int64_t>::min(),
3085 flatbuffers::numeric_limits<uint64_t>::max(), 2.3f, 2.3));
3087 auto p = builder.GetBufferPointer();
3088 auto ta = flatbuffers::GetRoot<TypeAliases>(p);
3090 TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
3091 TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
3092 TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
3093 TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
3094 TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
3095 TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
3096 TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
3097 TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
3098 TEST_EQ(ta->f32(), 2.3f);
3099 TEST_EQ(ta->f64(), 2.3);
3100 using namespace flatbuffers; // is_same
3101 static_assert(is_same<decltype(ta->i8()), int8_t>::value, "invalid type");
3102 static_assert(is_same<decltype(ta->i16()), int16_t>::value, "invalid type");
3103 static_assert(is_same<decltype(ta->i32()), int32_t>::value, "invalid type");
3104 static_assert(is_same<decltype(ta->i64()), int64_t>::value, "invalid type");
3105 static_assert(is_same<decltype(ta->u8()), uint8_t>::value, "invalid type");
3106 static_assert(is_same<decltype(ta->u16()), uint16_t>::value, "invalid type");
3107 static_assert(is_same<decltype(ta->u32()), uint32_t>::value, "invalid type");
3108 static_assert(is_same<decltype(ta->u64()), uint64_t>::value, "invalid type");
3109 static_assert(is_same<decltype(ta->f32()), float>::value, "invalid type");
3110 static_assert(is_same<decltype(ta->f64()), double>::value, "invalid type");
3113 void EndianSwapTest() {
3114 TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
3115 TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
3117 TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
3118 0xEFCDAB9078563412);
3119 TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
3122 void UninitializedVectorTest() {
3123 flatbuffers::FlatBufferBuilder builder;
3125 Test *buf = nullptr;
3126 auto vector_offset =
3127 builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
3129 buf[0] = Test(10, 20);
3130 buf[1] = Test(30, 40);
3132 auto required_name = builder.CreateString("myMonster");
3133 auto monster_builder = MonsterBuilder(builder);
3134 monster_builder.add_name(
3135 required_name); // required field mandated for monster.
3136 monster_builder.add_test4(vector_offset);
3137 builder.Finish(monster_builder.Finish());
3139 auto p = builder.GetBufferPointer();
3140 auto uvt = flatbuffers::GetRoot<Monster>(p);
3142 auto vec = uvt->test4();
3144 auto test_0 = vec->Get(0);
3145 auto test_1 = vec->Get(1);
3146 TEST_EQ(test_0->a(), 10);
3147 TEST_EQ(test_0->b(), 20);
3148 TEST_EQ(test_1->a(), 30);
3149 TEST_EQ(test_1->b(), 40);
3152 void EqualOperatorTest() {
3155 TEST_EQ(b == a, true);
3156 TEST_EQ(b != a, false);
3159 TEST_EQ(b == a, false);
3160 TEST_EQ(b != a, true);
3162 TEST_EQ(b == a, true);
3163 TEST_EQ(b != a, false);
3165 b.inventory.push_back(3);
3166 TEST_EQ(b == a, false);
3167 TEST_EQ(b != a, true);
3168 b.inventory.clear();
3169 TEST_EQ(b == a, true);
3170 TEST_EQ(b != a, false);
3172 b.test.type = Any_Monster;
3173 TEST_EQ(b == a, false);
3174 TEST_EQ(b != a, true);
3177 // For testing any binaries, e.g. from fuzzing.
3178 void LoadVerifyBinaryTest() {
3180 if (flatbuffers::LoadFile(
3181 (test_data_path + "fuzzer/your-filename-here").c_str(), true,
3183 flatbuffers::Verifier verifier(
3184 reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
3185 TEST_EQ(VerifyMonsterBuffer(verifier), true);
3189 void CreateSharedStringTest() {
3190 flatbuffers::FlatBufferBuilder builder;
3191 const auto one1 = builder.CreateSharedString("one");
3192 const auto two = builder.CreateSharedString("two");
3193 const auto one2 = builder.CreateSharedString("one");
3194 TEST_EQ(one1.o, one2.o);
3195 const auto onetwo = builder.CreateSharedString("onetwo");
3196 TEST_EQ(onetwo.o != one1.o, true);
3197 TEST_EQ(onetwo.o != two.o, true);
3199 // Support for embedded nulls
3200 const char chars_b[] = { 'a', '\0', 'b' };
3201 const char chars_c[] = { 'a', '\0', 'c' };
3202 const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3203 const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
3204 const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3205 TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
3206 TEST_EQ(null_b1.o, null_b2.o);
3208 // Put the strings into an array for round trip verification.
3209 const flatbuffers::Offset<flatbuffers::String> array[7] = {
3210 one1, two, one2, onetwo, null_b1, null_c, null_b2
3212 const auto vector_offset =
3213 builder.CreateVector(array, flatbuffers::uoffset_t(7));
3214 MonsterBuilder monster_builder(builder);
3215 monster_builder.add_name(two);
3216 monster_builder.add_testarrayofstring(vector_offset);
3217 builder.Finish(monster_builder.Finish());
3219 // Read the Monster back.
3220 const auto *monster =
3221 flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
3222 TEST_EQ_STR(monster->name()->c_str(), "two");
3223 const auto *testarrayofstring = monster->testarrayofstring();
3224 TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
3225 const auto &a = *testarrayofstring;
3226 TEST_EQ_STR(a[0]->c_str(), "one");
3227 TEST_EQ_STR(a[1]->c_str(), "two");
3228 TEST_EQ_STR(a[2]->c_str(), "one");
3229 TEST_EQ_STR(a[3]->c_str(), "onetwo");
3230 TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
3231 TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
3232 TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
3234 // Make sure String::operator< works, too, since it is related to
3235 // StringOffsetCompare.
3236 TEST_EQ((*a[0]) < (*a[1]), true);
3237 TEST_EQ((*a[1]) < (*a[0]), false);
3238 TEST_EQ((*a[1]) < (*a[2]), false);
3239 TEST_EQ((*a[2]) < (*a[1]), true);
3240 TEST_EQ((*a[4]) < (*a[3]), true);
3241 TEST_EQ((*a[5]) < (*a[4]), false);
3242 TEST_EQ((*a[5]) < (*a[4]), false);
3243 TEST_EQ((*a[6]) < (*a[5]), true);
3246 #if !defined(FLATBUFFERS_SPAN_MINIMAL)
3247 void FlatbuffersSpanTest() {
3248 // Compile-time checking of non-const [] to const [] conversions.
3249 using flatbuffers::internal::is_span_convertable;
3250 (void)is_span_convertable<int, 1, int, 1>::type(123);
3251 (void)is_span_convertable<const int, 1, int, 1>::type(123);
3252 (void)is_span_convertable<const int64_t, 1, int64_t, 1>::type(123);
3253 (void)is_span_convertable<const uint64_t, 1, uint64_t, 1>::type(123);
3254 (void)is_span_convertable<const int, 1, const int, 1>::type(123);
3255 (void)is_span_convertable<const int64_t, 1, const int64_t, 1>::type(123);
3256 (void)is_span_convertable<const uint64_t, 1, const uint64_t, 1>::type(123);
3258 using flatbuffers::span;
3260 TEST_EQ(c1.size(), 0);
3261 span<char, flatbuffers::dynamic_extent> c2;
3262 TEST_EQ(c2.size(), 0);
3264 TEST_EQ(c3.size(), 0);
3265 TEST_ASSERT(c1.empty() && c2.empty() && c3.empty());
3267 int i_data7[7] = { 0, 1, 2, 3, 4, 5, 6 };
3268 span<int, 7> i1(&i_data7[0], 7);
3269 span<int> i2(i1); // make dynamic from static
3270 TEST_EQ(i1.size(), 7);
3271 TEST_EQ(i1.empty(), false);
3272 TEST_EQ(i1.size(), i2.size());
3273 TEST_EQ(i1.data(), i_data7);
3275 // Make const span from a non-const one.
3276 span<const int, 7> i3(i1);
3277 // Construct from a C-array.
3278 span<int, 7> i4(i_data7);
3279 span<const int, 7> i5(i_data7);
3280 span<int> i6(i_data7);
3281 span<const int> i7(i_data7);
3282 TEST_EQ(i7.size(), 7);
3283 // Check construction from a const array.
3284 const int i_cdata5[5] = { 4, 3, 2, 1, 0 };
3285 span<const int, 5> i8(i_cdata5);
3286 span<const int> i9(i_cdata5);
3287 TEST_EQ(i9.size(), 5);
3288 // Construction from a (ptr, size) pair.
3289 span<int, 7> i10(i_data7, 7);
3290 span<int> i11(i_data7, 7);
3291 TEST_EQ(i11.size(), 7);
3292 span<const int, 5> i12(i_cdata5, 5);
3293 span<const int> i13(i_cdata5, 5);
3294 TEST_EQ(i13.size(), 5);
3295 // Construction from std::array.
3296 std::array<int, 6> i_arr6 = { { 0, 1, 2, 3, 4, 5 } };
3297 span<int, 6> i14(i_arr6);
3298 span<const int, 6> i15(i_arr6);
3299 span<int> i16(i_arr6);
3300 span<const int> i17(i_arr6);
3301 TEST_EQ(i17.size(), 6);
3302 const std::array<int, 8> i_carr8 = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
3303 span<const int, 8> i18(i_carr8);
3304 span<const int> i19(i_carr8);
3305 TEST_EQ(i18.size(), 8);
3306 TEST_EQ(i19.size(), 8);
3308 // Check compatibility with flatbuffers::Array.
3309 int fbs_int3_underlaying[3] = { 0 };
3310 int fbs_int3_data[3] = { 1, 2, 3 };
3311 auto &fbs_int3 = flatbuffers::CastToArray(fbs_int3_underlaying);
3312 fbs_int3.CopyFromSpan(fbs_int3_data);
3313 TEST_EQ(fbs_int3.Get(1), 2);
3314 const int fbs_cint3_data[3] = { 2, 3, 4 };
3315 fbs_int3.CopyFromSpan(fbs_cint3_data);
3316 TEST_EQ(fbs_int3.Get(1), 3);
3317 // Check with Array<Enum, N>
3318 enum class Dummy : uint16_t { Zero = 0, One, Two };
3319 Dummy fbs_dummy3_underlaying[3] = {};
3320 Dummy fbs_dummy3_data[3] = { Dummy::One, Dummy::Two, Dummy::Two };
3321 auto &fbs_dummy3 = flatbuffers::CastToArray(fbs_dummy3_underlaying);
3322 fbs_dummy3.CopyFromSpan(fbs_dummy3_data);
3323 TEST_EQ(fbs_dummy3.Get(1), Dummy::Two);
3326 void FlatbuffersSpanTest() {}
3329 void FixedLengthArrayTest() {
3330 // VS10 does not support typed enums, exclude from tests
3331 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3332 // Generate an ArrayTable containing one ArrayStruct.
3333 flatbuffers::FlatBufferBuilder fbb;
3334 MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
3335 TEST_NOTNULL(nStruct0.mutable_a());
3336 nStruct0.mutable_a()->Mutate(0, 1);
3337 nStruct0.mutable_a()->Mutate(1, 2);
3338 TEST_NOTNULL(nStruct0.mutable_c());
3339 nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3340 nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3341 TEST_NOTNULL(nStruct0.mutable_d());
3342 nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
3343 nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
3344 MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
3345 TEST_NOTNULL(nStruct1.mutable_a());
3346 nStruct1.mutable_a()->Mutate(0, 3);
3347 nStruct1.mutable_a()->Mutate(1, 4);
3348 TEST_NOTNULL(nStruct1.mutable_c());
3349 nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3350 nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3351 TEST_NOTNULL(nStruct1.mutable_d());
3352 nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
3353 nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
3354 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
3355 TEST_NOTNULL(aStruct.b());
3356 TEST_NOTNULL(aStruct.mutable_b());
3357 TEST_NOTNULL(aStruct.mutable_d());
3358 TEST_NOTNULL(aStruct.mutable_f());
3359 for (int i = 0; i < aStruct.b()->size(); i++)
3360 aStruct.mutable_b()->Mutate(i, i + 1);
3361 aStruct.mutable_d()->Mutate(0, nStruct0);
3362 aStruct.mutable_d()->Mutate(1, nStruct1);
3363 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
3364 MyGame::Example::FinishArrayTableBuffer(fbb, aTable);
3366 // Verify correctness of the ArrayTable.
3367 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
3368 MyGame::Example::VerifyArrayTableBuffer(verifier);
3369 auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
3370 auto mArStruct = p->mutable_a();
3371 TEST_NOTNULL(mArStruct);
3372 TEST_NOTNULL(mArStruct->b());
3373 TEST_NOTNULL(mArStruct->d());
3374 TEST_NOTNULL(mArStruct->f());
3375 TEST_NOTNULL(mArStruct->mutable_b());
3376 TEST_NOTNULL(mArStruct->mutable_d());
3377 TEST_NOTNULL(mArStruct->mutable_f());
3378 mArStruct->mutable_b()->Mutate(14, -14);
3379 TEST_EQ(mArStruct->a(), 2);
3380 TEST_EQ(mArStruct->b()->size(), 15);
3381 TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14);
3382 TEST_EQ(mArStruct->c(), 12);
3383 TEST_NOTNULL(mArStruct->d()->Get(0));
3384 TEST_NOTNULL(mArStruct->d()->Get(0)->a());
3385 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
3386 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
3387 TEST_NOTNULL(mArStruct->d()->Get(1));
3388 TEST_NOTNULL(mArStruct->d()->Get(1)->a());
3389 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
3390 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
3391 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
3392 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
3393 mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
3394 TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
3395 TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
3396 TEST_NOTNULL(mArStruct->d()->Get(0)->c());
3397 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
3398 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
3399 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3400 mArStruct->d()->Get(0)->d()->Get(0));
3401 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3402 mArStruct->d()->Get(0)->d()->Get(1));
3403 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
3404 TEST_NOTNULL(mArStruct->d()->Get(1)->c());
3405 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
3406 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
3407 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3408 mArStruct->d()->Get(1)->d()->Get(0));
3409 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3410 mArStruct->d()->Get(1)->d()->Get(1));
3411 for (int i = 0; i < mArStruct->b()->size() - 1; i++)
3412 TEST_EQ(mArStruct->b()->Get(i), i + 1);
3414 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
3415 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
3417 // Check if default constructor set all memory zero
3418 const size_t arr_size = sizeof(MyGame::Example::ArrayStruct);
3419 char non_zero_memory[arr_size];
3420 // set memory chunk of size ArrayStruct to 1's
3421 std::memset(static_cast<void *>(non_zero_memory), 1, arr_size);
3422 // after placement-new it should be all 0's
3423 # if defined(_MSC_VER) && defined(_DEBUG)
3426 MyGame::Example::ArrayStruct *ap =
3427 new (non_zero_memory) MyGame::Example::ArrayStruct;
3428 # if defined(_MSC_VER) && defined(_DEBUG)
3429 # define new DEBUG_NEW
3432 for (size_t i = 0; i < arr_size; ++i) { TEST_EQ(non_zero_memory[i], 0); }
3436 #if !defined(FLATBUFFERS_SPAN_MINIMAL) && \
3437 (!defined(_MSC_VER) || _MSC_VER >= 1700)
3438 void FixedLengthArrayConstructorTest() {
3439 const int32_t nested_a[2] = { 1, 2 };
3440 MyGame::Example::TestEnum nested_c[2] = { MyGame::Example::TestEnum::A,
3441 MyGame::Example::TestEnum::B };
3442 const int64_t int64_2[2] = { -2, -1 };
3444 std::array<MyGame::Example::NestedStruct, 2> init_d = {
3445 { MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
3447 MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::A,
3449 std::array<int64_t, 2>{ { 12, 13 } }) }
3452 MyGame::Example::ArrayStruct arr_struct(
3454 std::array<int32_t, 0xF>{
3455 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
3456 -17, init_d, 10, int64_2);
3457 TEST_EQ(arr_struct.a(), 8.125);
3458 TEST_EQ(arr_struct.b()->Get(2), 3);
3459 TEST_EQ(arr_struct.c(), -17);
3461 TEST_NOTNULL(arr_struct.d());
3462 const auto &arr_d_0 = *arr_struct.d()->Get(0);
3463 TEST_EQ(arr_d_0.a()->Get(0), 1);
3464 TEST_EQ(arr_d_0.a()->Get(1), 2);
3465 TEST_EQ(arr_d_0.b(), MyGame::Example::TestEnum::B);
3466 TEST_EQ(arr_d_0.c()->Get(0), MyGame::Example::TestEnum::A);
3467 TEST_EQ(arr_d_0.c()->Get(1), MyGame::Example::TestEnum::B);
3468 TEST_EQ(arr_d_0.d()->Get(0), -2);
3469 TEST_EQ(arr_d_0.d()->Get(1), -1);
3470 const auto &arr_d_1 = *arr_struct.d()->Get(1);
3471 TEST_EQ(arr_d_1.a()->Get(0), 1);
3472 TEST_EQ(arr_d_1.a()->Get(1), 2);
3473 TEST_EQ(arr_d_1.b(), MyGame::Example::TestEnum::A);
3474 TEST_EQ(arr_d_1.c()->Get(0), MyGame::Example::TestEnum::A);
3475 TEST_EQ(arr_d_1.c()->Get(1), MyGame::Example::TestEnum::B);
3476 TEST_EQ(arr_d_1.d()->Get(0), 12);
3477 TEST_EQ(arr_d_1.d()->Get(1), 13);
3479 TEST_EQ(arr_struct.e(), 10);
3480 TEST_EQ(arr_struct.f()->Get(0), -2);
3481 TEST_EQ(arr_struct.f()->Get(1), -1);
3484 void FixedLengthArrayConstructorTest() {}
3487 void NativeTypeTest() {
3490 Geometry::ApplicationDataT src_data;
3491 src_data.vectors.reserve(N);
3493 for (int i = 0; i < N; ++i) {
3494 src_data.vectors.push_back(
3495 Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
3498 flatbuffers::FlatBufferBuilder fbb;
3499 fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
3501 auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
3503 for (int i = 0; i < N; ++i) {
3504 Native::Vector3D &v = dstDataT->vectors[i];
3505 TEST_EQ(v.x, 10 * i + 0.1f);
3506 TEST_EQ(v.y, 10 * i + 0.2f);
3507 TEST_EQ(v.z, 10 * i + 0.3f);
3511 void FixedLengthArrayJsonTest(bool binary) {
3512 // VS10 does not support typed enums, exclude from tests
3513 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3514 // load FlatBuffer schema (.fbs) and JSON from disk
3515 std::string schemafile;
3516 std::string jsonfile;
3518 flatbuffers::LoadFile(
3519 (test_data_path + "arrays_test." + (binary ? "bfbs" : "fbs")).c_str(),
3520 binary, &schemafile),
3522 TEST_EQ(flatbuffers::LoadFile((test_data_path + "arrays_test.golden").c_str(),
3526 // parse schema first, so we can use it to parse the data after
3527 flatbuffers::Parser parserOrg, parserGen;
3529 flatbuffers::Verifier verifier(
3530 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
3532 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3533 TEST_EQ(parserOrg.Deserialize((const uint8_t *)schemafile.c_str(),
3536 TEST_EQ(parserGen.Deserialize((const uint8_t *)schemafile.c_str(),
3540 TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
3541 TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
3543 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3545 // First, verify it, just in case:
3546 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3547 parserOrg.builder_.GetSize());
3548 TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
3551 std::string jsonGen;
3553 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3557 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3559 // Verify buffer from generated JSON
3560 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3561 parserGen.builder_.GetSize());
3562 TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
3564 // Compare generated buffer to original
3565 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3566 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3567 parserGen.builder_.GetBufferPointer(),
3568 parserOrg.builder_.GetSize()),
3575 void TestEmbeddedBinarySchema() {
3576 // load JSON from disk
3577 std::string jsonfile;
3578 TEST_EQ(flatbuffers::LoadFile(
3579 (test_data_path + "monsterdata_test.golden").c_str(), false,
3583 // parse schema first, so we can use it to parse the data after
3584 flatbuffers::Parser parserOrg, parserGen;
3585 flatbuffers::Verifier verifier(MyGame::Example::MonsterBinarySchema::data(),
3586 MyGame::Example::MonsterBinarySchema::size());
3587 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3588 TEST_EQ(parserOrg.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3589 MyGame::Example::MonsterBinarySchema::size()),
3591 TEST_EQ(parserGen.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3592 MyGame::Example::MonsterBinarySchema::size()),
3594 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3596 // First, verify it, just in case:
3597 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3598 parserOrg.builder_.GetSize());
3599 TEST_EQ(VerifyMonsterBuffer(verifierOrg), true);
3602 std::string jsonGen;
3604 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3608 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3610 // Verify buffer from generated JSON
3611 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3612 parserGen.builder_.GetSize());
3613 TEST_EQ(VerifyMonsterBuffer(verifierGen), true);
3615 // Compare generated buffer to original
3616 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3617 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3618 parserGen.builder_.GetBufferPointer(),
3619 parserOrg.builder_.GetSize()),
3623 void OptionalScalarsTest() {
3624 // Simple schemas and a "has optional scalar" sentinal.
3625 std::vector<std::string> schemas;
3626 schemas.push_back("table Monster { mana : int; }");
3627 schemas.push_back("table Monster { mana : int = 42; }");
3628 schemas.push_back("table Monster { mana : int = null; }");
3629 schemas.push_back("table Monster { mana : long; }");
3630 schemas.push_back("table Monster { mana : long = 42; }");
3631 schemas.push_back("table Monster { mana : long = null; }");
3632 schemas.push_back("table Monster { mana : float; }");
3633 schemas.push_back("table Monster { mana : float = 42; }");
3634 schemas.push_back("table Monster { mana : float = null; }");
3635 schemas.push_back("table Monster { mana : double; }");
3636 schemas.push_back("table Monster { mana : double = 42; }");
3637 schemas.push_back("table Monster { mana : double = null; }");
3638 schemas.push_back("table Monster { mana : bool; }");
3639 schemas.push_back("table Monster { mana : bool = 42; }");
3640 schemas.push_back("table Monster { mana : bool = null; }");
3642 "enum Enum: int {A=0, B=1} "
3643 "table Monster { mana : Enum; }");
3645 "enum Enum: int {A=0, B=1} "
3646 "table Monster { mana : Enum = B; }");
3648 "enum Enum: int {A=0, B=1} "
3649 "table Monster { mana : Enum = null; }");
3651 // Check the FieldDef is correctly set.
3652 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3653 const bool has_null = schema->find("null") != std::string::npos;
3654 flatbuffers::Parser parser;
3655 TEST_ASSERT(parser.Parse(schema->c_str()));
3656 const auto *mana = parser.structs_.Lookup("Monster")->fields.Lookup("mana");
3657 TEST_EQ(mana->optional, has_null);
3660 // Test if nullable scalars are allowed for each language.
3661 for (unsigned lang = 1; lang < flatbuffers::IDLOptions::kMAX; lang <<= 1) {
3662 flatbuffers::IDLOptions opts;
3663 opts.lang_to_generate = lang;
3664 if (false == flatbuffers::Parser::SupportsOptionalScalars(opts)) {
3667 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3668 flatbuffers::Parser parser(opts);
3669 auto done = parser.Parse(schema->c_str());
3670 TEST_EQ_STR(parser.error_.c_str(), "");
3675 // test C++ nullable
3676 flatbuffers::FlatBufferBuilder fbb;
3677 FinishScalarStuffBuffer(
3678 fbb, optional_scalars::CreateScalarStuff(fbb, 1, static_cast<int8_t>(2)));
3679 auto opts = optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
3680 TEST_ASSERT(!opts->maybe_bool());
3681 TEST_ASSERT(!opts->maybe_f32().has_value());
3682 TEST_ASSERT(opts->maybe_i8().has_value());
3683 TEST_EQ(opts->maybe_i8().value(), 2);
3684 TEST_ASSERT(opts->mutate_maybe_i8(3));
3685 TEST_ASSERT(opts->maybe_i8().has_value());
3686 TEST_EQ(opts->maybe_i8().value(), 3);
3687 TEST_ASSERT(!opts->mutate_maybe_i16(-10));
3689 optional_scalars::ScalarStuffT obj;
3690 TEST_ASSERT(!obj.maybe_bool);
3691 TEST_ASSERT(!obj.maybe_f32.has_value());
3692 opts->UnPackTo(&obj);
3693 TEST_ASSERT(!obj.maybe_bool);
3694 TEST_ASSERT(!obj.maybe_f32.has_value());
3695 TEST_ASSERT(obj.maybe_i8.has_value() && obj.maybe_i8.value() == 3);
3696 TEST_ASSERT(obj.maybe_i8 && *obj.maybe_i8 == 3);
3698 obj.maybe_enum = optional_scalars::OptionalByte_Two;
3701 FinishScalarStuffBuffer(fbb, optional_scalars::ScalarStuff::Pack(fbb, &obj));
3702 opts = optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
3703 TEST_ASSERT(opts->maybe_i8().has_value());
3704 TEST_EQ(opts->maybe_i8().value(), 3);
3705 TEST_ASSERT(opts->maybe_i32().has_value());
3706 TEST_EQ(opts->maybe_i32().value(), -1);
3707 TEST_EQ(opts->maybe_enum().value(), optional_scalars::OptionalByte_Two);
3708 TEST_ASSERT(opts->maybe_i32() == flatbuffers::Optional<int64_t>(-1));
3711 void ParseFlexbuffersFromJsonWithNullTest() {
3712 // Test nulls are handled appropriately through flexbuffers to exercise other
3713 // code paths of ParseSingleValue in the optional scalars change.
3714 // TODO(cneo): Json -> Flatbuffers test once some language can generate code
3715 // with optional scalars.
3717 char json[] = "{\"opt_field\": 123 }";
3718 flatbuffers::Parser parser;
3719 flexbuffers::Builder flexbuild;
3720 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3721 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3722 TEST_EQ(root.AsMap()["opt_field"].AsInt64(), 123);
3725 char json[] = "{\"opt_field\": 123.4 }";
3726 flatbuffers::Parser parser;
3727 flexbuffers::Builder flexbuild;
3728 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3729 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3730 TEST_EQ(root.AsMap()["opt_field"].AsDouble(), 123.4);
3733 char json[] = "{\"opt_field\": null }";
3734 flatbuffers::Parser parser;
3735 flexbuffers::Builder flexbuild;
3736 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3737 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3738 TEST_ASSERT(!root.AsMap().IsTheEmptyMap());
3739 TEST_ASSERT(root.AsMap()["opt_field"].IsNull());
3740 TEST_EQ(root.ToString(), std::string("{ opt_field: null }"));
3744 void FieldIdentifierTest() {
3745 using flatbuffers::Parser;
3746 TEST_EQ(true, Parser().Parse("table T{ f: int (id:0); }"));
3747 // non-integer `id` should be rejected
3748 TEST_EQ(false, Parser().Parse("table T{ f: int (id:text); }"));
3749 TEST_EQ(false, Parser().Parse("table T{ f: int (id:\"text\"); }"));
3750 TEST_EQ(false, Parser().Parse("table T{ f: int (id:0text); }"));
3751 TEST_EQ(false, Parser().Parse("table T{ f: int (id:1.0); }"));
3752 TEST_EQ(false, Parser().Parse("table T{ f: int (id:-1); g: int (id:0); }"));
3753 TEST_EQ(false, Parser().Parse("table T{ f: int (id:129496726); }"));
3754 // A unuion filed occupys two ids: enumerator + pointer (offset).
3756 Parser().Parse("union X{} table T{ u: X(id:0); table F{x:int;\n}"));
3757 // Positive tests for unions
3758 TEST_EQ(true, Parser().Parse("union X{} table T{ u: X (id:1); }"));
3759 TEST_EQ(true, Parser().Parse("union X{} table T{ u: X; }"));
3762 int FlatBufferTests() {
3765 // Run our various test suites:
3768 auto flatbuf1 = CreateFlatBufferTest(rawbuf);
3769 #if !defined(FLATBUFFERS_CPP98_STL)
3770 auto flatbuf = std::move(flatbuf1); // Test move assignment.
3772 auto &flatbuf = flatbuf1;
3773 #endif // !defined(FLATBUFFERS_CPP98_STL)
3775 TriviallyCopyableTest();
3777 AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
3779 AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
3781 MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
3783 ObjectFlatBuffersTest(flatbuf.data());
3785 MiniReflectFlatBuffersTest(flatbuf.data());
3786 MiniReflectFixedLengthArrayTest();
3790 #ifndef FLATBUFFERS_NO_FILE_TESTS
3791 #ifdef FLATBUFFERS_TEST_PATH_PREFIX
3792 test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
3795 ParseAndGenerateTextTest(false);
3796 ParseAndGenerateTextTest(true);
3797 FixedLengthArrayJsonTest(false);
3798 FixedLengthArrayJsonTest(true);
3799 ReflectionTest(flatbuf.data(), flatbuf.size());
3801 ParseProtoTestWithSuffix();
3802 ParseProtoTestWithIncludes();
3804 UnionDeprecationTest();
3806 LoadVerifyBinaryTest();
3807 GenerateTableTextTest();
3808 TestEmbeddedBinarySchema();
3820 EnumOutOfRangeTest();
3821 IntegerOutOfRangeTest();
3822 IntegerBoundaryTest();
3824 UnicodeTestAllowNonUTF8();
3825 UnicodeTestGenerateTextFailsOnNonUTF8();
3826 UnicodeSurrogatesTest();
3827 UnicodeInvalidSurrogatesTest();
3829 UnknownFieldsTest();
3831 InvalidNestedFlatbufferTest();
3833 ParseProtoBufAsciiTest();
3836 CreateSharedStringTest();
3840 FlexBuffersDeprecatedTest();
3841 UninitializedVectorTest();
3842 EqualOperatorTest();
3847 TestMonsterExtraFloats();
3848 FixedLengthArrayTest();
3850 OptionalScalarsTest();
3851 ParseFlexbuffersFromJsonWithNullTest();
3852 FlatbuffersSpanTest();
3853 FixedLengthArrayConstructorTest();
3854 FieldIdentifierTest();
3858 int main(int /*argc*/, const char * /*argv*/[]) {
3861 std::string req_locale;
3862 if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
3864 TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
3865 req_locale.c_str());
3866 req_locale = flatbuffers::RemoveStringQuotes(req_locale);
3867 std::string the_locale;
3869 flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
3870 TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
3874 FlatBufferBuilderTest();
3876 if (!testing_fails) {
3877 TEST_OUTPUT_LINE("ALL TESTS PASSED");
3879 TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
3881 return CloseTestEngine();