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());
207 // Test vector of enums.
208 Color colors[] = { Color_Blue, Color_Green };
209 // We use this special creation function because we have an array of
210 // pre-C++11 (enum class) enums whose size likely is int, yet its declared
211 // type in the schema is byte.
212 auto vecofcolors = builder.CreateVectorScalarCast<uint8_t, Color>(colors, 2);
214 // shortcut for creating monster with all fields set:
215 auto mloc = CreateMonster(
216 builder, &vec, 150, 80, name, inventory, Color_Blue, Any_Monster,
217 mlocs[1].Union(), // Store a union.
218 testv, vecofstrings, vecoftables, 0, nested_flatbuffer_vector, 0, false,
219 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f, vecofstrings2,
220 vecofstructs, flex, testv2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
221 AnyUniqueAliases_NONE, 0, AnyAmbiguousAliases_NONE, 0, vecofcolors,
222 MyGame::Example::Race_None, 0, vec_of_stats);
224 FinishMonsterBuffer(builder, mloc);
227 #ifdef FLATBUFFERS_TEST_VERBOSE
228 // print byte data for debugging:
229 auto p = builder.GetBufferPointer();
230 for (flatbuffers::uoffset_t i = 0; i < builder.GetSize(); i++)
235 // return the buffer for the caller to use.
237 reinterpret_cast<const char *>(builder.GetBufferPointer());
238 buffer.assign(bufferpointer, bufferpointer + builder.GetSize());
240 return builder.Release();
243 // example of accessing a buffer loaded in memory:
244 void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
245 bool pooled = true) {
246 // First, verify the buffers integrity (optional)
247 flatbuffers::Verifier verifier(flatbuf, length);
248 TEST_EQ(VerifyMonsterBuffer(verifier), true);
251 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
252 std::vector<uint8_t> test_buff;
253 test_buff.resize(length * 2);
254 std::memcpy(&test_buff[0], flatbuf, length);
255 std::memcpy(&test_buff[length], flatbuf, length);
257 flatbuffers::Verifier verifier1(&test_buff[0], length);
258 TEST_EQ(VerifyMonsterBuffer(verifier1), true);
259 TEST_EQ(verifier1.GetComputedSize(), length);
261 flatbuffers::Verifier verifier2(&test_buff[length], length);
262 TEST_EQ(VerifyMonsterBuffer(verifier2), true);
263 TEST_EQ(verifier2.GetComputedSize(), length);
267 TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0);
268 TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true);
269 TEST_EQ(strcmp(MonsterExtension(), "mon"), 0);
271 // Access the buffer from the root.
272 auto monster = GetMonster(flatbuf);
274 TEST_EQ(monster->hp(), 80);
275 TEST_EQ(monster->mana(), 150); // default
276 TEST_EQ_STR(monster->name()->c_str(), "MyMonster");
277 // Can't access the following field, it is deprecated in the schema,
278 // which means accessors are not generated:
279 // monster.friendly()
281 auto pos = monster->pos();
283 TEST_EQ(pos->z(), 3);
284 TEST_EQ(pos->test3().a(), 10);
285 TEST_EQ(pos->test3().b(), 20);
287 auto inventory = monster->inventory();
288 TEST_EQ(VectorLength(inventory), 10UL); // Works even if inventory is null.
289 TEST_NOTNULL(inventory);
290 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
291 // Check compatibilty of iterators with STL.
292 std::vector<unsigned char> inv_vec(inventory->begin(), inventory->end());
294 for (auto it = inventory->begin(); it != inventory->end(); ++it, ++n) {
295 auto indx = it - inventory->begin();
296 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
297 TEST_EQ(*it, inv_data[indx]);
299 TEST_EQ(n, inv_vec.size());
302 for (auto it = inventory->cbegin(); it != inventory->cend(); ++it, ++n) {
303 auto indx = it - inventory->cbegin();
304 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
305 TEST_EQ(*it, inv_data[indx]);
307 TEST_EQ(n, inv_vec.size());
310 for (auto it = inventory->rbegin(); it != inventory->rend(); ++it, ++n) {
311 auto indx = inventory->rend() - it - 1;
312 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
313 TEST_EQ(*it, inv_data[indx]);
315 TEST_EQ(n, inv_vec.size());
318 for (auto it = inventory->crbegin(); it != inventory->crend(); ++it, ++n) {
319 auto indx = inventory->crend() - it - 1;
320 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
321 TEST_EQ(*it, inv_data[indx]);
323 TEST_EQ(n, inv_vec.size());
325 TEST_EQ(monster->color(), Color_Blue);
327 // Example of accessing a union:
328 TEST_EQ(monster->test_type(), Any_Monster); // First make sure which it is.
329 auto monster2 = reinterpret_cast<const Monster *>(monster->test());
330 TEST_NOTNULL(monster2);
331 TEST_EQ_STR(monster2->name()->c_str(), "Fred");
333 // Example of accessing a vector of strings:
334 auto vecofstrings = monster->testarrayofstring();
335 TEST_EQ(vecofstrings->size(), 4U);
336 TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
337 TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
339 // These should have pointer equality because of string pooling.
340 TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
341 TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
344 auto vecofstrings2 = monster->testarrayofstring2();
346 TEST_EQ(vecofstrings2->size(), 2U);
347 TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
348 TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
351 // Example of accessing a vector of tables:
352 auto vecoftables = monster->testarrayoftables();
353 TEST_EQ(vecoftables->size(), 3U);
354 for (auto it = vecoftables->begin(); it != vecoftables->end(); ++it) {
355 TEST_EQ(strlen(it->name()->c_str()) >= 4, true);
357 TEST_EQ_STR(vecoftables->Get(0)->name()->c_str(), "Barney");
358 TEST_EQ(vecoftables->Get(0)->hp(), 1000);
359 TEST_EQ_STR(vecoftables->Get(1)->name()->c_str(), "Fred");
360 TEST_EQ_STR(vecoftables->Get(2)->name()->c_str(), "Wilma");
361 TEST_NOTNULL(vecoftables->LookupByKey("Barney"));
362 TEST_NOTNULL(vecoftables->LookupByKey("Fred"));
363 TEST_NOTNULL(vecoftables->LookupByKey("Wilma"));
365 // Test accessing a vector of sorted structs
366 auto vecofstructs = monster->testarrayofsortedstruct();
367 if (vecofstructs) { // not filled in monster_test.bfbs
368 for (flatbuffers::uoffset_t i = 0; i < vecofstructs->size() - 1; i++) {
369 auto left = vecofstructs->Get(i);
370 auto right = vecofstructs->Get(i + 1);
371 TEST_EQ(true, (left->KeyCompareLessThan(right)));
373 TEST_NOTNULL(vecofstructs->LookupByKey(0)); // test default value
374 TEST_NOTNULL(vecofstructs->LookupByKey(3));
375 TEST_EQ(static_cast<const Ability *>(nullptr),
376 vecofstructs->LookupByKey(5));
379 if (auto vec_of_stat = monster->scalar_key_sorted_tables()) {
380 auto stat_0 = vec_of_stat->LookupByKey(static_cast<uint16_t>(0u));
381 TEST_NOTNULL(stat_0);
382 TEST_NOTNULL(stat_0->id());
383 TEST_EQ(0, stat_0->count());
384 TEST_EQ_STR("miss", stat_0->id()->c_str());
387 // Test nested FlatBuffers if available:
388 auto nested_buffer = monster->testnestedflatbuffer();
390 // nested_buffer is a vector of bytes you can memcpy. However, if you
391 // actually want to access the nested data, this is a convenient
392 // accessor that directly gives you the root table:
393 auto nested_monster = monster->testnestedflatbuffer_nested_root();
394 TEST_EQ_STR(nested_monster->name()->c_str(), "NestedMonster");
397 // Test flexbuffer if available:
398 auto flex = monster->flex();
399 // flex is a vector of bytes you can memcpy etc.
400 TEST_EQ(flex->size(), 4); // Encoded FlexBuffer bytes.
401 // However, if you actually want to access the nested data, this is a
402 // convenient accessor that directly gives you the root value:
403 TEST_EQ(monster->flex_flexbuffer_root().AsInt16(), 1234);
405 // Test vector of enums:
406 auto colors = monster->vector_of_enums();
408 TEST_EQ(colors->size(), 2);
409 TEST_EQ(colors->Get(0), Color_Blue);
410 TEST_EQ(colors->Get(1), Color_Green);
413 // Since Flatbuffers uses explicit mechanisms to override the default
414 // compiler alignment, double check that the compiler indeed obeys them:
415 // (Test consists of a short and byte):
416 TEST_EQ(flatbuffers::AlignOf<Test>(), 2UL);
417 TEST_EQ(sizeof(Test), 4UL);
419 const flatbuffers::Vector<const Test *> *tests_array[] = {
423 for (size_t i = 0; i < sizeof(tests_array) / sizeof(tests_array[0]); ++i) {
424 auto tests = tests_array[i];
426 auto test_0 = tests->Get(0);
427 auto test_1 = tests->Get(1);
428 TEST_EQ(test_0->a(), 10);
429 TEST_EQ(test_0->b(), 20);
430 TEST_EQ(test_1->a(), 30);
431 TEST_EQ(test_1->b(), 40);
432 for (auto it = tests->begin(); it != tests->end(); ++it) {
433 TEST_EQ(it->a() == 10 || it->a() == 30, true); // Just testing iterators.
437 // Checking for presence of fields:
438 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
439 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
441 // Obtaining a buffer from a root:
442 TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
445 // Change a FlatBuffer in-place, after it has been constructed.
446 void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
447 // Get non-const pointer to root.
448 auto monster = GetMutableMonster(flatbuf);
450 // Each of these tests mutates, then tests, then set back to the original,
451 // so we can test that the buffer in the end still passes our original test.
452 auto hp_ok = monster->mutate_hp(10);
453 TEST_EQ(hp_ok, true); // Field was present.
454 TEST_EQ(monster->hp(), 10);
455 // Mutate to default value
456 auto hp_ok_default = monster->mutate_hp(100);
457 TEST_EQ(hp_ok_default, true); // Field was present.
458 TEST_EQ(monster->hp(), 100);
459 // Test that mutate to default above keeps field valid for further mutations
460 auto hp_ok_2 = monster->mutate_hp(20);
461 TEST_EQ(hp_ok_2, true);
462 TEST_EQ(monster->hp(), 20);
463 monster->mutate_hp(80);
465 // Monster originally at 150 mana (default value)
466 auto mana_default_ok = monster->mutate_mana(150); // Mutate to default value.
467 TEST_EQ(mana_default_ok,
468 true); // Mutation should succeed, because default value.
469 TEST_EQ(monster->mana(), 150);
470 auto mana_ok = monster->mutate_mana(10);
471 TEST_EQ(mana_ok, false); // Field was NOT present, because default value.
472 TEST_EQ(monster->mana(), 150);
475 auto pos = monster->mutable_pos();
476 auto test3 = pos->mutable_test3(); // Struct inside a struct.
477 test3.mutate_a(50); // Struct fields never fail.
478 TEST_EQ(test3.a(), 50);
482 auto inventory = monster->mutable_inventory();
483 inventory->Mutate(9, 100);
484 TEST_EQ(inventory->Get(9), 100);
485 inventory->Mutate(9, 9);
487 auto tables = monster->mutable_testarrayoftables();
488 auto first = tables->GetMutableObject(0);
489 TEST_EQ(first->hp(), 1000);
491 TEST_EQ(first->hp(), 0);
492 first->mutate_hp(1000);
494 // Run the verifier and the regular test to make sure we didn't trample on
496 AccessFlatBufferTest(flatbuf, length);
499 // Unpack a FlatBuffer into objects.
500 void ObjectFlatBuffersTest(uint8_t *flatbuf) {
501 // Optional: we can specify resolver and rehasher functions to turn hashed
502 // strings into object pointers and back, to implement remote references
504 auto resolver = flatbuffers::resolver_function_t(
505 [](void **pointer_adr, flatbuffers::hash_value_t hash) {
508 // Don't actually do anything, leave variable null.
510 auto rehasher = flatbuffers::rehasher_function_t(
511 [](void *pointer) -> flatbuffers::hash_value_t {
516 // Turn a buffer into C++ objects.
517 auto monster1 = UnPackMonster(flatbuf, &resolver);
519 // Re-serialize the data.
520 flatbuffers::FlatBufferBuilder fbb1;
521 fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
522 MonsterIdentifier());
524 // Unpack again, and re-serialize again.
525 auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
526 flatbuffers::FlatBufferBuilder fbb2;
527 fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
528 MonsterIdentifier());
530 // Now we've gone full round-trip, the two buffers should match.
531 auto len1 = fbb1.GetSize();
532 auto len2 = fbb2.GetSize();
534 TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), len1), 0);
536 // Test it with the original buffer test to make sure all data survived.
537 AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
539 // Test accessing fields, similar to AccessFlatBufferTest above.
540 TEST_EQ(monster2->hp, 80);
541 TEST_EQ(monster2->mana, 150); // default
542 TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
544 auto &pos = monster2->pos;
546 TEST_EQ(pos->z(), 3);
547 TEST_EQ(pos->test3().a(), 10);
548 TEST_EQ(pos->test3().b(), 20);
550 auto &inventory = monster2->inventory;
551 TEST_EQ(inventory.size(), 10UL);
552 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
553 for (auto it = inventory.begin(); it != inventory.end(); ++it)
554 TEST_EQ(*it, inv_data[it - inventory.begin()]);
556 TEST_EQ(monster2->color, Color_Blue);
558 auto monster3 = monster2->test.AsMonster();
559 TEST_NOTNULL(monster3);
560 TEST_EQ_STR(monster3->name.c_str(), "Fred");
562 auto &vecofstrings = monster2->testarrayofstring;
563 TEST_EQ(vecofstrings.size(), 4U);
564 TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
565 TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
567 auto &vecofstrings2 = monster2->testarrayofstring2;
568 TEST_EQ(vecofstrings2.size(), 2U);
569 TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
570 TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
572 auto &vecoftables = monster2->testarrayoftables;
573 TEST_EQ(vecoftables.size(), 3U);
574 TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
575 TEST_EQ(vecoftables[0]->hp, 1000);
576 TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
577 TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
579 auto &tests = monster2->test4;
580 TEST_EQ(tests[0].a(), 10);
581 TEST_EQ(tests[0].b(), 20);
582 TEST_EQ(tests[1].a(), 30);
583 TEST_EQ(tests[1].b(), 40);
586 // Prefix a FlatBuffer with a size field.
587 void SizePrefixedTest() {
588 // Create size prefixed buffer.
589 flatbuffers::FlatBufferBuilder fbb;
590 FinishSizePrefixedMonsterBuffer(
591 fbb, CreateMonster(fbb, 0, 200, 300, fbb.CreateString("bob")));
594 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
595 TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier), true);
598 auto m = GetSizePrefixedMonster(fbb.GetBufferPointer());
599 TEST_EQ(m->mana(), 200);
600 TEST_EQ(m->hp(), 300);
601 TEST_EQ_STR(m->name()->c_str(), "bob");
604 void TriviallyCopyableTest() {
606 #if __GNUG__ && __GNUC__ < 5
607 TEST_EQ(__has_trivial_copy(Vec3), true);
609 #if __cplusplus >= 201103L
610 TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
616 // Check stringify of an default enum value to json
617 void JsonDefaultTest() {
618 // load FlatBuffer schema (.fbs) from disk
619 std::string schemafile;
620 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
623 // parse schema first, so we can use it to parse the data after
624 flatbuffers::Parser parser;
625 auto include_test_path =
626 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
627 const char *include_directories[] = { test_data_path.c_str(),
628 include_test_path.c_str(), nullptr };
630 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
631 // create incomplete monster and store to json
632 parser.opts.output_default_scalars_in_json = true;
633 parser.opts.output_enum_identifiers = true;
634 flatbuffers::FlatBufferBuilder builder;
635 auto name = builder.CreateString("default_enum");
636 MonsterBuilder color_monster(builder);
637 color_monster.add_name(name);
638 FinishMonsterBuffer(builder, color_monster.Finish());
640 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
641 TEST_EQ(result, true);
642 // default value of the "color" field is Blue
643 TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true);
644 // default value of the "testf" field is 3.14159
645 TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true);
648 void JsonEnumsTest() {
649 // load FlatBuffer schema (.fbs) from disk
650 std::string schemafile;
651 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
654 // parse schema first, so we can use it to parse the data after
655 flatbuffers::Parser parser;
656 auto include_test_path =
657 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
658 const char *include_directories[] = { test_data_path.c_str(),
659 include_test_path.c_str(), nullptr };
660 parser.opts.output_enum_identifiers = true;
661 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
662 flatbuffers::FlatBufferBuilder builder;
663 auto name = builder.CreateString("bitflag_enum");
664 MonsterBuilder color_monster(builder);
665 color_monster.add_name(name);
666 color_monster.add_color(Color(Color_Blue | Color_Red));
667 FinishMonsterBuffer(builder, color_monster.Finish());
669 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
670 TEST_EQ(result, true);
671 TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true);
672 // Test forward compatibility with 'output_enum_identifiers = true'.
673 // Current Color doesn't have '(1u << 2)' field, let's add it.
675 std::string future_json;
676 auto future_name = builder.CreateString("future bitflag_enum");
677 MonsterBuilder future_color(builder);
678 future_color.add_name(future_name);
679 future_color.add_color(
680 static_cast<Color>((1u << 2) | Color_Blue | Color_Red));
681 FinishMonsterBuffer(builder, future_color.Finish());
682 result = GenerateText(parser, builder.GetBufferPointer(), &future_json);
683 TEST_EQ(result, true);
684 TEST_EQ(std::string::npos != future_json.find("color: 13"), true);
687 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
688 // The IEEE-754 quiet_NaN is not simple binary constant.
689 // All binary NaN bit strings have all the bits of the biased exponent field E
690 // set to 1. A quiet NaN bit string should be encoded with the first bit d[1]
691 // of the trailing significand field T being 1 (d[0] is implicit bit).
692 // It is assumed that endianness of floating-point is same as integer.
693 template<typename T, typename U, U qnan_base> bool is_quiet_nan_impl(T v) {
694 static_assert(sizeof(T) == sizeof(U), "unexpected");
696 std::memcpy(&b, &v, sizeof(T));
697 return ((b & qnan_base) == qnan_base);
699 # if defined(__mips__) || defined(__hppa__)
700 static bool is_quiet_nan(float v) {
701 return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v) ||
702 is_quiet_nan_impl<float, uint32_t, 0x7FBFFFFFu>(v);
704 static bool is_quiet_nan(double v) {
705 return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v) ||
706 is_quiet_nan_impl<double, uint64_t, 0x7FF7FFFFFFFFFFFFu>(v);
709 static bool is_quiet_nan(float v) {
710 return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v);
712 static bool is_quiet_nan(double v) {
713 return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v);
717 void TestMonsterExtraFloats() {
718 TEST_EQ(is_quiet_nan(1.0), false);
719 TEST_EQ(is_quiet_nan(infinity_d), false);
720 TEST_EQ(is_quiet_nan(-infinity_f), false);
721 TEST_EQ(is_quiet_nan(std::numeric_limits<float>::quiet_NaN()), true);
722 TEST_EQ(is_quiet_nan(std::numeric_limits<double>::quiet_NaN()), true);
724 using namespace flatbuffers;
725 using namespace MyGame;
726 // Load FlatBuffer schema (.fbs) from disk.
727 std::string schemafile;
728 TEST_EQ(LoadFile((test_data_path + "monster_extra.fbs").c_str(), false,
731 // Parse schema first, so we can use it to parse the data after.
733 auto include_test_path = ConCatPathFileName(test_data_path, "include_test");
734 const char *include_directories[] = { test_data_path.c_str(),
735 include_test_path.c_str(), nullptr };
736 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
737 // Create empty extra and store to json.
738 parser.opts.output_default_scalars_in_json = true;
739 parser.opts.output_enum_identifiers = true;
740 FlatBufferBuilder builder;
741 const auto def_root = MonsterExtraBuilder(builder).Finish();
742 FinishMonsterExtraBuffer(builder, def_root);
743 const auto def_obj = builder.GetBufferPointer();
744 const auto def_extra = GetMonsterExtra(def_obj);
745 TEST_NOTNULL(def_extra);
746 TEST_EQ(is_quiet_nan(def_extra->f0()), true);
747 TEST_EQ(is_quiet_nan(def_extra->f1()), true);
748 TEST_EQ(def_extra->f2(), +infinity_f);
749 TEST_EQ(def_extra->f3(), -infinity_f);
750 TEST_EQ(is_quiet_nan(def_extra->d0()), true);
751 TEST_EQ(is_quiet_nan(def_extra->d1()), true);
752 TEST_EQ(def_extra->d2(), +infinity_d);
753 TEST_EQ(def_extra->d3(), -infinity_d);
755 auto result = GenerateText(parser, def_obj, &jsongen);
756 TEST_EQ(result, true);
757 // Check expected default values.
758 TEST_EQ(std::string::npos != jsongen.find("f0: nan"), true);
759 TEST_EQ(std::string::npos != jsongen.find("f1: nan"), true);
760 TEST_EQ(std::string::npos != jsongen.find("f2: inf"), true);
761 TEST_EQ(std::string::npos != jsongen.find("f3: -inf"), true);
762 TEST_EQ(std::string::npos != jsongen.find("d0: nan"), true);
763 TEST_EQ(std::string::npos != jsongen.find("d1: nan"), true);
764 TEST_EQ(std::string::npos != jsongen.find("d2: inf"), true);
765 TEST_EQ(std::string::npos != jsongen.find("d3: -inf"), true);
766 // Parse 'mosterdata_extra.json'.
767 const auto extra_base = test_data_path + "monsterdata_extra";
769 TEST_EQ(LoadFile((extra_base + ".json").c_str(), false, &jsongen), true);
770 TEST_EQ(parser.Parse(jsongen.c_str()), true);
771 const auto test_file = parser.builder_.GetBufferPointer();
772 const auto test_size = parser.builder_.GetSize();
773 Verifier verifier(test_file, test_size);
774 TEST_ASSERT(VerifyMonsterExtraBuffer(verifier));
775 const auto extra = GetMonsterExtra(test_file);
777 TEST_EQ(is_quiet_nan(extra->f0()), true);
778 TEST_EQ(is_quiet_nan(extra->f1()), true);
779 TEST_EQ(extra->f2(), +infinity_f);
780 TEST_EQ(extra->f3(), -infinity_f);
781 TEST_EQ(is_quiet_nan(extra->d0()), true);
782 TEST_EQ(extra->d1(), +infinity_d);
783 TEST_EQ(extra->d2(), -infinity_d);
784 TEST_EQ(is_quiet_nan(extra->d3()), true);
785 TEST_NOTNULL(extra->fvec());
786 TEST_EQ(extra->fvec()->size(), 4);
787 TEST_EQ(extra->fvec()->Get(0), 1.0f);
788 TEST_EQ(extra->fvec()->Get(1), -infinity_f);
789 TEST_EQ(extra->fvec()->Get(2), +infinity_f);
790 TEST_EQ(is_quiet_nan(extra->fvec()->Get(3)), true);
791 TEST_NOTNULL(extra->dvec());
792 TEST_EQ(extra->dvec()->size(), 4);
793 TEST_EQ(extra->dvec()->Get(0), 2.0);
794 TEST_EQ(extra->dvec()->Get(1), +infinity_d);
795 TEST_EQ(extra->dvec()->Get(2), -infinity_d);
796 TEST_EQ(is_quiet_nan(extra->dvec()->Get(3)), true);
799 void TestMonsterExtraFloats() {}
802 // example of parsing text straight into a buffer, and generating
803 // text back from it:
804 void ParseAndGenerateTextTest(bool binary) {
805 // load FlatBuffer schema (.fbs) and JSON from disk
806 std::string schemafile;
807 std::string jsonfile;
808 TEST_EQ(flatbuffers::LoadFile(
809 (test_data_path + "monster_test." + (binary ? "bfbs" : "fbs"))
811 binary, &schemafile),
813 TEST_EQ(flatbuffers::LoadFile(
814 (test_data_path + "monsterdata_test.golden").c_str(), false,
818 auto include_test_path =
819 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
820 const char *include_directories[] = { test_data_path.c_str(),
821 include_test_path.c_str(), nullptr };
823 // parse schema first, so we can use it to parse the data after
824 flatbuffers::Parser parser;
826 flatbuffers::Verifier verifier(
827 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
829 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
830 // auto schema = reflection::GetSchema(schemafile.c_str());
831 TEST_EQ(parser.Deserialize((const uint8_t *)schemafile.c_str(),
835 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
837 TEST_EQ(parser.ParseJson(jsonfile.c_str()), true);
839 // here, parser.builder_ contains a binary buffer that is the parsed data.
841 // First, verify it, just in case:
842 flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
843 parser.builder_.GetSize());
844 TEST_EQ(VerifyMonsterBuffer(verifier), true);
846 AccessFlatBufferTest(parser.builder_.GetBufferPointer(),
847 parser.builder_.GetSize(), false);
849 // to ensure it is correct, we now generate text back from the binary,
850 // and compare the two:
853 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
854 TEST_EQ(result, true);
855 TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
857 // We can also do the above using the convenient Registry that knows about
858 // a set of file_identifiers mapped to schemas.
859 flatbuffers::Registry registry;
860 // Make sure schemas can find their includes.
861 registry.AddIncludeDirectory(test_data_path.c_str());
862 registry.AddIncludeDirectory(include_test_path.c_str());
863 // Call this with many schemas if possible.
864 registry.Register(MonsterIdentifier(),
865 (test_data_path + "monster_test.fbs").c_str());
866 // Now we got this set up, we can parse by just specifying the identifier,
867 // the correct schema will be loaded on the fly:
868 auto buf = registry.TextToFlatBuffer(jsonfile.c_str(), MonsterIdentifier());
869 // If this fails, check registry.lasterror_.
870 TEST_NOTNULL(buf.data());
871 // Test the buffer, to be sure:
872 AccessFlatBufferTest(buf.data(), buf.size(), false);
873 // We can use the registry to turn this back into text, in this case it
874 // will get the file_identifier from the binary:
876 auto ok = registry.FlatBufferToText(buf.data(), buf.size(), &text);
877 // If this fails, check registry.lasterror_.
879 TEST_EQ_STR(text.c_str(), jsonfile.c_str());
881 // Generate text for UTF-8 strings without escapes.
882 std::string jsonfile_utf8;
883 TEST_EQ(flatbuffers::LoadFile((test_data_path + "unicode_test.json").c_str(),
884 false, &jsonfile_utf8),
886 TEST_EQ(parser.Parse(jsonfile_utf8.c_str(), include_directories), true);
887 // To ensure it is correct, generate utf-8 text back from the binary.
888 std::string jsongen_utf8;
889 // request natural printing for utf-8 strings
890 parser.opts.natural_utf8 = true;
891 parser.opts.strict_json = true;
893 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen_utf8),
895 TEST_EQ_STR(jsongen_utf8.c_str(), jsonfile_utf8.c_str());
898 void ReflectionTest(uint8_t *flatbuf, size_t length) {
899 // Load a binary schema.
900 std::string bfbsfile;
901 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.bfbs").c_str(),
905 // Verify it, just in case:
906 flatbuffers::Verifier verifier(
907 reinterpret_cast<const uint8_t *>(bfbsfile.c_str()), bfbsfile.length());
908 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
910 // Make sure the schema is what we expect it to be.
911 auto &schema = *reflection::GetSchema(bfbsfile.c_str());
912 auto root_table = schema.root_table();
913 TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
914 auto fields = root_table->fields();
915 auto hp_field_ptr = fields->LookupByKey("hp");
916 TEST_NOTNULL(hp_field_ptr);
917 auto &hp_field = *hp_field_ptr;
918 TEST_EQ_STR(hp_field.name()->c_str(), "hp");
919 TEST_EQ(hp_field.id(), 2);
920 TEST_EQ(hp_field.type()->base_type(), reflection::Short);
922 auto friendly_field_ptr = fields->LookupByKey("friendly");
923 TEST_NOTNULL(friendly_field_ptr);
924 TEST_NOTNULL(friendly_field_ptr->attributes());
925 TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
927 // Make sure the table index is what we expect it to be.
928 auto pos_field_ptr = fields->LookupByKey("pos");
929 TEST_NOTNULL(pos_field_ptr);
930 TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
931 auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
932 TEST_NOTNULL(pos_table_ptr);
933 TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
935 // Test nullability of fields: hp is a 0-default scalar, pos is a struct =>
936 // optional, and name is a required string => not optional.
937 TEST_EQ(hp_field.optional(), false);
938 TEST_EQ(pos_field_ptr->optional(), true);
939 TEST_EQ(fields->LookupByKey("name")->optional(), false);
941 // Now use it to dynamically access a buffer.
942 auto &root = *flatbuffers::GetAnyRoot(flatbuf);
944 // Verify the buffer first using reflection based verification
945 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
948 auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
951 // Rather than needing to know the type, we can also get the value of
952 // any field as an int64_t/double/string, regardless of what it actually is.
953 auto hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
954 TEST_EQ(hp_int64, 80);
955 auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
956 TEST_EQ(hp_double, 80.0);
957 auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
958 TEST_EQ_STR(hp_string.c_str(), "80");
960 // Get struct field through reflection
961 auto pos_struct = flatbuffers::GetFieldStruct(root, *pos_field_ptr);
962 TEST_NOTNULL(pos_struct);
963 TEST_EQ(flatbuffers::GetAnyFieldF(*pos_struct,
964 *pos_table_ptr->fields()->LookupByKey("z")),
967 auto test3_field = pos_table_ptr->fields()->LookupByKey("test3");
968 auto test3_struct = flatbuffers::GetFieldStruct(*pos_struct, *test3_field);
969 TEST_NOTNULL(test3_struct);
970 auto test3_object = schema.objects()->Get(test3_field->type()->index());
972 TEST_EQ(flatbuffers::GetAnyFieldF(*test3_struct,
973 *test3_object->fields()->LookupByKey("a")),
976 // We can also modify it.
977 flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
978 hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
981 // We can also set fields generically:
982 flatbuffers::SetAnyFieldI(&root, hp_field, 300);
983 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
984 TEST_EQ(hp_int64, 300);
985 flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
986 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
987 TEST_EQ(hp_int64, 300);
988 flatbuffers::SetAnyFieldS(&root, hp_field, "300");
989 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
990 TEST_EQ(hp_int64, 300);
992 // Test buffer is valid after the modifications
993 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
996 // Reset it, for further tests.
997 flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
999 // More advanced functionality: changing the size of items in-line!
1000 // First we put the FlatBuffer inside an std::vector.
1001 std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
1002 // Find the field we want to modify.
1003 auto &name_field = *fields->LookupByKey("name");
1005 // This time we wrap the result from GetAnyRoot in a smartpointer that
1006 // will keep rroot valid as resizingbuf resizes.
1007 auto rroot = flatbuffers::piv(
1008 flatbuffers::GetAnyRoot(flatbuffers::vector_data(resizingbuf)),
1010 SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
1012 // Here resizingbuf has changed, but rroot is still valid.
1013 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
1014 // Now lets extend a vector by 100 elements (10 -> 110).
1015 auto &inventory_field = *fields->LookupByKey("inventory");
1016 auto rinventory = flatbuffers::piv(
1017 flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field), resizingbuf);
1018 flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
1020 // rinventory still valid, so lets read from it.
1021 TEST_EQ(rinventory->Get(10), 50);
1023 // For reflection uses not covered already, there is a more powerful way:
1024 // we can simply generate whatever object we want to add/modify in a
1025 // FlatBuffer of its own, then add that to an existing FlatBuffer:
1026 // As an example, let's add a string to an array of strings.
1027 // First, find our field:
1028 auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
1029 // Find the vector value:
1030 auto rtestarrayofstring = flatbuffers::piv(
1031 flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
1032 **rroot, testarrayofstring_field),
1034 // It's a vector of 2 strings, to which we add one more, initialized to
1036 flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
1037 schema, 3, 0, *rtestarrayofstring, &resizingbuf);
1038 // Here we just create a buffer that contans a single string, but this
1039 // could also be any complex set of tables and other values.
1040 flatbuffers::FlatBufferBuilder stringfbb;
1041 stringfbb.Finish(stringfbb.CreateString("hank"));
1042 // Add the contents of it to our existing FlatBuffer.
1043 // We do this last, so the pointer doesn't get invalidated (since it is
1044 // at the end of the buffer):
1045 auto string_ptr = flatbuffers::AddFlatBuffer(
1046 resizingbuf, stringfbb.GetBufferPointer(), stringfbb.GetSize());
1047 // Finally, set the new value in the vector.
1048 rtestarrayofstring->MutateOffset(2, string_ptr);
1049 TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
1050 TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
1051 // Test integrity of all resize operations above.
1052 flatbuffers::Verifier resize_verifier(
1053 reinterpret_cast<const uint8_t *>(flatbuffers::vector_data(resizingbuf)),
1054 resizingbuf.size());
1055 TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
1057 // Test buffer is valid using reflection as well
1058 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1059 flatbuffers::vector_data(resizingbuf),
1060 resizingbuf.size()),
1063 // As an additional test, also set it on the name field.
1064 // Note: unlike the name change above, this just overwrites the offset,
1065 // rather than changing the string in-place.
1066 SetFieldT(*rroot, name_field, string_ptr);
1067 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
1069 // Using reflection, rather than mutating binary FlatBuffers, we can also copy
1070 // tables and other things out of other FlatBuffers into a FlatBufferBuilder,
1071 // either part or whole.
1072 flatbuffers::FlatBufferBuilder fbb;
1073 auto root_offset = flatbuffers::CopyTable(
1074 fbb, schema, *root_table, *flatbuffers::GetAnyRoot(flatbuf), true);
1075 fbb.Finish(root_offset, MonsterIdentifier());
1076 // Test that it was copied correctly:
1077 AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
1079 // Test buffer is valid using reflection as well
1080 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1081 fbb.GetBufferPointer(), fbb.GetSize()),
1085 void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
1087 flatbuffers::FlatBufferToString(flatbuf, Monster::MiniReflectTypeTable());
1091 "pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
1092 "{ a: 10, b: 20 } }, "
1094 "name: \"MyMonster\", "
1095 "inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
1096 "test_type: Monster, "
1097 "test: { name: \"Fred\" }, "
1098 "test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1099 "testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
1100 "testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" "
1102 "{ name: \"Wilma\" } ], "
1103 // TODO(wvo): should really print this nested buffer correctly.
1104 "testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, "
1106 "4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
1107 "101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
1108 "testarrayofstring2: [ \"jane\", \"mary\" ], "
1109 "testarrayofsortedstruct: [ { id: 0, distance: 0 }, "
1110 "{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
1111 "{ id: 4, distance: 40 } ], "
1112 "flex: [ 210, 4, 5, 2 ], "
1113 "test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1114 "vector_of_enums: [ Blue, Green ], "
1115 "scalar_key_sorted_tables: [ { id: \"miss\" } ] "
1119 Vec3 vec(1, 2, 3, 1.5, Color_Red, test);
1120 flatbuffers::FlatBufferBuilder vec_builder;
1121 vec_builder.Finish(vec_builder.CreateStruct(vec));
1122 auto vec_buffer = vec_builder.Release();
1123 auto vec_str = flatbuffers::FlatBufferToString(vec_buffer.data(),
1124 Vec3::MiniReflectTypeTable());
1125 TEST_EQ_STR(vec_str.c_str(),
1126 "{ x: 1.0, y: 2.0, z: 3.0, test1: 1.5, test2: Red, test3: { a: "
1130 void MiniReflectFixedLengthArrayTest() {
1131 // VS10 does not support typed enums, exclude from tests
1132 #if !defined(_MSC_VER) || _MSC_VER >= 1700
1133 flatbuffers::FlatBufferBuilder fbb;
1134 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
1135 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
1138 auto flatbuf = fbb.Release();
1139 auto s = flatbuffers::FlatBufferToString(
1140 flatbuf.data(), MyGame::Example::ArrayTableTypeTable());
1144 "b: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "
1146 "d: [ { a: [ 0, 0 ], b: A, c: [ A, A ], d: [ 0, 0 ] }, "
1147 "{ a: [ 0, 0 ], b: A, c: [ A, A ], d: [ 0, 0 ] } ], "
1148 "e: 1, f: [ 0, 0 ] } "
1154 // Parse a .proto schema, output as .fbs
1155 void ParseProtoTest() {
1156 // load the .proto and the golden file from disk
1157 std::string protofile;
1158 std::string goldenfile;
1159 std::string goldenunionfile;
1161 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1165 flatbuffers::LoadFile((test_data_path + "prototest/test.golden").c_str(),
1166 false, &goldenfile),
1168 TEST_EQ(flatbuffers::LoadFile(
1169 (test_data_path + "prototest/test_union.golden").c_str(), false,
1173 flatbuffers::IDLOptions opts;
1174 opts.include_dependence_headers = false;
1175 opts.proto_mode = true;
1178 flatbuffers::Parser parser(opts);
1179 auto protopath = test_data_path + "prototest/";
1180 const char *include_directories[] = { protopath.c_str(), nullptr };
1181 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1184 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1186 // Ensure generated file is parsable.
1187 flatbuffers::Parser parser2;
1188 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1189 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1191 // Parse proto with --oneof-union option.
1192 opts.proto_oneof_union = true;
1193 flatbuffers::Parser parser3(opts);
1194 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1197 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1199 // Ensure generated file is parsable.
1200 flatbuffers::Parser parser4;
1201 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1202 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1205 // Parse a .proto schema, output as .fbs
1206 void ParseProtoTestWithSuffix() {
1207 // load the .proto and the golden file from disk
1208 std::string protofile;
1209 std::string goldenfile;
1210 std::string goldenunionfile;
1212 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1215 TEST_EQ(flatbuffers::LoadFile(
1216 (test_data_path + "prototest/test_suffix.golden").c_str(), false,
1219 TEST_EQ(flatbuffers::LoadFile(
1220 (test_data_path + "prototest/test_union_suffix.golden").c_str(),
1221 false, &goldenunionfile),
1224 flatbuffers::IDLOptions opts;
1225 opts.include_dependence_headers = false;
1226 opts.proto_mode = true;
1227 opts.proto_namespace_suffix = "test_namespace_suffix";
1230 flatbuffers::Parser parser(opts);
1231 auto protopath = test_data_path + "prototest/";
1232 const char *include_directories[] = { protopath.c_str(), nullptr };
1233 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1236 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1238 // Ensure generated file is parsable.
1239 flatbuffers::Parser parser2;
1240 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1241 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1243 // Parse proto with --oneof-union option.
1244 opts.proto_oneof_union = true;
1245 flatbuffers::Parser parser3(opts);
1246 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1249 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1251 // Ensure generated file is parsable.
1252 flatbuffers::Parser parser4;
1253 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1254 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1257 // Parse a .proto schema, output as .fbs
1258 void ParseProtoTestWithIncludes() {
1259 // load the .proto and the golden file from disk
1260 std::string protofile;
1261 std::string goldenfile;
1262 std::string goldenunionfile;
1263 std::string importprotofile;
1265 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1268 TEST_EQ(flatbuffers::LoadFile(
1269 (test_data_path + "prototest/imported.proto").c_str(), false,
1272 TEST_EQ(flatbuffers::LoadFile(
1273 (test_data_path + "prototest/test_include.golden").c_str(), false,
1276 TEST_EQ(flatbuffers::LoadFile(
1277 (test_data_path + "prototest/test_union_include.golden").c_str(),
1278 false, &goldenunionfile),
1281 flatbuffers::IDLOptions opts;
1282 opts.include_dependence_headers = true;
1283 opts.proto_mode = true;
1286 flatbuffers::Parser parser(opts);
1287 auto protopath = test_data_path + "prototest/";
1288 const char *include_directories[] = { protopath.c_str(), nullptr };
1289 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1292 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1294 // Generate fbs from import.proto
1295 flatbuffers::Parser import_parser(opts);
1296 TEST_EQ(import_parser.Parse(importprotofile.c_str(), include_directories),
1298 auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test");
1300 // Ensure generated file is parsable.
1301 flatbuffers::Parser parser2;
1303 parser2.Parse(import_fbs.c_str(), include_directories, "imported.fbs"),
1305 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1306 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1308 // Parse proto with --oneof-union option.
1309 opts.proto_oneof_union = true;
1310 flatbuffers::Parser parser3(opts);
1311 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1314 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1316 // Ensure generated file is parsable.
1317 flatbuffers::Parser parser4;
1318 TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, "imported.fbs"), true);
1319 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1320 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1323 template<typename T>
1324 void CompareTableFieldValue(flatbuffers::Table *table,
1325 flatbuffers::voffset_t voffset, T val) {
1326 T read = table->GetField(voffset, static_cast<T>(0));
1330 // Low level stress/fuzz test: serialize/deserialize a variety of
1331 // different kinds of data in different combinations
1333 // Values we're testing against: chosen to ensure no bits get chopped
1334 // off anywhere, and also be different from eachother.
1335 const uint8_t bool_val = true;
1336 const int8_t char_val = -127; // 0x81
1337 const uint8_t uchar_val = 0xFF;
1338 const int16_t short_val = -32222; // 0x8222;
1339 const uint16_t ushort_val = 0xFEEE;
1340 const int32_t int_val = 0x83333333;
1341 const uint32_t uint_val = 0xFDDDDDDD;
1342 const int64_t long_val = 0x8444444444444444LL;
1343 const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
1344 const float float_val = 3.14159f;
1345 const double double_val = 3.14159265359;
1347 const int test_values_max = 11;
1348 const flatbuffers::voffset_t fields_per_object = 4;
1349 const int num_fuzz_objects = 10000; // The higher, the more thorough :)
1351 flatbuffers::FlatBufferBuilder builder;
1353 lcg_reset(); // Keep it deterministic.
1355 flatbuffers::uoffset_t objects[num_fuzz_objects];
1357 // Generate num_fuzz_objects random objects each consisting of
1358 // fields_per_object fields, each of a random type.
1359 for (int i = 0; i < num_fuzz_objects; i++) {
1360 auto start = builder.StartTable();
1361 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1362 int choice = lcg_rand() % test_values_max;
1363 auto off = flatbuffers::FieldIndexToOffset(f);
1365 case 0: builder.AddElement<uint8_t>(off, bool_val, 0); break;
1366 case 1: builder.AddElement<int8_t>(off, char_val, 0); break;
1367 case 2: builder.AddElement<uint8_t>(off, uchar_val, 0); break;
1368 case 3: builder.AddElement<int16_t>(off, short_val, 0); break;
1369 case 4: builder.AddElement<uint16_t>(off, ushort_val, 0); break;
1370 case 5: builder.AddElement<int32_t>(off, int_val, 0); break;
1371 case 6: builder.AddElement<uint32_t>(off, uint_val, 0); break;
1372 case 7: builder.AddElement<int64_t>(off, long_val, 0); break;
1373 case 8: builder.AddElement<uint64_t>(off, ulong_val, 0); break;
1374 case 9: builder.AddElement<float>(off, float_val, 0); break;
1375 case 10: builder.AddElement<double>(off, double_val, 0); break;
1378 objects[i] = builder.EndTable(start);
1380 builder.PreAlign<flatbuffers::largest_scalar_t>(0); // Align whole buffer.
1382 lcg_reset(); // Reset.
1384 uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
1386 // Test that all objects we generated are readable and return the
1387 // expected values. We generate random objects in the same order
1388 // so this is deterministic.
1389 for (int i = 0; i < num_fuzz_objects; i++) {
1390 auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
1391 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1392 int choice = lcg_rand() % test_values_max;
1393 flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
1395 case 0: CompareTableFieldValue(table, off, bool_val); break;
1396 case 1: CompareTableFieldValue(table, off, char_val); break;
1397 case 2: CompareTableFieldValue(table, off, uchar_val); break;
1398 case 3: CompareTableFieldValue(table, off, short_val); break;
1399 case 4: CompareTableFieldValue(table, off, ushort_val); break;
1400 case 5: CompareTableFieldValue(table, off, int_val); break;
1401 case 6: CompareTableFieldValue(table, off, uint_val); break;
1402 case 7: CompareTableFieldValue(table, off, long_val); break;
1403 case 8: CompareTableFieldValue(table, off, ulong_val); break;
1404 case 9: CompareTableFieldValue(table, off, float_val); break;
1405 case 10: CompareTableFieldValue(table, off, double_val); break;
1411 // High level stress/fuzz test: generate a big schema and
1412 // matching json data in random combinations, then parse both,
1413 // generate json back from the binary, and compare with the original.
1415 lcg_reset(); // Keep it deterministic.
1417 const int num_definitions = 30;
1418 const int num_struct_definitions = 5; // Subset of num_definitions.
1419 const int fields_per_definition = 15;
1420 const int instances_per_definition = 5;
1421 const int deprecation_rate = 10; // 1 in deprecation_rate fields will
1424 std::string schema = "namespace test;\n\n";
1427 std::string instances[instances_per_definition];
1429 // Since we're generating schema and corresponding data in tandem,
1430 // this convenience function adds strings to both at once.
1431 static void Add(RndDef (&definitions_l)[num_definitions],
1432 std::string &schema_l, const int instances_per_definition_l,
1433 const char *schema_add, const char *instance_add,
1435 schema_l += schema_add;
1436 for (int i = 0; i < instances_per_definition_l; i++)
1437 definitions_l[definition].instances[i] += instance_add;
1442 #define AddToSchemaAndInstances(schema_add, instance_add) \
1443 RndDef::Add(definitions, schema, instances_per_definition, \
1444 schema_add, instance_add, definition)
1447 RndDef::Add(definitions, schema, instances_per_definition, \
1448 "byte", "1", definition)
1451 RndDef definitions[num_definitions];
1453 // We are going to generate num_definitions, the first
1454 // num_struct_definitions will be structs, the rest tables. For each
1455 // generate random fields, some of which may be struct/table types
1456 // referring to previously generated structs/tables.
1457 // Simultanenously, we generate instances_per_definition JSON data
1458 // definitions, which will have identical structure to the schema
1459 // being generated. We generate multiple instances such that when creating
1460 // hierarchy, we get some variety by picking one randomly.
1461 for (int definition = 0; definition < num_definitions; definition++) {
1462 std::string definition_name = "D" + flatbuffers::NumToString(definition);
1464 bool is_struct = definition < num_struct_definitions;
1466 AddToSchemaAndInstances(
1467 ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
1470 for (int field = 0; field < fields_per_definition; field++) {
1471 const bool is_last_field = field == fields_per_definition - 1;
1473 // Deprecate 1 in deprecation_rate fields. Only table fields can be
1475 // Don't deprecate the last field to avoid dangling commas in JSON.
1476 const bool deprecated =
1477 !is_struct && !is_last_field && (lcg_rand() % deprecation_rate == 0);
1479 std::string field_name = "f" + flatbuffers::NumToString(field);
1480 AddToSchemaAndInstances((" " + field_name + ":").c_str(),
1481 deprecated ? "" : (field_name + ": ").c_str());
1482 // Pick random type:
1483 auto base_type = static_cast<flatbuffers::BaseType>(
1484 lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
1485 switch (base_type) {
1486 case flatbuffers::BASE_TYPE_STRING:
1488 Dummy(); // No strings in structs.
1490 AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
1493 case flatbuffers::BASE_TYPE_VECTOR:
1495 Dummy(); // No vectors in structs.
1497 AddToSchemaAndInstances("[ubyte]",
1498 deprecated ? "" : "[\n0,\n1,\n255\n]");
1501 case flatbuffers::BASE_TYPE_NONE:
1502 case flatbuffers::BASE_TYPE_UTYPE:
1503 case flatbuffers::BASE_TYPE_STRUCT:
1504 case flatbuffers::BASE_TYPE_UNION:
1506 // Pick a random previous definition and random data instance of
1508 int defref = lcg_rand() % definition;
1509 int instance = lcg_rand() % instances_per_definition;
1510 AddToSchemaAndInstances(
1511 ("D" + flatbuffers::NumToString(defref)).c_str(),
1513 : definitions[defref].instances[instance].c_str());
1515 // If this is the first definition, we have no definition we can
1520 case flatbuffers::BASE_TYPE_BOOL:
1521 AddToSchemaAndInstances(
1522 "bool", deprecated ? "" : (lcg_rand() % 2 ? "true" : "false"));
1524 case flatbuffers::BASE_TYPE_ARRAY:
1526 AddToSchemaAndInstances(
1528 deprecated ? "" : "255"); // No fixed-length arrays in tables.
1530 AddToSchemaAndInstances("[int:3]", deprecated ? "" : "[\n,\n,\n]");
1534 // All the scalar types.
1535 schema += flatbuffers::kTypeNames[base_type];
1538 // We want each instance to use its own random value.
1539 for (int inst = 0; inst < instances_per_definition; inst++)
1540 definitions[definition].instances[inst] +=
1541 flatbuffers::IsFloat(base_type)
1542 ? flatbuffers::NumToString<double>(lcg_rand() % 128)
1544 : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
1547 AddToSchemaAndInstances(deprecated ? "(deprecated);\n" : ";\n",
1548 deprecated ? "" : is_last_field ? "\n" : ",\n");
1550 AddToSchemaAndInstances("}\n\n", "}");
1553 schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
1556 flatbuffers::Parser parser;
1558 // Will not compare against the original if we don't write defaults
1559 parser.builder_.ForceDefaults(true);
1561 // Parse the schema, parse the generated data, then generate text back
1562 // from the binary and compare against the original.
1563 TEST_EQ(parser.Parse(schema.c_str()), true);
1565 const std::string &json =
1566 definitions[num_definitions - 1].instances[0] + "\n";
1568 TEST_EQ(parser.Parse(json.c_str()), true);
1570 std::string jsongen;
1571 parser.opts.indent_step = 0;
1573 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
1574 TEST_EQ(result, true);
1576 if (jsongen != json) {
1577 // These strings are larger than a megabyte, so we show the bytes around
1578 // the first bytes that are different rather than the whole string.
1579 size_t len = std::min(json.length(), jsongen.length());
1580 for (size_t i = 0; i < len; i++) {
1581 if (json[i] != jsongen[i]) {
1582 i -= std::min(static_cast<size_t>(10), i); // show some context;
1583 size_t end = std::min(len, i + 20);
1584 for (; i < end; i++)
1585 TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
1586 static_cast<int>(i), jsongen[i], json[i]);
1590 TEST_NOTNULL(nullptr); //-V501 (this comment supresses CWE-570 warning)
1594 #ifdef FLATBUFFERS_TEST_VERBOSE
1595 TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
1596 static_cast<int>(schema.length() / 1024),
1597 static_cast<int>(json.length() / 1024));
1602 // Test that parser errors are actually generated.
1603 void TestError_(const char *src, const char *error_substr, bool strict_json,
1604 const char *file, int line, const char *func) {
1605 flatbuffers::IDLOptions opts;
1606 opts.strict_json = strict_json;
1607 flatbuffers::Parser parser(opts);
1608 if (parser.Parse(src)) {
1609 TestFail("true", "false",
1610 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1612 } else if (!strstr(parser.error_.c_str(), error_substr)) {
1613 TestFail(error_substr, parser.error_.c_str(),
1614 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1619 void TestError_(const char *src, const char *error_substr, const char *file,
1620 int line, const char *func) {
1621 TestError_(src, error_substr, false, file, line, func);
1625 # define TestError(src, ...) \
1626 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
1628 # define TestError(src, ...) \
1629 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1632 // Test that parsing errors occur as we'd expect.
1633 // Also useful for coverage, making sure these paths are run.
1635 // In order they appear in idl_parser.cpp
1636 TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
1637 TestError("\"\0", "illegal");
1638 TestError("\"\\q", "escape code");
1639 TestError("table ///", "documentation");
1640 TestError("@", "illegal");
1641 TestError("table 1", "expecting");
1642 TestError("table X { Y:[[int]]; }", "nested vector");
1643 TestError("table X { Y:1; }", "illegal type");
1644 TestError("table X { Y:int; Y:int; }", "field already");
1645 TestError("table Y {} table X { Y:int; }", "same as table");
1646 TestError("struct X { Y:string; }", "only scalar");
1647 TestError("struct X { a:uint = 42; }", "default values");
1648 TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
1649 TestError("struct X { Y:int (deprecated); }", "deprecate");
1650 TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
1651 "missing type field");
1652 TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
1654 TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
1655 TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
1656 TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
1659 "struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
1662 TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
1663 "unknown enum value");
1664 TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
1665 TestError("enum X:byte { Y } enum X {", "enum already");
1666 TestError("enum X:float {}", "underlying");
1667 TestError("enum X:byte { Y, Y }", "value already");
1668 TestError("enum X:byte { Y=2, Z=2 }", "unique");
1669 TestError("table X { Y:int; } table X {", "datatype already");
1670 TestError("struct X (force_align: 7) { Y:int; }", "force_align");
1671 TestError("struct X {}", "size 0");
1672 TestError("{}", "no root");
1673 TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
1674 TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
1676 TestError("root_type X;", "unknown root");
1677 TestError("struct X { Y:int; } root_type X;", "a table");
1678 TestError("union X { Y }", "referenced");
1679 TestError("union Z { X } struct X { Y:int; }", "only tables");
1680 TestError("table X { Y:[int]; YLength:int; }", "clash");
1681 TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
1682 // float to integer conversion is forbidden
1683 TestError("table X { Y:int; } root_type X; { Y:1.0 }", "float");
1684 TestError("table X { Y:bool; } root_type X; { Y:1.0 }", "float");
1685 TestError("enum X:bool { Y = true }", "must be integral");
1686 // Array of non-scalar
1687 TestError("table X { x:int; } struct Y { y:[X:2]; }",
1688 "may contain only scalar or struct fields");
1689 // Non-snake case field names
1690 TestError("table X { Y: int; } root_type Y: {Y:1.0}", "snake_case");
1692 TestError("table X { y: string = 1; }", "expecting: string");
1693 TestError("table X { y: string = []; }", " Cannot assign token");
1694 TestError("table X { y: [int] = [1]; }", "Expected `]`");
1695 TestError("table X { y: [int] = [; }", "Expected `]`");
1696 TestError("table X { y: [int] = \"\"; }", "type mismatch");
1697 // An identifier can't start from sign (+|-)
1698 TestError("table X { -Y: int; } root_type Y: {Y:1.0}", "identifier");
1699 TestError("table X { +Y: int; } root_type Y: {Y:1.0}", "identifier");
1702 template<typename T>
1703 T TestValue(const char *json, const char *type_name,
1704 const char *decls = nullptr) {
1705 flatbuffers::Parser parser;
1706 parser.builder_.ForceDefaults(true); // return defaults
1707 auto check_default = json ? false : true;
1708 if (check_default) { parser.opts.output_default_scalars_in_json = true; }
1710 std::string schema = std::string(decls ? decls : "") + "\n" +
1711 "table X { y:" + std::string(type_name) +
1713 auto schema_done = parser.Parse(schema.c_str());
1714 TEST_EQ_STR(parser.error_.c_str(), "");
1715 TEST_EQ(schema_done, true);
1717 auto done = parser.Parse(check_default ? "{}" : json);
1718 TEST_EQ_STR(parser.error_.c_str(), "");
1719 TEST_EQ(done, true);
1721 // Check with print.
1722 std::string print_back;
1723 parser.opts.indent_step = -1;
1724 TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back),
1726 // restore value from its default
1727 if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); }
1729 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
1730 parser.builder_.GetBufferPointer());
1731 return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
1734 bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
1736 // Additional parser testing not covered elsewhere.
1738 // Test scientific notation numbers.
1740 FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
1743 TEST_EQ(FloatCompare(TestValue<float>("{ y:\"0.0314159e+2\" }", "float"),
1747 // Test conversion functions.
1748 TEST_EQ(FloatCompare(TestValue<float>("{ y:cos(rad(180)) }", "float"), -1),
1751 // int embedded to string
1752 TEST_EQ(TestValue<int>("{ y:\"-876\" }", "int=-123"), -876);
1753 TEST_EQ(TestValue<int>("{ y:\"876\" }", "int=-123"), 876);
1755 // Test negative hex constant.
1756 TEST_EQ(TestValue<int>("{ y:-0x8ea0 }", "int=-0x8ea0"), -36512);
1757 TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
1759 // positive hex constant
1760 TEST_EQ(TestValue<int>("{ y:0x1abcdef }", "int=0x1"), 0x1abcdef);
1761 // with optional '+' sign
1762 TEST_EQ(TestValue<int>("{ y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
1764 TEST_EQ(TestValue<int>("{ y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
1766 // Make sure we do unsigned 64bit correctly.
1767 TEST_EQ(TestValue<uint64_t>("{ y:12335089644688340133 }", "ulong"),
1768 12335089644688340133ULL);
1771 TEST_EQ(TestValue<bool>("{ y:\"false\" }", "bool=true"), false);
1772 TEST_EQ(TestValue<bool>("{ y:\"true\" }", "bool=\"true\""), true);
1773 TEST_EQ(TestValue<bool>("{ y:'false' }", "bool=true"), false);
1774 TEST_EQ(TestValue<bool>("{ y:'true' }", "bool=\"true\""), true);
1776 // check comments before and after json object
1777 TEST_EQ(TestValue<int>("/*before*/ { y:1 } /*after*/", "int"), 1);
1778 TEST_EQ(TestValue<int>("//before \n { y:1 } //after", "int"), 1);
1781 void NestedListTest() {
1782 flatbuffers::Parser parser1;
1783 TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
1785 "{ F:[ [10,20], [30,40]] }"),
1789 void EnumStringsTest() {
1790 flatbuffers::Parser parser1;
1791 TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
1793 "{ F:[ A, B, \"C\", \"A B C\" ] }"),
1795 flatbuffers::Parser parser2;
1796 TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
1798 "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"),
1800 // unsigned bit_flags
1801 flatbuffers::Parser parser3;
1803 parser3.Parse("enum E:uint16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }"
1804 " table T { F: E = \"F15 F08\"; }"
1809 void EnumNamesTest() {
1810 TEST_EQ_STR("Red", EnumNameColor(Color_Red));
1811 TEST_EQ_STR("Green", EnumNameColor(Color_Green));
1812 TEST_EQ_STR("Blue", EnumNameColor(Color_Blue));
1813 // Check that Color to string don't crash while decode a mixture of Colors.
1814 // 1) Example::Color enum is enum with unfixed underlying type.
1815 // 2) Valid enum range: [0; 2^(ceil(log2(Color_ANY))) - 1].
1816 // Consequence: A value is out of this range will lead to UB (since C++17).
1817 // For details see C++17 standard or explanation on the SO:
1818 // stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class
1819 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(0)));
1820 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY - 1)));
1821 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY + 1)));
1824 void EnumOutOfRangeTest() {
1825 TestError("enum X:byte { Y = 128 }", "enum value does not fit");
1826 TestError("enum X:byte { Y = -129 }", "enum value does not fit");
1827 TestError("enum X:byte { Y = 126, Z0, Z1 }", "enum value does not fit");
1828 TestError("enum X:ubyte { Y = -1 }", "enum value does not fit");
1829 TestError("enum X:ubyte { Y = 256 }", "enum value does not fit");
1830 TestError("enum X:ubyte { Y = 255, Z }", "enum value does not fit");
1831 TestError("table Y{} union X { Y = -1 }", "enum value does not fit");
1832 TestError("table Y{} union X { Y = 256 }", "enum value does not fit");
1833 TestError("table Y{} union X { Y = 255, Z:Y }", "enum value does not fit");
1834 TestError("enum X:int { Y = -2147483649 }", "enum value does not fit");
1835 TestError("enum X:int { Y = 2147483648 }", "enum value does not fit");
1836 TestError("enum X:uint { Y = -1 }", "enum value does not fit");
1837 TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit");
1838 TestError("enum X:long { Y = 9223372036854775808 }", "does not fit");
1839 TestError("enum X:long { Y = 9223372036854775807, Z }",
1840 "enum value does not fit");
1841 TestError("enum X:ulong { Y = -1 }", "does not fit");
1842 TestError("enum X:ubyte (bit_flags) { Y=8 }", "bit flag out");
1843 TestError("enum X:byte (bit_flags) { Y=7 }", "must be unsigned"); // -128
1844 // bit_flgs out of range
1845 TestError("enum X:ubyte (bit_flags) { Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8 }",
1849 void EnumValueTest() {
1850 // json: "{ Y:0 }", schema: table X { y: "E"}
1851 // 0 in enum (V=0) E then Y=0 is valid.
1852 TEST_EQ(TestValue<int>("{ y:0 }", "E", "enum E:int { V }"), 0);
1853 TEST_EQ(TestValue<int>("{ y:V }", "E", "enum E:int { V }"), 0);
1854 // A default value of Y is 0.
1855 TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
1856 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { V=5 }"), 5);
1857 // Generate json with defaults and check.
1858 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
1860 TEST_EQ(TestValue<int>("{ y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
1861 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
1862 // Generate json with defaults and check.
1863 TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
1864 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
1866 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1867 "enum E:ulong { V = 13835058055282163712 }"),
1868 13835058055282163712ULL);
1869 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1870 "enum E:ulong { V = 18446744073709551615 }"),
1871 18446744073709551615ULL);
1872 // Assign non-enum value to enum field. Is it right?
1873 TEST_EQ(TestValue<int>("{ y:7 }", "E", "enum E:int { V = 0 }"), 7);
1874 // Check that non-ascending values are valid.
1875 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z=10, V=5 }"), 5);
1878 void IntegerOutOfRangeTest() {
1879 TestError("table T { F:byte; } root_type T; { F:128 }",
1880 "constant does not fit");
1881 TestError("table T { F:byte; } root_type T; { F:-129 }",
1882 "constant does not fit");
1883 TestError("table T { F:ubyte; } root_type T; { F:256 }",
1884 "constant does not fit");
1885 TestError("table T { F:ubyte; } root_type T; { F:-1 }",
1886 "constant does not fit");
1887 TestError("table T { F:short; } root_type T; { F:32768 }",
1888 "constant does not fit");
1889 TestError("table T { F:short; } root_type T; { F:-32769 }",
1890 "constant does not fit");
1891 TestError("table T { F:ushort; } root_type T; { F:65536 }",
1892 "constant does not fit");
1893 TestError("table T { F:ushort; } root_type T; { F:-1 }",
1894 "constant does not fit");
1895 TestError("table T { F:int; } root_type T; { F:2147483648 }",
1896 "constant does not fit");
1897 TestError("table T { F:int; } root_type T; { F:-2147483649 }",
1898 "constant does not fit");
1899 TestError("table T { F:uint; } root_type T; { F:4294967296 }",
1900 "constant does not fit");
1901 TestError("table T { F:uint; } root_type T; { F:-1 }",
1902 "constant does not fit");
1903 // Check fixed width aliases
1904 TestError("table X { Y:uint8; } root_type X; { Y: -1 }", "does not fit");
1905 TestError("table X { Y:uint8; } root_type X; { Y: 256 }", "does not fit");
1906 TestError("table X { Y:uint16; } root_type X; { Y: -1 }", "does not fit");
1907 TestError("table X { Y:uint16; } root_type X; { Y: 65536 }", "does not fit");
1908 TestError("table X { Y:uint32; } root_type X; { Y: -1 }", "");
1909 TestError("table X { Y:uint32; } root_type X; { Y: 4294967296 }",
1911 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1912 TestError("table X { Y:uint64; } root_type X; { Y: -9223372036854775809 }",
1914 TestError("table X { Y:uint64; } root_type X; { Y: 18446744073709551616 }",
1917 TestError("table X { Y:int8; } root_type X; { Y: -129 }", "does not fit");
1918 TestError("table X { Y:int8; } root_type X; { Y: 128 }", "does not fit");
1919 TestError("table X { Y:int16; } root_type X; { Y: -32769 }", "does not fit");
1920 TestError("table X { Y:int16; } root_type X; { Y: 32768 }", "does not fit");
1921 TestError("table X { Y:int32; } root_type X; { Y: -2147483649 }", "");
1922 TestError("table X { Y:int32; } root_type X; { Y: 2147483648 }",
1924 TestError("table X { Y:int64; } root_type X; { Y: -9223372036854775809 }",
1926 TestError("table X { Y:int64; } root_type X; { Y: 9223372036854775808 }",
1928 // check out-of-int64 as int8
1929 TestError("table X { Y:int8; } root_type X; { Y: -9223372036854775809 }",
1931 TestError("table X { Y:int8; } root_type X; { Y: 9223372036854775808 }",
1934 // Check default values
1935 TestError("table X { Y:int64=-9223372036854775809; } root_type X; {}",
1937 TestError("table X { Y:int64= 9223372036854775808; } root_type X; {}",
1939 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1940 TestError("table X { Y:uint64=-9223372036854775809; } root_type X; {}",
1942 TestError("table X { Y:uint64= 18446744073709551616; } root_type X; {}",
1946 void IntegerBoundaryTest() {
1947 // Check numerical compatibility with non-C++ languages.
1948 // By the C++ standard, std::numerical_limits<int64_t>::min() ==
1949 // -9223372036854775807 (-2^63+1) or less* The Flatbuffers grammar and most of
1950 // the languages (C#, Java, Rust) expect that minimum values are: -128,
1951 // -32768,.., -9223372036854775808. Since C++20,
1952 // static_cast<int64>(0x8000000000000000ULL) is well-defined two's complement
1953 // cast. Therefore -9223372036854775808 should be valid negative value.
1954 TEST_EQ(flatbuffers::numeric_limits<int8_t>::min(), -128);
1955 TEST_EQ(flatbuffers::numeric_limits<int8_t>::max(), 127);
1956 TEST_EQ(flatbuffers::numeric_limits<int16_t>::min(), -32768);
1957 TEST_EQ(flatbuffers::numeric_limits<int16_t>::max(), 32767);
1958 TEST_EQ(flatbuffers::numeric_limits<int32_t>::min() + 1, -2147483647);
1959 TEST_EQ(flatbuffers::numeric_limits<int32_t>::max(), 2147483647ULL);
1960 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min() + 1LL,
1961 -9223372036854775807LL);
1962 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(), 9223372036854775807ULL);
1963 TEST_EQ(flatbuffers::numeric_limits<uint8_t>::max(), 255);
1964 TEST_EQ(flatbuffers::numeric_limits<uint16_t>::max(), 65535);
1965 TEST_EQ(flatbuffers::numeric_limits<uint32_t>::max(), 4294967295ULL);
1966 TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
1967 18446744073709551615ULL);
1969 TEST_EQ(TestValue<int8_t>("{ y:127 }", "byte"), 127);
1970 TEST_EQ(TestValue<int8_t>("{ y:-128 }", "byte"), -128);
1971 TEST_EQ(TestValue<uint8_t>("{ y:255 }", "ubyte"), 255);
1972 TEST_EQ(TestValue<uint8_t>("{ y:0 }", "ubyte"), 0);
1973 TEST_EQ(TestValue<int16_t>("{ y:32767 }", "short"), 32767);
1974 TEST_EQ(TestValue<int16_t>("{ y:-32768 }", "short"), -32768);
1975 TEST_EQ(TestValue<uint16_t>("{ y:65535 }", "ushort"), 65535);
1976 TEST_EQ(TestValue<uint16_t>("{ y:0 }", "ushort"), 0);
1977 TEST_EQ(TestValue<int32_t>("{ y:2147483647 }", "int"), 2147483647);
1978 TEST_EQ(TestValue<int32_t>("{ y:-2147483648 }", "int") + 1, -2147483647);
1979 TEST_EQ(TestValue<uint32_t>("{ y:4294967295 }", "uint"), 4294967295);
1980 TEST_EQ(TestValue<uint32_t>("{ y:0 }", "uint"), 0);
1981 TEST_EQ(TestValue<int64_t>("{ y:9223372036854775807 }", "long"),
1982 9223372036854775807LL);
1983 TEST_EQ(TestValue<int64_t>("{ y:-9223372036854775808 }", "long") + 1LL,
1984 -9223372036854775807LL);
1985 TEST_EQ(TestValue<uint64_t>("{ y:18446744073709551615 }", "ulong"),
1986 18446744073709551615ULL);
1987 TEST_EQ(TestValue<uint64_t>("{ y:0 }", "ulong"), 0);
1988 TEST_EQ(TestValue<uint64_t>("{ y: 18446744073709551615 }", "uint64"),
1989 18446744073709551615ULL);
1990 // check that the default works
1991 TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
1992 18446744073709551615ULL);
1995 void ValidFloatTest() {
1996 // check rounding to infinity
1997 TEST_EQ(TestValue<float>("{ y:+3.4029e+38 }", "float"), +infinity_f);
1998 TEST_EQ(TestValue<float>("{ y:-3.4029e+38 }", "float"), -infinity_f);
1999 TEST_EQ(TestValue<double>("{ y:+1.7977e+308 }", "double"), +infinity_d);
2000 TEST_EQ(TestValue<double>("{ y:-1.7977e+308 }", "double"), -infinity_d);
2003 FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
2006 TEST_EQ(FloatCompare(TestValue<float>("{ y:\" 0.0314159e+2 \" }", "float"),
2010 TEST_EQ(TestValue<float>("{ y:1 }", "float"), 1.0f);
2011 TEST_EQ(TestValue<float>("{ y:1.0 }", "float"), 1.0f);
2012 TEST_EQ(TestValue<float>("{ y:1. }", "float"), 1.0f);
2013 TEST_EQ(TestValue<float>("{ y:+1. }", "float"), 1.0f);
2014 TEST_EQ(TestValue<float>("{ y:-1. }", "float"), -1.0f);
2015 TEST_EQ(TestValue<float>("{ y:1.e0 }", "float"), 1.0f);
2016 TEST_EQ(TestValue<float>("{ y:1.e+0 }", "float"), 1.0f);
2017 TEST_EQ(TestValue<float>("{ y:1.e-0 }", "float"), 1.0f);
2018 TEST_EQ(TestValue<float>("{ y:0.125 }", "float"), 0.125f);
2019 TEST_EQ(TestValue<float>("{ y:.125 }", "float"), 0.125f);
2020 TEST_EQ(TestValue<float>("{ y:-.125 }", "float"), -0.125f);
2021 TEST_EQ(TestValue<float>("{ y:+.125 }", "float"), +0.125f);
2022 TEST_EQ(TestValue<float>("{ y:5 }", "float"), 5.0f);
2023 TEST_EQ(TestValue<float>("{ y:\"5\" }", "float"), 5.0f);
2025 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
2026 // Old MSVC versions may have problem with this check.
2027 // https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
2028 TEST_EQ(TestValue<double>("{ y:6.9294956446009195e15 }", "double"),
2029 6929495644600920.0);
2031 TEST_EQ(std::isnan(TestValue<double>("{ y:nan }", "double")), true);
2032 TEST_EQ(std::isnan(TestValue<float>("{ y:nan }", "float")), true);
2033 TEST_EQ(std::isnan(TestValue<float>("{ y:\"nan\" }", "float")), true);
2034 TEST_EQ(std::isnan(TestValue<float>("{ y:\"+nan\" }", "float")), true);
2035 TEST_EQ(std::isnan(TestValue<float>("{ y:\"-nan\" }", "float")), true);
2036 TEST_EQ(std::isnan(TestValue<float>("{ y:+nan }", "float")), true);
2037 TEST_EQ(std::isnan(TestValue<float>("{ y:-nan }", "float")), true);
2038 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
2039 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
2041 TEST_EQ(TestValue<float>("{ y:inf }", "float"), infinity_f);
2042 TEST_EQ(TestValue<float>("{ y:\"inf\" }", "float"), infinity_f);
2043 TEST_EQ(TestValue<float>("{ y:\"-inf\" }", "float"), -infinity_f);
2044 TEST_EQ(TestValue<float>("{ y:\"+inf\" }", "float"), infinity_f);
2045 TEST_EQ(TestValue<float>("{ y:+inf }", "float"), infinity_f);
2046 TEST_EQ(TestValue<float>("{ y:-inf }", "float"), -infinity_f);
2047 TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinity_f);
2048 TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinity_f);
2050 "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
2054 "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
2058 // Test binary format of float point.
2059 // https://en.cppreference.com/w/cpp/language/floating_literal
2060 // 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
2061 TEST_EQ(TestValue<double>("{ y:0x12.34p-1 }", "double"), 9.1015625);
2062 // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
2063 TEST_EQ(TestValue<float>("{ y:-0x0.2p0 }", "float"), -0.125f);
2064 TEST_EQ(TestValue<float>("{ y:-0x.2p1 }", "float"), -0.25f);
2065 TEST_EQ(TestValue<float>("{ y:0x1.2p3 }", "float"), 9.0f);
2066 TEST_EQ(TestValue<float>("{ y:0x10.1p0 }", "float"), 16.0625f);
2067 TEST_EQ(TestValue<double>("{ y:0x1.2p3 }", "double"), 9.0);
2068 TEST_EQ(TestValue<double>("{ y:0x10.1p0 }", "double"), 16.0625);
2069 TEST_EQ(TestValue<double>("{ y:0xC.68p+2 }", "double"), 49.625);
2070 TestValue<double>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
2071 TestValue<float>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
2073 #else // FLATBUFFERS_HAS_NEW_STRTOD
2074 TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");
2075 #endif // !FLATBUFFERS_HAS_NEW_STRTOD
2078 void InvalidFloatTest() {
2079 auto invalid_msg = "invalid number";
2080 auto comma_msg = "expecting: ,";
2081 TestError("table T { F:float; } root_type T; { F:1,0 }", "");
2082 TestError("table T { F:float; } root_type T; { F:. }", "");
2083 TestError("table T { F:float; } root_type T; { F:- }", invalid_msg);
2084 TestError("table T { F:float; } root_type T; { F:+ }", invalid_msg);
2085 TestError("table T { F:float; } root_type T; { F:-. }", invalid_msg);
2086 TestError("table T { F:float; } root_type T; { F:+. }", invalid_msg);
2087 TestError("table T { F:float; } root_type T; { F:.e }", "");
2088 TestError("table T { F:float; } root_type T; { F:-e }", invalid_msg);
2089 TestError("table T { F:float; } root_type T; { F:+e }", invalid_msg);
2090 TestError("table T { F:float; } root_type T; { F:-.e }", invalid_msg);
2091 TestError("table T { F:float; } root_type T; { F:+.e }", invalid_msg);
2092 TestError("table T { F:float; } root_type T; { F:-e1 }", invalid_msg);
2093 TestError("table T { F:float; } root_type T; { F:+e1 }", invalid_msg);
2094 TestError("table T { F:float; } root_type T; { F:1.0e+ }", invalid_msg);
2095 TestError("table T { F:float; } root_type T; { F:1.0e- }", invalid_msg);
2096 // exponent pP is mandatory for hex-float
2097 TestError("table T { F:float; } root_type T; { F:0x0 }", invalid_msg);
2098 TestError("table T { F:float; } root_type T; { F:-0x. }", invalid_msg);
2099 TestError("table T { F:float; } root_type T; { F:0x. }", invalid_msg);
2100 TestError("table T { F:float; } root_type T; { F:0Xe }", invalid_msg);
2101 TestError("table T { F:float; } root_type T; { F:\"0Xe\" }", invalid_msg);
2102 TestError("table T { F:float; } root_type T; { F:\"nan(1)\" }", invalid_msg);
2103 // eE not exponent in hex-float!
2104 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
2105 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
2106 TestError("table T { F:float; } root_type T; { F:0x0.0p }", invalid_msg);
2107 TestError("table T { F:float; } root_type T; { F:0x0.0p+ }", invalid_msg);
2108 TestError("table T { F:float; } root_type T; { F:0x0.0p- }", invalid_msg);
2109 TestError("table T { F:float; } root_type T; { F:0x0.0pa1 }", invalid_msg);
2110 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
2111 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
2112 TestError("table T { F:float; } root_type T; { F:0x0.0e+0 }", invalid_msg);
2113 TestError("table T { F:float; } root_type T; { F:0x0.0e-0 }", invalid_msg);
2114 TestError("table T { F:float; } root_type T; { F:0x0.0ep+ }", invalid_msg);
2115 TestError("table T { F:float; } root_type T; { F:0x0.0ep- }", invalid_msg);
2116 TestError("table T { F:float; } root_type T; { F:1.2.3 }", invalid_msg);
2117 TestError("table T { F:float; } root_type T; { F:1.2.e3 }", invalid_msg);
2118 TestError("table T { F:float; } root_type T; { F:1.2e.3 }", invalid_msg);
2119 TestError("table T { F:float; } root_type T; { F:1.2e0.3 }", invalid_msg);
2120 TestError("table T { F:float; } root_type T; { F:1.2e3. }", invalid_msg);
2121 TestError("table T { F:float; } root_type T; { F:1.2e3.0 }", invalid_msg);
2122 TestError("table T { F:float; } root_type T; { F:+-1.0 }", invalid_msg);
2123 TestError("table T { F:float; } root_type T; { F:1.0e+-1 }", invalid_msg);
2124 TestError("table T { F:float; } root_type T; { F:\"1.0e+-1\" }", invalid_msg);
2125 TestError("table T { F:float; } root_type T; { F:1.e0e }", comma_msg);
2126 TestError("table T { F:float; } root_type T; { F:0x1.p0e }", comma_msg);
2127 TestError("table T { F:float; } root_type T; { F:\" 0x10 \" }", invalid_msg);
2129 TestError("table T { F:float; } root_type T; { F:\"1,2.\" }", invalid_msg);
2130 TestError("table T { F:float; } root_type T; { F:\"1.2e3.\" }", invalid_msg);
2131 TestError("table T { F:float; } root_type T; { F:\"0x1.p0e\" }", invalid_msg);
2132 TestError("table T { F:float; } root_type T; { F:\"0x1.0\" }", invalid_msg);
2133 TestError("table T { F:float; } root_type T; { F:\" 0x1.0\" }", invalid_msg);
2134 TestError("table T { F:float; } root_type T; { F:\"+ 0\" }", invalid_msg);
2135 // disable escapes for "number-in-string"
2136 TestError("table T { F:float; } root_type T; { F:\"\\f1.2e3.\" }", "invalid");
2137 TestError("table T { F:float; } root_type T; { F:\"\\t1.2e3.\" }", "invalid");
2138 TestError("table T { F:float; } root_type T; { F:\"\\n1.2e3.\" }", "invalid");
2139 TestError("table T { F:float; } root_type T; { F:\"\\r1.2e3.\" }", "invalid");
2140 TestError("table T { F:float; } root_type T; { F:\"4\\x005\" }", "invalid");
2141 TestError("table T { F:float; } root_type T; { F:\"\'12\'\" }", invalid_msg);
2142 // null is not a number constant!
2143 TestError("table T { F:float; } root_type T; { F:\"null\" }", invalid_msg);
2144 TestError("table T { F:float; } root_type T; { F:null }", invalid_msg);
2147 void GenerateTableTextTest() {
2148 std::string schemafile;
2149 std::string jsonfile;
2151 flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2152 false, &schemafile) &&
2153 flatbuffers::LoadFile((test_data_path + "monsterdata_test.json").c_str(),
2156 auto include_test_path =
2157 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2158 const char *include_directories[] = { test_data_path.c_str(),
2159 include_test_path.c_str(), nullptr };
2160 flatbuffers::IDLOptions opt;
2161 opt.indent_step = -1;
2162 flatbuffers::Parser parser(opt);
2163 ok = parser.Parse(schemafile.c_str(), include_directories) &&
2164 parser.Parse(jsonfile.c_str(), include_directories);
2167 const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
2168 const auto abilities = monster->testarrayofsortedstruct();
2169 TEST_EQ(abilities->size(), 3);
2170 TEST_EQ(abilities->Get(0)->id(), 0);
2171 TEST_EQ(abilities->Get(0)->distance(), 45);
2172 TEST_EQ(abilities->Get(1)->id(), 1);
2173 TEST_EQ(abilities->Get(1)->distance(), 21);
2174 TEST_EQ(abilities->Get(2)->id(), 5);
2175 TEST_EQ(abilities->Get(2)->distance(), 12);
2177 std::string jsongen;
2178 auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster",
2180 TEST_EQ(result, true);
2182 const Vec3 *pos = monster->pos();
2184 result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
2185 TEST_EQ(result, true);
2188 "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
2189 const Test &test3 = pos->test3();
2192 GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
2193 TEST_EQ(result, true);
2194 TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
2195 const Test *test4 = monster->test4()->Get(0);
2198 GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
2199 TEST_EQ(result, true);
2200 TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
2203 template<typename T>
2204 void NumericUtilsTestInteger(const char *lower, const char *upper) {
2206 TEST_EQ(flatbuffers::StringToNumber("1q", &x), false);
2208 TEST_EQ(flatbuffers::StringToNumber(upper, &x), false);
2209 TEST_EQ(x, flatbuffers::numeric_limits<T>::max());
2210 TEST_EQ(flatbuffers::StringToNumber(lower, &x), false);
2211 auto expval = flatbuffers::is_unsigned<T>::value
2212 ? flatbuffers::numeric_limits<T>::max()
2213 : flatbuffers::numeric_limits<T>::lowest();
2217 template<typename T>
2218 void NumericUtilsTestFloat(const char *lower, const char *upper) {
2220 TEST_EQ(flatbuffers::StringToNumber("", &f), false);
2221 TEST_EQ(flatbuffers::StringToNumber("1q", &f), false);
2223 TEST_EQ(flatbuffers::StringToNumber(upper, &f), true);
2224 TEST_EQ(f, +flatbuffers::numeric_limits<T>::infinity());
2225 TEST_EQ(flatbuffers::StringToNumber(lower, &f), true);
2226 TEST_EQ(f, -flatbuffers::numeric_limits<T>::infinity());
2229 void NumericUtilsTest() {
2230 NumericUtilsTestInteger<uint64_t>("-1", "18446744073709551616");
2231 NumericUtilsTestInteger<uint8_t>("-1", "256");
2232 NumericUtilsTestInteger<int64_t>("-9223372036854775809",
2233 "9223372036854775808");
2234 NumericUtilsTestInteger<int8_t>("-129", "128");
2235 NumericUtilsTestFloat<float>("-3.4029e+38", "+3.4029e+38");
2236 NumericUtilsTestFloat<float>("-1.7977e+308", "+1.7977e+308");
2239 void IsAsciiUtilsTest() {
2241 for (int cnt = 0; cnt < 256; cnt++) {
2242 auto alpha = (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
2243 auto dec = (('0' <= c) && (c <= '9'));
2244 auto hex = (('a' <= c) && (c <= 'f')) || (('A' <= c) && (c <= 'F'));
2245 TEST_EQ(flatbuffers::is_alpha(c), alpha);
2246 TEST_EQ(flatbuffers::is_alnum(c), alpha || dec);
2247 TEST_EQ(flatbuffers::is_digit(c), dec);
2248 TEST_EQ(flatbuffers::is_xdigit(c), dec || hex);
2253 void UnicodeTest() {
2254 flatbuffers::Parser parser;
2255 // Without setting allow_non_utf8 = true, we treat \x sequences as byte
2256 // sequences which are then validated as UTF-8.
2257 TEST_EQ(parser.Parse("table T { F:string; }"
2259 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2260 "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD8"
2263 std::string jsongen;
2264 parser.opts.indent_step = -1;
2266 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2267 TEST_EQ(result, true);
2268 TEST_EQ_STR(jsongen.c_str(),
2269 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2270 "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
2273 void UnicodeTestAllowNonUTF8() {
2274 flatbuffers::Parser parser;
2275 parser.opts.allow_non_utf8 = true;
2278 "table T { F:string; }"
2280 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2281 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2283 std::string jsongen;
2284 parser.opts.indent_step = -1;
2286 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2287 TEST_EQ(result, true);
2290 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2291 "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
2294 void UnicodeTestGenerateTextFailsOnNonUTF8() {
2295 flatbuffers::Parser parser;
2296 // Allow non-UTF-8 initially to model what happens when we load a binary
2297 // flatbuffer from disk which contains non-UTF-8 strings.
2298 parser.opts.allow_non_utf8 = true;
2301 "table T { F:string; }"
2303 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2304 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2306 std::string jsongen;
2307 parser.opts.indent_step = -1;
2308 // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates
2310 parser.opts.allow_non_utf8 = false;
2312 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2313 TEST_EQ(result, false);
2316 void UnicodeSurrogatesTest() {
2317 flatbuffers::Parser parser;
2319 TEST_EQ(parser.Parse("table T { F:string (id: 0); }"
2321 "{ F:\"\\uD83D\\uDCA9\"}"),
2323 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
2324 parser.builder_.GetBufferPointer());
2325 auto string = root->GetPointer<flatbuffers::String *>(
2326 flatbuffers::FieldIndexToOffset(0));
2327 TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
2330 void UnicodeInvalidSurrogatesTest() {
2332 "table T { F:string; }"
2335 "unpaired high surrogate");
2337 "table T { F:string; }"
2339 "{ F:\"\\uD800abcd\"}",
2340 "unpaired high surrogate");
2342 "table T { F:string; }"
2344 "{ F:\"\\uD800\\n\"}",
2345 "unpaired high surrogate");
2347 "table T { F:string; }"
2349 "{ F:\"\\uD800\\uD800\"}",
2350 "multiple high surrogates");
2352 "table T { F:string; }"
2355 "unpaired low surrogate");
2358 void InvalidUTF8Test() {
2359 // "1 byte" pattern, under min length of 2 bytes
2361 "table T { F:string; }"
2364 "illegal UTF-8 sequence");
2365 // 2 byte pattern, string too short
2367 "table T { F:string; }"
2370 "illegal UTF-8 sequence");
2371 // 3 byte pattern, string too short
2373 "table T { F:string; }"
2375 "{ F:\"\xEF\xBF\"}",
2376 "illegal UTF-8 sequence");
2377 // 4 byte pattern, string too short
2379 "table T { F:string; }"
2381 "{ F:\"\xF7\xBF\xBF\"}",
2382 "illegal UTF-8 sequence");
2383 // "5 byte" pattern, string too short
2385 "table T { F:string; }"
2387 "{ F:\"\xFB\xBF\xBF\xBF\"}",
2388 "illegal UTF-8 sequence");
2389 // "6 byte" pattern, string too short
2391 "table T { F:string; }"
2393 "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}",
2394 "illegal UTF-8 sequence");
2395 // "7 byte" pattern, string too short
2397 "table T { F:string; }"
2399 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}",
2400 "illegal UTF-8 sequence");
2401 // "5 byte" pattern, over max length of 4 bytes
2403 "table T { F:string; }"
2405 "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}",
2406 "illegal UTF-8 sequence");
2407 // "6 byte" pattern, over max length of 4 bytes
2409 "table T { F:string; }"
2411 "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}",
2412 "illegal UTF-8 sequence");
2413 // "7 byte" pattern, over max length of 4 bytes
2415 "table T { F:string; }"
2417 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}",
2418 "illegal UTF-8 sequence");
2420 // Three invalid encodings for U+000A (\n, aka NEWLINE)
2422 "table T { F:string; }"
2424 "{ F:\"\xC0\x8A\"}",
2425 "illegal UTF-8 sequence");
2427 "table T { F:string; }"
2429 "{ F:\"\xE0\x80\x8A\"}",
2430 "illegal UTF-8 sequence");
2432 "table T { F:string; }"
2434 "{ F:\"\xF0\x80\x80\x8A\"}",
2435 "illegal UTF-8 sequence");
2437 // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
2439 "table T { F:string; }"
2441 "{ F:\"\xE0\x81\xA9\"}",
2442 "illegal UTF-8 sequence");
2444 "table T { F:string; }"
2446 "{ F:\"\xF0\x80\x81\xA9\"}",
2447 "illegal UTF-8 sequence");
2449 // Invalid encoding for U+20AC (EURO SYMBOL)
2451 "table T { F:string; }"
2453 "{ F:\"\xF0\x82\x82\xAC\"}",
2454 "illegal UTF-8 sequence");
2456 // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in
2459 "table T { F:string; }"
2461 // U+10400 "encoded" as U+D801 U+DC00
2462 "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}",
2463 "illegal UTF-8 sequence");
2465 // Check independence of identifier from locale.
2466 std::string locale_ident;
2467 locale_ident += "table T { F";
2468 locale_ident += static_cast<char>(-32); // unsigned 0xE0
2469 locale_ident += " :string; }";
2470 locale_ident += "root_type T;";
2471 locale_ident += "{}";
2472 TestError(locale_ident.c_str(), "");
2475 void UnknownFieldsTest() {
2476 flatbuffers::IDLOptions opts;
2477 opts.skip_unexpected_fields_in_json = true;
2478 flatbuffers::Parser parser(opts);
2480 TEST_EQ(parser.Parse("table T { str:string; i:int;}"
2483 "unknown_string:\"test\","
2484 "\"unknown_string\":\"test\","
2486 "unknown_float:1.0,"
2487 "unknown_array: [ 1, 2, 3, 4],"
2488 "unknown_object: { i: 10 },"
2489 "\"unknown_object\": { \"i\": 10 },"
2493 std::string jsongen;
2494 parser.opts.indent_step = -1;
2496 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2497 TEST_EQ(result, true);
2498 TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
2501 void ParseUnionTest() {
2502 // Unions must be parseable with the type field following the object.
2503 flatbuffers::Parser parser;
2504 TEST_EQ(parser.Parse("table T { A:int; }"
2508 "{ X:{ A:1 }, X_type: T }"),
2510 // Unions must be parsable with prefixed namespace.
2511 flatbuffers::Parser parser2;
2512 TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
2513 "table B { e:U; } root_type B;"
2514 "{ e_type: N_A, e: {} }"),
2518 void InvalidNestedFlatbufferTest() {
2519 // First, load and parse FlatBuffer schema (.fbs)
2520 std::string schemafile;
2521 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2522 false, &schemafile),
2524 auto include_test_path =
2525 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2526 const char *include_directories[] = { test_data_path.c_str(),
2527 include_test_path.c_str(), nullptr };
2528 flatbuffers::Parser parser1;
2529 TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
2531 // "color" inside nested flatbuffer contains invalid enum value
2532 TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
2533 "\"Leela\", color: \"nonexistent\"}}"),
2537 void EvolutionTest() {
2538 // VS10 does not support typed enums, exclude from tests
2539 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2540 const int NUM_VERSIONS = 2;
2541 std::string schemas[NUM_VERSIONS];
2542 std::string jsonfiles[NUM_VERSIONS];
2543 std::vector<uint8_t> binaries[NUM_VERSIONS];
2545 flatbuffers::IDLOptions idl_opts;
2546 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2547 flatbuffers::Parser parser(idl_opts);
2549 // Load all the schema versions and their associated data.
2550 for (int i = 0; i < NUM_VERSIONS; ++i) {
2551 std::string schema = test_data_path + "evolution_test/evolution_v" +
2552 flatbuffers::NumToString(i + 1) + ".fbs";
2553 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2554 std::string json = test_data_path + "evolution_test/evolution_v" +
2555 flatbuffers::NumToString(i + 1) + ".json";
2556 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2558 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2559 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2561 auto bufLen = parser.builder_.GetSize();
2562 auto buf = parser.builder_.GetBufferPointer();
2563 binaries[i].reserve(bufLen);
2564 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2567 // Assert that all the verifiers for the different schema versions properly
2568 // verify any version data.
2569 for (int i = 0; i < NUM_VERSIONS; ++i) {
2570 flatbuffers::Verifier verifier(&binaries[i].front(), binaries[i].size());
2571 TEST_ASSERT(Evolution::V1::VerifyRootBuffer(verifier));
2572 TEST_ASSERT(Evolution::V2::VerifyRootBuffer(verifier));
2575 // Test backwards compatibility by reading old data with an evolved schema.
2576 auto root_v1_viewed_from_v2 = Evolution::V2::GetRoot(&binaries[0].front());
2577 // field 'k' is new in version 2, so it should be null.
2578 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->k());
2579 // field 'l' is new in version 2 with a default of 56.
2580 TEST_EQ(root_v1_viewed_from_v2->l(), 56);
2581 // field 'c' of 'TableA' is new in version 2, so it should be null.
2582 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->e()->c());
2583 // 'TableC' was added to field 'c' union in version 2, so it should be null.
2584 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->c_as_TableC());
2585 // The field 'c' union should be of type 'TableB' regardless of schema version
2586 TEST_ASSERT(root_v1_viewed_from_v2->c_type() == Evolution::V2::Union::TableB);
2587 // The field 'f' was renamed to 'ff' in version 2, it should still be
2589 TEST_EQ(root_v1_viewed_from_v2->ff()->a(), 16);
2591 // Test forwards compatibility by reading new data with an old schema.
2592 auto root_v2_viewed_from_v1 = Evolution::V1::GetRoot(&binaries[1].front());
2593 // The field 'c' union in version 2 is a new table (index = 3) and should
2594 // still be accessible, but not interpretable.
2595 TEST_EQ(static_cast<uint8_t>(root_v2_viewed_from_v1->c_type()), 3);
2596 TEST_NOTNULL(root_v2_viewed_from_v1->c());
2597 // The field 'd' enum in verison 2 has new members and should still be
2598 // accessible, but not interpretable.
2599 TEST_EQ(static_cast<int8_t>(root_v2_viewed_from_v1->d()), 3);
2600 // The field 'a' in version 2 is deprecated and should return the default
2601 // value (0) instead of the value stored in the in the buffer (42).
2602 TEST_EQ(root_v2_viewed_from_v1->a(), 0);
2603 // The field 'ff' was originally named 'f' in version 1, it should still be
2605 TEST_EQ(root_v2_viewed_from_v1->f()->a(), 35);
2609 void UnionDeprecationTest() {
2610 const int NUM_VERSIONS = 2;
2611 std::string schemas[NUM_VERSIONS];
2612 std::string jsonfiles[NUM_VERSIONS];
2613 std::vector<uint8_t> binaries[NUM_VERSIONS];
2615 flatbuffers::IDLOptions idl_opts;
2616 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2617 flatbuffers::Parser parser(idl_opts);
2619 // Load all the schema versions and their associated data.
2620 for (int i = 0; i < NUM_VERSIONS; ++i) {
2621 std::string schema = test_data_path + "evolution_test/evolution_v" +
2622 flatbuffers::NumToString(i + 1) + ".fbs";
2623 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2624 std::string json = test_data_path + "evolution_test/evolution_v" +
2625 flatbuffers::NumToString(i + 1) + ".json";
2626 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2628 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2629 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2631 auto bufLen = parser.builder_.GetSize();
2632 auto buf = parser.builder_.GetBufferPointer();
2633 binaries[i].reserve(bufLen);
2634 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2637 auto v2 = parser.LookupStruct("Evolution.V2.Root");
2639 auto j_type_field = v2->fields.Lookup("j_type");
2640 TEST_NOTNULL(j_type_field);
2641 TEST_ASSERT(j_type_field->deprecated);
2644 void UnionVectorTest() {
2645 // load FlatBuffer fbs schema and json.
2646 std::string schemafile, jsonfile;
2647 TEST_EQ(flatbuffers::LoadFile(
2648 (test_data_path + "union_vector/union_vector.fbs").c_str(), false,
2651 TEST_EQ(flatbuffers::LoadFile(
2652 (test_data_path + "union_vector/union_vector.json").c_str(),
2657 flatbuffers::IDLOptions idl_opts;
2658 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2659 flatbuffers::Parser parser(idl_opts);
2660 TEST_EQ(parser.Parse(schemafile.c_str()), true);
2662 flatbuffers::FlatBufferBuilder fbb;
2665 std::vector<uint8_t> types;
2666 types.push_back(static_cast<uint8_t>(Character_Belle));
2667 types.push_back(static_cast<uint8_t>(Character_MuLan));
2668 types.push_back(static_cast<uint8_t>(Character_BookFan));
2669 types.push_back(static_cast<uint8_t>(Character_Other));
2670 types.push_back(static_cast<uint8_t>(Character_Unused));
2673 std::vector<flatbuffers::Offset<void>> characters;
2674 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
2675 characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
2676 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
2677 characters.push_back(fbb.CreateString("Other").Union());
2678 characters.push_back(fbb.CreateString("Unused").Union());
2681 const auto movie_offset =
2682 CreateMovie(fbb, Character_Rapunzel,
2683 fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
2684 fbb.CreateVector(types), fbb.CreateVector(characters));
2685 FinishMovieBuffer(fbb, movie_offset);
2687 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
2688 TEST_EQ(VerifyMovieBuffer(verifier), true);
2690 auto flat_movie = GetMovie(fbb.GetBufferPointer());
2692 auto TestMovie = [](const Movie *movie) {
2693 TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
2695 auto cts = movie->characters_type();
2696 TEST_EQ(movie->characters_type()->size(), 5);
2697 TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
2698 TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
2699 TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
2700 TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
2701 TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
2703 auto rapunzel = movie->main_character_as_Rapunzel();
2704 TEST_NOTNULL(rapunzel);
2705 TEST_EQ(rapunzel->hair_length(), 6);
2707 auto cs = movie->characters();
2708 TEST_EQ(cs->size(), 5);
2709 auto belle = cs->GetAs<BookReader>(0);
2710 TEST_EQ(belle->books_read(), 7);
2711 auto mu_lan = cs->GetAs<Attacker>(1);
2712 TEST_EQ(mu_lan->sword_attack_damage(), 5);
2713 auto book_fan = cs->GetAs<BookReader>(2);
2714 TEST_EQ(book_fan->books_read(), 2);
2715 auto other = cs->GetAsString(3);
2716 TEST_EQ_STR(other->c_str(), "Other");
2717 auto unused = cs->GetAsString(4);
2718 TEST_EQ_STR(unused->c_str(), "Unused");
2721 TestMovie(flat_movie);
2723 // Also test the JSON we loaded above.
2724 TEST_EQ(parser.Parse(jsonfile.c_str()), true);
2725 auto jbuf = parser.builder_.GetBufferPointer();
2726 flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
2727 TEST_EQ(VerifyMovieBuffer(jverifier), true);
2728 TestMovie(GetMovie(jbuf));
2730 auto movie_object = flat_movie->UnPack();
2731 TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
2732 TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
2733 TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
2734 TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
2735 TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
2736 TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
2739 fbb.Finish(Movie::Pack(fbb, movie_object));
2741 delete movie_object;
2743 auto repacked_movie = GetMovie(fbb.GetBufferPointer());
2745 TestMovie(repacked_movie);
2747 // Generate text using mini-reflection.
2749 flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
2752 "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
2753 "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
2754 "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
2755 "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
2757 flatbuffers::ToStringVisitor visitor("\n", true, " ");
2758 IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
2759 TEST_EQ_STR(visitor.s.c_str(),
2761 " \"main_character_type\": \"Rapunzel\",\n"
2762 " \"main_character\": {\n"
2763 " \"hair_length\": 6\n"
2765 " \"characters_type\": [\n"
2772 " \"characters\": [\n"
2774 " \"books_read\": 7\n"
2777 " \"sword_attack_damage\": 5\n"
2780 " \"books_read\": 2\n"
2787 // Generate text using parsed schema.
2788 std::string jsongen;
2789 auto result = GenerateText(parser, fbb.GetBufferPointer(), &jsongen);
2790 TEST_EQ(result, true);
2791 TEST_EQ_STR(jsongen.c_str(),
2793 " main_character_type: \"Rapunzel\",\n"
2794 " main_character: {\n"
2797 " characters_type: [\n"
2809 " sword_attack_damage: 5\n"
2819 // Simple test with reflection.
2821 auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
2822 auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
2823 fbb.GetBufferPointer(), fbb.GetSize());
2826 flatbuffers::Parser parser2(idl_opts);
2827 TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
2828 "union Any { Bool }"
2829 "table Root { a:Any; }"
2832 TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
2835 void ConformTest() {
2836 flatbuffers::Parser parser;
2837 TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
2839 auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
2840 const char *expected_err) {
2841 flatbuffers::Parser parser2;
2842 TEST_EQ(parser2.Parse(test), true);
2843 auto err = parser2.ConformTo(parser1);
2844 TEST_NOTNULL(strstr(err.c_str(), expected_err));
2847 test_conform(parser, "table T { A:byte; }", "types differ for field");
2848 test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
2849 test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
2850 test_conform(parser, "table T { B:float; }",
2851 "field renamed to different type");
2852 test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
2855 void ParseProtoBufAsciiTest() {
2856 // We can put the parser in a mode where it will accept JSON that looks more
2857 // like Protobuf ASCII, for users that have data in that format.
2858 // This uses no "" for field names (which we already support by default,
2859 // omits `,`, `:` before `{` and a couple of other features.
2860 flatbuffers::Parser parser;
2861 parser.opts.protobuf_ascii_alike = true;
2863 parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
2865 TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
2866 // Similarly, in text output, it should omit these.
2868 auto ok = flatbuffers::GenerateText(
2869 parser, parser.builder_.GetBufferPointer(), &text);
2871 TEST_EQ_STR(text.c_str(),
2872 "{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n");
2875 void FlexBuffersTest() {
2876 flexbuffers::Builder slb(512,
2877 flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
2879 // Write the equivalent of:
2880 // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ],
2881 // foo: 100, bool: true, mymap: { foo: "Fred" } }
2883 #ifndef FLATBUFFERS_CPP98_STL
2884 // It's possible to do this without std::function support as well.
2886 slb.Vector("vec", [&]() {
2887 slb += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2889 slb.IndirectFloat(4.0f);
2890 auto i_f = slb.LastValue();
2891 uint8_t blob[] = { 77 };
2894 slb.ReuseValue(i_f);
2896 int ints[] = { 1, 2, 3 };
2897 slb.Vector("bar", ints, 3);
2898 slb.FixedTypedVector("bar3", ints, 3);
2899 bool bools[] = {true, false, true, false};
2900 slb.Vector("bools", bools, 4);
2901 slb.Bool("bool", true);
2902 slb.Double("foo", 100);
2903 slb.Map("mymap", [&]() {
2904 slb.String("foo", "Fred"); // Testing key and string reuse.
2909 // It's possible to do this without std::function support as well.
2910 slb.Map([](flexbuffers::Builder& slb2) {
2911 slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
2912 slb3 += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2914 slb3.IndirectFloat(4.0f);
2915 auto i_f = slb3.LastValue();
2916 uint8_t blob[] = { 77 };
2919 slb3.ReuseValue(i_f);
2921 int ints[] = { 1, 2, 3 };
2922 slb2.Vector("bar", ints, 3);
2923 slb2.FixedTypedVector("bar3", ints, 3);
2924 slb2.Bool("bool", true);
2925 slb2.Double("foo", 100);
2926 slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
2927 slb3.String("foo", "Fred"); // Testing key and string reuse.
2931 #endif // FLATBUFFERS_CPP98_STL
2933 #ifdef FLATBUFFERS_TEST_VERBOSE
2934 for (size_t i = 0; i < slb.GetBuffer().size(); i++)
2935 printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
2940 auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
2941 TEST_EQ(map.size(), 7);
2942 auto vec = map["vec"].AsVector();
2943 TEST_EQ(vec.size(), 6);
2944 TEST_EQ(vec[0].AsInt64(), -100);
2945 TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
2946 TEST_EQ(vec[1].AsInt64(), 0); // Number parsing failed.
2947 TEST_EQ(vec[2].AsDouble(), 4.0);
2948 TEST_EQ(vec[2].AsString().IsTheEmptyString(), true); // Wrong Type.
2949 TEST_EQ_STR(vec[2].AsString().c_str(), ""); // This still works though.
2950 TEST_EQ_STR(vec[2].ToString().c_str(), "4.0"); // Or have it converted.
2951 // Few tests for templated version of As.
2952 TEST_EQ(vec[0].As<int64_t>(), -100);
2953 TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
2954 TEST_EQ(vec[1].As<int64_t>(), 0); // Number parsing failed.
2955 TEST_EQ(vec[2].As<double>(), 4.0);
2956 // Test that the blob can be accessed.
2957 TEST_EQ(vec[3].IsBlob(), true);
2958 auto blob = vec[3].AsBlob();
2959 TEST_EQ(blob.size(), 1);
2960 TEST_EQ(blob.data()[0], 77);
2961 TEST_EQ(vec[4].IsBool(), true); // Check if type is a bool
2962 TEST_EQ(vec[4].AsBool(), false); // Check if value is false
2963 TEST_EQ(vec[5].AsDouble(), 4.0); // This is shared with vec[2] !
2964 auto tvec = map["bar"].AsTypedVector();
2965 TEST_EQ(tvec.size(), 3);
2966 TEST_EQ(tvec[2].AsInt8(), 3);
2967 auto tvec3 = map["bar3"].AsFixedTypedVector();
2968 TEST_EQ(tvec3.size(), 3);
2969 TEST_EQ(tvec3[2].AsInt8(), 3);
2970 TEST_EQ(map["bool"].AsBool(), true);
2971 auto tvecb = map["bools"].AsTypedVector();
2972 TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
2973 TEST_EQ(map["foo"].AsUInt8(), 100);
2974 TEST_EQ(map["unknown"].IsNull(), true);
2975 auto mymap = map["mymap"].AsMap();
2976 // These should be equal by pointer equality, since key and value are shared.
2977 TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
2978 TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
2979 // We can mutate values in the buffer.
2980 TEST_EQ(vec[0].MutateInt(-99), true);
2981 TEST_EQ(vec[0].AsInt64(), -99);
2982 TEST_EQ(vec[1].MutateString("John"), true); // Size must match.
2983 TEST_EQ_STR(vec[1].AsString().c_str(), "John");
2984 TEST_EQ(vec[1].MutateString("Alfred"), false); // Too long.
2985 TEST_EQ(vec[2].MutateFloat(2.0f), true);
2986 TEST_EQ(vec[2].AsFloat(), 2.0f);
2987 TEST_EQ(vec[2].MutateFloat(3.14159), false); // Double does not fit in float.
2988 TEST_EQ(vec[4].AsBool(), false); // Is false before change
2989 TEST_EQ(vec[4].MutateBool(true), true); // Can change a bool
2990 TEST_EQ(vec[4].AsBool(), true); // Changed bool is now true
2993 flatbuffers::Parser parser;
2995 auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
2996 TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
2997 auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
2998 auto jmap = jroot.AsMap();
2999 auto jvec = jmap["a"].AsVector();
3000 TEST_EQ(jvec[0].AsInt64(), 123);
3001 TEST_EQ(jvec[1].AsDouble(), 456.0);
3002 TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
3003 TEST_EQ(jmap["c"].IsBool(), true); // Parsed correctly to a bool
3004 TEST_EQ(jmap["c"].AsBool(), true); // Parsed correctly to true
3005 TEST_EQ(jmap["d"].IsBool(), true); // Parsed correctly to a bool
3006 TEST_EQ(jmap["d"].AsBool(), false); // Parsed correctly to false
3007 // And from FlexBuffer back to JSON:
3008 auto jsonback = jroot.ToString();
3009 TEST_EQ_STR(jsontest, jsonback.c_str());
3013 for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
3015 for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
3020 TEST_EQ(slb.GetSize(), 664);
3023 void FlexBuffersDeprecatedTest() {
3024 // FlexBuffers as originally designed had a flaw involving the
3025 // FBT_VECTOR_STRING datatype, and this test documents/tests the fix for it.
3026 // Discussion: https://github.com/google/flatbuffers/issues/5627
3027 flexbuffers::Builder slb;
3028 // FBT_VECTOR_* are "typed vectors" where all elements are of the same type.
3029 // Problem is, when storing FBT_STRING elements, it relies on that type to
3030 // get the bit-width for the size field of the string, which in this case
3031 // isn't present, and instead defaults to 8-bit. This means that any strings
3032 // stored inside such a vector, when accessed thru the old API that returns
3033 // a String reference, will appear to be truncated if the string stored is
3034 // actually >=256 bytes.
3035 std::string test_data(300, 'A');
3036 auto start = slb.StartVector();
3037 // This one will have a 16-bit size field.
3038 slb.String(test_data);
3039 // This one will have an 8-bit size field.
3040 slb.String("hello");
3041 // We're asking this to be serialized as a typed vector (true), but not
3042 // fixed size (false). The type will be FBT_VECTOR_STRING with a bit-width
3043 // of whatever the offsets in the vector need, the bit-widths of the strings
3044 // are not stored(!) <- the actual design flaw.
3045 // Note that even in the fixed code, we continue to serialize the elements of
3046 // FBT_VECTOR_STRING as FBT_STRING, since there may be old code out there
3047 // reading new data that we want to continue to function.
3048 // Thus, FBT_VECTOR_STRING, while deprecated, will always be represented the
3049 // same way, the fix lies on the reading side.
3050 slb.EndVector(start, true, false);
3052 // So now lets read this data back.
3053 // For existing data, since we have no way of knowing what the actual
3054 // bit-width of the size field of the string is, we are going to ignore this
3055 // field, and instead treat these strings as FBT_KEY (null-terminated), so we
3056 // can deal with strings of arbitrary length. This of course truncates strings
3057 // with embedded nulls, but we think that that is preferrable over truncating
3058 // strings >= 256 bytes.
3059 auto vec = flexbuffers::GetRoot(slb.GetBuffer()).AsTypedVector();
3060 // Even though this was serialized as FBT_VECTOR_STRING, it is read as
3062 TEST_EQ(vec.ElementType(), flexbuffers::FBT_KEY);
3063 // Access the long string. Previously, this would return a string of size 1,
3064 // since it would read the high-byte of the 16-bit length.
3065 // This should now correctly test the full 300 bytes, using AsKey():
3066 TEST_EQ_STR(vec[0].AsKey(), test_data.c_str());
3067 // Old code that called AsString will continue to work, as the String
3068 // accessor objects now use a cached size that can come from a key as well.
3069 TEST_EQ_STR(vec[0].AsString().c_str(), test_data.c_str());
3070 // Short strings work as before:
3071 TEST_EQ_STR(vec[1].AsKey(), "hello");
3072 TEST_EQ_STR(vec[1].AsString().c_str(), "hello");
3073 // So, while existing code and data mostly "just work" with the fixes applied
3074 // to AsTypedVector and AsString, what do you do going forward?
3075 // Code accessing existing data doesn't necessarily need to change, though
3076 // you could consider using AsKey instead of AsString for a) documenting
3077 // that you are accessing keys, or b) a speedup if you don't actually use
3079 // For new data, or data that doesn't need to be backwards compatible,
3080 // instead serialize as FBT_VECTOR (call EndVector with typed = false, then
3081 // read elements with AsString), or, for maximum compactness, use
3082 // FBT_VECTOR_KEY (call slb.Key above instead, read with AsKey or AsString).
3085 void TypeAliasesTest() {
3086 flatbuffers::FlatBufferBuilder builder;
3088 builder.Finish(CreateTypeAliases(
3089 builder, flatbuffers::numeric_limits<int8_t>::min(),
3090 flatbuffers::numeric_limits<uint8_t>::max(),
3091 flatbuffers::numeric_limits<int16_t>::min(),
3092 flatbuffers::numeric_limits<uint16_t>::max(),
3093 flatbuffers::numeric_limits<int32_t>::min(),
3094 flatbuffers::numeric_limits<uint32_t>::max(),
3095 flatbuffers::numeric_limits<int64_t>::min(),
3096 flatbuffers::numeric_limits<uint64_t>::max(), 2.3f, 2.3));
3098 auto p = builder.GetBufferPointer();
3099 auto ta = flatbuffers::GetRoot<TypeAliases>(p);
3101 TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
3102 TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
3103 TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
3104 TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
3105 TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
3106 TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
3107 TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
3108 TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
3109 TEST_EQ(ta->f32(), 2.3f);
3110 TEST_EQ(ta->f64(), 2.3);
3111 using namespace flatbuffers; // is_same
3112 static_assert(is_same<decltype(ta->i8()), int8_t>::value, "invalid type");
3113 static_assert(is_same<decltype(ta->i16()), int16_t>::value, "invalid type");
3114 static_assert(is_same<decltype(ta->i32()), int32_t>::value, "invalid type");
3115 static_assert(is_same<decltype(ta->i64()), int64_t>::value, "invalid type");
3116 static_assert(is_same<decltype(ta->u8()), uint8_t>::value, "invalid type");
3117 static_assert(is_same<decltype(ta->u16()), uint16_t>::value, "invalid type");
3118 static_assert(is_same<decltype(ta->u32()), uint32_t>::value, "invalid type");
3119 static_assert(is_same<decltype(ta->u64()), uint64_t>::value, "invalid type");
3120 static_assert(is_same<decltype(ta->f32()), float>::value, "invalid type");
3121 static_assert(is_same<decltype(ta->f64()), double>::value, "invalid type");
3124 void EndianSwapTest() {
3125 TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
3126 TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
3128 TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
3129 0xEFCDAB9078563412);
3130 TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
3133 void UninitializedVectorTest() {
3134 flatbuffers::FlatBufferBuilder builder;
3136 Test *buf = nullptr;
3137 auto vector_offset =
3138 builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
3140 buf[0] = Test(10, 20);
3141 buf[1] = Test(30, 40);
3143 auto required_name = builder.CreateString("myMonster");
3144 auto monster_builder = MonsterBuilder(builder);
3145 monster_builder.add_name(
3146 required_name); // required field mandated for monster.
3147 monster_builder.add_test4(vector_offset);
3148 builder.Finish(monster_builder.Finish());
3150 auto p = builder.GetBufferPointer();
3151 auto uvt = flatbuffers::GetRoot<Monster>(p);
3153 auto vec = uvt->test4();
3155 auto test_0 = vec->Get(0);
3156 auto test_1 = vec->Get(1);
3157 TEST_EQ(test_0->a(), 10);
3158 TEST_EQ(test_0->b(), 20);
3159 TEST_EQ(test_1->a(), 30);
3160 TEST_EQ(test_1->b(), 40);
3163 void EqualOperatorTest() {
3166 TEST_EQ(b == a, true);
3167 TEST_EQ(b != a, false);
3170 TEST_EQ(b == a, false);
3171 TEST_EQ(b != a, true);
3173 TEST_EQ(b == a, true);
3174 TEST_EQ(b != a, false);
3176 b.inventory.push_back(3);
3177 TEST_EQ(b == a, false);
3178 TEST_EQ(b != a, true);
3179 b.inventory.clear();
3180 TEST_EQ(b == a, true);
3181 TEST_EQ(b != a, false);
3183 b.test.type = Any_Monster;
3184 TEST_EQ(b == a, false);
3185 TEST_EQ(b != a, true);
3188 // For testing any binaries, e.g. from fuzzing.
3189 void LoadVerifyBinaryTest() {
3191 if (flatbuffers::LoadFile(
3192 (test_data_path + "fuzzer/your-filename-here").c_str(), true,
3194 flatbuffers::Verifier verifier(
3195 reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
3196 TEST_EQ(VerifyMonsterBuffer(verifier), true);
3200 void CreateSharedStringTest() {
3201 flatbuffers::FlatBufferBuilder builder;
3202 const auto one1 = builder.CreateSharedString("one");
3203 const auto two = builder.CreateSharedString("two");
3204 const auto one2 = builder.CreateSharedString("one");
3205 TEST_EQ(one1.o, one2.o);
3206 const auto onetwo = builder.CreateSharedString("onetwo");
3207 TEST_EQ(onetwo.o != one1.o, true);
3208 TEST_EQ(onetwo.o != two.o, true);
3210 // Support for embedded nulls
3211 const char chars_b[] = { 'a', '\0', 'b' };
3212 const char chars_c[] = { 'a', '\0', 'c' };
3213 const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3214 const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
3215 const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3216 TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
3217 TEST_EQ(null_b1.o, null_b2.o);
3219 // Put the strings into an array for round trip verification.
3220 const flatbuffers::Offset<flatbuffers::String> array[7] = {
3221 one1, two, one2, onetwo, null_b1, null_c, null_b2
3223 const auto vector_offset =
3224 builder.CreateVector(array, flatbuffers::uoffset_t(7));
3225 MonsterBuilder monster_builder(builder);
3226 monster_builder.add_name(two);
3227 monster_builder.add_testarrayofstring(vector_offset);
3228 builder.Finish(monster_builder.Finish());
3230 // Read the Monster back.
3231 const auto *monster =
3232 flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
3233 TEST_EQ_STR(monster->name()->c_str(), "two");
3234 const auto *testarrayofstring = monster->testarrayofstring();
3235 TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
3236 const auto &a = *testarrayofstring;
3237 TEST_EQ_STR(a[0]->c_str(), "one");
3238 TEST_EQ_STR(a[1]->c_str(), "two");
3239 TEST_EQ_STR(a[2]->c_str(), "one");
3240 TEST_EQ_STR(a[3]->c_str(), "onetwo");
3241 TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
3242 TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
3243 TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
3245 // Make sure String::operator< works, too, since it is related to
3246 // StringOffsetCompare.
3247 TEST_EQ((*a[0]) < (*a[1]), true);
3248 TEST_EQ((*a[1]) < (*a[0]), false);
3249 TEST_EQ((*a[1]) < (*a[2]), false);
3250 TEST_EQ((*a[2]) < (*a[1]), true);
3251 TEST_EQ((*a[4]) < (*a[3]), true);
3252 TEST_EQ((*a[5]) < (*a[4]), false);
3253 TEST_EQ((*a[5]) < (*a[4]), false);
3254 TEST_EQ((*a[6]) < (*a[5]), true);
3257 #if !defined(FLATBUFFERS_SPAN_MINIMAL)
3258 void FlatbuffersSpanTest() {
3259 // Compile-time checking of non-const [] to const [] conversions.
3260 using flatbuffers::internal::is_span_convertable;
3261 (void)is_span_convertable<int, 1, int, 1>::type(123);
3262 (void)is_span_convertable<const int, 1, int, 1>::type(123);
3263 (void)is_span_convertable<const int64_t, 1, int64_t, 1>::type(123);
3264 (void)is_span_convertable<const uint64_t, 1, uint64_t, 1>::type(123);
3265 (void)is_span_convertable<const int, 1, const int, 1>::type(123);
3266 (void)is_span_convertable<const int64_t, 1, const int64_t, 1>::type(123);
3267 (void)is_span_convertable<const uint64_t, 1, const uint64_t, 1>::type(123);
3269 using flatbuffers::span;
3271 TEST_EQ(c1.size(), 0);
3272 span<char, flatbuffers::dynamic_extent> c2;
3273 TEST_EQ(c2.size(), 0);
3275 TEST_EQ(c3.size(), 0);
3276 TEST_ASSERT(c1.empty() && c2.empty() && c3.empty());
3278 int i_data7[7] = { 0, 1, 2, 3, 4, 5, 6 };
3279 span<int, 7> i1(&i_data7[0], 7);
3280 span<int> i2(i1); // make dynamic from static
3281 TEST_EQ(i1.size(), 7);
3282 TEST_EQ(i1.empty(), false);
3283 TEST_EQ(i1.size(), i2.size());
3284 TEST_EQ(i1.data(), i_data7);
3286 // Make const span from a non-const one.
3287 span<const int, 7> i3(i1);
3288 // Construct from a C-array.
3289 span<int, 7> i4(i_data7);
3290 span<const int, 7> i5(i_data7);
3291 span<int> i6(i_data7);
3292 span<const int> i7(i_data7);
3293 TEST_EQ(i7.size(), 7);
3294 // Check construction from a const array.
3295 const int i_cdata5[5] = { 4, 3, 2, 1, 0 };
3296 span<const int, 5> i8(i_cdata5);
3297 span<const int> i9(i_cdata5);
3298 TEST_EQ(i9.size(), 5);
3299 // Construction from a (ptr, size) pair.
3300 span<int, 7> i10(i_data7, 7);
3301 span<int> i11(i_data7, 7);
3302 TEST_EQ(i11.size(), 7);
3303 span<const int, 5> i12(i_cdata5, 5);
3304 span<const int> i13(i_cdata5, 5);
3305 TEST_EQ(i13.size(), 5);
3306 // Construction from std::array.
3307 std::array<int, 6> i_arr6 = { { 0, 1, 2, 3, 4, 5 } };
3308 span<int, 6> i14(i_arr6);
3309 span<const int, 6> i15(i_arr6);
3310 span<int> i16(i_arr6);
3311 span<const int> i17(i_arr6);
3312 TEST_EQ(i17.size(), 6);
3313 const std::array<int, 8> i_carr8 = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
3314 span<const int, 8> i18(i_carr8);
3315 span<const int> i19(i_carr8);
3316 TEST_EQ(i18.size(), 8);
3317 TEST_EQ(i19.size(), 8);
3319 // Check compatibility with flatbuffers::Array.
3320 int fbs_int3_underlaying[3] = { 0 };
3321 int fbs_int3_data[3] = { 1, 2, 3 };
3322 auto &fbs_int3 = flatbuffers::CastToArray(fbs_int3_underlaying);
3323 fbs_int3.CopyFromSpan(fbs_int3_data);
3324 TEST_EQ(fbs_int3.Get(1), 2);
3325 const int fbs_cint3_data[3] = { 2, 3, 4 };
3326 fbs_int3.CopyFromSpan(fbs_cint3_data);
3327 TEST_EQ(fbs_int3.Get(1), 3);
3328 // Check with Array<Enum, N>
3329 enum class Dummy : uint16_t { Zero = 0, One, Two };
3330 Dummy fbs_dummy3_underlaying[3] = {};
3331 Dummy fbs_dummy3_data[3] = { Dummy::One, Dummy::Two, Dummy::Two };
3332 auto &fbs_dummy3 = flatbuffers::CastToArray(fbs_dummy3_underlaying);
3333 fbs_dummy3.CopyFromSpan(fbs_dummy3_data);
3334 TEST_EQ(fbs_dummy3.Get(1), Dummy::Two);
3337 void FlatbuffersSpanTest() {}
3340 void FixedLengthArrayTest() {
3341 // VS10 does not support typed enums, exclude from tests
3342 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3343 // Generate an ArrayTable containing one ArrayStruct.
3344 flatbuffers::FlatBufferBuilder fbb;
3345 MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
3346 TEST_NOTNULL(nStruct0.mutable_a());
3347 nStruct0.mutable_a()->Mutate(0, 1);
3348 nStruct0.mutable_a()->Mutate(1, 2);
3349 TEST_NOTNULL(nStruct0.mutable_c());
3350 nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3351 nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3352 TEST_NOTNULL(nStruct0.mutable_d());
3353 nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
3354 nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
3355 MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
3356 TEST_NOTNULL(nStruct1.mutable_a());
3357 nStruct1.mutable_a()->Mutate(0, 3);
3358 nStruct1.mutable_a()->Mutate(1, 4);
3359 TEST_NOTNULL(nStruct1.mutable_c());
3360 nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3361 nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3362 TEST_NOTNULL(nStruct1.mutable_d());
3363 nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
3364 nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
3365 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
3366 TEST_NOTNULL(aStruct.b());
3367 TEST_NOTNULL(aStruct.mutable_b());
3368 TEST_NOTNULL(aStruct.mutable_d());
3369 TEST_NOTNULL(aStruct.mutable_f());
3370 for (int i = 0; i < aStruct.b()->size(); i++)
3371 aStruct.mutable_b()->Mutate(i, i + 1);
3372 aStruct.mutable_d()->Mutate(0, nStruct0);
3373 aStruct.mutable_d()->Mutate(1, nStruct1);
3374 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
3375 MyGame::Example::FinishArrayTableBuffer(fbb, aTable);
3377 // Verify correctness of the ArrayTable.
3378 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
3379 MyGame::Example::VerifyArrayTableBuffer(verifier);
3380 auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
3381 auto mArStruct = p->mutable_a();
3382 TEST_NOTNULL(mArStruct);
3383 TEST_NOTNULL(mArStruct->b());
3384 TEST_NOTNULL(mArStruct->d());
3385 TEST_NOTNULL(mArStruct->f());
3386 TEST_NOTNULL(mArStruct->mutable_b());
3387 TEST_NOTNULL(mArStruct->mutable_d());
3388 TEST_NOTNULL(mArStruct->mutable_f());
3389 mArStruct->mutable_b()->Mutate(14, -14);
3390 TEST_EQ(mArStruct->a(), 2);
3391 TEST_EQ(mArStruct->b()->size(), 15);
3392 TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14);
3393 TEST_EQ(mArStruct->c(), 12);
3394 TEST_NOTNULL(mArStruct->d()->Get(0));
3395 TEST_NOTNULL(mArStruct->d()->Get(0)->a());
3396 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
3397 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
3398 TEST_NOTNULL(mArStruct->d()->Get(1));
3399 TEST_NOTNULL(mArStruct->d()->Get(1)->a());
3400 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
3401 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
3402 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
3403 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
3404 mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
3405 TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
3406 TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
3407 TEST_NOTNULL(mArStruct->d()->Get(0)->c());
3408 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
3409 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
3410 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3411 mArStruct->d()->Get(0)->d()->Get(0));
3412 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3413 mArStruct->d()->Get(0)->d()->Get(1));
3414 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
3415 TEST_NOTNULL(mArStruct->d()->Get(1)->c());
3416 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
3417 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
3418 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3419 mArStruct->d()->Get(1)->d()->Get(0));
3420 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3421 mArStruct->d()->Get(1)->d()->Get(1));
3422 for (int i = 0; i < mArStruct->b()->size() - 1; i++)
3423 TEST_EQ(mArStruct->b()->Get(i), i + 1);
3425 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
3426 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
3428 // Check if default constructor set all memory zero
3429 const size_t arr_size = sizeof(MyGame::Example::ArrayStruct);
3430 char non_zero_memory[arr_size];
3431 // set memory chunk of size ArrayStruct to 1's
3432 std::memset(static_cast<void *>(non_zero_memory), 1, arr_size);
3433 // after placement-new it should be all 0's
3434 # if defined(_MSC_VER) && defined(_DEBUG)
3437 MyGame::Example::ArrayStruct *ap =
3438 new (non_zero_memory) MyGame::Example::ArrayStruct;
3439 # if defined(_MSC_VER) && defined(_DEBUG)
3440 # define new DEBUG_NEW
3443 for (size_t i = 0; i < arr_size; ++i) { TEST_EQ(non_zero_memory[i], 0); }
3447 #if !defined(FLATBUFFERS_SPAN_MINIMAL) && \
3448 (!defined(_MSC_VER) || _MSC_VER >= 1700)
3449 void FixedLengthArrayConstructorTest() {
3450 const int32_t nested_a[2] = { 1, 2 };
3451 MyGame::Example::TestEnum nested_c[2] = { MyGame::Example::TestEnum::A,
3452 MyGame::Example::TestEnum::B };
3453 const int64_t int64_2[2] = { -2, -1 };
3455 std::array<MyGame::Example::NestedStruct, 2> init_d = {
3456 { MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
3458 MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::A,
3460 std::array<int64_t, 2>{ { 12, 13 } }) }
3463 MyGame::Example::ArrayStruct arr_struct(
3465 std::array<int32_t, 0xF>{
3466 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
3467 -17, init_d, 10, int64_2);
3468 TEST_EQ(arr_struct.a(), 8.125);
3469 TEST_EQ(arr_struct.b()->Get(2), 3);
3470 TEST_EQ(arr_struct.c(), -17);
3472 TEST_NOTNULL(arr_struct.d());
3473 const auto &arr_d_0 = *arr_struct.d()->Get(0);
3474 TEST_EQ(arr_d_0.a()->Get(0), 1);
3475 TEST_EQ(arr_d_0.a()->Get(1), 2);
3476 TEST_EQ(arr_d_0.b(), MyGame::Example::TestEnum::B);
3477 TEST_EQ(arr_d_0.c()->Get(0), MyGame::Example::TestEnum::A);
3478 TEST_EQ(arr_d_0.c()->Get(1), MyGame::Example::TestEnum::B);
3479 TEST_EQ(arr_d_0.d()->Get(0), -2);
3480 TEST_EQ(arr_d_0.d()->Get(1), -1);
3481 const auto &arr_d_1 = *arr_struct.d()->Get(1);
3482 TEST_EQ(arr_d_1.a()->Get(0), 1);
3483 TEST_EQ(arr_d_1.a()->Get(1), 2);
3484 TEST_EQ(arr_d_1.b(), MyGame::Example::TestEnum::A);
3485 TEST_EQ(arr_d_1.c()->Get(0), MyGame::Example::TestEnum::A);
3486 TEST_EQ(arr_d_1.c()->Get(1), MyGame::Example::TestEnum::B);
3487 TEST_EQ(arr_d_1.d()->Get(0), 12);
3488 TEST_EQ(arr_d_1.d()->Get(1), 13);
3490 TEST_EQ(arr_struct.e(), 10);
3491 TEST_EQ(arr_struct.f()->Get(0), -2);
3492 TEST_EQ(arr_struct.f()->Get(1), -1);
3495 void FixedLengthArrayConstructorTest() {}
3498 void NativeTypeTest() {
3501 Geometry::ApplicationDataT src_data;
3502 src_data.vectors.reserve(N);
3504 for (int i = 0; i < N; ++i) {
3505 src_data.vectors.push_back(
3506 Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
3509 flatbuffers::FlatBufferBuilder fbb;
3510 fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
3512 auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
3514 for (int i = 0; i < N; ++i) {
3515 Native::Vector3D &v = dstDataT->vectors[i];
3516 TEST_EQ(v.x, 10 * i + 0.1f);
3517 TEST_EQ(v.y, 10 * i + 0.2f);
3518 TEST_EQ(v.z, 10 * i + 0.3f);
3522 void FixedLengthArrayJsonTest(bool binary) {
3523 // VS10 does not support typed enums, exclude from tests
3524 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3525 // load FlatBuffer schema (.fbs) and JSON from disk
3526 std::string schemafile;
3527 std::string jsonfile;
3529 flatbuffers::LoadFile(
3530 (test_data_path + "arrays_test." + (binary ? "bfbs" : "fbs")).c_str(),
3531 binary, &schemafile),
3533 TEST_EQ(flatbuffers::LoadFile((test_data_path + "arrays_test.golden").c_str(),
3537 // parse schema first, so we can use it to parse the data after
3538 flatbuffers::Parser parserOrg, parserGen;
3540 flatbuffers::Verifier verifier(
3541 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
3543 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3544 TEST_EQ(parserOrg.Deserialize((const uint8_t *)schemafile.c_str(),
3547 TEST_EQ(parserGen.Deserialize((const uint8_t *)schemafile.c_str(),
3551 TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
3552 TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
3554 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3556 // First, verify it, just in case:
3557 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3558 parserOrg.builder_.GetSize());
3559 TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
3562 std::string jsonGen;
3564 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3568 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3570 // Verify buffer from generated JSON
3571 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3572 parserGen.builder_.GetSize());
3573 TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
3575 // Compare generated buffer to original
3576 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3577 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3578 parserGen.builder_.GetBufferPointer(),
3579 parserOrg.builder_.GetSize()),
3586 void TestEmbeddedBinarySchema() {
3587 // load JSON from disk
3588 std::string jsonfile;
3589 TEST_EQ(flatbuffers::LoadFile(
3590 (test_data_path + "monsterdata_test.golden").c_str(), false,
3594 // parse schema first, so we can use it to parse the data after
3595 flatbuffers::Parser parserOrg, parserGen;
3596 flatbuffers::Verifier verifier(MyGame::Example::MonsterBinarySchema::data(),
3597 MyGame::Example::MonsterBinarySchema::size());
3598 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3599 TEST_EQ(parserOrg.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3600 MyGame::Example::MonsterBinarySchema::size()),
3602 TEST_EQ(parserGen.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3603 MyGame::Example::MonsterBinarySchema::size()),
3605 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3607 // First, verify it, just in case:
3608 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3609 parserOrg.builder_.GetSize());
3610 TEST_EQ(VerifyMonsterBuffer(verifierOrg), true);
3613 std::string jsonGen;
3615 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3619 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3621 // Verify buffer from generated JSON
3622 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3623 parserGen.builder_.GetSize());
3624 TEST_EQ(VerifyMonsterBuffer(verifierGen), true);
3626 // Compare generated buffer to original
3627 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3628 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3629 parserGen.builder_.GetBufferPointer(),
3630 parserOrg.builder_.GetSize()),
3634 void StringVectorDefaultsTest() {
3635 std::vector<std::string> schemas;
3636 schemas.push_back("table Monster { mana: string = \"\"; }");
3637 schemas.push_back("table Monster { mana: string = \"mystr\"; }");
3638 schemas.push_back("table Monster { mana: string = \" \"; }");
3639 schemas.push_back("table Monster { mana: [int] = []; }");
3640 schemas.push_back("table Monster { mana: [uint] = [ ]; }");
3641 schemas.push_back("table Monster { mana: [byte] = [\t\t\n]; }");
3642 for (auto s = schemas.begin(); s < schemas.end(); s++) {
3643 flatbuffers::Parser parser;
3644 TEST_ASSERT(parser.Parse(s->c_str()));
3645 const auto *mana = parser.structs_.Lookup("Monster")->fields.Lookup("mana");
3646 TEST_EQ(mana->IsDefault(), true);
3650 void OptionalScalarsTest() {
3651 // Simple schemas and a "has optional scalar" sentinal.
3652 std::vector<std::string> schemas;
3653 schemas.push_back("table Monster { mana : int; }");
3654 schemas.push_back("table Monster { mana : int = 42; }");
3655 schemas.push_back("table Monster { mana : int = null; }");
3656 schemas.push_back("table Monster { mana : long; }");
3657 schemas.push_back("table Monster { mana : long = 42; }");
3658 schemas.push_back("table Monster { mana : long = null; }");
3659 schemas.push_back("table Monster { mana : float; }");
3660 schemas.push_back("table Monster { mana : float = 42; }");
3661 schemas.push_back("table Monster { mana : float = null; }");
3662 schemas.push_back("table Monster { mana : double; }");
3663 schemas.push_back("table Monster { mana : double = 42; }");
3664 schemas.push_back("table Monster { mana : double = null; }");
3665 schemas.push_back("table Monster { mana : bool; }");
3666 schemas.push_back("table Monster { mana : bool = 42; }");
3667 schemas.push_back("table Monster { mana : bool = null; }");
3669 "enum Enum: int {A=0, B=1} "
3670 "table Monster { mana : Enum; }");
3672 "enum Enum: int {A=0, B=1} "
3673 "table Monster { mana : Enum = B; }");
3675 "enum Enum: int {A=0, B=1} "
3676 "table Monster { mana : Enum = null; }");
3678 // Check the FieldDef is correctly set.
3679 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3680 const bool has_null = schema->find("null") != std::string::npos;
3681 flatbuffers::Parser parser;
3682 TEST_ASSERT(parser.Parse(schema->c_str()));
3683 const auto *mana = parser.structs_.Lookup("Monster")->fields.Lookup("mana");
3684 TEST_EQ(mana->IsOptional(), has_null);
3687 // Test if nullable scalars are allowed for each language.
3688 for (unsigned lang = 1; lang < flatbuffers::IDLOptions::kMAX; lang <<= 1) {
3689 flatbuffers::IDLOptions opts;
3690 opts.lang_to_generate = lang;
3691 if (false == flatbuffers::Parser::SupportsOptionalScalars(opts)) {
3694 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3695 flatbuffers::Parser parser(opts);
3696 auto done = parser.Parse(schema->c_str());
3697 TEST_EQ_STR(parser.error_.c_str(), "");
3702 // test C++ nullable
3703 flatbuffers::FlatBufferBuilder fbb;
3704 FinishScalarStuffBuffer(
3705 fbb, optional_scalars::CreateScalarStuff(fbb, 1, static_cast<int8_t>(2)));
3706 auto opts = optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
3707 TEST_ASSERT(!opts->maybe_bool());
3708 TEST_ASSERT(!opts->maybe_f32().has_value());
3709 TEST_ASSERT(opts->maybe_i8().has_value());
3710 TEST_EQ(opts->maybe_i8().value(), 2);
3711 TEST_ASSERT(opts->mutate_maybe_i8(3));
3712 TEST_ASSERT(opts->maybe_i8().has_value());
3713 TEST_EQ(opts->maybe_i8().value(), 3);
3714 TEST_ASSERT(!opts->mutate_maybe_i16(-10));
3716 optional_scalars::ScalarStuffT obj;
3717 TEST_ASSERT(!obj.maybe_bool);
3718 TEST_ASSERT(!obj.maybe_f32.has_value());
3719 opts->UnPackTo(&obj);
3720 TEST_ASSERT(!obj.maybe_bool);
3721 TEST_ASSERT(!obj.maybe_f32.has_value());
3722 TEST_ASSERT(obj.maybe_i8.has_value() && obj.maybe_i8.value() == 3);
3723 TEST_ASSERT(obj.maybe_i8 && *obj.maybe_i8 == 3);
3725 obj.maybe_enum = optional_scalars::OptionalByte_Two;
3728 FinishScalarStuffBuffer(fbb, optional_scalars::ScalarStuff::Pack(fbb, &obj));
3729 opts = optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
3730 TEST_ASSERT(opts->maybe_i8().has_value());
3731 TEST_EQ(opts->maybe_i8().value(), 3);
3732 TEST_ASSERT(opts->maybe_i32().has_value());
3733 TEST_EQ(opts->maybe_i32().value(), -1);
3734 TEST_EQ(opts->maybe_enum().value(), optional_scalars::OptionalByte_Two);
3735 TEST_ASSERT(opts->maybe_i32() == flatbuffers::Optional<int64_t>(-1));
3738 void ParseFlexbuffersFromJsonWithNullTest() {
3739 // Test nulls are handled appropriately through flexbuffers to exercise other
3740 // code paths of ParseSingleValue in the optional scalars change.
3741 // TODO(cneo): Json -> Flatbuffers test once some language can generate code
3742 // with optional scalars.
3744 char json[] = "{\"opt_field\": 123 }";
3745 flatbuffers::Parser parser;
3746 flexbuffers::Builder flexbuild;
3747 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3748 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3749 TEST_EQ(root.AsMap()["opt_field"].AsInt64(), 123);
3752 char json[] = "{\"opt_field\": 123.4 }";
3753 flatbuffers::Parser parser;
3754 flexbuffers::Builder flexbuild;
3755 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3756 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3757 TEST_EQ(root.AsMap()["opt_field"].AsDouble(), 123.4);
3760 char json[] = "{\"opt_field\": null }";
3761 flatbuffers::Parser parser;
3762 flexbuffers::Builder flexbuild;
3763 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3764 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3765 TEST_ASSERT(!root.AsMap().IsTheEmptyMap());
3766 TEST_ASSERT(root.AsMap()["opt_field"].IsNull());
3767 TEST_EQ(root.ToString(), std::string("{ opt_field: null }"));
3771 void FieldIdentifierTest() {
3772 using flatbuffers::Parser;
3773 TEST_EQ(true, Parser().Parse("table T{ f: int (id:0); }"));
3774 // non-integer `id` should be rejected
3775 TEST_EQ(false, Parser().Parse("table T{ f: int (id:text); }"));
3776 TEST_EQ(false, Parser().Parse("table T{ f: int (id:\"text\"); }"));
3777 TEST_EQ(false, Parser().Parse("table T{ f: int (id:0text); }"));
3778 TEST_EQ(false, Parser().Parse("table T{ f: int (id:1.0); }"));
3779 TEST_EQ(false, Parser().Parse("table T{ f: int (id:-1); g: int (id:0); }"));
3780 TEST_EQ(false, Parser().Parse("table T{ f: int (id:129496726); }"));
3781 // A unuion filed occupys two ids: enumerator + pointer (offset).
3783 Parser().Parse("union X{} table T{ u: X(id:0); table F{x:int;\n}"));
3784 // Positive tests for unions
3785 TEST_EQ(true, Parser().Parse("union X{} table T{ u: X (id:1); }"));
3786 TEST_EQ(true, Parser().Parse("union X{} table T{ u: X; }"));
3787 // Test using 'inf' and 'nan' words both as identifiers and as default values.
3788 TEST_EQ(true, Parser().Parse("table T{ nan: string; }"));
3789 TEST_EQ(true, Parser().Parse("table T{ inf: string; }"));
3790 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
3791 TEST_EQ(true, Parser().Parse("table T{ inf: float = inf; }"));
3792 TEST_EQ(true, Parser().Parse("table T{ nan: float = inf; }"));
3796 void ParseIncorrectMonsterJsonTest() {
3797 std::string schemafile;
3798 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.bfbs").c_str(),
3801 flatbuffers::Parser parser;
3802 flatbuffers::Verifier verifier(
3803 reinterpret_cast<const uint8_t *>(schemafile.c_str()), schemafile.size());
3804 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3805 TEST_EQ(parser.Deserialize((const uint8_t *)schemafile.c_str(),
3808 TEST_EQ(parser.ParseJson("{name:\"monster\"}"), true);
3809 TEST_EQ(parser.ParseJson(""), false);
3810 TEST_EQ(parser.ParseJson("{name: 1}"), false);
3811 TEST_EQ(parser.ParseJson("{name:+1}"), false);
3812 TEST_EQ(parser.ParseJson("{name:-1}"), false);
3813 TEST_EQ(parser.ParseJson("{name:-f}"), false);
3814 TEST_EQ(parser.ParseJson("{name:+f}"), false);
3817 int FlatBufferTests() {
3820 // Run our various test suites:
3823 auto flatbuf1 = CreateFlatBufferTest(rawbuf);
3824 #if !defined(FLATBUFFERS_CPP98_STL)
3825 auto flatbuf = std::move(flatbuf1); // Test move assignment.
3827 auto &flatbuf = flatbuf1;
3828 #endif // !defined(FLATBUFFERS_CPP98_STL)
3830 TriviallyCopyableTest();
3832 AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
3834 AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
3836 MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
3838 ObjectFlatBuffersTest(flatbuf.data());
3840 MiniReflectFlatBuffersTest(flatbuf.data());
3841 MiniReflectFixedLengthArrayTest();
3845 #ifndef FLATBUFFERS_NO_FILE_TESTS
3846 #ifdef FLATBUFFERS_TEST_PATH_PREFIX
3847 test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
3850 ParseAndGenerateTextTest(false);
3851 ParseAndGenerateTextTest(true);
3852 FixedLengthArrayJsonTest(false);
3853 FixedLengthArrayJsonTest(true);
3854 ReflectionTest(flatbuf.data(), flatbuf.size());
3856 ParseProtoTestWithSuffix();
3857 ParseProtoTestWithIncludes();
3859 UnionDeprecationTest();
3861 LoadVerifyBinaryTest();
3862 GenerateTableTextTest();
3863 TestEmbeddedBinarySchema();
3875 EnumOutOfRangeTest();
3876 IntegerOutOfRangeTest();
3877 IntegerBoundaryTest();
3879 UnicodeTestAllowNonUTF8();
3880 UnicodeTestGenerateTextFailsOnNonUTF8();
3881 UnicodeSurrogatesTest();
3882 UnicodeInvalidSurrogatesTest();
3884 UnknownFieldsTest();
3886 InvalidNestedFlatbufferTest();
3888 ParseProtoBufAsciiTest();
3891 CreateSharedStringTest();
3895 FlexBuffersDeprecatedTest();
3896 UninitializedVectorTest();
3897 EqualOperatorTest();
3902 TestMonsterExtraFloats();
3903 FixedLengthArrayTest();
3905 OptionalScalarsTest();
3906 ParseFlexbuffersFromJsonWithNullTest();
3907 FlatbuffersSpanTest();
3908 FixedLengthArrayConstructorTest();
3909 FieldIdentifierTest();
3910 StringVectorDefaultsTest();
3911 ParseIncorrectMonsterJsonTest();
3915 int main(int /*argc*/, const char * /*argv*/[]) {
3918 std::string req_locale;
3919 if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
3921 TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
3922 req_locale.c_str());
3923 req_locale = flatbuffers::RemoveStringQuotes(req_locale);
3924 std::string the_locale;
3926 flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
3927 TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
3931 FlatBufferBuilderTest();
3933 if (!testing_fails) {
3934 TEST_OUTPUT_LINE("ALL TESTS PASSED");
3936 TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
3938 return CloseTestEngine();