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
26 #include "flatbuffers/stl_emulation.h"
28 using flatbuffers::unique_ptr;
33 #include "monster_test_generated.h"
34 #include "namespace_test/namespace_test1_generated.h"
35 #include "namespace_test/namespace_test2_generated.h"
36 #include "union_vector/union_vector_generated.h"
37 #include "monster_extra_generated.h"
38 #if !defined(_MSC_VER) || _MSC_VER >= 1700
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 infinityf = std::numeric_limits<float>::infinity();
67 static const auto infinityd = 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(1, 10));
170 auto vecofstructs = builder.CreateVectorOfSortedStructs(&abilities);
172 // Create a nested FlatBuffer.
173 // Nested FlatBuffers are stored in a ubyte vector, which can be convenient
174 // since they can be memcpy'd around much easier than other FlatBuffer
175 // values. They have little overhead compared to storing the table directly.
176 // As a test, create a mostly empty Monster buffer:
177 flatbuffers::FlatBufferBuilder nested_builder;
178 auto nmloc = CreateMonster(nested_builder, nullptr, 0, 0,
179 nested_builder.CreateString("NestedMonster"));
180 FinishMonsterBuffer(nested_builder, nmloc);
181 // Now we can store the buffer in the parent. Note that by default, vectors
182 // are only aligned to their elements or size field, so in this case if the
183 // buffer contains 64-bit elements, they may not be correctly aligned. We fix
185 builder.ForceVectorAlignment(nested_builder.GetSize(), sizeof(uint8_t),
186 nested_builder.GetBufferMinAlignment());
187 // If for whatever reason you don't have the nested_builder available, you
188 // can substitute flatbuffers::largest_scalar_t (64-bit) for the alignment, or
189 // the largest force_align value in your schema if you're using it.
190 auto nested_flatbuffer_vector = builder.CreateVector(
191 nested_builder.GetBufferPointer(), nested_builder.GetSize());
193 // Test a nested FlexBuffer:
194 flexbuffers::Builder flexbuild;
197 auto flex = builder.CreateVector(flexbuild.GetBuffer());
199 // Test vector of enums.
200 Color colors[] = { Color_Blue, Color_Green };
201 // We use this special creation function because we have an array of
202 // pre-C++11 (enum class) enums whose size likely is int, yet its declared
203 // type in the schema is byte.
204 auto vecofcolors = builder.CreateVectorScalarCast<uint8_t, Color>(colors, 2);
206 // shortcut for creating monster with all fields set:
207 auto mloc = CreateMonster(
208 builder, &vec, 150, 80, name, inventory, Color_Blue, Any_Monster,
209 mlocs[1].Union(), // Store a union.
210 testv, vecofstrings, vecoftables, 0, nested_flatbuffer_vector, 0, false,
211 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f, vecofstrings2,
212 vecofstructs, flex, testv2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
213 AnyUniqueAliases_NONE, 0, AnyAmbiguousAliases_NONE, 0, vecofcolors);
215 FinishMonsterBuffer(builder, mloc);
218 #ifdef FLATBUFFERS_TEST_VERBOSE
219 // print byte data for debugging:
220 auto p = builder.GetBufferPointer();
221 for (flatbuffers::uoffset_t i = 0; i < builder.GetSize(); i++)
226 // return the buffer for the caller to use.
228 reinterpret_cast<const char *>(builder.GetBufferPointer());
229 buffer.assign(bufferpointer, bufferpointer + builder.GetSize());
231 return builder.Release();
234 // example of accessing a buffer loaded in memory:
235 void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
236 bool pooled = true) {
237 // First, verify the buffers integrity (optional)
238 flatbuffers::Verifier verifier(flatbuf, length);
239 TEST_EQ(VerifyMonsterBuffer(verifier), true);
242 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
243 std::vector<uint8_t> test_buff;
244 test_buff.resize(length * 2);
245 std::memcpy(&test_buff[0], flatbuf, length);
246 std::memcpy(&test_buff[length], flatbuf, length);
248 flatbuffers::Verifier verifier1(&test_buff[0], length);
249 TEST_EQ(VerifyMonsterBuffer(verifier1), true);
250 TEST_EQ(verifier1.GetComputedSize(), length);
252 flatbuffers::Verifier verifier2(&test_buff[length], length);
253 TEST_EQ(VerifyMonsterBuffer(verifier2), true);
254 TEST_EQ(verifier2.GetComputedSize(), length);
258 TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0);
259 TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true);
260 TEST_EQ(strcmp(MonsterExtension(), "mon"), 0);
262 // Access the buffer from the root.
263 auto monster = GetMonster(flatbuf);
265 TEST_EQ(monster->hp(), 80);
266 TEST_EQ(monster->mana(), 150); // default
267 TEST_EQ_STR(monster->name()->c_str(), "MyMonster");
268 // Can't access the following field, it is deprecated in the schema,
269 // which means accessors are not generated:
270 // monster.friendly()
272 auto pos = monster->pos();
274 TEST_EQ(pos->z(), 3);
275 TEST_EQ(pos->test3().a(), 10);
276 TEST_EQ(pos->test3().b(), 20);
278 auto inventory = monster->inventory();
279 TEST_EQ(VectorLength(inventory), 10UL); // Works even if inventory is null.
280 TEST_NOTNULL(inventory);
281 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
282 // Check compatibilty of iterators with STL.
283 std::vector<unsigned char> inv_vec(inventory->begin(), inventory->end());
285 for (auto it = inventory->begin(); it != inventory->end(); ++it, ++n) {
286 auto indx = it - inventory->begin();
287 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
288 TEST_EQ(*it, inv_data[indx]);
290 TEST_EQ(n, inv_vec.size());
293 for (auto it = inventory->cbegin(); it != inventory->cend(); ++it, ++n) {
294 auto indx = it - inventory->cbegin();
295 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
296 TEST_EQ(*it, inv_data[indx]);
298 TEST_EQ(n, inv_vec.size());
301 for (auto it = inventory->rbegin(); it != inventory->rend(); ++it, ++n) {
302 auto indx = inventory->rend() - it - 1;
303 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
304 TEST_EQ(*it, inv_data[indx]);
306 TEST_EQ(n, inv_vec.size());
309 for (auto it = inventory->crbegin(); it != inventory->crend(); ++it, ++n) {
310 auto indx = inventory->crend() - it - 1;
311 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
312 TEST_EQ(*it, inv_data[indx]);
314 TEST_EQ(n, inv_vec.size());
316 TEST_EQ(monster->color(), Color_Blue);
318 // Example of accessing a union:
319 TEST_EQ(monster->test_type(), Any_Monster); // First make sure which it is.
320 auto monster2 = reinterpret_cast<const Monster *>(monster->test());
321 TEST_NOTNULL(monster2);
322 TEST_EQ_STR(monster2->name()->c_str(), "Fred");
324 // Example of accessing a vector of strings:
325 auto vecofstrings = monster->testarrayofstring();
326 TEST_EQ(vecofstrings->size(), 4U);
327 TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
328 TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
330 // These should have pointer equality because of string pooling.
331 TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
332 TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
335 auto vecofstrings2 = monster->testarrayofstring2();
337 TEST_EQ(vecofstrings2->size(), 2U);
338 TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
339 TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
342 // Example of accessing a vector of tables:
343 auto vecoftables = monster->testarrayoftables();
344 TEST_EQ(vecoftables->size(), 3U);
345 for (auto it = vecoftables->begin(); it != vecoftables->end(); ++it) {
346 TEST_EQ(strlen(it->name()->c_str()) >= 4, true);
348 TEST_EQ_STR(vecoftables->Get(0)->name()->c_str(), "Barney");
349 TEST_EQ(vecoftables->Get(0)->hp(), 1000);
350 TEST_EQ_STR(vecoftables->Get(1)->name()->c_str(), "Fred");
351 TEST_EQ_STR(vecoftables->Get(2)->name()->c_str(), "Wilma");
352 TEST_NOTNULL(vecoftables->LookupByKey("Barney"));
353 TEST_NOTNULL(vecoftables->LookupByKey("Fred"));
354 TEST_NOTNULL(vecoftables->LookupByKey("Wilma"));
356 // Test accessing a vector of sorted structs
357 auto vecofstructs = monster->testarrayofsortedstruct();
358 if (vecofstructs) { // not filled in monster_test.bfbs
359 for (flatbuffers::uoffset_t i = 0; i < vecofstructs->size() - 1; i++) {
360 auto left = vecofstructs->Get(i);
361 auto right = vecofstructs->Get(i + 1);
362 TEST_EQ(true, (left->KeyCompareLessThan(right)));
364 TEST_NOTNULL(vecofstructs->LookupByKey(3));
365 TEST_EQ(static_cast<const Ability *>(nullptr),
366 vecofstructs->LookupByKey(5));
369 // Test nested FlatBuffers if available:
370 auto nested_buffer = monster->testnestedflatbuffer();
372 // nested_buffer is a vector of bytes you can memcpy. However, if you
373 // actually want to access the nested data, this is a convenient
374 // accessor that directly gives you the root table:
375 auto nested_monster = monster->testnestedflatbuffer_nested_root();
376 TEST_EQ_STR(nested_monster->name()->c_str(), "NestedMonster");
379 // Test flexbuffer if available:
380 auto flex = monster->flex();
381 // flex is a vector of bytes you can memcpy etc.
382 TEST_EQ(flex->size(), 4); // Encoded FlexBuffer bytes.
383 // However, if you actually want to access the nested data, this is a
384 // convenient accessor that directly gives you the root value:
385 TEST_EQ(monster->flex_flexbuffer_root().AsInt16(), 1234);
387 // Test vector of enums:
388 auto colors = monster->vector_of_enums();
390 TEST_EQ(colors->size(), 2);
391 TEST_EQ(colors->Get(0), Color_Blue);
392 TEST_EQ(colors->Get(1), Color_Green);
395 // Since Flatbuffers uses explicit mechanisms to override the default
396 // compiler alignment, double check that the compiler indeed obeys them:
397 // (Test consists of a short and byte):
398 TEST_EQ(flatbuffers::AlignOf<Test>(), 2UL);
399 TEST_EQ(sizeof(Test), 4UL);
401 const flatbuffers::Vector<const Test *> *tests_array[] = {
405 for (size_t i = 0; i < sizeof(tests_array) / sizeof(tests_array[0]); ++i) {
406 auto tests = tests_array[i];
408 auto test_0 = tests->Get(0);
409 auto test_1 = tests->Get(1);
410 TEST_EQ(test_0->a(), 10);
411 TEST_EQ(test_0->b(), 20);
412 TEST_EQ(test_1->a(), 30);
413 TEST_EQ(test_1->b(), 40);
414 for (auto it = tests->begin(); it != tests->end(); ++it) {
415 TEST_EQ(it->a() == 10 || it->a() == 30, true); // Just testing iterators.
419 // Checking for presence of fields:
420 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
421 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
423 // Obtaining a buffer from a root:
424 TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
427 // Change a FlatBuffer in-place, after it has been constructed.
428 void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
429 // Get non-const pointer to root.
430 auto monster = GetMutableMonster(flatbuf);
432 // Each of these tests mutates, then tests, then set back to the original,
433 // so we can test that the buffer in the end still passes our original test.
434 auto hp_ok = monster->mutate_hp(10);
435 TEST_EQ(hp_ok, true); // Field was present.
436 TEST_EQ(monster->hp(), 10);
437 // Mutate to default value
438 auto hp_ok_default = monster->mutate_hp(100);
439 TEST_EQ(hp_ok_default, true); // Field was present.
440 TEST_EQ(monster->hp(), 100);
441 // Test that mutate to default above keeps field valid for further mutations
442 auto hp_ok_2 = monster->mutate_hp(20);
443 TEST_EQ(hp_ok_2, true);
444 TEST_EQ(monster->hp(), 20);
445 monster->mutate_hp(80);
447 // Monster originally at 150 mana (default value)
448 auto mana_default_ok = monster->mutate_mana(150); // Mutate to default value.
449 TEST_EQ(mana_default_ok,
450 true); // Mutation should succeed, because default value.
451 TEST_EQ(monster->mana(), 150);
452 auto mana_ok = monster->mutate_mana(10);
453 TEST_EQ(mana_ok, false); // Field was NOT present, because default value.
454 TEST_EQ(monster->mana(), 150);
457 auto pos = monster->mutable_pos();
458 auto test3 = pos->mutable_test3(); // Struct inside a struct.
459 test3.mutate_a(50); // Struct fields never fail.
460 TEST_EQ(test3.a(), 50);
464 auto inventory = monster->mutable_inventory();
465 inventory->Mutate(9, 100);
466 TEST_EQ(inventory->Get(9), 100);
467 inventory->Mutate(9, 9);
469 auto tables = monster->mutable_testarrayoftables();
470 auto first = tables->GetMutableObject(0);
471 TEST_EQ(first->hp(), 1000);
473 TEST_EQ(first->hp(), 0);
474 first->mutate_hp(1000);
476 // Run the verifier and the regular test to make sure we didn't trample on
478 AccessFlatBufferTest(flatbuf, length);
481 // Unpack a FlatBuffer into objects.
482 void ObjectFlatBuffersTest(uint8_t *flatbuf) {
483 // Optional: we can specify resolver and rehasher functions to turn hashed
484 // strings into object pointers and back, to implement remote references
486 auto resolver = flatbuffers::resolver_function_t(
487 [](void **pointer_adr, flatbuffers::hash_value_t hash) {
490 // Don't actually do anything, leave variable null.
492 auto rehasher = flatbuffers::rehasher_function_t(
493 [](void *pointer) -> flatbuffers::hash_value_t {
498 // Turn a buffer into C++ objects.
499 auto monster1 = UnPackMonster(flatbuf, &resolver);
501 // Re-serialize the data.
502 flatbuffers::FlatBufferBuilder fbb1;
503 fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
504 MonsterIdentifier());
506 // Unpack again, and re-serialize again.
507 auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
508 flatbuffers::FlatBufferBuilder fbb2;
509 fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
510 MonsterIdentifier());
512 // Now we've gone full round-trip, the two buffers should match.
513 auto len1 = fbb1.GetSize();
514 auto len2 = fbb2.GetSize();
516 TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), len1), 0);
518 // Test it with the original buffer test to make sure all data survived.
519 AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
521 // Test accessing fields, similar to AccessFlatBufferTest above.
522 TEST_EQ(monster2->hp, 80);
523 TEST_EQ(monster2->mana, 150); // default
524 TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
526 auto &pos = monster2->pos;
528 TEST_EQ(pos->z(), 3);
529 TEST_EQ(pos->test3().a(), 10);
530 TEST_EQ(pos->test3().b(), 20);
532 auto &inventory = monster2->inventory;
533 TEST_EQ(inventory.size(), 10UL);
534 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
535 for (auto it = inventory.begin(); it != inventory.end(); ++it)
536 TEST_EQ(*it, inv_data[it - inventory.begin()]);
538 TEST_EQ(monster2->color, Color_Blue);
540 auto monster3 = monster2->test.AsMonster();
541 TEST_NOTNULL(monster3);
542 TEST_EQ_STR(monster3->name.c_str(), "Fred");
544 auto &vecofstrings = monster2->testarrayofstring;
545 TEST_EQ(vecofstrings.size(), 4U);
546 TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
547 TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
549 auto &vecofstrings2 = monster2->testarrayofstring2;
550 TEST_EQ(vecofstrings2.size(), 2U);
551 TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
552 TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
554 auto &vecoftables = monster2->testarrayoftables;
555 TEST_EQ(vecoftables.size(), 3U);
556 TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
557 TEST_EQ(vecoftables[0]->hp, 1000);
558 TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
559 TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
561 auto &tests = monster2->test4;
562 TEST_EQ(tests[0].a(), 10);
563 TEST_EQ(tests[0].b(), 20);
564 TEST_EQ(tests[1].a(), 30);
565 TEST_EQ(tests[1].b(), 40);
568 // Prefix a FlatBuffer with a size field.
569 void SizePrefixedTest() {
570 // Create size prefixed buffer.
571 flatbuffers::FlatBufferBuilder fbb;
572 FinishSizePrefixedMonsterBuffer(
573 fbb, CreateMonster(fbb, 0, 200, 300, fbb.CreateString("bob")));
576 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
577 TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier), true);
580 auto m = GetSizePrefixedMonster(fbb.GetBufferPointer());
581 TEST_EQ(m->mana(), 200);
582 TEST_EQ(m->hp(), 300);
583 TEST_EQ_STR(m->name()->c_str(), "bob");
586 void TriviallyCopyableTest() {
588 #if __GNUG__ && __GNUC__ < 5
589 TEST_EQ(__has_trivial_copy(Vec3), true);
591 #if __cplusplus >= 201103L
592 TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
598 // Check stringify of an default enum value to json
599 void JsonDefaultTest() {
600 // load FlatBuffer schema (.fbs) from disk
601 std::string schemafile;
602 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
605 // parse schema first, so we can use it to parse the data after
606 flatbuffers::Parser parser;
607 auto include_test_path =
608 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
609 const char *include_directories[] = { test_data_path.c_str(),
610 include_test_path.c_str(), nullptr };
612 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
613 // create incomplete monster and store to json
614 parser.opts.output_default_scalars_in_json = true;
615 parser.opts.output_enum_identifiers = true;
616 flatbuffers::FlatBufferBuilder builder;
617 auto name = builder.CreateString("default_enum");
618 MonsterBuilder color_monster(builder);
619 color_monster.add_name(name);
620 FinishMonsterBuffer(builder, color_monster.Finish());
622 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
623 TEST_EQ(result, true);
624 // default value of the "color" field is Blue
625 TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true);
626 // default value of the "testf" field is 3.14159
627 TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true);
630 void JsonEnumsTest() {
631 // load FlatBuffer schema (.fbs) from disk
632 std::string schemafile;
633 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
636 // parse schema first, so we can use it to parse the data after
637 flatbuffers::Parser parser;
638 auto include_test_path =
639 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
640 const char *include_directories[] = { test_data_path.c_str(),
641 include_test_path.c_str(), nullptr };
642 parser.opts.output_enum_identifiers = true;
643 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
644 flatbuffers::FlatBufferBuilder builder;
645 auto name = builder.CreateString("bitflag_enum");
646 MonsterBuilder color_monster(builder);
647 color_monster.add_name(name);
648 color_monster.add_color(Color(Color_Blue | Color_Red));
649 FinishMonsterBuffer(builder, color_monster.Finish());
651 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
652 TEST_EQ(result, true);
653 TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true);
654 // Test forward compatibility with 'output_enum_identifiers = true'.
655 // Current Color doesn't have '(1u << 2)' field, let's add it.
657 std::string future_json;
658 auto future_name = builder.CreateString("future bitflag_enum");
659 MonsterBuilder future_color(builder);
660 future_color.add_name(future_name);
661 future_color.add_color(
662 static_cast<Color>((1u << 2) | Color_Blue | Color_Red));
663 FinishMonsterBuffer(builder, future_color.Finish());
664 result = GenerateText(parser, builder.GetBufferPointer(), &future_json);
665 TEST_EQ(result, true);
666 TEST_EQ(std::string::npos != future_json.find("color: 13"), true);
669 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
670 // The IEEE-754 quiet_NaN is not simple binary constant.
671 // All binary NaN bit strings have all the bits of the biased exponent field E
672 // set to 1. A quiet NaN bit string should be encoded with the first bit d[1]
673 // of the trailing significand field T being 1 (d[0] is implicit bit).
674 // It is assumed that endianness of floating-point is same as integer.
675 template<typename T, typename U, U qnan_base> bool is_quiet_nan_impl(T v) {
676 static_assert(sizeof(T) == sizeof(U), "unexpected");
678 std::memcpy(&b, &v, sizeof(T));
679 return ((b & qnan_base) == qnan_base);
681 #if defined(__mips__) || defined(__hppa__)
682 static bool is_quiet_nan(float v) {
683 return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v) ||
684 is_quiet_nan_impl<float, uint32_t, 0x7FBFFFFFu>(v);
686 static bool is_quiet_nan(double v) {
687 return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v) ||
688 is_quiet_nan_impl<double, uint64_t, 0x7FF7FFFFFFFFFFFFu>(v);
691 static bool is_quiet_nan(float v) {
692 return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v);
694 static bool is_quiet_nan(double v) {
695 return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v);
699 void TestMonsterExtraFloats() {
700 TEST_EQ(is_quiet_nan(1.0), false);
701 TEST_EQ(is_quiet_nan(infinityd), false);
702 TEST_EQ(is_quiet_nan(-infinityf), false);
703 TEST_EQ(is_quiet_nan(std::numeric_limits<float>::quiet_NaN()), true);
704 TEST_EQ(is_quiet_nan(std::numeric_limits<double>::quiet_NaN()), true);
706 using namespace flatbuffers;
707 using namespace MyGame;
708 // Load FlatBuffer schema (.fbs) from disk.
709 std::string schemafile;
710 TEST_EQ(LoadFile((test_data_path + "monster_extra.fbs").c_str(), false,
713 // Parse schema first, so we can use it to parse the data after.
715 auto include_test_path = ConCatPathFileName(test_data_path, "include_test");
716 const char *include_directories[] = { test_data_path.c_str(),
717 include_test_path.c_str(), nullptr };
718 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
719 // Create empty extra and store to json.
720 parser.opts.output_default_scalars_in_json = true;
721 parser.opts.output_enum_identifiers = true;
722 FlatBufferBuilder builder;
723 const auto def_root = MonsterExtraBuilder(builder).Finish();
724 FinishMonsterExtraBuffer(builder, def_root);
725 const auto def_obj = builder.GetBufferPointer();
726 const auto def_extra = GetMonsterExtra(def_obj);
727 TEST_NOTNULL(def_extra);
728 TEST_EQ(is_quiet_nan(def_extra->f0()), true);
729 TEST_EQ(is_quiet_nan(def_extra->f1()), true);
730 TEST_EQ(def_extra->f2(), +infinityf);
731 TEST_EQ(def_extra->f3(), -infinityf);
732 TEST_EQ(is_quiet_nan(def_extra->d0()), true);
733 TEST_EQ(is_quiet_nan(def_extra->d1()), true);
734 TEST_EQ(def_extra->d2(), +infinityd);
735 TEST_EQ(def_extra->d3(), -infinityd);
737 auto result = GenerateText(parser, def_obj, &jsongen);
738 TEST_EQ(result, true);
739 // Check expected default values.
740 TEST_EQ(std::string::npos != jsongen.find("f0: nan"), true);
741 TEST_EQ(std::string::npos != jsongen.find("f1: nan"), true);
742 TEST_EQ(std::string::npos != jsongen.find("f2: inf"), true);
743 TEST_EQ(std::string::npos != jsongen.find("f3: -inf"), true);
744 TEST_EQ(std::string::npos != jsongen.find("d0: nan"), true);
745 TEST_EQ(std::string::npos != jsongen.find("d1: nan"), true);
746 TEST_EQ(std::string::npos != jsongen.find("d2: inf"), true);
747 TEST_EQ(std::string::npos != jsongen.find("d3: -inf"), true);
748 // Parse 'mosterdata_extra.json'.
749 const auto extra_base = test_data_path + "monsterdata_extra";
751 TEST_EQ(LoadFile((extra_base + ".json").c_str(), false, &jsongen), true);
752 TEST_EQ(parser.Parse(jsongen.c_str()), true);
753 const auto test_file = parser.builder_.GetBufferPointer();
754 const auto test_size = parser.builder_.GetSize();
755 Verifier verifier(test_file, test_size);
756 TEST_ASSERT(VerifyMonsterExtraBuffer(verifier));
757 const auto extra = GetMonsterExtra(test_file);
759 TEST_EQ(is_quiet_nan(extra->f0()), true);
760 TEST_EQ(is_quiet_nan(extra->f1()), true);
761 TEST_EQ(extra->f2(), +infinityf);
762 TEST_EQ(extra->f3(), -infinityf);
763 TEST_EQ(is_quiet_nan(extra->d0()), true);
764 TEST_EQ(extra->d1(), +infinityd);
765 TEST_EQ(extra->d2(), -infinityd);
766 TEST_EQ(is_quiet_nan(extra->d3()), true);
767 TEST_NOTNULL(extra->fvec());
768 TEST_EQ(extra->fvec()->size(), 4);
769 TEST_EQ(extra->fvec()->Get(0), 1.0f);
770 TEST_EQ(extra->fvec()->Get(1), -infinityf);
771 TEST_EQ(extra->fvec()->Get(2), +infinityf);
772 TEST_EQ(is_quiet_nan(extra->fvec()->Get(3)), true);
773 TEST_NOTNULL(extra->dvec());
774 TEST_EQ(extra->dvec()->size(), 4);
775 TEST_EQ(extra->dvec()->Get(0), 2.0);
776 TEST_EQ(extra->dvec()->Get(1), +infinityd);
777 TEST_EQ(extra->dvec()->Get(2), -infinityd);
778 TEST_EQ(is_quiet_nan(extra->dvec()->Get(3)), true);
781 void TestMonsterExtraFloats() {}
784 // example of parsing text straight into a buffer, and generating
785 // text back from it:
786 void ParseAndGenerateTextTest(bool binary) {
787 // load FlatBuffer schema (.fbs) and JSON from disk
788 std::string schemafile;
789 std::string jsonfile;
790 TEST_EQ(flatbuffers::LoadFile(
791 (test_data_path + "monster_test." + (binary ? "bfbs" : "fbs"))
793 binary, &schemafile),
795 TEST_EQ(flatbuffers::LoadFile(
796 (test_data_path + "monsterdata_test.golden").c_str(), false,
800 auto include_test_path =
801 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
802 const char *include_directories[] = { test_data_path.c_str(),
803 include_test_path.c_str(), nullptr };
805 // parse schema first, so we can use it to parse the data after
806 flatbuffers::Parser parser;
808 flatbuffers::Verifier verifier(
809 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
811 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
812 // auto schema = reflection::GetSchema(schemafile.c_str());
813 TEST_EQ(parser.Deserialize((const uint8_t *)schemafile.c_str(),
817 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
819 TEST_EQ(parser.Parse(jsonfile.c_str(), include_directories), true);
821 // here, parser.builder_ contains a binary buffer that is the parsed data.
823 // First, verify it, just in case:
824 flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
825 parser.builder_.GetSize());
826 TEST_EQ(VerifyMonsterBuffer(verifier), true);
828 AccessFlatBufferTest(parser.builder_.GetBufferPointer(),
829 parser.builder_.GetSize(), false);
831 // to ensure it is correct, we now generate text back from the binary,
832 // and compare the two:
835 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
836 TEST_EQ(result, true);
837 TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
839 // We can also do the above using the convenient Registry that knows about
840 // a set of file_identifiers mapped to schemas.
841 flatbuffers::Registry registry;
842 // Make sure schemas can find their includes.
843 registry.AddIncludeDirectory(test_data_path.c_str());
844 registry.AddIncludeDirectory(include_test_path.c_str());
845 // Call this with many schemas if possible.
846 registry.Register(MonsterIdentifier(),
847 (test_data_path + "monster_test.fbs").c_str());
848 // Now we got this set up, we can parse by just specifying the identifier,
849 // the correct schema will be loaded on the fly:
850 auto buf = registry.TextToFlatBuffer(jsonfile.c_str(), MonsterIdentifier());
851 // If this fails, check registry.lasterror_.
852 TEST_NOTNULL(buf.data());
853 // Test the buffer, to be sure:
854 AccessFlatBufferTest(buf.data(), buf.size(), false);
855 // We can use the registry to turn this back into text, in this case it
856 // will get the file_identifier from the binary:
858 auto ok = registry.FlatBufferToText(buf.data(), buf.size(), &text);
859 // If this fails, check registry.lasterror_.
861 TEST_EQ_STR(text.c_str(), jsonfile.c_str());
863 // Generate text for UTF-8 strings without escapes.
864 std::string jsonfile_utf8;
865 TEST_EQ(flatbuffers::LoadFile((test_data_path + "unicode_test.json").c_str(),
866 false, &jsonfile_utf8),
868 TEST_EQ(parser.Parse(jsonfile_utf8.c_str(), include_directories), true);
869 // To ensure it is correct, generate utf-8 text back from the binary.
870 std::string jsongen_utf8;
871 // request natural printing for utf-8 strings
872 parser.opts.natural_utf8 = true;
873 parser.opts.strict_json = true;
875 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen_utf8),
877 TEST_EQ_STR(jsongen_utf8.c_str(), jsonfile_utf8.c_str());
880 void ReflectionTest(uint8_t *flatbuf, size_t length) {
881 // Load a binary schema.
882 std::string bfbsfile;
883 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.bfbs").c_str(),
887 // Verify it, just in case:
888 flatbuffers::Verifier verifier(
889 reinterpret_cast<const uint8_t *>(bfbsfile.c_str()), bfbsfile.length());
890 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
892 // Make sure the schema is what we expect it to be.
893 auto &schema = *reflection::GetSchema(bfbsfile.c_str());
894 auto root_table = schema.root_table();
895 TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
896 auto fields = root_table->fields();
897 auto hp_field_ptr = fields->LookupByKey("hp");
898 TEST_NOTNULL(hp_field_ptr);
899 auto &hp_field = *hp_field_ptr;
900 TEST_EQ_STR(hp_field.name()->c_str(), "hp");
901 TEST_EQ(hp_field.id(), 2);
902 TEST_EQ(hp_field.type()->base_type(), reflection::Short);
903 auto friendly_field_ptr = fields->LookupByKey("friendly");
904 TEST_NOTNULL(friendly_field_ptr);
905 TEST_NOTNULL(friendly_field_ptr->attributes());
906 TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
908 // Make sure the table index is what we expect it to be.
909 auto pos_field_ptr = fields->LookupByKey("pos");
910 TEST_NOTNULL(pos_field_ptr);
911 TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
912 auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
913 TEST_NOTNULL(pos_table_ptr);
914 TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
916 // Now use it to dynamically access a buffer.
917 auto &root = *flatbuffers::GetAnyRoot(flatbuf);
919 // Verify the buffer first using reflection based verification
920 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
923 auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
926 // Rather than needing to know the type, we can also get the value of
927 // any field as an int64_t/double/string, regardless of what it actually is.
928 auto hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
929 TEST_EQ(hp_int64, 80);
930 auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
931 TEST_EQ(hp_double, 80.0);
932 auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
933 TEST_EQ_STR(hp_string.c_str(), "80");
935 // Get struct field through reflection
936 auto pos_struct = flatbuffers::GetFieldStruct(root, *pos_field_ptr);
937 TEST_NOTNULL(pos_struct);
938 TEST_EQ(flatbuffers::GetAnyFieldF(*pos_struct,
939 *pos_table_ptr->fields()->LookupByKey("z")),
942 auto test3_field = pos_table_ptr->fields()->LookupByKey("test3");
943 auto test3_struct = flatbuffers::GetFieldStruct(*pos_struct, *test3_field);
944 TEST_NOTNULL(test3_struct);
945 auto test3_object = schema.objects()->Get(test3_field->type()->index());
947 TEST_EQ(flatbuffers::GetAnyFieldF(*test3_struct,
948 *test3_object->fields()->LookupByKey("a")),
951 // We can also modify it.
952 flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
953 hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
956 // We can also set fields generically:
957 flatbuffers::SetAnyFieldI(&root, hp_field, 300);
958 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
959 TEST_EQ(hp_int64, 300);
960 flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
961 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
962 TEST_EQ(hp_int64, 300);
963 flatbuffers::SetAnyFieldS(&root, hp_field, "300");
964 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
965 TEST_EQ(hp_int64, 300);
967 // Test buffer is valid after the modifications
968 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
971 // Reset it, for further tests.
972 flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
974 // More advanced functionality: changing the size of items in-line!
975 // First we put the FlatBuffer inside an std::vector.
976 std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
977 // Find the field we want to modify.
978 auto &name_field = *fields->LookupByKey("name");
980 // This time we wrap the result from GetAnyRoot in a smartpointer that
981 // will keep rroot valid as resizingbuf resizes.
982 auto rroot = flatbuffers::piv(
983 flatbuffers::GetAnyRoot(flatbuffers::vector_data(resizingbuf)),
985 SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
987 // Here resizingbuf has changed, but rroot is still valid.
988 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
989 // Now lets extend a vector by 100 elements (10 -> 110).
990 auto &inventory_field = *fields->LookupByKey("inventory");
991 auto rinventory = flatbuffers::piv(
992 flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field), resizingbuf);
993 flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
995 // rinventory still valid, so lets read from it.
996 TEST_EQ(rinventory->Get(10), 50);
998 // For reflection uses not covered already, there is a more powerful way:
999 // we can simply generate whatever object we want to add/modify in a
1000 // FlatBuffer of its own, then add that to an existing FlatBuffer:
1001 // As an example, let's add a string to an array of strings.
1002 // First, find our field:
1003 auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
1004 // Find the vector value:
1005 auto rtestarrayofstring = flatbuffers::piv(
1006 flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
1007 **rroot, testarrayofstring_field),
1009 // It's a vector of 2 strings, to which we add one more, initialized to
1011 flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
1012 schema, 3, 0, *rtestarrayofstring, &resizingbuf);
1013 // Here we just create a buffer that contans a single string, but this
1014 // could also be any complex set of tables and other values.
1015 flatbuffers::FlatBufferBuilder stringfbb;
1016 stringfbb.Finish(stringfbb.CreateString("hank"));
1017 // Add the contents of it to our existing FlatBuffer.
1018 // We do this last, so the pointer doesn't get invalidated (since it is
1019 // at the end of the buffer):
1020 auto string_ptr = flatbuffers::AddFlatBuffer(
1021 resizingbuf, stringfbb.GetBufferPointer(), stringfbb.GetSize());
1022 // Finally, set the new value in the vector.
1023 rtestarrayofstring->MutateOffset(2, string_ptr);
1024 TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
1025 TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
1026 // Test integrity of all resize operations above.
1027 flatbuffers::Verifier resize_verifier(
1028 reinterpret_cast<const uint8_t *>(flatbuffers::vector_data(resizingbuf)),
1029 resizingbuf.size());
1030 TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
1032 // Test buffer is valid using reflection as well
1033 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1034 flatbuffers::vector_data(resizingbuf),
1035 resizingbuf.size()),
1038 // As an additional test, also set it on the name field.
1039 // Note: unlike the name change above, this just overwrites the offset,
1040 // rather than changing the string in-place.
1041 SetFieldT(*rroot, name_field, string_ptr);
1042 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
1044 // Using reflection, rather than mutating binary FlatBuffers, we can also copy
1045 // tables and other things out of other FlatBuffers into a FlatBufferBuilder,
1046 // either part or whole.
1047 flatbuffers::FlatBufferBuilder fbb;
1048 auto root_offset = flatbuffers::CopyTable(
1049 fbb, schema, *root_table, *flatbuffers::GetAnyRoot(flatbuf), true);
1050 fbb.Finish(root_offset, MonsterIdentifier());
1051 // Test that it was copied correctly:
1052 AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
1054 // Test buffer is valid using reflection as well
1055 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1056 fbb.GetBufferPointer(), fbb.GetSize()),
1060 void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
1062 flatbuffers::FlatBufferToString(flatbuf, Monster::MiniReflectTypeTable());
1066 "pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
1067 "{ a: 10, b: 20 } }, "
1069 "name: \"MyMonster\", "
1070 "inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
1071 "test_type: Monster, "
1072 "test: { name: \"Fred\" }, "
1073 "test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1074 "testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
1075 "testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" "
1077 "{ name: \"Wilma\" } ], "
1078 // TODO(wvo): should really print this nested buffer correctly.
1079 "testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, "
1081 "4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
1082 "101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
1083 "testarrayofstring2: [ \"jane\", \"mary\" ], "
1084 "testarrayofsortedstruct: [ { id: 1, distance: 10 }, "
1085 "{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
1086 "{ id: 4, distance: 40 } ], "
1087 "flex: [ 210, 4, 5, 2 ], "
1088 "test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1089 "vector_of_enums: [ Blue, Green ] "
1093 Vec3 vec(1, 2, 3, 1.5, Color_Red, test);
1094 flatbuffers::FlatBufferBuilder vec_builder;
1095 vec_builder.Finish(vec_builder.CreateStruct(vec));
1096 auto vec_buffer = vec_builder.Release();
1097 auto vec_str = flatbuffers::FlatBufferToString(vec_buffer.data(),
1098 Vec3::MiniReflectTypeTable());
1099 TEST_EQ_STR(vec_str.c_str(),
1100 "{ x: 1.0, y: 2.0, z: 3.0, test1: 1.5, test2: Red, test3: { a: "
1104 // Parse a .proto schema, output as .fbs
1105 void ParseProtoTest() {
1106 // load the .proto and the golden file from disk
1107 std::string protofile;
1108 std::string goldenfile;
1109 std::string goldenunionfile;
1111 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1115 flatbuffers::LoadFile((test_data_path + "prototest/test.golden").c_str(),
1116 false, &goldenfile),
1118 TEST_EQ(flatbuffers::LoadFile(
1119 (test_data_path + "prototest/test_union.golden").c_str(), false,
1123 flatbuffers::IDLOptions opts;
1124 opts.include_dependence_headers = false;
1125 opts.proto_mode = true;
1128 flatbuffers::Parser parser(opts);
1129 auto protopath = test_data_path + "prototest/";
1130 const char *include_directories[] = { protopath.c_str(), nullptr };
1131 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1134 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1136 // Ensure generated file is parsable.
1137 flatbuffers::Parser parser2;
1138 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1139 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1141 // Parse proto with --oneof-union option.
1142 opts.proto_oneof_union = true;
1143 flatbuffers::Parser parser3(opts);
1144 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1147 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1149 // Ensure generated file is parsable.
1150 flatbuffers::Parser parser4;
1151 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1152 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1155 // Parse a .proto schema, output as .fbs
1156 void ParseProtoTestWithSuffix() {
1157 // load the .proto and the golden file from disk
1158 std::string protofile;
1159 std::string goldenfile;
1160 std::string goldenunionfile;
1162 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1165 TEST_EQ(flatbuffers::LoadFile(
1166 (test_data_path + "prototest/test_suffix.golden").c_str(), false,
1169 TEST_EQ(flatbuffers::LoadFile(
1170 (test_data_path + "prototest/test_union_suffix.golden").c_str(),
1171 false, &goldenunionfile),
1174 flatbuffers::IDLOptions opts;
1175 opts.include_dependence_headers = false;
1176 opts.proto_mode = true;
1177 opts.proto_namespace_suffix = "test_namespace_suffix";
1180 flatbuffers::Parser parser(opts);
1181 auto protopath = test_data_path + "prototest/";
1182 const char *include_directories[] = { protopath.c_str(), nullptr };
1183 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1186 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1188 // Ensure generated file is parsable.
1189 flatbuffers::Parser parser2;
1190 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1191 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1193 // Parse proto with --oneof-union option.
1194 opts.proto_oneof_union = true;
1195 flatbuffers::Parser parser3(opts);
1196 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1199 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1201 // Ensure generated file is parsable.
1202 flatbuffers::Parser parser4;
1203 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1204 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1207 // Parse a .proto schema, output as .fbs
1208 void ParseProtoTestWithIncludes() {
1209 // load the .proto and the golden file from disk
1210 std::string protofile;
1211 std::string goldenfile;
1212 std::string goldenunionfile;
1213 std::string importprotofile;
1215 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1218 TEST_EQ(flatbuffers::LoadFile(
1219 (test_data_path + "prototest/imported.proto").c_str(), false,
1222 TEST_EQ(flatbuffers::LoadFile(
1223 (test_data_path + "prototest/test_include.golden").c_str(), false,
1226 TEST_EQ(flatbuffers::LoadFile(
1227 (test_data_path + "prototest/test_union_include.golden").c_str(),
1228 false, &goldenunionfile),
1231 flatbuffers::IDLOptions opts;
1232 opts.include_dependence_headers = true;
1233 opts.proto_mode = true;
1236 flatbuffers::Parser parser(opts);
1237 auto protopath = test_data_path + "prototest/";
1238 const char *include_directories[] = { protopath.c_str(), nullptr };
1239 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1242 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1244 // Generate fbs from import.proto
1245 flatbuffers::Parser import_parser(opts);
1246 TEST_EQ(import_parser.Parse(importprotofile.c_str(), include_directories),
1248 auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test");
1250 // Ensure generated file is parsable.
1251 flatbuffers::Parser parser2;
1253 parser2.Parse(import_fbs.c_str(), include_directories, "imported.fbs"),
1255 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1256 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1258 // Parse proto with --oneof-union option.
1259 opts.proto_oneof_union = true;
1260 flatbuffers::Parser parser3(opts);
1261 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1264 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1266 // Ensure generated file is parsable.
1267 flatbuffers::Parser parser4;
1268 TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, "imported.fbs"), true);
1269 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1270 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1273 template<typename T>
1274 void CompareTableFieldValue(flatbuffers::Table *table,
1275 flatbuffers::voffset_t voffset, T val) {
1276 T read = table->GetField(voffset, static_cast<T>(0));
1280 // Low level stress/fuzz test: serialize/deserialize a variety of
1281 // different kinds of data in different combinations
1283 // Values we're testing against: chosen to ensure no bits get chopped
1284 // off anywhere, and also be different from eachother.
1285 const uint8_t bool_val = true;
1286 const int8_t char_val = -127; // 0x81
1287 const uint8_t uchar_val = 0xFF;
1288 const int16_t short_val = -32222; // 0x8222;
1289 const uint16_t ushort_val = 0xFEEE;
1290 const int32_t int_val = 0x83333333;
1291 const uint32_t uint_val = 0xFDDDDDDD;
1292 const int64_t long_val = 0x8444444444444444LL;
1293 const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
1294 const float float_val = 3.14159f;
1295 const double double_val = 3.14159265359;
1297 const int test_values_max = 11;
1298 const flatbuffers::voffset_t fields_per_object = 4;
1299 const int num_fuzz_objects = 10000; // The higher, the more thorough :)
1301 flatbuffers::FlatBufferBuilder builder;
1303 lcg_reset(); // Keep it deterministic.
1305 flatbuffers::uoffset_t objects[num_fuzz_objects];
1307 // Generate num_fuzz_objects random objects each consisting of
1308 // fields_per_object fields, each of a random type.
1309 for (int i = 0; i < num_fuzz_objects; i++) {
1310 auto start = builder.StartTable();
1311 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1312 int choice = lcg_rand() % test_values_max;
1313 auto off = flatbuffers::FieldIndexToOffset(f);
1315 case 0: builder.AddElement<uint8_t>(off, bool_val, 0); break;
1316 case 1: builder.AddElement<int8_t>(off, char_val, 0); break;
1317 case 2: builder.AddElement<uint8_t>(off, uchar_val, 0); break;
1318 case 3: builder.AddElement<int16_t>(off, short_val, 0); break;
1319 case 4: builder.AddElement<uint16_t>(off, ushort_val, 0); break;
1320 case 5: builder.AddElement<int32_t>(off, int_val, 0); break;
1321 case 6: builder.AddElement<uint32_t>(off, uint_val, 0); break;
1322 case 7: builder.AddElement<int64_t>(off, long_val, 0); break;
1323 case 8: builder.AddElement<uint64_t>(off, ulong_val, 0); break;
1324 case 9: builder.AddElement<float>(off, float_val, 0); break;
1325 case 10: builder.AddElement<double>(off, double_val, 0); break;
1328 objects[i] = builder.EndTable(start);
1330 builder.PreAlign<flatbuffers::largest_scalar_t>(0); // Align whole buffer.
1332 lcg_reset(); // Reset.
1334 uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
1336 // Test that all objects we generated are readable and return the
1337 // expected values. We generate random objects in the same order
1338 // so this is deterministic.
1339 for (int i = 0; i < num_fuzz_objects; i++) {
1340 auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
1341 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1342 int choice = lcg_rand() % test_values_max;
1343 flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
1345 case 0: CompareTableFieldValue(table, off, bool_val); break;
1346 case 1: CompareTableFieldValue(table, off, char_val); break;
1347 case 2: CompareTableFieldValue(table, off, uchar_val); break;
1348 case 3: CompareTableFieldValue(table, off, short_val); break;
1349 case 4: CompareTableFieldValue(table, off, ushort_val); break;
1350 case 5: CompareTableFieldValue(table, off, int_val); break;
1351 case 6: CompareTableFieldValue(table, off, uint_val); break;
1352 case 7: CompareTableFieldValue(table, off, long_val); break;
1353 case 8: CompareTableFieldValue(table, off, ulong_val); break;
1354 case 9: CompareTableFieldValue(table, off, float_val); break;
1355 case 10: CompareTableFieldValue(table, off, double_val); break;
1361 // High level stress/fuzz test: generate a big schema and
1362 // matching json data in random combinations, then parse both,
1363 // generate json back from the binary, and compare with the original.
1365 lcg_reset(); // Keep it deterministic.
1367 const int num_definitions = 30;
1368 const int num_struct_definitions = 5; // Subset of num_definitions.
1369 const int fields_per_definition = 15;
1370 const int instances_per_definition = 5;
1371 const int deprecation_rate = 10; // 1 in deprecation_rate fields will
1374 std::string schema = "namespace test;\n\n";
1377 std::string instances[instances_per_definition];
1379 // Since we're generating schema and corresponding data in tandem,
1380 // this convenience function adds strings to both at once.
1381 static void Add(RndDef (&definitions_l)[num_definitions],
1382 std::string &schema_l, const int instances_per_definition_l,
1383 const char *schema_add, const char *instance_add,
1385 schema_l += schema_add;
1386 for (int i = 0; i < instances_per_definition_l; i++)
1387 definitions_l[definition].instances[i] += instance_add;
1392 #define AddToSchemaAndInstances(schema_add, instance_add) \
1393 RndDef::Add(definitions, schema, instances_per_definition, \
1394 schema_add, instance_add, definition)
1397 RndDef::Add(definitions, schema, instances_per_definition, \
1398 "byte", "1", definition)
1401 RndDef definitions[num_definitions];
1403 // We are going to generate num_definitions, the first
1404 // num_struct_definitions will be structs, the rest tables. For each
1405 // generate random fields, some of which may be struct/table types
1406 // referring to previously generated structs/tables.
1407 // Simultanenously, we generate instances_per_definition JSON data
1408 // definitions, which will have identical structure to the schema
1409 // being generated. We generate multiple instances such that when creating
1410 // hierarchy, we get some variety by picking one randomly.
1411 for (int definition = 0; definition < num_definitions; definition++) {
1412 std::string definition_name = "D" + flatbuffers::NumToString(definition);
1414 bool is_struct = definition < num_struct_definitions;
1416 AddToSchemaAndInstances(
1417 ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
1420 for (int field = 0; field < fields_per_definition; field++) {
1421 const bool is_last_field = field == fields_per_definition - 1;
1423 // Deprecate 1 in deprecation_rate fields. Only table fields can be
1425 // Don't deprecate the last field to avoid dangling commas in JSON.
1426 const bool deprecated =
1427 !is_struct && !is_last_field && (lcg_rand() % deprecation_rate == 0);
1429 std::string field_name = "f" + flatbuffers::NumToString(field);
1430 AddToSchemaAndInstances((" " + field_name + ":").c_str(),
1431 deprecated ? "" : (field_name + ": ").c_str());
1432 // Pick random type:
1433 auto base_type = static_cast<flatbuffers::BaseType>(
1434 lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
1435 switch (base_type) {
1436 case flatbuffers::BASE_TYPE_STRING:
1438 Dummy(); // No strings in structs.
1440 AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
1443 case flatbuffers::BASE_TYPE_VECTOR:
1445 Dummy(); // No vectors in structs.
1447 AddToSchemaAndInstances("[ubyte]",
1448 deprecated ? "" : "[\n0,\n1,\n255\n]");
1451 case flatbuffers::BASE_TYPE_NONE:
1452 case flatbuffers::BASE_TYPE_UTYPE:
1453 case flatbuffers::BASE_TYPE_STRUCT:
1454 case flatbuffers::BASE_TYPE_UNION:
1456 // Pick a random previous definition and random data instance of
1458 int defref = lcg_rand() % definition;
1459 int instance = lcg_rand() % instances_per_definition;
1460 AddToSchemaAndInstances(
1461 ("D" + flatbuffers::NumToString(defref)).c_str(),
1463 : definitions[defref].instances[instance].c_str());
1465 // If this is the first definition, we have no definition we can
1470 case flatbuffers::BASE_TYPE_BOOL:
1471 AddToSchemaAndInstances(
1472 "bool", deprecated ? "" : (lcg_rand() % 2 ? "true" : "false"));
1474 case flatbuffers::BASE_TYPE_ARRAY:
1476 AddToSchemaAndInstances(
1478 deprecated ? "" : "255"); // No fixed-length arrays in tables.
1480 AddToSchemaAndInstances("[int:3]", deprecated ? "" : "[\n,\n,\n]");
1484 // All the scalar types.
1485 schema += flatbuffers::kTypeNames[base_type];
1488 // We want each instance to use its own random value.
1489 for (int inst = 0; inst < instances_per_definition; inst++)
1490 definitions[definition].instances[inst] +=
1491 flatbuffers::IsFloat(base_type)
1492 ? flatbuffers::NumToString<double>(lcg_rand() % 128)
1494 : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
1497 AddToSchemaAndInstances(deprecated ? "(deprecated);\n" : ";\n",
1498 deprecated ? "" : is_last_field ? "\n" : ",\n");
1500 AddToSchemaAndInstances("}\n\n", "}");
1503 schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
1506 flatbuffers::Parser parser;
1508 // Will not compare against the original if we don't write defaults
1509 parser.builder_.ForceDefaults(true);
1511 // Parse the schema, parse the generated data, then generate text back
1512 // from the binary and compare against the original.
1513 TEST_EQ(parser.Parse(schema.c_str()), true);
1515 const std::string &json =
1516 definitions[num_definitions - 1].instances[0] + "\n";
1518 TEST_EQ(parser.Parse(json.c_str()), true);
1520 std::string jsongen;
1521 parser.opts.indent_step = 0;
1523 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
1524 TEST_EQ(result, true);
1526 if (jsongen != json) {
1527 // These strings are larger than a megabyte, so we show the bytes around
1528 // the first bytes that are different rather than the whole string.
1529 size_t len = std::min(json.length(), jsongen.length());
1530 for (size_t i = 0; i < len; i++) {
1531 if (json[i] != jsongen[i]) {
1532 i -= std::min(static_cast<size_t>(10), i); // show some context;
1533 size_t end = std::min(len, i + 20);
1534 for (; i < end; i++)
1535 TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
1536 static_cast<int>(i), jsongen[i], json[i]);
1540 TEST_NOTNULL(nullptr); //-V501 (this comment supresses CWE-570 warning)
1544 #ifdef FLATBUFFERS_TEST_VERBOSE
1545 TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
1546 static_cast<int>(schema.length() / 1024),
1547 static_cast<int>(json.length() / 1024));
1552 // Test that parser errors are actually generated.
1553 void TestError_(const char *src, const char *error_substr, bool strict_json,
1554 const char *file, int line, const char *func) {
1555 flatbuffers::IDLOptions opts;
1556 opts.strict_json = strict_json;
1557 flatbuffers::Parser parser(opts);
1558 if (parser.Parse(src)) {
1559 TestFail("true", "false",
1560 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1562 } else if (!strstr(parser.error_.c_str(), error_substr)) {
1563 TestFail(error_substr, parser.error_.c_str(),
1564 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1569 void TestError_(const char *src, const char *error_substr, const char *file,
1570 int line, const char *func) {
1571 TestError_(src, error_substr, false, file, line, func);
1575 # define TestError(src, ...) \
1576 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
1578 # define TestError(src, ...) \
1579 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1582 // Test that parsing errors occur as we'd expect.
1583 // Also useful for coverage, making sure these paths are run.
1585 // In order they appear in idl_parser.cpp
1586 TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
1587 TestError("\"\0", "illegal");
1588 TestError("\"\\q", "escape code");
1589 TestError("table ///", "documentation");
1590 TestError("@", "illegal");
1591 TestError("table 1", "expecting");
1592 TestError("table X { Y:[[int]]; }", "nested vector");
1593 TestError("table X { Y:1; }", "illegal type");
1594 TestError("table X { Y:int; Y:int; }", "field already");
1595 TestError("table Y {} table X { Y:int; }", "same as table");
1596 TestError("struct X { Y:string; }", "only scalar");
1597 TestError("table X { Y:string = \"\"; }", "default values");
1598 TestError("struct X { a:uint = 42; }", "default values");
1599 TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
1600 TestError("struct X { Y:int (deprecated); }", "deprecate");
1601 TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
1602 "missing type field");
1603 TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
1605 TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
1606 TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
1607 TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
1610 "struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
1613 TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
1614 "unknown enum value");
1615 TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
1616 TestError("enum X:byte { Y } enum X {", "enum already");
1617 TestError("enum X:float {}", "underlying");
1618 TestError("enum X:byte { Y, Y }", "value already");
1619 TestError("enum X:byte { Y=2, Z=2 }", "unique");
1620 TestError("table X { Y:int; } table X {", "datatype already");
1621 TestError("struct X (force_align: 7) { Y:int; }", "force_align");
1622 TestError("struct X {}", "size 0");
1623 TestError("{}", "no root");
1624 TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
1625 TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
1627 TestError("root_type X;", "unknown root");
1628 TestError("struct X { Y:int; } root_type X;", "a table");
1629 TestError("union X { Y }", "referenced");
1630 TestError("union Z { X } struct X { Y:int; }", "only tables");
1631 TestError("table X { Y:[int]; YLength:int; }", "clash");
1632 TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
1633 // float to integer conversion is forbidden
1634 TestError("table X { Y:int; } root_type X; { Y:1.0 }", "float");
1635 TestError("table X { Y:bool; } root_type X; { Y:1.0 }", "float");
1636 TestError("enum X:bool { Y = true }", "must be integral");
1637 // Array of non-scalar
1638 TestError("table X { x:int; } struct Y { y:[X:2]; }",
1639 "may contain only scalar or struct fields");
1640 // Non-snake case field names
1641 TestError("table X { Y: int; } root_type Y: {Y:1.0}", "snake_case");
1644 template<typename T>
1645 T TestValue(const char *json, const char *type_name,
1646 const char *decls = nullptr) {
1647 flatbuffers::Parser parser;
1648 parser.builder_.ForceDefaults(true); // return defaults
1649 auto check_default = json ? false : true;
1650 if (check_default) { parser.opts.output_default_scalars_in_json = true; }
1652 std::string schema = std::string(decls ? decls : "") + "\n" +
1653 "table X { y:" + std::string(type_name) +
1655 auto schema_done = parser.Parse(schema.c_str());
1656 TEST_EQ_STR(parser.error_.c_str(), "");
1657 TEST_EQ(schema_done, true);
1659 auto done = parser.Parse(check_default ? "{}" : json);
1660 TEST_EQ_STR(parser.error_.c_str(), "");
1661 TEST_EQ(done, true);
1663 // Check with print.
1664 std::string print_back;
1665 parser.opts.indent_step = -1;
1666 TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back),
1668 // restore value from its default
1669 if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); }
1671 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
1672 parser.builder_.GetBufferPointer());
1673 return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
1676 bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
1678 // Additional parser testing not covered elsewhere.
1680 // Test scientific notation numbers.
1682 FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
1685 TEST_EQ(FloatCompare(TestValue<float>("{ y:\"0.0314159e+2\" }", "float"),
1689 // Test conversion functions.
1690 TEST_EQ(FloatCompare(TestValue<float>("{ y:cos(rad(180)) }", "float"), -1),
1693 // int embedded to string
1694 TEST_EQ(TestValue<int>("{ y:\"-876\" }", "int=-123"), -876);
1695 TEST_EQ(TestValue<int>("{ y:\"876\" }", "int=-123"), 876);
1697 // Test negative hex constant.
1698 TEST_EQ(TestValue<int>("{ y:-0x8ea0 }", "int=-0x8ea0"), -36512);
1699 TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
1701 // positive hex constant
1702 TEST_EQ(TestValue<int>("{ y:0x1abcdef }", "int=0x1"), 0x1abcdef);
1703 // with optional '+' sign
1704 TEST_EQ(TestValue<int>("{ y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
1706 TEST_EQ(TestValue<int>("{ y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
1708 // Make sure we do unsigned 64bit correctly.
1709 TEST_EQ(TestValue<uint64_t>("{ y:12335089644688340133 }", "ulong"),
1710 12335089644688340133ULL);
1713 TEST_EQ(TestValue<bool>("{ y:\"false\" }", "bool=true"), false);
1714 TEST_EQ(TestValue<bool>("{ y:\"true\" }", "bool=\"true\""), true);
1715 TEST_EQ(TestValue<bool>("{ y:'false' }", "bool=true"), false);
1716 TEST_EQ(TestValue<bool>("{ y:'true' }", "bool=\"true\""), true);
1718 // check comments before and after json object
1719 TEST_EQ(TestValue<int>("/*before*/ { y:1 } /*after*/", "int"), 1);
1720 TEST_EQ(TestValue<int>("//before \n { y:1 } //after", "int"), 1);
1723 void NestedListTest() {
1724 flatbuffers::Parser parser1;
1725 TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
1727 "{ F:[ [10,20], [30,40]] }"),
1731 void EnumStringsTest() {
1732 flatbuffers::Parser parser1;
1733 TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
1735 "{ F:[ A, B, \"C\", \"A B C\" ] }"),
1737 flatbuffers::Parser parser2;
1738 TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
1740 "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"),
1742 // unsigned bit_flags
1743 flatbuffers::Parser parser3;
1745 parser3.Parse("enum E:uint16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }"
1746 " table T { F: E = \"F15 F08\"; }"
1751 void EnumNamesTest() {
1752 TEST_EQ_STR("Red", EnumNameColor(Color_Red));
1753 TEST_EQ_STR("Green", EnumNameColor(Color_Green));
1754 TEST_EQ_STR("Blue", EnumNameColor(Color_Blue));
1755 // Check that Color to string don't crash while decode a mixture of Colors.
1756 // 1) Example::Color enum is enum with unfixed underlying type.
1757 // 2) Valid enum range: [0; 2^(ceil(log2(Color_ANY))) - 1].
1758 // Consequence: A value is out of this range will lead to UB (since C++17).
1759 // For details see C++17 standard or explanation on the SO:
1760 // stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class
1761 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(0)));
1762 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY - 1)));
1763 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY + 1)));
1766 void EnumOutOfRangeTest() {
1767 TestError("enum X:byte { Y = 128 }", "enum value does not fit");
1768 TestError("enum X:byte { Y = -129 }", "enum value does not fit");
1769 TestError("enum X:byte { Y = 126, Z0, Z1 }", "enum value does not fit");
1770 TestError("enum X:ubyte { Y = -1 }", "enum value does not fit");
1771 TestError("enum X:ubyte { Y = 256 }", "enum value does not fit");
1772 TestError("enum X:ubyte { Y = 255, Z }", "enum value does not fit");
1773 TestError("table Y{} union X { Y = -1 }", "enum value does not fit");
1774 TestError("table Y{} union X { Y = 256 }", "enum value does not fit");
1775 TestError("table Y{} union X { Y = 255, Z:Y }", "enum value does not fit");
1776 TestError("enum X:int { Y = -2147483649 }", "enum value does not fit");
1777 TestError("enum X:int { Y = 2147483648 }", "enum value does not fit");
1778 TestError("enum X:uint { Y = -1 }", "enum value does not fit");
1779 TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit");
1780 TestError("enum X:long { Y = 9223372036854775808 }", "does not fit");
1781 TestError("enum X:long { Y = 9223372036854775807, Z }",
1782 "enum value does not fit");
1783 TestError("enum X:ulong { Y = -1 }", "does not fit");
1784 TestError("enum X:ubyte (bit_flags) { Y=8 }", "bit flag out");
1785 TestError("enum X:byte (bit_flags) { Y=7 }", "must be unsigned"); // -128
1786 // bit_flgs out of range
1787 TestError("enum X:ubyte (bit_flags) { Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8 }",
1791 void EnumValueTest() {
1792 // json: "{ Y:0 }", schema: table X { y: "E"}
1793 // 0 in enum (V=0) E then Y=0 is valid.
1794 TEST_EQ(TestValue<int>("{ y:0 }", "E", "enum E:int { V }"), 0);
1795 TEST_EQ(TestValue<int>("{ y:V }", "E", "enum E:int { V }"), 0);
1796 // A default value of Y is 0.
1797 TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
1798 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { V=5 }"), 5);
1799 // Generate json with defaults and check.
1800 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
1802 TEST_EQ(TestValue<int>("{ y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
1803 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
1804 // Generate json with defaults and check.
1805 TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
1806 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
1808 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1809 "enum E:ulong { V = 13835058055282163712 }"),
1810 13835058055282163712ULL);
1811 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1812 "enum E:ulong { V = 18446744073709551615 }"),
1813 18446744073709551615ULL);
1814 // Assign non-enum value to enum field. Is it right?
1815 TEST_EQ(TestValue<int>("{ y:7 }", "E", "enum E:int { V = 0 }"), 7);
1816 // Check that non-ascending values are valid.
1817 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z=10, V=5 }"), 5);
1820 void IntegerOutOfRangeTest() {
1821 TestError("table T { F:byte; } root_type T; { F:128 }",
1822 "constant does not fit");
1823 TestError("table T { F:byte; } root_type T; { F:-129 }",
1824 "constant does not fit");
1825 TestError("table T { F:ubyte; } root_type T; { F:256 }",
1826 "constant does not fit");
1827 TestError("table T { F:ubyte; } root_type T; { F:-1 }",
1828 "constant does not fit");
1829 TestError("table T { F:short; } root_type T; { F:32768 }",
1830 "constant does not fit");
1831 TestError("table T { F:short; } root_type T; { F:-32769 }",
1832 "constant does not fit");
1833 TestError("table T { F:ushort; } root_type T; { F:65536 }",
1834 "constant does not fit");
1835 TestError("table T { F:ushort; } root_type T; { F:-1 }",
1836 "constant does not fit");
1837 TestError("table T { F:int; } root_type T; { F:2147483648 }",
1838 "constant does not fit");
1839 TestError("table T { F:int; } root_type T; { F:-2147483649 }",
1840 "constant does not fit");
1841 TestError("table T { F:uint; } root_type T; { F:4294967296 }",
1842 "constant does not fit");
1843 TestError("table T { F:uint; } root_type T; { F:-1 }",
1844 "constant does not fit");
1845 // Check fixed width aliases
1846 TestError("table X { Y:uint8; } root_type X; { Y: -1 }", "does not fit");
1847 TestError("table X { Y:uint8; } root_type X; { Y: 256 }", "does not fit");
1848 TestError("table X { Y:uint16; } root_type X; { Y: -1 }", "does not fit");
1849 TestError("table X { Y:uint16; } root_type X; { Y: 65536 }", "does not fit");
1850 TestError("table X { Y:uint32; } root_type X; { Y: -1 }", "");
1851 TestError("table X { Y:uint32; } root_type X; { Y: 4294967296 }",
1853 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1854 TestError("table X { Y:uint64; } root_type X; { Y: -9223372036854775809 }",
1856 TestError("table X { Y:uint64; } root_type X; { Y: 18446744073709551616 }",
1859 TestError("table X { Y:int8; } root_type X; { Y: -129 }", "does not fit");
1860 TestError("table X { Y:int8; } root_type X; { Y: 128 }", "does not fit");
1861 TestError("table X { Y:int16; } root_type X; { Y: -32769 }", "does not fit");
1862 TestError("table X { Y:int16; } root_type X; { Y: 32768 }", "does not fit");
1863 TestError("table X { Y:int32; } root_type X; { Y: -2147483649 }", "");
1864 TestError("table X { Y:int32; } root_type X; { Y: 2147483648 }",
1866 TestError("table X { Y:int64; } root_type X; { Y: -9223372036854775809 }",
1868 TestError("table X { Y:int64; } root_type X; { Y: 9223372036854775808 }",
1870 // check out-of-int64 as int8
1871 TestError("table X { Y:int8; } root_type X; { Y: -9223372036854775809 }",
1873 TestError("table X { Y:int8; } root_type X; { Y: 9223372036854775808 }",
1876 // Check default values
1877 TestError("table X { Y:int64=-9223372036854775809; } root_type X; {}",
1879 TestError("table X { Y:int64= 9223372036854775808; } root_type X; {}",
1881 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1882 TestError("table X { Y:uint64=-9223372036854775809; } root_type X; {}",
1884 TestError("table X { Y:uint64= 18446744073709551616; } root_type X; {}",
1888 void IntegerBoundaryTest() {
1889 // Check numerical compatibility with non-C++ languages.
1890 // By the C++ standard, std::numerical_limits<int64_t>::min() ==
1891 // -9223372036854775807 (-2^63+1) or less* The Flatbuffers grammar and most of
1892 // the languages (C#, Java, Rust) expect that minimum values are: -128,
1893 // -32768,.., -9223372036854775808. Since C++20,
1894 // static_cast<int64>(0x8000000000000000ULL) is well-defined two's complement
1895 // cast. Therefore -9223372036854775808 should be valid negative value.
1896 TEST_EQ(flatbuffers::numeric_limits<int8_t>::min(), -128);
1897 TEST_EQ(flatbuffers::numeric_limits<int8_t>::max(), 127);
1898 TEST_EQ(flatbuffers::numeric_limits<int16_t>::min(), -32768);
1899 TEST_EQ(flatbuffers::numeric_limits<int16_t>::max(), 32767);
1900 TEST_EQ(flatbuffers::numeric_limits<int32_t>::min() + 1, -2147483647);
1901 TEST_EQ(flatbuffers::numeric_limits<int32_t>::max(), 2147483647ULL);
1902 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min() + 1LL,
1903 -9223372036854775807LL);
1904 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(), 9223372036854775807ULL);
1905 TEST_EQ(flatbuffers::numeric_limits<uint8_t>::max(), 255);
1906 TEST_EQ(flatbuffers::numeric_limits<uint16_t>::max(), 65535);
1907 TEST_EQ(flatbuffers::numeric_limits<uint32_t>::max(), 4294967295ULL);
1908 TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
1909 18446744073709551615ULL);
1911 TEST_EQ(TestValue<int8_t>("{ y:127 }", "byte"), 127);
1912 TEST_EQ(TestValue<int8_t>("{ y:-128 }", "byte"), -128);
1913 TEST_EQ(TestValue<uint8_t>("{ y:255 }", "ubyte"), 255);
1914 TEST_EQ(TestValue<uint8_t>("{ y:0 }", "ubyte"), 0);
1915 TEST_EQ(TestValue<int16_t>("{ y:32767 }", "short"), 32767);
1916 TEST_EQ(TestValue<int16_t>("{ y:-32768 }", "short"), -32768);
1917 TEST_EQ(TestValue<uint16_t>("{ y:65535 }", "ushort"), 65535);
1918 TEST_EQ(TestValue<uint16_t>("{ y:0 }", "ushort"), 0);
1919 TEST_EQ(TestValue<int32_t>("{ y:2147483647 }", "int"), 2147483647);
1920 TEST_EQ(TestValue<int32_t>("{ y:-2147483648 }", "int") + 1, -2147483647);
1921 TEST_EQ(TestValue<uint32_t>("{ y:4294967295 }", "uint"), 4294967295);
1922 TEST_EQ(TestValue<uint32_t>("{ y:0 }", "uint"), 0);
1923 TEST_EQ(TestValue<int64_t>("{ y:9223372036854775807 }", "long"),
1924 9223372036854775807LL);
1925 TEST_EQ(TestValue<int64_t>("{ y:-9223372036854775808 }", "long") + 1LL,
1926 -9223372036854775807LL);
1927 TEST_EQ(TestValue<uint64_t>("{ y:18446744073709551615 }", "ulong"),
1928 18446744073709551615ULL);
1929 TEST_EQ(TestValue<uint64_t>("{ y:0 }", "ulong"), 0);
1930 TEST_EQ(TestValue<uint64_t>("{ y: 18446744073709551615 }", "uint64"),
1931 18446744073709551615ULL);
1932 // check that the default works
1933 TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
1934 18446744073709551615ULL);
1937 void ValidFloatTest() {
1938 // check rounding to infinity
1939 TEST_EQ(TestValue<float>("{ y:+3.4029e+38 }", "float"), +infinityf);
1940 TEST_EQ(TestValue<float>("{ y:-3.4029e+38 }", "float"), -infinityf);
1941 TEST_EQ(TestValue<double>("{ y:+1.7977e+308 }", "double"), +infinityd);
1942 TEST_EQ(TestValue<double>("{ y:-1.7977e+308 }", "double"), -infinityd);
1945 FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
1948 TEST_EQ(FloatCompare(TestValue<float>("{ y:\" 0.0314159e+2 \" }", "float"),
1952 TEST_EQ(TestValue<float>("{ y:1 }", "float"), 1.0f);
1953 TEST_EQ(TestValue<float>("{ y:1.0 }", "float"), 1.0f);
1954 TEST_EQ(TestValue<float>("{ y:1. }", "float"), 1.0f);
1955 TEST_EQ(TestValue<float>("{ y:+1. }", "float"), 1.0f);
1956 TEST_EQ(TestValue<float>("{ y:-1. }", "float"), -1.0f);
1957 TEST_EQ(TestValue<float>("{ y:1.e0 }", "float"), 1.0f);
1958 TEST_EQ(TestValue<float>("{ y:1.e+0 }", "float"), 1.0f);
1959 TEST_EQ(TestValue<float>("{ y:1.e-0 }", "float"), 1.0f);
1960 TEST_EQ(TestValue<float>("{ y:0.125 }", "float"), 0.125f);
1961 TEST_EQ(TestValue<float>("{ y:.125 }", "float"), 0.125f);
1962 TEST_EQ(TestValue<float>("{ y:-.125 }", "float"), -0.125f);
1963 TEST_EQ(TestValue<float>("{ y:+.125 }", "float"), +0.125f);
1964 TEST_EQ(TestValue<float>("{ y:5 }", "float"), 5.0f);
1965 TEST_EQ(TestValue<float>("{ y:\"5\" }", "float"), 5.0f);
1967 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
1968 // Old MSVC versions may have problem with this check.
1969 // https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
1970 TEST_EQ(TestValue<double>("{ y:6.9294956446009195e15 }", "double"),
1971 6929495644600920.0);
1973 TEST_EQ(std::isnan(TestValue<double>("{ y:nan }", "double")), true);
1974 TEST_EQ(std::isnan(TestValue<float>("{ y:nan }", "float")), true);
1975 TEST_EQ(std::isnan(TestValue<float>("{ y:\"nan\" }", "float")), true);
1976 TEST_EQ(std::isnan(TestValue<float>("{ y:+nan }", "float")), true);
1977 TEST_EQ(std::isnan(TestValue<float>("{ y:-nan }", "float")), true);
1978 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
1979 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
1981 TEST_EQ(TestValue<float>("{ y:inf }", "float"), infinityf);
1982 TEST_EQ(TestValue<float>("{ y:\"inf\" }", "float"), infinityf);
1983 TEST_EQ(TestValue<float>("{ y:+inf }", "float"), infinityf);
1984 TEST_EQ(TestValue<float>("{ y:-inf }", "float"), -infinityf);
1985 TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinityf);
1986 TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinityf);
1988 "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
1992 "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
1996 // Test binary format of float point.
1997 // https://en.cppreference.com/w/cpp/language/floating_literal
1998 // 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
1999 TEST_EQ(TestValue<double>("{ y:0x12.34p-1 }", "double"), 9.1015625);
2000 // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
2001 TEST_EQ(TestValue<float>("{ y:-0x0.2p0 }", "float"), -0.125f);
2002 TEST_EQ(TestValue<float>("{ y:-0x.2p1 }", "float"), -0.25f);
2003 TEST_EQ(TestValue<float>("{ y:0x1.2p3 }", "float"), 9.0f);
2004 TEST_EQ(TestValue<float>("{ y:0x10.1p0 }", "float"), 16.0625f);
2005 TEST_EQ(TestValue<double>("{ y:0x1.2p3 }", "double"), 9.0);
2006 TEST_EQ(TestValue<double>("{ y:0x10.1p0 }", "double"), 16.0625);
2007 TEST_EQ(TestValue<double>("{ y:0xC.68p+2 }", "double"), 49.625);
2008 TestValue<double>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
2009 TestValue<float>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
2011 #else // FLATBUFFERS_HAS_NEW_STRTOD
2012 TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");
2013 #endif // !FLATBUFFERS_HAS_NEW_STRTOD
2016 void InvalidFloatTest() {
2017 auto invalid_msg = "invalid number";
2018 auto comma_msg = "expecting: ,";
2019 TestError("table T { F:float; } root_type T; { F:1,0 }", "");
2020 TestError("table T { F:float; } root_type T; { F:. }", "");
2021 TestError("table T { F:float; } root_type T; { F:- }", invalid_msg);
2022 TestError("table T { F:float; } root_type T; { F:+ }", invalid_msg);
2023 TestError("table T { F:float; } root_type T; { F:-. }", invalid_msg);
2024 TestError("table T { F:float; } root_type T; { F:+. }", invalid_msg);
2025 TestError("table T { F:float; } root_type T; { F:.e }", "");
2026 TestError("table T { F:float; } root_type T; { F:-e }", invalid_msg);
2027 TestError("table T { F:float; } root_type T; { F:+e }", invalid_msg);
2028 TestError("table T { F:float; } root_type T; { F:-.e }", invalid_msg);
2029 TestError("table T { F:float; } root_type T; { F:+.e }", invalid_msg);
2030 TestError("table T { F:float; } root_type T; { F:-e1 }", invalid_msg);
2031 TestError("table T { F:float; } root_type T; { F:+e1 }", invalid_msg);
2032 TestError("table T { F:float; } root_type T; { F:1.0e+ }", invalid_msg);
2033 TestError("table T { F:float; } root_type T; { F:1.0e- }", invalid_msg);
2034 // exponent pP is mandatory for hex-float
2035 TestError("table T { F:float; } root_type T; { F:0x0 }", invalid_msg);
2036 TestError("table T { F:float; } root_type T; { F:-0x. }", invalid_msg);
2037 TestError("table T { F:float; } root_type T; { F:0x. }", invalid_msg);
2038 TestError("table T { F:float; } root_type T; { F:0Xe }", invalid_msg);
2039 TestError("table T { F:float; } root_type T; { F:\"0Xe\" }", invalid_msg);
2040 TestError("table T { F:float; } root_type T; { F:\"nan(1)\" }", invalid_msg);
2041 // eE not exponent in hex-float!
2042 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
2043 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
2044 TestError("table T { F:float; } root_type T; { F:0x0.0p }", invalid_msg);
2045 TestError("table T { F:float; } root_type T; { F:0x0.0p+ }", invalid_msg);
2046 TestError("table T { F:float; } root_type T; { F:0x0.0p- }", invalid_msg);
2047 TestError("table T { F:float; } root_type T; { F:0x0.0pa1 }", invalid_msg);
2048 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
2049 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
2050 TestError("table T { F:float; } root_type T; { F:0x0.0e+0 }", invalid_msg);
2051 TestError("table T { F:float; } root_type T; { F:0x0.0e-0 }", invalid_msg);
2052 TestError("table T { F:float; } root_type T; { F:0x0.0ep+ }", invalid_msg);
2053 TestError("table T { F:float; } root_type T; { F:0x0.0ep- }", invalid_msg);
2054 TestError("table T { F:float; } root_type T; { F:1.2.3 }", invalid_msg);
2055 TestError("table T { F:float; } root_type T; { F:1.2.e3 }", invalid_msg);
2056 TestError("table T { F:float; } root_type T; { F:1.2e.3 }", invalid_msg);
2057 TestError("table T { F:float; } root_type T; { F:1.2e0.3 }", invalid_msg);
2058 TestError("table T { F:float; } root_type T; { F:1.2e3. }", invalid_msg);
2059 TestError("table T { F:float; } root_type T; { F:1.2e3.0 }", invalid_msg);
2060 TestError("table T { F:float; } root_type T; { F:+-1.0 }", invalid_msg);
2061 TestError("table T { F:float; } root_type T; { F:1.0e+-1 }", invalid_msg);
2062 TestError("table T { F:float; } root_type T; { F:\"1.0e+-1\" }", invalid_msg);
2063 TestError("table T { F:float; } root_type T; { F:1.e0e }", comma_msg);
2064 TestError("table T { F:float; } root_type T; { F:0x1.p0e }", comma_msg);
2065 TestError("table T { F:float; } root_type T; { F:\" 0x10 \" }", invalid_msg);
2067 TestError("table T { F:float; } root_type T; { F:\"1,2.\" }", invalid_msg);
2068 TestError("table T { F:float; } root_type T; { F:\"1.2e3.\" }", invalid_msg);
2069 TestError("table T { F:float; } root_type T; { F:\"0x1.p0e\" }", invalid_msg);
2070 TestError("table T { F:float; } root_type T; { F:\"0x1.0\" }", invalid_msg);
2071 TestError("table T { F:float; } root_type T; { F:\" 0x1.0\" }", invalid_msg);
2072 TestError("table T { F:float; } root_type T; { F:\"+ 0\" }", invalid_msg);
2073 // disable escapes for "number-in-string"
2074 TestError("table T { F:float; } root_type T; { F:\"\\f1.2e3.\" }", "invalid");
2075 TestError("table T { F:float; } root_type T; { F:\"\\t1.2e3.\" }", "invalid");
2076 TestError("table T { F:float; } root_type T; { F:\"\\n1.2e3.\" }", "invalid");
2077 TestError("table T { F:float; } root_type T; { F:\"\\r1.2e3.\" }", "invalid");
2078 TestError("table T { F:float; } root_type T; { F:\"4\\x005\" }", "invalid");
2079 TestError("table T { F:float; } root_type T; { F:\"\'12\'\" }", invalid_msg);
2080 // null is not a number constant!
2081 TestError("table T { F:float; } root_type T; { F:\"null\" }", invalid_msg);
2082 TestError("table T { F:float; } root_type T; { F:null }", invalid_msg);
2085 void GenerateTableTextTest() {
2086 std::string schemafile;
2087 std::string jsonfile;
2089 flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2090 false, &schemafile) &&
2091 flatbuffers::LoadFile((test_data_path + "monsterdata_test.json").c_str(),
2094 auto include_test_path =
2095 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2096 const char *include_directories[] = { test_data_path.c_str(),
2097 include_test_path.c_str(), nullptr };
2098 flatbuffers::IDLOptions opt;
2099 opt.indent_step = -1;
2100 flatbuffers::Parser parser(opt);
2101 ok = parser.Parse(schemafile.c_str(), include_directories) &&
2102 parser.Parse(jsonfile.c_str(), include_directories);
2105 const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
2106 std::string jsongen;
2107 auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster",
2109 TEST_EQ(result, true);
2111 const Vec3 *pos = monster->pos();
2113 result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
2114 TEST_EQ(result, true);
2117 "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
2118 const Test &test3 = pos->test3();
2121 GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
2122 TEST_EQ(result, true);
2123 TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
2124 const Test *test4 = monster->test4()->Get(0);
2127 GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
2128 TEST_EQ(result, true);
2129 TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
2132 template<typename T>
2133 void NumericUtilsTestInteger(const char *lower, const char *upper) {
2135 TEST_EQ(flatbuffers::StringToNumber("1q", &x), false);
2137 TEST_EQ(flatbuffers::StringToNumber(upper, &x), false);
2138 TEST_EQ(x, flatbuffers::numeric_limits<T>::max());
2139 TEST_EQ(flatbuffers::StringToNumber(lower, &x), false);
2140 auto expval = flatbuffers::is_unsigned<T>::value
2141 ? flatbuffers::numeric_limits<T>::max()
2142 : flatbuffers::numeric_limits<T>::lowest();
2146 template<typename T>
2147 void NumericUtilsTestFloat(const char *lower, const char *upper) {
2149 TEST_EQ(flatbuffers::StringToNumber("", &f), false);
2150 TEST_EQ(flatbuffers::StringToNumber("1q", &f), false);
2152 TEST_EQ(flatbuffers::StringToNumber(upper, &f), true);
2153 TEST_EQ(f, +flatbuffers::numeric_limits<T>::infinity());
2154 TEST_EQ(flatbuffers::StringToNumber(lower, &f), true);
2155 TEST_EQ(f, -flatbuffers::numeric_limits<T>::infinity());
2158 void NumericUtilsTest() {
2159 NumericUtilsTestInteger<uint64_t>("-1", "18446744073709551616");
2160 NumericUtilsTestInteger<uint8_t>("-1", "256");
2161 NumericUtilsTestInteger<int64_t>("-9223372036854775809",
2162 "9223372036854775808");
2163 NumericUtilsTestInteger<int8_t>("-129", "128");
2164 NumericUtilsTestFloat<float>("-3.4029e+38", "+3.4029e+38");
2165 NumericUtilsTestFloat<float>("-1.7977e+308", "+1.7977e+308");
2168 void IsAsciiUtilsTest() {
2170 for (int cnt = 0; cnt < 256; cnt++) {
2171 auto alpha = (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
2172 auto dec = (('0' <= c) && (c <= '9'));
2173 auto hex = (('a' <= c) && (c <= 'f')) || (('A' <= c) && (c <= 'F'));
2174 TEST_EQ(flatbuffers::is_alpha(c), alpha);
2175 TEST_EQ(flatbuffers::is_alnum(c), alpha || dec);
2176 TEST_EQ(flatbuffers::is_digit(c), dec);
2177 TEST_EQ(flatbuffers::is_xdigit(c), dec || hex);
2182 void UnicodeTest() {
2183 flatbuffers::Parser parser;
2184 // Without setting allow_non_utf8 = true, we treat \x sequences as byte
2185 // sequences which are then validated as UTF-8.
2186 TEST_EQ(parser.Parse("table T { F:string; }"
2188 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2189 "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD8"
2192 std::string jsongen;
2193 parser.opts.indent_step = -1;
2195 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2196 TEST_EQ(result, true);
2197 TEST_EQ_STR(jsongen.c_str(),
2198 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2199 "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
2202 void UnicodeTestAllowNonUTF8() {
2203 flatbuffers::Parser parser;
2204 parser.opts.allow_non_utf8 = true;
2207 "table T { F:string; }"
2209 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2210 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2212 std::string jsongen;
2213 parser.opts.indent_step = -1;
2215 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2216 TEST_EQ(result, true);
2219 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2220 "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
2223 void UnicodeTestGenerateTextFailsOnNonUTF8() {
2224 flatbuffers::Parser parser;
2225 // Allow non-UTF-8 initially to model what happens when we load a binary
2226 // flatbuffer from disk which contains non-UTF-8 strings.
2227 parser.opts.allow_non_utf8 = true;
2230 "table T { F:string; }"
2232 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2233 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2235 std::string jsongen;
2236 parser.opts.indent_step = -1;
2237 // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates
2239 parser.opts.allow_non_utf8 = false;
2241 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2242 TEST_EQ(result, false);
2245 void UnicodeSurrogatesTest() {
2246 flatbuffers::Parser parser;
2248 TEST_EQ(parser.Parse("table T { F:string (id: 0); }"
2250 "{ F:\"\\uD83D\\uDCA9\"}"),
2252 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
2253 parser.builder_.GetBufferPointer());
2254 auto string = root->GetPointer<flatbuffers::String *>(
2255 flatbuffers::FieldIndexToOffset(0));
2256 TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
2259 void UnicodeInvalidSurrogatesTest() {
2261 "table T { F:string; }"
2264 "unpaired high surrogate");
2266 "table T { F:string; }"
2268 "{ F:\"\\uD800abcd\"}",
2269 "unpaired high surrogate");
2271 "table T { F:string; }"
2273 "{ F:\"\\uD800\\n\"}",
2274 "unpaired high surrogate");
2276 "table T { F:string; }"
2278 "{ F:\"\\uD800\\uD800\"}",
2279 "multiple high surrogates");
2281 "table T { F:string; }"
2284 "unpaired low surrogate");
2287 void InvalidUTF8Test() {
2288 // "1 byte" pattern, under min length of 2 bytes
2290 "table T { F:string; }"
2293 "illegal UTF-8 sequence");
2294 // 2 byte pattern, string too short
2296 "table T { F:string; }"
2299 "illegal UTF-8 sequence");
2300 // 3 byte pattern, string too short
2302 "table T { F:string; }"
2304 "{ F:\"\xEF\xBF\"}",
2305 "illegal UTF-8 sequence");
2306 // 4 byte pattern, string too short
2308 "table T { F:string; }"
2310 "{ F:\"\xF7\xBF\xBF\"}",
2311 "illegal UTF-8 sequence");
2312 // "5 byte" pattern, string too short
2314 "table T { F:string; }"
2316 "{ F:\"\xFB\xBF\xBF\xBF\"}",
2317 "illegal UTF-8 sequence");
2318 // "6 byte" pattern, string too short
2320 "table T { F:string; }"
2322 "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}",
2323 "illegal UTF-8 sequence");
2324 // "7 byte" pattern, string too short
2326 "table T { F:string; }"
2328 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}",
2329 "illegal UTF-8 sequence");
2330 // "5 byte" pattern, over max length of 4 bytes
2332 "table T { F:string; }"
2334 "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}",
2335 "illegal UTF-8 sequence");
2336 // "6 byte" pattern, over max length of 4 bytes
2338 "table T { F:string; }"
2340 "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}",
2341 "illegal UTF-8 sequence");
2342 // "7 byte" pattern, over max length of 4 bytes
2344 "table T { F:string; }"
2346 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}",
2347 "illegal UTF-8 sequence");
2349 // Three invalid encodings for U+000A (\n, aka NEWLINE)
2351 "table T { F:string; }"
2353 "{ F:\"\xC0\x8A\"}",
2354 "illegal UTF-8 sequence");
2356 "table T { F:string; }"
2358 "{ F:\"\xE0\x80\x8A\"}",
2359 "illegal UTF-8 sequence");
2361 "table T { F:string; }"
2363 "{ F:\"\xF0\x80\x80\x8A\"}",
2364 "illegal UTF-8 sequence");
2366 // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
2368 "table T { F:string; }"
2370 "{ F:\"\xE0\x81\xA9\"}",
2371 "illegal UTF-8 sequence");
2373 "table T { F:string; }"
2375 "{ F:\"\xF0\x80\x81\xA9\"}",
2376 "illegal UTF-8 sequence");
2378 // Invalid encoding for U+20AC (EURO SYMBOL)
2380 "table T { F:string; }"
2382 "{ F:\"\xF0\x82\x82\xAC\"}",
2383 "illegal UTF-8 sequence");
2385 // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in
2388 "table T { F:string; }"
2390 // U+10400 "encoded" as U+D801 U+DC00
2391 "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}",
2392 "illegal UTF-8 sequence");
2394 // Check independence of identifier from locale.
2395 std::string locale_ident;
2396 locale_ident += "table T { F";
2397 locale_ident += static_cast<char>(-32); // unsigned 0xE0
2398 locale_ident += " :string; }";
2399 locale_ident += "root_type T;";
2400 locale_ident += "{}";
2401 TestError(locale_ident.c_str(), "");
2404 void UnknownFieldsTest() {
2405 flatbuffers::IDLOptions opts;
2406 opts.skip_unexpected_fields_in_json = true;
2407 flatbuffers::Parser parser(opts);
2409 TEST_EQ(parser.Parse("table T { str:string; i:int;}"
2412 "unknown_string:\"test\","
2413 "\"unknown_string\":\"test\","
2415 "unknown_float:1.0,"
2416 "unknown_array: [ 1, 2, 3, 4],"
2417 "unknown_object: { i: 10 },"
2418 "\"unknown_object\": { \"i\": 10 },"
2422 std::string jsongen;
2423 parser.opts.indent_step = -1;
2425 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2426 TEST_EQ(result, true);
2427 TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
2430 void ParseUnionTest() {
2431 // Unions must be parseable with the type field following the object.
2432 flatbuffers::Parser parser;
2433 TEST_EQ(parser.Parse("table T { A:int; }"
2437 "{ X:{ A:1 }, X_type: T }"),
2439 // Unions must be parsable with prefixed namespace.
2440 flatbuffers::Parser parser2;
2441 TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
2442 "table B { e:U; } root_type B;"
2443 "{ e_type: N_A, e: {} }"),
2447 void InvalidNestedFlatbufferTest() {
2448 // First, load and parse FlatBuffer schema (.fbs)
2449 std::string schemafile;
2450 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2451 false, &schemafile),
2453 auto include_test_path =
2454 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2455 const char *include_directories[] = { test_data_path.c_str(),
2456 include_test_path.c_str(), nullptr };
2457 flatbuffers::Parser parser1;
2458 TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
2460 // "color" inside nested flatbuffer contains invalid enum value
2461 TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
2462 "\"Leela\", color: \"nonexistent\"}}"),
2466 void EvolutionTest() {
2467 // VS10 does not support typed enums, exclude from tests
2468 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2469 const int NUM_VERSIONS = 2;
2470 std::string schemas[NUM_VERSIONS];
2471 std::string jsonfiles[NUM_VERSIONS];
2472 std::vector<uint8_t> binaries[NUM_VERSIONS];
2474 flatbuffers::IDLOptions idl_opts;
2475 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2476 flatbuffers::Parser parser(idl_opts);
2478 // Load all the schema versions and their associated data.
2479 for (int i = 0; i < NUM_VERSIONS; ++i) {
2480 std::string schema = test_data_path + "evolution_test/evolution_v" +
2481 flatbuffers::NumToString(i + 1) + ".fbs";
2482 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2483 std::string json = test_data_path + "evolution_test/evolution_v" +
2484 flatbuffers::NumToString(i + 1) + ".json";
2485 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2487 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2488 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2490 auto bufLen = parser.builder_.GetSize();
2491 auto buf = parser.builder_.GetBufferPointer();
2492 binaries[i].reserve(bufLen);
2493 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2496 // Assert that all the verifiers for the different schema versions properly
2497 // verify any version data.
2498 for (int i = 0; i < NUM_VERSIONS; ++i) {
2499 flatbuffers::Verifier verifier(&binaries[i].front(), binaries[i].size());
2500 TEST_ASSERT(Evolution::V1::VerifyRootBuffer(verifier));
2501 TEST_ASSERT(Evolution::V2::VerifyRootBuffer(verifier));
2504 // Test backwards compatibility by reading old data with an evolved schema.
2505 auto root_v1_viewed_from_v2 = Evolution::V2::GetRoot(&binaries[0].front());
2506 // field 'k' is new in version 2, so it should be null.
2507 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->k());
2508 // field 'l' is new in version 2 with a default of 56.
2509 TEST_EQ(root_v1_viewed_from_v2->l(), 56);
2510 // field 'c' of 'TableA' is new in version 2, so it should be null.
2511 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->e()->c());
2512 // 'TableC' was added to field 'c' union in version 2, so it should be null.
2513 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->c_as_TableC());
2514 // The field 'c' union should be of type 'TableB' regardless of schema version
2515 TEST_ASSERT(root_v1_viewed_from_v2->c_type() == Evolution::V2::Union::TableB);
2516 // The field 'f' was renamed to 'ff' in version 2, it should still be
2518 TEST_EQ(root_v1_viewed_from_v2->ff()->a(), 16);
2520 // Test forwards compatibility by reading new data with an old schema.
2521 auto root_v2_viewed_from_v1 = Evolution::V1::GetRoot(&binaries[1].front());
2522 // The field 'c' union in version 2 is a new table (index = 3) and should
2523 // still be accessible, but not interpretable.
2524 TEST_EQ(static_cast<uint8_t>(root_v2_viewed_from_v1->c_type()), 3);
2525 TEST_NOTNULL(root_v2_viewed_from_v1->c());
2526 // The field 'd' enum in verison 2 has new members and should still be
2527 // accessible, but not interpretable.
2528 TEST_EQ(static_cast<int8_t>(root_v2_viewed_from_v1->d()), 3);
2529 // The field 'a' in version 2 is deprecated and should return the default
2530 // value (0) instead of the value stored in the in the buffer (42).
2531 TEST_EQ(root_v2_viewed_from_v1->a(), 0);
2532 // The field 'ff' was originally named 'f' in version 1, it should still be
2534 TEST_EQ(root_v2_viewed_from_v1->f()->a(), 35);
2538 void UnionDeprecationTest() {
2539 const int NUM_VERSIONS = 2;
2540 std::string schemas[NUM_VERSIONS];
2541 std::string jsonfiles[NUM_VERSIONS];
2542 std::vector<uint8_t> binaries[NUM_VERSIONS];
2544 flatbuffers::IDLOptions idl_opts;
2545 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2546 flatbuffers::Parser parser(idl_opts);
2548 // Load all the schema versions and their associated data.
2549 for (int i = 0; i < NUM_VERSIONS; ++i) {
2550 std::string schema = test_data_path + "evolution_test/evolution_v" +
2551 flatbuffers::NumToString(i + 1) + ".fbs";
2552 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2553 std::string json = test_data_path + "evolution_test/evolution_v" +
2554 flatbuffers::NumToString(i + 1) + ".json";
2555 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2557 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2558 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2560 auto bufLen = parser.builder_.GetSize();
2561 auto buf = parser.builder_.GetBufferPointer();
2562 binaries[i].reserve(bufLen);
2563 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2566 auto v2 = parser.LookupStruct("Evolution.V2.Root");
2568 auto j_type_field = v2->fields.Lookup("j_type");
2569 TEST_NOTNULL(j_type_field);
2570 TEST_ASSERT(j_type_field->deprecated);
2573 void UnionVectorTest() {
2574 // load FlatBuffer fbs schema and json.
2575 std::string schemafile, jsonfile;
2576 TEST_EQ(flatbuffers::LoadFile(
2577 (test_data_path + "union_vector/union_vector.fbs").c_str(), false,
2580 TEST_EQ(flatbuffers::LoadFile(
2581 (test_data_path + "union_vector/union_vector.json").c_str(),
2586 flatbuffers::IDLOptions idl_opts;
2587 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2588 flatbuffers::Parser parser(idl_opts);
2589 TEST_EQ(parser.Parse(schemafile.c_str()), true);
2591 flatbuffers::FlatBufferBuilder fbb;
2594 std::vector<uint8_t> types;
2595 types.push_back(static_cast<uint8_t>(Character_Belle));
2596 types.push_back(static_cast<uint8_t>(Character_MuLan));
2597 types.push_back(static_cast<uint8_t>(Character_BookFan));
2598 types.push_back(static_cast<uint8_t>(Character_Other));
2599 types.push_back(static_cast<uint8_t>(Character_Unused));
2602 std::vector<flatbuffers::Offset<void>> characters;
2603 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
2604 characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
2605 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
2606 characters.push_back(fbb.CreateString("Other").Union());
2607 characters.push_back(fbb.CreateString("Unused").Union());
2610 const auto movie_offset =
2611 CreateMovie(fbb, Character_Rapunzel,
2612 fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
2613 fbb.CreateVector(types), fbb.CreateVector(characters));
2614 FinishMovieBuffer(fbb, movie_offset);
2616 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
2617 TEST_EQ(VerifyMovieBuffer(verifier), true);
2619 auto flat_movie = GetMovie(fbb.GetBufferPointer());
2621 auto TestMovie = [](const Movie *movie) {
2622 TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
2624 auto cts = movie->characters_type();
2625 TEST_EQ(movie->characters_type()->size(), 5);
2626 TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
2627 TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
2628 TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
2629 TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
2630 TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
2632 auto rapunzel = movie->main_character_as_Rapunzel();
2633 TEST_NOTNULL(rapunzel);
2634 TEST_EQ(rapunzel->hair_length(), 6);
2636 auto cs = movie->characters();
2637 TEST_EQ(cs->size(), 5);
2638 auto belle = cs->GetAs<BookReader>(0);
2639 TEST_EQ(belle->books_read(), 7);
2640 auto mu_lan = cs->GetAs<Attacker>(1);
2641 TEST_EQ(mu_lan->sword_attack_damage(), 5);
2642 auto book_fan = cs->GetAs<BookReader>(2);
2643 TEST_EQ(book_fan->books_read(), 2);
2644 auto other = cs->GetAsString(3);
2645 TEST_EQ_STR(other->c_str(), "Other");
2646 auto unused = cs->GetAsString(4);
2647 TEST_EQ_STR(unused->c_str(), "Unused");
2650 TestMovie(flat_movie);
2652 // Also test the JSON we loaded above.
2653 TEST_EQ(parser.Parse(jsonfile.c_str()), true);
2654 auto jbuf = parser.builder_.GetBufferPointer();
2655 flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
2656 TEST_EQ(VerifyMovieBuffer(jverifier), true);
2657 TestMovie(GetMovie(jbuf));
2659 auto movie_object = flat_movie->UnPack();
2660 TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
2661 TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
2662 TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
2663 TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
2664 TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
2665 TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
2668 fbb.Finish(Movie::Pack(fbb, movie_object));
2670 delete movie_object;
2672 auto repacked_movie = GetMovie(fbb.GetBufferPointer());
2674 TestMovie(repacked_movie);
2676 // Generate text using mini-reflection.
2678 flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
2681 "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
2682 "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
2683 "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
2684 "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
2686 flatbuffers::ToStringVisitor visitor("\n", true, " ");
2687 IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
2688 TEST_EQ_STR(visitor.s.c_str(),
2690 " \"main_character_type\": \"Rapunzel\",\n"
2691 " \"main_character\": {\n"
2692 " \"hair_length\": 6\n"
2694 " \"characters_type\": [\n"
2701 " \"characters\": [\n"
2703 " \"books_read\": 7\n"
2706 " \"sword_attack_damage\": 5\n"
2709 " \"books_read\": 2\n"
2716 // Generate text using parsed schema.
2717 std::string jsongen;
2718 auto result = GenerateText(parser, fbb.GetBufferPointer(), &jsongen);
2719 TEST_EQ(result, true);
2720 TEST_EQ_STR(jsongen.c_str(),
2722 " main_character_type: \"Rapunzel\",\n"
2723 " main_character: {\n"
2726 " characters_type: [\n"
2738 " sword_attack_damage: 5\n"
2748 // Simple test with reflection.
2750 auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
2751 auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
2752 fbb.GetBufferPointer(), fbb.GetSize());
2755 flatbuffers::Parser parser2(idl_opts);
2756 TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
2757 "union Any { Bool }"
2758 "table Root { a:Any; }"
2761 TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
2764 void ConformTest() {
2765 flatbuffers::Parser parser;
2766 TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
2768 auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
2769 const char *expected_err) {
2770 flatbuffers::Parser parser2;
2771 TEST_EQ(parser2.Parse(test), true);
2772 auto err = parser2.ConformTo(parser1);
2773 TEST_NOTNULL(strstr(err.c_str(), expected_err));
2776 test_conform(parser, "table T { A:byte; }", "types differ for field");
2777 test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
2778 test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
2779 test_conform(parser, "table T { B:float; }",
2780 "field renamed to different type");
2781 test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
2784 void ParseProtoBufAsciiTest() {
2785 // We can put the parser in a mode where it will accept JSON that looks more
2786 // like Protobuf ASCII, for users that have data in that format.
2787 // This uses no "" for field names (which we already support by default,
2788 // omits `,`, `:` before `{` and a couple of other features.
2789 flatbuffers::Parser parser;
2790 parser.opts.protobuf_ascii_alike = true;
2792 parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
2794 TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
2795 // Similarly, in text output, it should omit these.
2797 auto ok = flatbuffers::GenerateText(
2798 parser, parser.builder_.GetBufferPointer(), &text);
2800 TEST_EQ_STR(text.c_str(),
2801 "{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n");
2804 void FlexBuffersTest() {
2805 flexbuffers::Builder slb(512,
2806 flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
2808 // Write the equivalent of:
2809 // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ],
2810 // foo: 100, bool: true, mymap: { foo: "Fred" } }
2812 #ifndef FLATBUFFERS_CPP98_STL
2813 // It's possible to do this without std::function support as well.
2815 slb.Vector("vec", [&]() {
2816 slb += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2818 slb.IndirectFloat(4.0f);
2819 auto i_f = slb.LastValue();
2820 uint8_t blob[] = { 77 };
2823 slb.ReuseValue(i_f);
2825 int ints[] = { 1, 2, 3 };
2826 slb.Vector("bar", ints, 3);
2827 slb.FixedTypedVector("bar3", ints, 3);
2828 bool bools[] = {true, false, true, false};
2829 slb.Vector("bools", bools, 4);
2830 slb.Bool("bool", true);
2831 slb.Double("foo", 100);
2832 slb.Map("mymap", [&]() {
2833 slb.String("foo", "Fred"); // Testing key and string reuse.
2838 // It's possible to do this without std::function support as well.
2839 slb.Map([](flexbuffers::Builder& slb2) {
2840 slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
2841 slb3 += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2843 slb3.IndirectFloat(4.0f);
2844 auto i_f = slb3.LastValue();
2845 uint8_t blob[] = { 77 };
2848 slb3.ReuseValue(i_f);
2850 int ints[] = { 1, 2, 3 };
2851 slb2.Vector("bar", ints, 3);
2852 slb2.FixedTypedVector("bar3", ints, 3);
2853 slb2.Bool("bool", true);
2854 slb2.Double("foo", 100);
2855 slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
2856 slb3.String("foo", "Fred"); // Testing key and string reuse.
2860 #endif // FLATBUFFERS_CPP98_STL
2862 #ifdef FLATBUFFERS_TEST_VERBOSE
2863 for (size_t i = 0; i < slb.GetBuffer().size(); i++)
2864 printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
2869 auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
2870 TEST_EQ(map.size(), 7);
2871 auto vec = map["vec"].AsVector();
2872 TEST_EQ(vec.size(), 6);
2873 TEST_EQ(vec[0].AsInt64(), -100);
2874 TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
2875 TEST_EQ(vec[1].AsInt64(), 0); // Number parsing failed.
2876 TEST_EQ(vec[2].AsDouble(), 4.0);
2877 TEST_EQ(vec[2].AsString().IsTheEmptyString(), true); // Wrong Type.
2878 TEST_EQ_STR(vec[2].AsString().c_str(), ""); // This still works though.
2879 TEST_EQ_STR(vec[2].ToString().c_str(), "4.0"); // Or have it converted.
2880 // Few tests for templated version of As.
2881 TEST_EQ(vec[0].As<int64_t>(), -100);
2882 TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
2883 TEST_EQ(vec[1].As<int64_t>(), 0); // Number parsing failed.
2884 TEST_EQ(vec[2].As<double>(), 4.0);
2885 // Test that the blob can be accessed.
2886 TEST_EQ(vec[3].IsBlob(), true);
2887 auto blob = vec[3].AsBlob();
2888 TEST_EQ(blob.size(), 1);
2889 TEST_EQ(blob.data()[0], 77);
2890 TEST_EQ(vec[4].IsBool(), true); // Check if type is a bool
2891 TEST_EQ(vec[4].AsBool(), false); // Check if value is false
2892 TEST_EQ(vec[5].AsDouble(), 4.0); // This is shared with vec[2] !
2893 auto tvec = map["bar"].AsTypedVector();
2894 TEST_EQ(tvec.size(), 3);
2895 TEST_EQ(tvec[2].AsInt8(), 3);
2896 auto tvec3 = map["bar3"].AsFixedTypedVector();
2897 TEST_EQ(tvec3.size(), 3);
2898 TEST_EQ(tvec3[2].AsInt8(), 3);
2899 TEST_EQ(map["bool"].AsBool(), true);
2900 auto tvecb = map["bools"].AsTypedVector();
2901 TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
2902 TEST_EQ(map["foo"].AsUInt8(), 100);
2903 TEST_EQ(map["unknown"].IsNull(), true);
2904 auto mymap = map["mymap"].AsMap();
2905 // These should be equal by pointer equality, since key and value are shared.
2906 TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
2907 TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
2908 // We can mutate values in the buffer.
2909 TEST_EQ(vec[0].MutateInt(-99), true);
2910 TEST_EQ(vec[0].AsInt64(), -99);
2911 TEST_EQ(vec[1].MutateString("John"), true); // Size must match.
2912 TEST_EQ_STR(vec[1].AsString().c_str(), "John");
2913 TEST_EQ(vec[1].MutateString("Alfred"), false); // Too long.
2914 TEST_EQ(vec[2].MutateFloat(2.0f), true);
2915 TEST_EQ(vec[2].AsFloat(), 2.0f);
2916 TEST_EQ(vec[2].MutateFloat(3.14159), false); // Double does not fit in float.
2917 TEST_EQ(vec[4].AsBool(), false); // Is false before change
2918 TEST_EQ(vec[4].MutateBool(true), true); // Can change a bool
2919 TEST_EQ(vec[4].AsBool(), true); // Changed bool is now true
2922 flatbuffers::Parser parser;
2924 auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
2925 TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
2926 auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
2927 auto jmap = jroot.AsMap();
2928 auto jvec = jmap["a"].AsVector();
2929 TEST_EQ(jvec[0].AsInt64(), 123);
2930 TEST_EQ(jvec[1].AsDouble(), 456.0);
2931 TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
2932 TEST_EQ(jmap["c"].IsBool(), true); // Parsed correctly to a bool
2933 TEST_EQ(jmap["c"].AsBool(), true); // Parsed correctly to true
2934 TEST_EQ(jmap["d"].IsBool(), true); // Parsed correctly to a bool
2935 TEST_EQ(jmap["d"].AsBool(), false); // Parsed correctly to false
2936 // And from FlexBuffer back to JSON:
2937 auto jsonback = jroot.ToString();
2938 TEST_EQ_STR(jsontest, jsonback.c_str());
2942 for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
2944 for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
2949 TEST_EQ(slb.GetSize(), 664);
2952 void FlexBuffersDeprecatedTest() {
2953 // FlexBuffers as originally designed had a flaw involving the
2954 // FBT_VECTOR_STRING datatype, and this test documents/tests the fix for it.
2955 // Discussion: https://github.com/google/flatbuffers/issues/5627
2956 flexbuffers::Builder slb;
2957 // FBT_VECTOR_* are "typed vectors" where all elements are of the same type.
2958 // Problem is, when storing FBT_STRING elements, it relies on that type to
2959 // get the bit-width for the size field of the string, which in this case
2960 // isn't present, and instead defaults to 8-bit. This means that any strings
2961 // stored inside such a vector, when accessed thru the old API that returns
2962 // a String reference, will appear to be truncated if the string stored is
2963 // actually >=256 bytes.
2964 std::string test_data(300, 'A');
2965 auto start = slb.StartVector();
2966 // This one will have a 16-bit size field.
2967 slb.String(test_data);
2968 // This one will have an 8-bit size field.
2969 slb.String("hello");
2970 // We're asking this to be serialized as a typed vector (true), but not
2971 // fixed size (false). The type will be FBT_VECTOR_STRING with a bit-width
2972 // of whatever the offsets in the vector need, the bit-widths of the strings
2973 // are not stored(!) <- the actual design flaw.
2974 // Note that even in the fixed code, we continue to serialize the elements of
2975 // FBT_VECTOR_STRING as FBT_STRING, since there may be old code out there
2976 // reading new data that we want to continue to function.
2977 // Thus, FBT_VECTOR_STRING, while deprecated, will always be represented the
2978 // same way, the fix lies on the reading side.
2979 slb.EndVector(start, true, false);
2981 // So now lets read this data back.
2982 // For existing data, since we have no way of knowing what the actual
2983 // bit-width of the size field of the string is, we are going to ignore this
2984 // field, and instead treat these strings as FBT_KEY (null-terminated), so we
2985 // can deal with strings of arbitrary length. This of course truncates strings
2986 // with embedded nulls, but we think that that is preferrable over truncating
2987 // strings >= 256 bytes.
2988 auto vec = flexbuffers::GetRoot(slb.GetBuffer()).AsTypedVector();
2989 // Even though this was serialized as FBT_VECTOR_STRING, it is read as
2991 TEST_EQ(vec.ElementType(), flexbuffers::FBT_KEY);
2992 // Access the long string. Previously, this would return a string of size 1,
2993 // since it would read the high-byte of the 16-bit length.
2994 // This should now correctly test the full 300 bytes, using AsKey():
2995 TEST_EQ_STR(vec[0].AsKey(), test_data.c_str());
2996 // Old code that called AsString will continue to work, as the String
2997 // accessor objects now use a cached size that can come from a key as well.
2998 TEST_EQ_STR(vec[0].AsString().c_str(), test_data.c_str());
2999 // Short strings work as before:
3000 TEST_EQ_STR(vec[1].AsKey(), "hello");
3001 TEST_EQ_STR(vec[1].AsString().c_str(), "hello");
3002 // So, while existing code and data mostly "just work" with the fixes applied
3003 // to AsTypedVector and AsString, what do you do going forward?
3004 // Code accessing existing data doesn't necessarily need to change, though
3005 // you could consider using AsKey instead of AsString for a) documenting
3006 // that you are accessing keys, or b) a speedup if you don't actually use
3008 // For new data, or data that doesn't need to be backwards compatible,
3009 // instead serialize as FBT_VECTOR (call EndVector with typed = false, then
3010 // read elements with AsString), or, for maximum compactness, use
3011 // FBT_VECTOR_KEY (call slb.Key above instead, read with AsKey or AsString).
3014 void TypeAliasesTest() {
3015 flatbuffers::FlatBufferBuilder builder;
3017 builder.Finish(CreateTypeAliases(
3018 builder, flatbuffers::numeric_limits<int8_t>::min(),
3019 flatbuffers::numeric_limits<uint8_t>::max(),
3020 flatbuffers::numeric_limits<int16_t>::min(),
3021 flatbuffers::numeric_limits<uint16_t>::max(),
3022 flatbuffers::numeric_limits<int32_t>::min(),
3023 flatbuffers::numeric_limits<uint32_t>::max(),
3024 flatbuffers::numeric_limits<int64_t>::min(),
3025 flatbuffers::numeric_limits<uint64_t>::max(), 2.3f, 2.3));
3027 auto p = builder.GetBufferPointer();
3028 auto ta = flatbuffers::GetRoot<TypeAliases>(p);
3030 TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
3031 TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
3032 TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
3033 TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
3034 TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
3035 TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
3036 TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
3037 TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
3038 TEST_EQ(ta->f32(), 2.3f);
3039 TEST_EQ(ta->f64(), 2.3);
3040 using namespace flatbuffers; // is_same
3041 static_assert(is_same<decltype(ta->i8()), int8_t>::value, "invalid type");
3042 static_assert(is_same<decltype(ta->i16()), int16_t>::value, "invalid type");
3043 static_assert(is_same<decltype(ta->i32()), int32_t>::value, "invalid type");
3044 static_assert(is_same<decltype(ta->i64()), int64_t>::value, "invalid type");
3045 static_assert(is_same<decltype(ta->u8()), uint8_t>::value, "invalid type");
3046 static_assert(is_same<decltype(ta->u16()), uint16_t>::value, "invalid type");
3047 static_assert(is_same<decltype(ta->u32()), uint32_t>::value, "invalid type");
3048 static_assert(is_same<decltype(ta->u64()), uint64_t>::value, "invalid type");
3049 static_assert(is_same<decltype(ta->f32()), float>::value, "invalid type");
3050 static_assert(is_same<decltype(ta->f64()), double>::value, "invalid type");
3053 void EndianSwapTest() {
3054 TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
3055 TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
3057 TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
3058 0xEFCDAB9078563412);
3059 TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
3062 void UninitializedVectorTest() {
3063 flatbuffers::FlatBufferBuilder builder;
3065 Test *buf = nullptr;
3066 auto vector_offset =
3067 builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
3069 buf[0] = Test(10, 20);
3070 buf[1] = Test(30, 40);
3072 auto required_name = builder.CreateString("myMonster");
3073 auto monster_builder = MonsterBuilder(builder);
3074 monster_builder.add_name(
3075 required_name); // required field mandated for monster.
3076 monster_builder.add_test4(vector_offset);
3077 builder.Finish(monster_builder.Finish());
3079 auto p = builder.GetBufferPointer();
3080 auto uvt = flatbuffers::GetRoot<Monster>(p);
3082 auto vec = uvt->test4();
3084 auto test_0 = vec->Get(0);
3085 auto test_1 = vec->Get(1);
3086 TEST_EQ(test_0->a(), 10);
3087 TEST_EQ(test_0->b(), 20);
3088 TEST_EQ(test_1->a(), 30);
3089 TEST_EQ(test_1->b(), 40);
3092 void EqualOperatorTest() {
3095 TEST_EQ(b == a, true);
3096 TEST_EQ(b != a, false);
3099 TEST_EQ(b == a, false);
3100 TEST_EQ(b != a, true);
3102 TEST_EQ(b == a, true);
3103 TEST_EQ(b != a, false);
3105 b.inventory.push_back(3);
3106 TEST_EQ(b == a, false);
3107 TEST_EQ(b != a, true);
3108 b.inventory.clear();
3109 TEST_EQ(b == a, true);
3110 TEST_EQ(b != a, false);
3112 b.test.type = Any_Monster;
3113 TEST_EQ(b == a, false);
3114 TEST_EQ(b != a, true);
3117 // For testing any binaries, e.g. from fuzzing.
3118 void LoadVerifyBinaryTest() {
3120 if (flatbuffers::LoadFile(
3121 (test_data_path + "fuzzer/your-filename-here").c_str(), true,
3123 flatbuffers::Verifier verifier(
3124 reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
3125 TEST_EQ(VerifyMonsterBuffer(verifier), true);
3129 void CreateSharedStringTest() {
3130 flatbuffers::FlatBufferBuilder builder;
3131 const auto one1 = builder.CreateSharedString("one");
3132 const auto two = builder.CreateSharedString("two");
3133 const auto one2 = builder.CreateSharedString("one");
3134 TEST_EQ(one1.o, one2.o);
3135 const auto onetwo = builder.CreateSharedString("onetwo");
3136 TEST_EQ(onetwo.o != one1.o, true);
3137 TEST_EQ(onetwo.o != two.o, true);
3139 // Support for embedded nulls
3140 const char chars_b[] = { 'a', '\0', 'b' };
3141 const char chars_c[] = { 'a', '\0', 'c' };
3142 const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3143 const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
3144 const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3145 TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
3146 TEST_EQ(null_b1.o, null_b2.o);
3148 // Put the strings into an array for round trip verification.
3149 const flatbuffers::Offset<flatbuffers::String> array[7] = {
3150 one1, two, one2, onetwo, null_b1, null_c, null_b2
3152 const auto vector_offset =
3153 builder.CreateVector(array, flatbuffers::uoffset_t(7));
3154 MonsterBuilder monster_builder(builder);
3155 monster_builder.add_name(two);
3156 monster_builder.add_testarrayofstring(vector_offset);
3157 builder.Finish(monster_builder.Finish());
3159 // Read the Monster back.
3160 const auto *monster =
3161 flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
3162 TEST_EQ_STR(monster->name()->c_str(), "two");
3163 const auto *testarrayofstring = monster->testarrayofstring();
3164 TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
3165 const auto &a = *testarrayofstring;
3166 TEST_EQ_STR(a[0]->c_str(), "one");
3167 TEST_EQ_STR(a[1]->c_str(), "two");
3168 TEST_EQ_STR(a[2]->c_str(), "one");
3169 TEST_EQ_STR(a[3]->c_str(), "onetwo");
3170 TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
3171 TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
3172 TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
3174 // Make sure String::operator< works, too, since it is related to
3175 // StringOffsetCompare.
3176 TEST_EQ((*a[0]) < (*a[1]), true);
3177 TEST_EQ((*a[1]) < (*a[0]), false);
3178 TEST_EQ((*a[1]) < (*a[2]), false);
3179 TEST_EQ((*a[2]) < (*a[1]), true);
3180 TEST_EQ((*a[4]) < (*a[3]), true);
3181 TEST_EQ((*a[5]) < (*a[4]), false);
3182 TEST_EQ((*a[5]) < (*a[4]), false);
3183 TEST_EQ((*a[6]) < (*a[5]), true);
3186 void FixedLengthArrayTest() {
3187 // VS10 does not support typed enums, exclude from tests
3188 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3189 // Generate an ArrayTable containing one ArrayStruct.
3190 flatbuffers::FlatBufferBuilder fbb;
3191 MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
3192 TEST_NOTNULL(nStruct0.mutable_a());
3193 nStruct0.mutable_a()->Mutate(0, 1);
3194 nStruct0.mutable_a()->Mutate(1, 2);
3195 TEST_NOTNULL(nStruct0.mutable_c());
3196 nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3197 nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3198 TEST_NOTNULL(nStruct0.mutable_d());
3199 nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
3200 nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
3201 MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
3202 TEST_NOTNULL(nStruct1.mutable_a());
3203 nStruct1.mutable_a()->Mutate(0, 3);
3204 nStruct1.mutable_a()->Mutate(1, 4);
3205 TEST_NOTNULL(nStruct1.mutable_c());
3206 nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3207 nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3208 TEST_NOTNULL(nStruct1.mutable_d());
3209 nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
3210 nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
3211 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
3212 TEST_NOTNULL(aStruct.b());
3213 TEST_NOTNULL(aStruct.mutable_b());
3214 TEST_NOTNULL(aStruct.mutable_d());
3215 TEST_NOTNULL(aStruct.mutable_f());
3216 for (int i = 0; i < aStruct.b()->size(); i++)
3217 aStruct.mutable_b()->Mutate(i, i + 1);
3218 aStruct.mutable_d()->Mutate(0, nStruct0);
3219 aStruct.mutable_d()->Mutate(1, nStruct1);
3220 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
3223 // Verify correctness of the ArrayTable.
3224 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
3225 MyGame::Example::VerifyArrayTableBuffer(verifier);
3226 auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
3227 auto mArStruct = p->mutable_a();
3228 TEST_NOTNULL(mArStruct);
3229 TEST_NOTNULL(mArStruct->b());
3230 TEST_NOTNULL(mArStruct->d());
3231 TEST_NOTNULL(mArStruct->f());
3232 TEST_NOTNULL(mArStruct->mutable_b());
3233 TEST_NOTNULL(mArStruct->mutable_d());
3234 TEST_NOTNULL(mArStruct->mutable_f());
3235 mArStruct->mutable_b()->Mutate(14, -14);
3236 TEST_EQ(mArStruct->a(), 2);
3237 TEST_EQ(mArStruct->b()->size(), 15);
3238 TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14);
3239 TEST_EQ(mArStruct->c(), 12);
3240 TEST_NOTNULL(mArStruct->d()->Get(0));
3241 TEST_NOTNULL(mArStruct->d()->Get(0)->a());
3242 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
3243 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
3244 TEST_NOTNULL(mArStruct->d()->Get(1));
3245 TEST_NOTNULL(mArStruct->d()->Get(1)->a());
3246 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
3247 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
3248 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
3249 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
3250 mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
3251 TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
3252 TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
3253 TEST_NOTNULL(mArStruct->d()->Get(0)->c());
3254 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
3255 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
3256 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3257 mArStruct->d()->Get(0)->d()->Get(0));
3258 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3259 mArStruct->d()->Get(0)->d()->Get(1));
3260 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
3261 TEST_NOTNULL(mArStruct->d()->Get(1)->c());
3262 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
3263 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
3264 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3265 mArStruct->d()->Get(1)->d()->Get(0));
3266 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3267 mArStruct->d()->Get(1)->d()->Get(1));
3268 for (int i = 0; i < mArStruct->b()->size() - 1; i++)
3269 TEST_EQ(mArStruct->b()->Get(i), i + 1);
3271 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
3272 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
3274 // Check if default constructor set all memory zero
3275 const size_t arr_size = sizeof(MyGame::Example::ArrayStruct);
3276 char non_zero_memory[arr_size];
3277 // set memory chunk of size ArrayStruct to 1's
3278 std::memset(static_cast<void *>(non_zero_memory), 1, arr_size);
3279 // after placement-new it should be all 0's
3280 #if defined (_MSC_VER) && defined (_DEBUG)
3283 MyGame::Example::ArrayStruct *ap = new (non_zero_memory) MyGame::Example::ArrayStruct;
3284 #if defined (_MSC_VER) && defined (_DEBUG)
3285 #define new DEBUG_NEW
3288 for (size_t i = 0; i < arr_size; ++i) {
3289 TEST_EQ(non_zero_memory[i], 0);
3294 void NativeTypeTest() {
3297 Geometry::ApplicationDataT src_data;
3298 src_data.vectors.reserve(N);
3300 for (int i = 0; i < N; ++i) {
3301 src_data.vectors.push_back(
3302 Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
3305 flatbuffers::FlatBufferBuilder fbb;
3306 fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
3308 auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
3310 for (int i = 0; i < N; ++i) {
3311 Native::Vector3D &v = dstDataT->vectors[i];
3312 TEST_EQ(v.x, 10 * i + 0.1f);
3313 TEST_EQ(v.y, 10 * i + 0.2f);
3314 TEST_EQ(v.z, 10 * i + 0.3f);
3318 void FixedLengthArrayJsonTest(bool binary) {
3319 // VS10 does not support typed enums, exclude from tests
3320 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3321 // load FlatBuffer schema (.fbs) and JSON from disk
3322 std::string schemafile;
3323 std::string jsonfile;
3325 flatbuffers::LoadFile(
3326 (test_data_path + "arrays_test." + (binary ? "bfbs" : "fbs")).c_str(),
3327 binary, &schemafile),
3329 TEST_EQ(flatbuffers::LoadFile((test_data_path + "arrays_test.golden").c_str(),
3333 // parse schema first, so we can use it to parse the data after
3334 flatbuffers::Parser parserOrg, parserGen;
3336 flatbuffers::Verifier verifier(
3337 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
3339 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3340 TEST_EQ(parserOrg.Deserialize((const uint8_t *)schemafile.c_str(),
3343 TEST_EQ(parserGen.Deserialize((const uint8_t *)schemafile.c_str(),
3347 TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
3348 TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
3350 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3352 // First, verify it, just in case:
3353 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3354 parserOrg.builder_.GetSize());
3355 TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
3358 std::string jsonGen;
3360 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3364 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3366 // Verify buffer from generated JSON
3367 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3368 parserGen.builder_.GetSize());
3369 TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
3371 // Compare generated buffer to original
3372 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3373 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3374 parserGen.builder_.GetBufferPointer(),
3375 parserOrg.builder_.GetSize()),
3382 void TestEmbeddedBinarySchema() {
3383 // load JSON from disk
3384 std::string jsonfile;
3385 TEST_EQ(flatbuffers::LoadFile(
3386 (test_data_path + "monsterdata_test.golden").c_str(), false,
3390 // parse schema first, so we can use it to parse the data after
3391 flatbuffers::Parser parserOrg, parserGen;
3392 flatbuffers::Verifier verifier(MyGame::Example::MonsterBinarySchema::data(),
3393 MyGame::Example::MonsterBinarySchema::size());
3394 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3395 TEST_EQ(parserOrg.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3396 MyGame::Example::MonsterBinarySchema::size()),
3398 TEST_EQ(parserGen.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3399 MyGame::Example::MonsterBinarySchema::size()),
3401 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3403 // First, verify it, just in case:
3404 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3405 parserOrg.builder_.GetSize());
3406 TEST_EQ(VerifyMonsterBuffer(verifierOrg), true);
3409 std::string jsonGen;
3411 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3415 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3417 // Verify buffer from generated JSON
3418 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3419 parserGen.builder_.GetSize());
3420 TEST_EQ(VerifyMonsterBuffer(verifierGen), true);
3422 // Compare generated buffer to original
3423 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3424 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3425 parserGen.builder_.GetBufferPointer(),
3426 parserOrg.builder_.GetSize()),
3430 void NullableScalarsTest() {
3431 // Simple schemas and a "has nullable scalar" sentinal.
3432 std::vector<std::string> schemas;
3433 schemas.push_back("table Monster { mana : int; }");
3434 schemas.push_back("table Monster { mana : int = 42; }");
3435 schemas.push_back("table Monster { mana : int = null; }");
3436 schemas.push_back("table Monster { mana : long; }");
3437 schemas.push_back("table Monster { mana : long = 42; }");
3438 schemas.push_back("table Monster { mana : long = null; }");
3439 schemas.push_back("table Monster { mana : float; }");
3440 schemas.push_back("table Monster { mana : float = 42; }");
3441 schemas.push_back("table Monster { mana : float = null; }");
3442 schemas.push_back("table Monster { mana : double; }");
3443 schemas.push_back("table Monster { mana : double = 42; }");
3444 schemas.push_back("table Monster { mana : double = null; }");
3445 schemas.push_back("table Monster { mana : bool; }");
3446 schemas.push_back("table Monster { mana : bool = 42; }");
3447 schemas.push_back("table Monster { mana : bool = null; }");
3449 // Check the FieldDef is correctly set.
3450 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3451 const bool has_null = schema->find("null") != std::string::npos;
3452 flatbuffers::Parser parser;
3453 TEST_ASSERT(parser.Parse(schema->c_str()));
3454 const auto *mana = parser.structs_.Lookup("Monster")->fields.Lookup("mana");
3455 TEST_EQ(mana->nullable, has_null);
3458 // Test if nullable scalars are allowed for each language.
3459 const int kNumLanguages = 17;
3460 for (int lang=0; lang<kNumLanguages; lang++) {
3461 flatbuffers::IDLOptions opts;
3462 opts.lang_to_generate |= 1 << lang;
3463 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3464 const bool has_null = schema->find("null") != std::string::npos;
3465 flatbuffers::Parser parser(opts);
3466 // Its not supported in any language yet so has_null means error.
3467 TEST_EQ(parser.Parse(schema->c_str()), !has_null);
3472 void ParseFlexbuffersFromJsonWithNullTest() {
3473 // Test nulls are handled appropriately through flexbuffers to exercise other
3474 // code paths of ParseSingleValue in the nullable scalars change.
3475 // TODO(cneo): Json -> Flatbuffers test once some language can generate code
3476 // with nullable scalars.
3478 char json[] = "{\"opt_field\": 123 }";
3479 flatbuffers::Parser parser;
3480 flexbuffers::Builder flexbuild;
3481 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3482 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3483 TEST_EQ(root.AsMap()["opt_field"].AsInt64(), 123);
3486 char json[] = "{\"opt_field\": 123.4 }";
3487 flatbuffers::Parser parser;
3488 flexbuffers::Builder flexbuild;
3489 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3490 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3491 TEST_EQ(root.AsMap()["opt_field"].AsDouble(), 123.4);
3494 char json[] = "{\"opt_field\": null }";
3495 flatbuffers::Parser parser;
3496 flexbuffers::Builder flexbuild;
3497 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3498 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3499 TEST_ASSERT(!root.AsMap().IsTheEmptyMap());
3500 TEST_ASSERT(root.AsMap()["opt_field"].IsNull());
3501 TEST_EQ(root.ToString(), std::string("{ opt_field: null }"));
3505 int FlatBufferTests() {
3508 // Run our various test suites:
3511 auto flatbuf1 = CreateFlatBufferTest(rawbuf);
3512 #if !defined(FLATBUFFERS_CPP98_STL)
3513 auto flatbuf = std::move(flatbuf1); // Test move assignment.
3515 auto &flatbuf = flatbuf1;
3516 #endif // !defined(FLATBUFFERS_CPP98_STL)
3518 TriviallyCopyableTest();
3520 AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
3522 AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
3524 MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
3526 ObjectFlatBuffersTest(flatbuf.data());
3528 MiniReflectFlatBuffersTest(flatbuf.data());
3532 #ifndef FLATBUFFERS_NO_FILE_TESTS
3533 #ifdef FLATBUFFERS_TEST_PATH_PREFIX
3534 test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
3537 ParseAndGenerateTextTest(false);
3538 ParseAndGenerateTextTest(true);
3539 FixedLengthArrayJsonTest(false);
3540 FixedLengthArrayJsonTest(true);
3541 ReflectionTest(flatbuf.data(), flatbuf.size());
3543 ParseProtoTestWithSuffix();
3544 ParseProtoTestWithIncludes();
3546 UnionDeprecationTest();
3548 LoadVerifyBinaryTest();
3549 GenerateTableTextTest();
3550 TestEmbeddedBinarySchema();
3562 EnumOutOfRangeTest();
3563 IntegerOutOfRangeTest();
3564 IntegerBoundaryTest();
3566 UnicodeTestAllowNonUTF8();
3567 UnicodeTestGenerateTextFailsOnNonUTF8();
3568 UnicodeSurrogatesTest();
3569 UnicodeInvalidSurrogatesTest();
3571 UnknownFieldsTest();
3573 InvalidNestedFlatbufferTest();
3575 ParseProtoBufAsciiTest();
3578 CreateSharedStringTest();
3582 FlexBuffersDeprecatedTest();
3583 UninitializedVectorTest();
3584 EqualOperatorTest();
3589 TestMonsterExtraFloats();
3590 FixedLengthArrayTest();
3592 NullableScalarsTest();
3593 ParseFlexbuffersFromJsonWithNullTest();
3597 int main(int /*argc*/, const char * /*argv*/[]) {
3600 std::string req_locale;
3601 if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
3603 TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
3604 req_locale.c_str());
3605 req_locale = flatbuffers::RemoveStringQuotes(req_locale);
3606 std::string the_locale;
3608 flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
3609 TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
3613 FlatBufferBuilderTest();
3615 if (!testing_fails) {
3616 TEST_OUTPUT_LINE("ALL TESTS PASSED");
3618 TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
3620 return CloseTestEngine();