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);
904 auto friendly_field_ptr = fields->LookupByKey("friendly");
905 TEST_NOTNULL(friendly_field_ptr);
906 TEST_NOTNULL(friendly_field_ptr->attributes());
907 TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
909 // Make sure the table index is what we expect it to be.
910 auto pos_field_ptr = fields->LookupByKey("pos");
911 TEST_NOTNULL(pos_field_ptr);
912 TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
913 auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
914 TEST_NOTNULL(pos_table_ptr);
915 TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
917 // Test nullability of fields: hp is a 0-default scalar, pos is a struct =>
918 // optional, and name is a required string => not optional.
919 TEST_EQ(hp_field.optional(), false);
920 TEST_EQ(pos_field_ptr->optional(), true);
921 TEST_EQ(fields->LookupByKey("name")->optional(), false);
923 // Now use it to dynamically access a buffer.
924 auto &root = *flatbuffers::GetAnyRoot(flatbuf);
926 // Verify the buffer first using reflection based verification
927 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
930 auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
933 // Rather than needing to know the type, we can also get the value of
934 // any field as an int64_t/double/string, regardless of what it actually is.
935 auto hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
936 TEST_EQ(hp_int64, 80);
937 auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
938 TEST_EQ(hp_double, 80.0);
939 auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
940 TEST_EQ_STR(hp_string.c_str(), "80");
942 // Get struct field through reflection
943 auto pos_struct = flatbuffers::GetFieldStruct(root, *pos_field_ptr);
944 TEST_NOTNULL(pos_struct);
945 TEST_EQ(flatbuffers::GetAnyFieldF(*pos_struct,
946 *pos_table_ptr->fields()->LookupByKey("z")),
949 auto test3_field = pos_table_ptr->fields()->LookupByKey("test3");
950 auto test3_struct = flatbuffers::GetFieldStruct(*pos_struct, *test3_field);
951 TEST_NOTNULL(test3_struct);
952 auto test3_object = schema.objects()->Get(test3_field->type()->index());
954 TEST_EQ(flatbuffers::GetAnyFieldF(*test3_struct,
955 *test3_object->fields()->LookupByKey("a")),
958 // We can also modify it.
959 flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
960 hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
963 // We can also set fields generically:
964 flatbuffers::SetAnyFieldI(&root, hp_field, 300);
965 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
966 TEST_EQ(hp_int64, 300);
967 flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
968 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
969 TEST_EQ(hp_int64, 300);
970 flatbuffers::SetAnyFieldS(&root, hp_field, "300");
971 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
972 TEST_EQ(hp_int64, 300);
974 // Test buffer is valid after the modifications
975 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
978 // Reset it, for further tests.
979 flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
981 // More advanced functionality: changing the size of items in-line!
982 // First we put the FlatBuffer inside an std::vector.
983 std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
984 // Find the field we want to modify.
985 auto &name_field = *fields->LookupByKey("name");
987 // This time we wrap the result from GetAnyRoot in a smartpointer that
988 // will keep rroot valid as resizingbuf resizes.
989 auto rroot = flatbuffers::piv(
990 flatbuffers::GetAnyRoot(flatbuffers::vector_data(resizingbuf)),
992 SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
994 // Here resizingbuf has changed, but rroot is still valid.
995 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
996 // Now lets extend a vector by 100 elements (10 -> 110).
997 auto &inventory_field = *fields->LookupByKey("inventory");
998 auto rinventory = flatbuffers::piv(
999 flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field), resizingbuf);
1000 flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
1002 // rinventory still valid, so lets read from it.
1003 TEST_EQ(rinventory->Get(10), 50);
1005 // For reflection uses not covered already, there is a more powerful way:
1006 // we can simply generate whatever object we want to add/modify in a
1007 // FlatBuffer of its own, then add that to an existing FlatBuffer:
1008 // As an example, let's add a string to an array of strings.
1009 // First, find our field:
1010 auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
1011 // Find the vector value:
1012 auto rtestarrayofstring = flatbuffers::piv(
1013 flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
1014 **rroot, testarrayofstring_field),
1016 // It's a vector of 2 strings, to which we add one more, initialized to
1018 flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
1019 schema, 3, 0, *rtestarrayofstring, &resizingbuf);
1020 // Here we just create a buffer that contans a single string, but this
1021 // could also be any complex set of tables and other values.
1022 flatbuffers::FlatBufferBuilder stringfbb;
1023 stringfbb.Finish(stringfbb.CreateString("hank"));
1024 // Add the contents of it to our existing FlatBuffer.
1025 // We do this last, so the pointer doesn't get invalidated (since it is
1026 // at the end of the buffer):
1027 auto string_ptr = flatbuffers::AddFlatBuffer(
1028 resizingbuf, stringfbb.GetBufferPointer(), stringfbb.GetSize());
1029 // Finally, set the new value in the vector.
1030 rtestarrayofstring->MutateOffset(2, string_ptr);
1031 TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
1032 TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
1033 // Test integrity of all resize operations above.
1034 flatbuffers::Verifier resize_verifier(
1035 reinterpret_cast<const uint8_t *>(flatbuffers::vector_data(resizingbuf)),
1036 resizingbuf.size());
1037 TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
1039 // Test buffer is valid using reflection as well
1040 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1041 flatbuffers::vector_data(resizingbuf),
1042 resizingbuf.size()),
1045 // As an additional test, also set it on the name field.
1046 // Note: unlike the name change above, this just overwrites the offset,
1047 // rather than changing the string in-place.
1048 SetFieldT(*rroot, name_field, string_ptr);
1049 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
1051 // Using reflection, rather than mutating binary FlatBuffers, we can also copy
1052 // tables and other things out of other FlatBuffers into a FlatBufferBuilder,
1053 // either part or whole.
1054 flatbuffers::FlatBufferBuilder fbb;
1055 auto root_offset = flatbuffers::CopyTable(
1056 fbb, schema, *root_table, *flatbuffers::GetAnyRoot(flatbuf), true);
1057 fbb.Finish(root_offset, MonsterIdentifier());
1058 // Test that it was copied correctly:
1059 AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
1061 // Test buffer is valid using reflection as well
1062 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1063 fbb.GetBufferPointer(), fbb.GetSize()),
1067 void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
1069 flatbuffers::FlatBufferToString(flatbuf, Monster::MiniReflectTypeTable());
1073 "pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
1074 "{ a: 10, b: 20 } }, "
1076 "name: \"MyMonster\", "
1077 "inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
1078 "test_type: Monster, "
1079 "test: { name: \"Fred\" }, "
1080 "test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1081 "testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
1082 "testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" "
1084 "{ name: \"Wilma\" } ], "
1085 // TODO(wvo): should really print this nested buffer correctly.
1086 "testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, "
1088 "4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
1089 "101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
1090 "testarrayofstring2: [ \"jane\", \"mary\" ], "
1091 "testarrayofsortedstruct: [ { id: 1, distance: 10 }, "
1092 "{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
1093 "{ id: 4, distance: 40 } ], "
1094 "flex: [ 210, 4, 5, 2 ], "
1095 "test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1096 "vector_of_enums: [ Blue, Green ] "
1100 Vec3 vec(1, 2, 3, 1.5, Color_Red, test);
1101 flatbuffers::FlatBufferBuilder vec_builder;
1102 vec_builder.Finish(vec_builder.CreateStruct(vec));
1103 auto vec_buffer = vec_builder.Release();
1104 auto vec_str = flatbuffers::FlatBufferToString(vec_buffer.data(),
1105 Vec3::MiniReflectTypeTable());
1106 TEST_EQ_STR(vec_str.c_str(),
1107 "{ x: 1.0, y: 2.0, z: 3.0, test1: 1.5, test2: Red, test3: { a: "
1111 // Parse a .proto schema, output as .fbs
1112 void ParseProtoTest() {
1113 // load the .proto and the golden file from disk
1114 std::string protofile;
1115 std::string goldenfile;
1116 std::string goldenunionfile;
1118 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1122 flatbuffers::LoadFile((test_data_path + "prototest/test.golden").c_str(),
1123 false, &goldenfile),
1125 TEST_EQ(flatbuffers::LoadFile(
1126 (test_data_path + "prototest/test_union.golden").c_str(), false,
1130 flatbuffers::IDLOptions opts;
1131 opts.include_dependence_headers = false;
1132 opts.proto_mode = true;
1135 flatbuffers::Parser parser(opts);
1136 auto protopath = test_data_path + "prototest/";
1137 const char *include_directories[] = { protopath.c_str(), nullptr };
1138 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1141 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1143 // Ensure generated file is parsable.
1144 flatbuffers::Parser parser2;
1145 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1146 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1148 // Parse proto with --oneof-union option.
1149 opts.proto_oneof_union = true;
1150 flatbuffers::Parser parser3(opts);
1151 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1154 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1156 // Ensure generated file is parsable.
1157 flatbuffers::Parser parser4;
1158 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1159 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1162 // Parse a .proto schema, output as .fbs
1163 void ParseProtoTestWithSuffix() {
1164 // load the .proto and the golden file from disk
1165 std::string protofile;
1166 std::string goldenfile;
1167 std::string goldenunionfile;
1169 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1172 TEST_EQ(flatbuffers::LoadFile(
1173 (test_data_path + "prototest/test_suffix.golden").c_str(), false,
1176 TEST_EQ(flatbuffers::LoadFile(
1177 (test_data_path + "prototest/test_union_suffix.golden").c_str(),
1178 false, &goldenunionfile),
1181 flatbuffers::IDLOptions opts;
1182 opts.include_dependence_headers = false;
1183 opts.proto_mode = true;
1184 opts.proto_namespace_suffix = "test_namespace_suffix";
1187 flatbuffers::Parser parser(opts);
1188 auto protopath = test_data_path + "prototest/";
1189 const char *include_directories[] = { protopath.c_str(), nullptr };
1190 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1193 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1195 // Ensure generated file is parsable.
1196 flatbuffers::Parser parser2;
1197 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1198 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1200 // Parse proto with --oneof-union option.
1201 opts.proto_oneof_union = true;
1202 flatbuffers::Parser parser3(opts);
1203 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1206 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1208 // Ensure generated file is parsable.
1209 flatbuffers::Parser parser4;
1210 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1211 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1214 // Parse a .proto schema, output as .fbs
1215 void ParseProtoTestWithIncludes() {
1216 // load the .proto and the golden file from disk
1217 std::string protofile;
1218 std::string goldenfile;
1219 std::string goldenunionfile;
1220 std::string importprotofile;
1222 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1225 TEST_EQ(flatbuffers::LoadFile(
1226 (test_data_path + "prototest/imported.proto").c_str(), false,
1229 TEST_EQ(flatbuffers::LoadFile(
1230 (test_data_path + "prototest/test_include.golden").c_str(), false,
1233 TEST_EQ(flatbuffers::LoadFile(
1234 (test_data_path + "prototest/test_union_include.golden").c_str(),
1235 false, &goldenunionfile),
1238 flatbuffers::IDLOptions opts;
1239 opts.include_dependence_headers = true;
1240 opts.proto_mode = true;
1243 flatbuffers::Parser parser(opts);
1244 auto protopath = test_data_path + "prototest/";
1245 const char *include_directories[] = { protopath.c_str(), nullptr };
1246 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1249 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1251 // Generate fbs from import.proto
1252 flatbuffers::Parser import_parser(opts);
1253 TEST_EQ(import_parser.Parse(importprotofile.c_str(), include_directories),
1255 auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test");
1257 // Ensure generated file is parsable.
1258 flatbuffers::Parser parser2;
1260 parser2.Parse(import_fbs.c_str(), include_directories, "imported.fbs"),
1262 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1263 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1265 // Parse proto with --oneof-union option.
1266 opts.proto_oneof_union = true;
1267 flatbuffers::Parser parser3(opts);
1268 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1271 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1273 // Ensure generated file is parsable.
1274 flatbuffers::Parser parser4;
1275 TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, "imported.fbs"), true);
1276 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1277 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1280 template<typename T>
1281 void CompareTableFieldValue(flatbuffers::Table *table,
1282 flatbuffers::voffset_t voffset, T val) {
1283 T read = table->GetField(voffset, static_cast<T>(0));
1287 // Low level stress/fuzz test: serialize/deserialize a variety of
1288 // different kinds of data in different combinations
1290 // Values we're testing against: chosen to ensure no bits get chopped
1291 // off anywhere, and also be different from eachother.
1292 const uint8_t bool_val = true;
1293 const int8_t char_val = -127; // 0x81
1294 const uint8_t uchar_val = 0xFF;
1295 const int16_t short_val = -32222; // 0x8222;
1296 const uint16_t ushort_val = 0xFEEE;
1297 const int32_t int_val = 0x83333333;
1298 const uint32_t uint_val = 0xFDDDDDDD;
1299 const int64_t long_val = 0x8444444444444444LL;
1300 const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
1301 const float float_val = 3.14159f;
1302 const double double_val = 3.14159265359;
1304 const int test_values_max = 11;
1305 const flatbuffers::voffset_t fields_per_object = 4;
1306 const int num_fuzz_objects = 10000; // The higher, the more thorough :)
1308 flatbuffers::FlatBufferBuilder builder;
1310 lcg_reset(); // Keep it deterministic.
1312 flatbuffers::uoffset_t objects[num_fuzz_objects];
1314 // Generate num_fuzz_objects random objects each consisting of
1315 // fields_per_object fields, each of a random type.
1316 for (int i = 0; i < num_fuzz_objects; i++) {
1317 auto start = builder.StartTable();
1318 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1319 int choice = lcg_rand() % test_values_max;
1320 auto off = flatbuffers::FieldIndexToOffset(f);
1322 case 0: builder.AddElement<uint8_t>(off, bool_val, 0); break;
1323 case 1: builder.AddElement<int8_t>(off, char_val, 0); break;
1324 case 2: builder.AddElement<uint8_t>(off, uchar_val, 0); break;
1325 case 3: builder.AddElement<int16_t>(off, short_val, 0); break;
1326 case 4: builder.AddElement<uint16_t>(off, ushort_val, 0); break;
1327 case 5: builder.AddElement<int32_t>(off, int_val, 0); break;
1328 case 6: builder.AddElement<uint32_t>(off, uint_val, 0); break;
1329 case 7: builder.AddElement<int64_t>(off, long_val, 0); break;
1330 case 8: builder.AddElement<uint64_t>(off, ulong_val, 0); break;
1331 case 9: builder.AddElement<float>(off, float_val, 0); break;
1332 case 10: builder.AddElement<double>(off, double_val, 0); break;
1335 objects[i] = builder.EndTable(start);
1337 builder.PreAlign<flatbuffers::largest_scalar_t>(0); // Align whole buffer.
1339 lcg_reset(); // Reset.
1341 uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
1343 // Test that all objects we generated are readable and return the
1344 // expected values. We generate random objects in the same order
1345 // so this is deterministic.
1346 for (int i = 0; i < num_fuzz_objects; i++) {
1347 auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
1348 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1349 int choice = lcg_rand() % test_values_max;
1350 flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
1352 case 0: CompareTableFieldValue(table, off, bool_val); break;
1353 case 1: CompareTableFieldValue(table, off, char_val); break;
1354 case 2: CompareTableFieldValue(table, off, uchar_val); break;
1355 case 3: CompareTableFieldValue(table, off, short_val); break;
1356 case 4: CompareTableFieldValue(table, off, ushort_val); break;
1357 case 5: CompareTableFieldValue(table, off, int_val); break;
1358 case 6: CompareTableFieldValue(table, off, uint_val); break;
1359 case 7: CompareTableFieldValue(table, off, long_val); break;
1360 case 8: CompareTableFieldValue(table, off, ulong_val); break;
1361 case 9: CompareTableFieldValue(table, off, float_val); break;
1362 case 10: CompareTableFieldValue(table, off, double_val); break;
1368 // High level stress/fuzz test: generate a big schema and
1369 // matching json data in random combinations, then parse both,
1370 // generate json back from the binary, and compare with the original.
1372 lcg_reset(); // Keep it deterministic.
1374 const int num_definitions = 30;
1375 const int num_struct_definitions = 5; // Subset of num_definitions.
1376 const int fields_per_definition = 15;
1377 const int instances_per_definition = 5;
1378 const int deprecation_rate = 10; // 1 in deprecation_rate fields will
1381 std::string schema = "namespace test;\n\n";
1384 std::string instances[instances_per_definition];
1386 // Since we're generating schema and corresponding data in tandem,
1387 // this convenience function adds strings to both at once.
1388 static void Add(RndDef (&definitions_l)[num_definitions],
1389 std::string &schema_l, const int instances_per_definition_l,
1390 const char *schema_add, const char *instance_add,
1392 schema_l += schema_add;
1393 for (int i = 0; i < instances_per_definition_l; i++)
1394 definitions_l[definition].instances[i] += instance_add;
1399 #define AddToSchemaAndInstances(schema_add, instance_add) \
1400 RndDef::Add(definitions, schema, instances_per_definition, \
1401 schema_add, instance_add, definition)
1404 RndDef::Add(definitions, schema, instances_per_definition, \
1405 "byte", "1", definition)
1408 RndDef definitions[num_definitions];
1410 // We are going to generate num_definitions, the first
1411 // num_struct_definitions will be structs, the rest tables. For each
1412 // generate random fields, some of which may be struct/table types
1413 // referring to previously generated structs/tables.
1414 // Simultanenously, we generate instances_per_definition JSON data
1415 // definitions, which will have identical structure to the schema
1416 // being generated. We generate multiple instances such that when creating
1417 // hierarchy, we get some variety by picking one randomly.
1418 for (int definition = 0; definition < num_definitions; definition++) {
1419 std::string definition_name = "D" + flatbuffers::NumToString(definition);
1421 bool is_struct = definition < num_struct_definitions;
1423 AddToSchemaAndInstances(
1424 ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
1427 for (int field = 0; field < fields_per_definition; field++) {
1428 const bool is_last_field = field == fields_per_definition - 1;
1430 // Deprecate 1 in deprecation_rate fields. Only table fields can be
1432 // Don't deprecate the last field to avoid dangling commas in JSON.
1433 const bool deprecated =
1434 !is_struct && !is_last_field && (lcg_rand() % deprecation_rate == 0);
1436 std::string field_name = "f" + flatbuffers::NumToString(field);
1437 AddToSchemaAndInstances((" " + field_name + ":").c_str(),
1438 deprecated ? "" : (field_name + ": ").c_str());
1439 // Pick random type:
1440 auto base_type = static_cast<flatbuffers::BaseType>(
1441 lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
1442 switch (base_type) {
1443 case flatbuffers::BASE_TYPE_STRING:
1445 Dummy(); // No strings in structs.
1447 AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
1450 case flatbuffers::BASE_TYPE_VECTOR:
1452 Dummy(); // No vectors in structs.
1454 AddToSchemaAndInstances("[ubyte]",
1455 deprecated ? "" : "[\n0,\n1,\n255\n]");
1458 case flatbuffers::BASE_TYPE_NONE:
1459 case flatbuffers::BASE_TYPE_UTYPE:
1460 case flatbuffers::BASE_TYPE_STRUCT:
1461 case flatbuffers::BASE_TYPE_UNION:
1463 // Pick a random previous definition and random data instance of
1465 int defref = lcg_rand() % definition;
1466 int instance = lcg_rand() % instances_per_definition;
1467 AddToSchemaAndInstances(
1468 ("D" + flatbuffers::NumToString(defref)).c_str(),
1470 : definitions[defref].instances[instance].c_str());
1472 // If this is the first definition, we have no definition we can
1477 case flatbuffers::BASE_TYPE_BOOL:
1478 AddToSchemaAndInstances(
1479 "bool", deprecated ? "" : (lcg_rand() % 2 ? "true" : "false"));
1481 case flatbuffers::BASE_TYPE_ARRAY:
1483 AddToSchemaAndInstances(
1485 deprecated ? "" : "255"); // No fixed-length arrays in tables.
1487 AddToSchemaAndInstances("[int:3]", deprecated ? "" : "[\n,\n,\n]");
1491 // All the scalar types.
1492 schema += flatbuffers::kTypeNames[base_type];
1495 // We want each instance to use its own random value.
1496 for (int inst = 0; inst < instances_per_definition; inst++)
1497 definitions[definition].instances[inst] +=
1498 flatbuffers::IsFloat(base_type)
1499 ? flatbuffers::NumToString<double>(lcg_rand() % 128)
1501 : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
1504 AddToSchemaAndInstances(deprecated ? "(deprecated);\n" : ";\n",
1505 deprecated ? "" : is_last_field ? "\n" : ",\n");
1507 AddToSchemaAndInstances("}\n\n", "}");
1510 schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
1513 flatbuffers::Parser parser;
1515 // Will not compare against the original if we don't write defaults
1516 parser.builder_.ForceDefaults(true);
1518 // Parse the schema, parse the generated data, then generate text back
1519 // from the binary and compare against the original.
1520 TEST_EQ(parser.Parse(schema.c_str()), true);
1522 const std::string &json =
1523 definitions[num_definitions - 1].instances[0] + "\n";
1525 TEST_EQ(parser.Parse(json.c_str()), true);
1527 std::string jsongen;
1528 parser.opts.indent_step = 0;
1530 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
1531 TEST_EQ(result, true);
1533 if (jsongen != json) {
1534 // These strings are larger than a megabyte, so we show the bytes around
1535 // the first bytes that are different rather than the whole string.
1536 size_t len = std::min(json.length(), jsongen.length());
1537 for (size_t i = 0; i < len; i++) {
1538 if (json[i] != jsongen[i]) {
1539 i -= std::min(static_cast<size_t>(10), i); // show some context;
1540 size_t end = std::min(len, i + 20);
1541 for (; i < end; i++)
1542 TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
1543 static_cast<int>(i), jsongen[i], json[i]);
1547 TEST_NOTNULL(nullptr); //-V501 (this comment supresses CWE-570 warning)
1551 #ifdef FLATBUFFERS_TEST_VERBOSE
1552 TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
1553 static_cast<int>(schema.length() / 1024),
1554 static_cast<int>(json.length() / 1024));
1559 // Test that parser errors are actually generated.
1560 void TestError_(const char *src, const char *error_substr, bool strict_json,
1561 const char *file, int line, const char *func) {
1562 flatbuffers::IDLOptions opts;
1563 opts.strict_json = strict_json;
1564 flatbuffers::Parser parser(opts);
1565 if (parser.Parse(src)) {
1566 TestFail("true", "false",
1567 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1569 } else if (!strstr(parser.error_.c_str(), error_substr)) {
1570 TestFail(error_substr, parser.error_.c_str(),
1571 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1576 void TestError_(const char *src, const char *error_substr, const char *file,
1577 int line, const char *func) {
1578 TestError_(src, error_substr, false, file, line, func);
1582 # define TestError(src, ...) \
1583 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
1585 # define TestError(src, ...) \
1586 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1589 // Test that parsing errors occur as we'd expect.
1590 // Also useful for coverage, making sure these paths are run.
1592 // In order they appear in idl_parser.cpp
1593 TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
1594 TestError("\"\0", "illegal");
1595 TestError("\"\\q", "escape code");
1596 TestError("table ///", "documentation");
1597 TestError("@", "illegal");
1598 TestError("table 1", "expecting");
1599 TestError("table X { Y:[[int]]; }", "nested vector");
1600 TestError("table X { Y:1; }", "illegal type");
1601 TestError("table X { Y:int; Y:int; }", "field already");
1602 TestError("table Y {} table X { Y:int; }", "same as table");
1603 TestError("struct X { Y:string; }", "only scalar");
1604 TestError("table X { Y:string = \"\"; }", "default values");
1605 TestError("struct X { a:uint = 42; }", "default values");
1606 TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
1607 TestError("struct X { Y:int (deprecated); }", "deprecate");
1608 TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
1609 "missing type field");
1610 TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
1612 TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
1613 TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
1614 TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
1617 "struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
1620 TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
1621 "unknown enum value");
1622 TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
1623 TestError("enum X:byte { Y } enum X {", "enum already");
1624 TestError("enum X:float {}", "underlying");
1625 TestError("enum X:byte { Y, Y }", "value already");
1626 TestError("enum X:byte { Y=2, Z=2 }", "unique");
1627 TestError("table X { Y:int; } table X {", "datatype already");
1628 TestError("struct X (force_align: 7) { Y:int; }", "force_align");
1629 TestError("struct X {}", "size 0");
1630 TestError("{}", "no root");
1631 TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
1632 TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
1634 TestError("root_type X;", "unknown root");
1635 TestError("struct X { Y:int; } root_type X;", "a table");
1636 TestError("union X { Y }", "referenced");
1637 TestError("union Z { X } struct X { Y:int; }", "only tables");
1638 TestError("table X { Y:[int]; YLength:int; }", "clash");
1639 TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
1640 // float to integer conversion is forbidden
1641 TestError("table X { Y:int; } root_type X; { Y:1.0 }", "float");
1642 TestError("table X { Y:bool; } root_type X; { Y:1.0 }", "float");
1643 TestError("enum X:bool { Y = true }", "must be integral");
1644 // Array of non-scalar
1645 TestError("table X { x:int; } struct Y { y:[X:2]; }",
1646 "may contain only scalar or struct fields");
1647 // Non-snake case field names
1648 TestError("table X { Y: int; } root_type Y: {Y:1.0}", "snake_case");
1651 template<typename T>
1652 T TestValue(const char *json, const char *type_name,
1653 const char *decls = nullptr) {
1654 flatbuffers::Parser parser;
1655 parser.builder_.ForceDefaults(true); // return defaults
1656 auto check_default = json ? false : true;
1657 if (check_default) { parser.opts.output_default_scalars_in_json = true; }
1659 std::string schema = std::string(decls ? decls : "") + "\n" +
1660 "table X { y:" + std::string(type_name) +
1662 auto schema_done = parser.Parse(schema.c_str());
1663 TEST_EQ_STR(parser.error_.c_str(), "");
1664 TEST_EQ(schema_done, true);
1666 auto done = parser.Parse(check_default ? "{}" : json);
1667 TEST_EQ_STR(parser.error_.c_str(), "");
1668 TEST_EQ(done, true);
1670 // Check with print.
1671 std::string print_back;
1672 parser.opts.indent_step = -1;
1673 TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back),
1675 // restore value from its default
1676 if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); }
1678 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
1679 parser.builder_.GetBufferPointer());
1680 return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
1683 bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
1685 // Additional parser testing not covered elsewhere.
1687 // Test scientific notation numbers.
1689 FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
1692 TEST_EQ(FloatCompare(TestValue<float>("{ y:\"0.0314159e+2\" }", "float"),
1696 // Test conversion functions.
1697 TEST_EQ(FloatCompare(TestValue<float>("{ y:cos(rad(180)) }", "float"), -1),
1700 // int embedded to string
1701 TEST_EQ(TestValue<int>("{ y:\"-876\" }", "int=-123"), -876);
1702 TEST_EQ(TestValue<int>("{ y:\"876\" }", "int=-123"), 876);
1704 // Test negative hex constant.
1705 TEST_EQ(TestValue<int>("{ y:-0x8ea0 }", "int=-0x8ea0"), -36512);
1706 TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
1708 // positive hex constant
1709 TEST_EQ(TestValue<int>("{ y:0x1abcdef }", "int=0x1"), 0x1abcdef);
1710 // with optional '+' sign
1711 TEST_EQ(TestValue<int>("{ y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
1713 TEST_EQ(TestValue<int>("{ y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
1715 // Make sure we do unsigned 64bit correctly.
1716 TEST_EQ(TestValue<uint64_t>("{ y:12335089644688340133 }", "ulong"),
1717 12335089644688340133ULL);
1720 TEST_EQ(TestValue<bool>("{ y:\"false\" }", "bool=true"), false);
1721 TEST_EQ(TestValue<bool>("{ y:\"true\" }", "bool=\"true\""), true);
1722 TEST_EQ(TestValue<bool>("{ y:'false' }", "bool=true"), false);
1723 TEST_EQ(TestValue<bool>("{ y:'true' }", "bool=\"true\""), true);
1725 // check comments before and after json object
1726 TEST_EQ(TestValue<int>("/*before*/ { y:1 } /*after*/", "int"), 1);
1727 TEST_EQ(TestValue<int>("//before \n { y:1 } //after", "int"), 1);
1730 void NestedListTest() {
1731 flatbuffers::Parser parser1;
1732 TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
1734 "{ F:[ [10,20], [30,40]] }"),
1738 void EnumStringsTest() {
1739 flatbuffers::Parser parser1;
1740 TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
1742 "{ F:[ A, B, \"C\", \"A B C\" ] }"),
1744 flatbuffers::Parser parser2;
1745 TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
1747 "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"),
1749 // unsigned bit_flags
1750 flatbuffers::Parser parser3;
1752 parser3.Parse("enum E:uint16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }"
1753 " table T { F: E = \"F15 F08\"; }"
1758 void EnumNamesTest() {
1759 TEST_EQ_STR("Red", EnumNameColor(Color_Red));
1760 TEST_EQ_STR("Green", EnumNameColor(Color_Green));
1761 TEST_EQ_STR("Blue", EnumNameColor(Color_Blue));
1762 // Check that Color to string don't crash while decode a mixture of Colors.
1763 // 1) Example::Color enum is enum with unfixed underlying type.
1764 // 2) Valid enum range: [0; 2^(ceil(log2(Color_ANY))) - 1].
1765 // Consequence: A value is out of this range will lead to UB (since C++17).
1766 // For details see C++17 standard or explanation on the SO:
1767 // stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class
1768 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(0)));
1769 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY - 1)));
1770 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY + 1)));
1773 void EnumOutOfRangeTest() {
1774 TestError("enum X:byte { Y = 128 }", "enum value does not fit");
1775 TestError("enum X:byte { Y = -129 }", "enum value does not fit");
1776 TestError("enum X:byte { Y = 126, Z0, Z1 }", "enum value does not fit");
1777 TestError("enum X:ubyte { Y = -1 }", "enum value does not fit");
1778 TestError("enum X:ubyte { Y = 256 }", "enum value does not fit");
1779 TestError("enum X:ubyte { Y = 255, Z }", "enum value does not fit");
1780 TestError("table Y{} union X { Y = -1 }", "enum value does not fit");
1781 TestError("table Y{} union X { Y = 256 }", "enum value does not fit");
1782 TestError("table Y{} union X { Y = 255, Z:Y }", "enum value does not fit");
1783 TestError("enum X:int { Y = -2147483649 }", "enum value does not fit");
1784 TestError("enum X:int { Y = 2147483648 }", "enum value does not fit");
1785 TestError("enum X:uint { Y = -1 }", "enum value does not fit");
1786 TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit");
1787 TestError("enum X:long { Y = 9223372036854775808 }", "does not fit");
1788 TestError("enum X:long { Y = 9223372036854775807, Z }",
1789 "enum value does not fit");
1790 TestError("enum X:ulong { Y = -1 }", "does not fit");
1791 TestError("enum X:ubyte (bit_flags) { Y=8 }", "bit flag out");
1792 TestError("enum X:byte (bit_flags) { Y=7 }", "must be unsigned"); // -128
1793 // bit_flgs out of range
1794 TestError("enum X:ubyte (bit_flags) { Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8 }",
1798 void EnumValueTest() {
1799 // json: "{ Y:0 }", schema: table X { y: "E"}
1800 // 0 in enum (V=0) E then Y=0 is valid.
1801 TEST_EQ(TestValue<int>("{ y:0 }", "E", "enum E:int { V }"), 0);
1802 TEST_EQ(TestValue<int>("{ y:V }", "E", "enum E:int { V }"), 0);
1803 // A default value of Y is 0.
1804 TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
1805 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { V=5 }"), 5);
1806 // Generate json with defaults and check.
1807 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
1809 TEST_EQ(TestValue<int>("{ y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
1810 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
1811 // Generate json with defaults and check.
1812 TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
1813 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
1815 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1816 "enum E:ulong { V = 13835058055282163712 }"),
1817 13835058055282163712ULL);
1818 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1819 "enum E:ulong { V = 18446744073709551615 }"),
1820 18446744073709551615ULL);
1821 // Assign non-enum value to enum field. Is it right?
1822 TEST_EQ(TestValue<int>("{ y:7 }", "E", "enum E:int { V = 0 }"), 7);
1823 // Check that non-ascending values are valid.
1824 TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z=10, V=5 }"), 5);
1827 void IntegerOutOfRangeTest() {
1828 TestError("table T { F:byte; } root_type T; { F:128 }",
1829 "constant does not fit");
1830 TestError("table T { F:byte; } root_type T; { F:-129 }",
1831 "constant does not fit");
1832 TestError("table T { F:ubyte; } root_type T; { F:256 }",
1833 "constant does not fit");
1834 TestError("table T { F:ubyte; } root_type T; { F:-1 }",
1835 "constant does not fit");
1836 TestError("table T { F:short; } root_type T; { F:32768 }",
1837 "constant does not fit");
1838 TestError("table T { F:short; } root_type T; { F:-32769 }",
1839 "constant does not fit");
1840 TestError("table T { F:ushort; } root_type T; { F:65536 }",
1841 "constant does not fit");
1842 TestError("table T { F:ushort; } root_type T; { F:-1 }",
1843 "constant does not fit");
1844 TestError("table T { F:int; } root_type T; { F:2147483648 }",
1845 "constant does not fit");
1846 TestError("table T { F:int; } root_type T; { F:-2147483649 }",
1847 "constant does not fit");
1848 TestError("table T { F:uint; } root_type T; { F:4294967296 }",
1849 "constant does not fit");
1850 TestError("table T { F:uint; } root_type T; { F:-1 }",
1851 "constant does not fit");
1852 // Check fixed width aliases
1853 TestError("table X { Y:uint8; } root_type X; { Y: -1 }", "does not fit");
1854 TestError("table X { Y:uint8; } root_type X; { Y: 256 }", "does not fit");
1855 TestError("table X { Y:uint16; } root_type X; { Y: -1 }", "does not fit");
1856 TestError("table X { Y:uint16; } root_type X; { Y: 65536 }", "does not fit");
1857 TestError("table X { Y:uint32; } root_type X; { Y: -1 }", "");
1858 TestError("table X { Y:uint32; } root_type X; { Y: 4294967296 }",
1860 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1861 TestError("table X { Y:uint64; } root_type X; { Y: -9223372036854775809 }",
1863 TestError("table X { Y:uint64; } root_type X; { Y: 18446744073709551616 }",
1866 TestError("table X { Y:int8; } root_type X; { Y: -129 }", "does not fit");
1867 TestError("table X { Y:int8; } root_type X; { Y: 128 }", "does not fit");
1868 TestError("table X { Y:int16; } root_type X; { Y: -32769 }", "does not fit");
1869 TestError("table X { Y:int16; } root_type X; { Y: 32768 }", "does not fit");
1870 TestError("table X { Y:int32; } root_type X; { Y: -2147483649 }", "");
1871 TestError("table X { Y:int32; } root_type X; { Y: 2147483648 }",
1873 TestError("table X { Y:int64; } root_type X; { Y: -9223372036854775809 }",
1875 TestError("table X { Y:int64; } root_type X; { Y: 9223372036854775808 }",
1877 // check out-of-int64 as int8
1878 TestError("table X { Y:int8; } root_type X; { Y: -9223372036854775809 }",
1880 TestError("table X { Y:int8; } root_type X; { Y: 9223372036854775808 }",
1883 // Check default values
1884 TestError("table X { Y:int64=-9223372036854775809; } root_type X; {}",
1886 TestError("table X { Y:int64= 9223372036854775808; } root_type X; {}",
1888 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1889 TestError("table X { Y:uint64=-9223372036854775809; } root_type X; {}",
1891 TestError("table X { Y:uint64= 18446744073709551616; } root_type X; {}",
1895 void IntegerBoundaryTest() {
1896 // Check numerical compatibility with non-C++ languages.
1897 // By the C++ standard, std::numerical_limits<int64_t>::min() ==
1898 // -9223372036854775807 (-2^63+1) or less* The Flatbuffers grammar and most of
1899 // the languages (C#, Java, Rust) expect that minimum values are: -128,
1900 // -32768,.., -9223372036854775808. Since C++20,
1901 // static_cast<int64>(0x8000000000000000ULL) is well-defined two's complement
1902 // cast. Therefore -9223372036854775808 should be valid negative value.
1903 TEST_EQ(flatbuffers::numeric_limits<int8_t>::min(), -128);
1904 TEST_EQ(flatbuffers::numeric_limits<int8_t>::max(), 127);
1905 TEST_EQ(flatbuffers::numeric_limits<int16_t>::min(), -32768);
1906 TEST_EQ(flatbuffers::numeric_limits<int16_t>::max(), 32767);
1907 TEST_EQ(flatbuffers::numeric_limits<int32_t>::min() + 1, -2147483647);
1908 TEST_EQ(flatbuffers::numeric_limits<int32_t>::max(), 2147483647ULL);
1909 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min() + 1LL,
1910 -9223372036854775807LL);
1911 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(), 9223372036854775807ULL);
1912 TEST_EQ(flatbuffers::numeric_limits<uint8_t>::max(), 255);
1913 TEST_EQ(flatbuffers::numeric_limits<uint16_t>::max(), 65535);
1914 TEST_EQ(flatbuffers::numeric_limits<uint32_t>::max(), 4294967295ULL);
1915 TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
1916 18446744073709551615ULL);
1918 TEST_EQ(TestValue<int8_t>("{ y:127 }", "byte"), 127);
1919 TEST_EQ(TestValue<int8_t>("{ y:-128 }", "byte"), -128);
1920 TEST_EQ(TestValue<uint8_t>("{ y:255 }", "ubyte"), 255);
1921 TEST_EQ(TestValue<uint8_t>("{ y:0 }", "ubyte"), 0);
1922 TEST_EQ(TestValue<int16_t>("{ y:32767 }", "short"), 32767);
1923 TEST_EQ(TestValue<int16_t>("{ y:-32768 }", "short"), -32768);
1924 TEST_EQ(TestValue<uint16_t>("{ y:65535 }", "ushort"), 65535);
1925 TEST_EQ(TestValue<uint16_t>("{ y:0 }", "ushort"), 0);
1926 TEST_EQ(TestValue<int32_t>("{ y:2147483647 }", "int"), 2147483647);
1927 TEST_EQ(TestValue<int32_t>("{ y:-2147483648 }", "int") + 1, -2147483647);
1928 TEST_EQ(TestValue<uint32_t>("{ y:4294967295 }", "uint"), 4294967295);
1929 TEST_EQ(TestValue<uint32_t>("{ y:0 }", "uint"), 0);
1930 TEST_EQ(TestValue<int64_t>("{ y:9223372036854775807 }", "long"),
1931 9223372036854775807LL);
1932 TEST_EQ(TestValue<int64_t>("{ y:-9223372036854775808 }", "long") + 1LL,
1933 -9223372036854775807LL);
1934 TEST_EQ(TestValue<uint64_t>("{ y:18446744073709551615 }", "ulong"),
1935 18446744073709551615ULL);
1936 TEST_EQ(TestValue<uint64_t>("{ y:0 }", "ulong"), 0);
1937 TEST_EQ(TestValue<uint64_t>("{ y: 18446744073709551615 }", "uint64"),
1938 18446744073709551615ULL);
1939 // check that the default works
1940 TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
1941 18446744073709551615ULL);
1944 void ValidFloatTest() {
1945 // check rounding to infinity
1946 TEST_EQ(TestValue<float>("{ y:+3.4029e+38 }", "float"), +infinityf);
1947 TEST_EQ(TestValue<float>("{ y:-3.4029e+38 }", "float"), -infinityf);
1948 TEST_EQ(TestValue<double>("{ y:+1.7977e+308 }", "double"), +infinityd);
1949 TEST_EQ(TestValue<double>("{ y:-1.7977e+308 }", "double"), -infinityd);
1952 FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
1955 TEST_EQ(FloatCompare(TestValue<float>("{ y:\" 0.0314159e+2 \" }", "float"),
1959 TEST_EQ(TestValue<float>("{ y:1 }", "float"), 1.0f);
1960 TEST_EQ(TestValue<float>("{ y:1.0 }", "float"), 1.0f);
1961 TEST_EQ(TestValue<float>("{ y:1. }", "float"), 1.0f);
1962 TEST_EQ(TestValue<float>("{ y:+1. }", "float"), 1.0f);
1963 TEST_EQ(TestValue<float>("{ y:-1. }", "float"), -1.0f);
1964 TEST_EQ(TestValue<float>("{ y:1.e0 }", "float"), 1.0f);
1965 TEST_EQ(TestValue<float>("{ y:1.e+0 }", "float"), 1.0f);
1966 TEST_EQ(TestValue<float>("{ y:1.e-0 }", "float"), 1.0f);
1967 TEST_EQ(TestValue<float>("{ y:0.125 }", "float"), 0.125f);
1968 TEST_EQ(TestValue<float>("{ y:.125 }", "float"), 0.125f);
1969 TEST_EQ(TestValue<float>("{ y:-.125 }", "float"), -0.125f);
1970 TEST_EQ(TestValue<float>("{ y:+.125 }", "float"), +0.125f);
1971 TEST_EQ(TestValue<float>("{ y:5 }", "float"), 5.0f);
1972 TEST_EQ(TestValue<float>("{ y:\"5\" }", "float"), 5.0f);
1974 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
1975 // Old MSVC versions may have problem with this check.
1976 // https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
1977 TEST_EQ(TestValue<double>("{ y:6.9294956446009195e15 }", "double"),
1978 6929495644600920.0);
1980 TEST_EQ(std::isnan(TestValue<double>("{ y:nan }", "double")), true);
1981 TEST_EQ(std::isnan(TestValue<float>("{ y:nan }", "float")), true);
1982 TEST_EQ(std::isnan(TestValue<float>("{ y:\"nan\" }", "float")), true);
1983 TEST_EQ(std::isnan(TestValue<float>("{ y:+nan }", "float")), true);
1984 TEST_EQ(std::isnan(TestValue<float>("{ y:-nan }", "float")), true);
1985 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
1986 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
1988 TEST_EQ(TestValue<float>("{ y:inf }", "float"), infinityf);
1989 TEST_EQ(TestValue<float>("{ y:\"inf\" }", "float"), infinityf);
1990 TEST_EQ(TestValue<float>("{ y:+inf }", "float"), infinityf);
1991 TEST_EQ(TestValue<float>("{ y:-inf }", "float"), -infinityf);
1992 TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinityf);
1993 TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinityf);
1995 "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
1999 "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
2003 // Test binary format of float point.
2004 // https://en.cppreference.com/w/cpp/language/floating_literal
2005 // 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
2006 TEST_EQ(TestValue<double>("{ y:0x12.34p-1 }", "double"), 9.1015625);
2007 // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
2008 TEST_EQ(TestValue<float>("{ y:-0x0.2p0 }", "float"), -0.125f);
2009 TEST_EQ(TestValue<float>("{ y:-0x.2p1 }", "float"), -0.25f);
2010 TEST_EQ(TestValue<float>("{ y:0x1.2p3 }", "float"), 9.0f);
2011 TEST_EQ(TestValue<float>("{ y:0x10.1p0 }", "float"), 16.0625f);
2012 TEST_EQ(TestValue<double>("{ y:0x1.2p3 }", "double"), 9.0);
2013 TEST_EQ(TestValue<double>("{ y:0x10.1p0 }", "double"), 16.0625);
2014 TEST_EQ(TestValue<double>("{ y:0xC.68p+2 }", "double"), 49.625);
2015 TestValue<double>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
2016 TestValue<float>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
2018 #else // FLATBUFFERS_HAS_NEW_STRTOD
2019 TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");
2020 #endif // !FLATBUFFERS_HAS_NEW_STRTOD
2023 void InvalidFloatTest() {
2024 auto invalid_msg = "invalid number";
2025 auto comma_msg = "expecting: ,";
2026 TestError("table T { F:float; } root_type T; { F:1,0 }", "");
2027 TestError("table T { F:float; } root_type T; { F:. }", "");
2028 TestError("table T { F:float; } root_type T; { F:- }", invalid_msg);
2029 TestError("table T { F:float; } root_type T; { F:+ }", invalid_msg);
2030 TestError("table T { F:float; } root_type T; { F:-. }", invalid_msg);
2031 TestError("table T { F:float; } root_type T; { F:+. }", invalid_msg);
2032 TestError("table T { F:float; } root_type T; { F:.e }", "");
2033 TestError("table T { F:float; } root_type T; { F:-e }", invalid_msg);
2034 TestError("table T { F:float; } root_type T; { F:+e }", invalid_msg);
2035 TestError("table T { F:float; } root_type T; { F:-.e }", invalid_msg);
2036 TestError("table T { F:float; } root_type T; { F:+.e }", invalid_msg);
2037 TestError("table T { F:float; } root_type T; { F:-e1 }", invalid_msg);
2038 TestError("table T { F:float; } root_type T; { F:+e1 }", invalid_msg);
2039 TestError("table T { F:float; } root_type T; { F:1.0e+ }", invalid_msg);
2040 TestError("table T { F:float; } root_type T; { F:1.0e- }", invalid_msg);
2041 // exponent pP is mandatory for hex-float
2042 TestError("table T { F:float; } root_type T; { F:0x0 }", invalid_msg);
2043 TestError("table T { F:float; } root_type T; { F:-0x. }", invalid_msg);
2044 TestError("table T { F:float; } root_type T; { F:0x. }", invalid_msg);
2045 TestError("table T { F:float; } root_type T; { F:0Xe }", invalid_msg);
2046 TestError("table T { F:float; } root_type T; { F:\"0Xe\" }", invalid_msg);
2047 TestError("table T { F:float; } root_type T; { F:\"nan(1)\" }", invalid_msg);
2048 // eE not exponent in hex-float!
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- }", invalid_msg);
2051 TestError("table T { F:float; } root_type T; { F:0x0.0p }", invalid_msg);
2052 TestError("table T { F:float; } root_type T; { F:0x0.0p+ }", invalid_msg);
2053 TestError("table T { F:float; } root_type T; { F:0x0.0p- }", invalid_msg);
2054 TestError("table T { F:float; } root_type T; { F:0x0.0pa1 }", invalid_msg);
2055 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
2056 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
2057 TestError("table T { F:float; } root_type T; { F:0x0.0e+0 }", invalid_msg);
2058 TestError("table T { F:float; } root_type T; { F:0x0.0e-0 }", invalid_msg);
2059 TestError("table T { F:float; } root_type T; { F:0x0.0ep+ }", invalid_msg);
2060 TestError("table T { F:float; } root_type T; { F:0x0.0ep- }", invalid_msg);
2061 TestError("table T { F:float; } root_type T; { F:1.2.3 }", invalid_msg);
2062 TestError("table T { F:float; } root_type T; { F:1.2.e3 }", invalid_msg);
2063 TestError("table T { F:float; } root_type T; { F:1.2e.3 }", invalid_msg);
2064 TestError("table T { F:float; } root_type T; { F:1.2e0.3 }", invalid_msg);
2065 TestError("table T { F:float; } root_type T; { F:1.2e3. }", invalid_msg);
2066 TestError("table T { F:float; } root_type T; { F:1.2e3.0 }", invalid_msg);
2067 TestError("table T { F:float; } root_type T; { F:+-1.0 }", invalid_msg);
2068 TestError("table T { F:float; } root_type T; { F:1.0e+-1 }", invalid_msg);
2069 TestError("table T { F:float; } root_type T; { F:\"1.0e+-1\" }", invalid_msg);
2070 TestError("table T { F:float; } root_type T; { F:1.e0e }", comma_msg);
2071 TestError("table T { F:float; } root_type T; { F:0x1.p0e }", comma_msg);
2072 TestError("table T { F:float; } root_type T; { F:\" 0x10 \" }", invalid_msg);
2074 TestError("table T { F:float; } root_type T; { F:\"1,2.\" }", invalid_msg);
2075 TestError("table T { F:float; } root_type T; { F:\"1.2e3.\" }", invalid_msg);
2076 TestError("table T { F:float; } root_type T; { F:\"0x1.p0e\" }", invalid_msg);
2077 TestError("table T { F:float; } root_type T; { F:\"0x1.0\" }", invalid_msg);
2078 TestError("table T { F:float; } root_type T; { F:\" 0x1.0\" }", invalid_msg);
2079 TestError("table T { F:float; } root_type T; { F:\"+ 0\" }", invalid_msg);
2080 // disable escapes for "number-in-string"
2081 TestError("table T { F:float; } root_type T; { F:\"\\f1.2e3.\" }", "invalid");
2082 TestError("table T { F:float; } root_type T; { F:\"\\t1.2e3.\" }", "invalid");
2083 TestError("table T { F:float; } root_type T; { F:\"\\n1.2e3.\" }", "invalid");
2084 TestError("table T { F:float; } root_type T; { F:\"\\r1.2e3.\" }", "invalid");
2085 TestError("table T { F:float; } root_type T; { F:\"4\\x005\" }", "invalid");
2086 TestError("table T { F:float; } root_type T; { F:\"\'12\'\" }", invalid_msg);
2087 // null is not a number constant!
2088 TestError("table T { F:float; } root_type T; { F:\"null\" }", invalid_msg);
2089 TestError("table T { F:float; } root_type T; { F:null }", invalid_msg);
2092 void GenerateTableTextTest() {
2093 std::string schemafile;
2094 std::string jsonfile;
2096 flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2097 false, &schemafile) &&
2098 flatbuffers::LoadFile((test_data_path + "monsterdata_test.json").c_str(),
2101 auto include_test_path =
2102 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2103 const char *include_directories[] = { test_data_path.c_str(),
2104 include_test_path.c_str(), nullptr };
2105 flatbuffers::IDLOptions opt;
2106 opt.indent_step = -1;
2107 flatbuffers::Parser parser(opt);
2108 ok = parser.Parse(schemafile.c_str(), include_directories) &&
2109 parser.Parse(jsonfile.c_str(), include_directories);
2112 const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
2113 std::string jsongen;
2114 auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster",
2116 TEST_EQ(result, true);
2118 const Vec3 *pos = monster->pos();
2120 result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
2121 TEST_EQ(result, true);
2124 "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
2125 const Test &test3 = pos->test3();
2128 GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
2129 TEST_EQ(result, true);
2130 TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
2131 const Test *test4 = monster->test4()->Get(0);
2134 GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
2135 TEST_EQ(result, true);
2136 TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
2139 template<typename T>
2140 void NumericUtilsTestInteger(const char *lower, const char *upper) {
2142 TEST_EQ(flatbuffers::StringToNumber("1q", &x), false);
2144 TEST_EQ(flatbuffers::StringToNumber(upper, &x), false);
2145 TEST_EQ(x, flatbuffers::numeric_limits<T>::max());
2146 TEST_EQ(flatbuffers::StringToNumber(lower, &x), false);
2147 auto expval = flatbuffers::is_unsigned<T>::value
2148 ? flatbuffers::numeric_limits<T>::max()
2149 : flatbuffers::numeric_limits<T>::lowest();
2153 template<typename T>
2154 void NumericUtilsTestFloat(const char *lower, const char *upper) {
2156 TEST_EQ(flatbuffers::StringToNumber("", &f), false);
2157 TEST_EQ(flatbuffers::StringToNumber("1q", &f), false);
2159 TEST_EQ(flatbuffers::StringToNumber(upper, &f), true);
2160 TEST_EQ(f, +flatbuffers::numeric_limits<T>::infinity());
2161 TEST_EQ(flatbuffers::StringToNumber(lower, &f), true);
2162 TEST_EQ(f, -flatbuffers::numeric_limits<T>::infinity());
2165 void NumericUtilsTest() {
2166 NumericUtilsTestInteger<uint64_t>("-1", "18446744073709551616");
2167 NumericUtilsTestInteger<uint8_t>("-1", "256");
2168 NumericUtilsTestInteger<int64_t>("-9223372036854775809",
2169 "9223372036854775808");
2170 NumericUtilsTestInteger<int8_t>("-129", "128");
2171 NumericUtilsTestFloat<float>("-3.4029e+38", "+3.4029e+38");
2172 NumericUtilsTestFloat<float>("-1.7977e+308", "+1.7977e+308");
2175 void IsAsciiUtilsTest() {
2177 for (int cnt = 0; cnt < 256; cnt++) {
2178 auto alpha = (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
2179 auto dec = (('0' <= c) && (c <= '9'));
2180 auto hex = (('a' <= c) && (c <= 'f')) || (('A' <= c) && (c <= 'F'));
2181 TEST_EQ(flatbuffers::is_alpha(c), alpha);
2182 TEST_EQ(flatbuffers::is_alnum(c), alpha || dec);
2183 TEST_EQ(flatbuffers::is_digit(c), dec);
2184 TEST_EQ(flatbuffers::is_xdigit(c), dec || hex);
2189 void UnicodeTest() {
2190 flatbuffers::Parser parser;
2191 // Without setting allow_non_utf8 = true, we treat \x sequences as byte
2192 // sequences which are then validated as UTF-8.
2193 TEST_EQ(parser.Parse("table T { F:string; }"
2195 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2196 "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD8"
2199 std::string jsongen;
2200 parser.opts.indent_step = -1;
2202 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2203 TEST_EQ(result, true);
2204 TEST_EQ_STR(jsongen.c_str(),
2205 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2206 "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
2209 void UnicodeTestAllowNonUTF8() {
2210 flatbuffers::Parser parser;
2211 parser.opts.allow_non_utf8 = true;
2214 "table T { F:string; }"
2216 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2217 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2219 std::string jsongen;
2220 parser.opts.indent_step = -1;
2222 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2223 TEST_EQ(result, true);
2226 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2227 "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
2230 void UnicodeTestGenerateTextFailsOnNonUTF8() {
2231 flatbuffers::Parser parser;
2232 // Allow non-UTF-8 initially to model what happens when we load a binary
2233 // flatbuffer from disk which contains non-UTF-8 strings.
2234 parser.opts.allow_non_utf8 = true;
2237 "table T { F:string; }"
2239 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2240 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2242 std::string jsongen;
2243 parser.opts.indent_step = -1;
2244 // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates
2246 parser.opts.allow_non_utf8 = false;
2248 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2249 TEST_EQ(result, false);
2252 void UnicodeSurrogatesTest() {
2253 flatbuffers::Parser parser;
2255 TEST_EQ(parser.Parse("table T { F:string (id: 0); }"
2257 "{ F:\"\\uD83D\\uDCA9\"}"),
2259 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
2260 parser.builder_.GetBufferPointer());
2261 auto string = root->GetPointer<flatbuffers::String *>(
2262 flatbuffers::FieldIndexToOffset(0));
2263 TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
2266 void UnicodeInvalidSurrogatesTest() {
2268 "table T { F:string; }"
2271 "unpaired high surrogate");
2273 "table T { F:string; }"
2275 "{ F:\"\\uD800abcd\"}",
2276 "unpaired high surrogate");
2278 "table T { F:string; }"
2280 "{ F:\"\\uD800\\n\"}",
2281 "unpaired high surrogate");
2283 "table T { F:string; }"
2285 "{ F:\"\\uD800\\uD800\"}",
2286 "multiple high surrogates");
2288 "table T { F:string; }"
2291 "unpaired low surrogate");
2294 void InvalidUTF8Test() {
2295 // "1 byte" pattern, under min length of 2 bytes
2297 "table T { F:string; }"
2300 "illegal UTF-8 sequence");
2301 // 2 byte pattern, string too short
2303 "table T { F:string; }"
2306 "illegal UTF-8 sequence");
2307 // 3 byte pattern, string too short
2309 "table T { F:string; }"
2311 "{ F:\"\xEF\xBF\"}",
2312 "illegal UTF-8 sequence");
2313 // 4 byte pattern, string too short
2315 "table T { F:string; }"
2317 "{ F:\"\xF7\xBF\xBF\"}",
2318 "illegal UTF-8 sequence");
2319 // "5 byte" pattern, string too short
2321 "table T { F:string; }"
2323 "{ F:\"\xFB\xBF\xBF\xBF\"}",
2324 "illegal UTF-8 sequence");
2325 // "6 byte" pattern, string too short
2327 "table T { F:string; }"
2329 "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}",
2330 "illegal UTF-8 sequence");
2331 // "7 byte" pattern, string too short
2333 "table T { F:string; }"
2335 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}",
2336 "illegal UTF-8 sequence");
2337 // "5 byte" pattern, over max length of 4 bytes
2339 "table T { F:string; }"
2341 "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}",
2342 "illegal UTF-8 sequence");
2343 // "6 byte" pattern, over max length of 4 bytes
2345 "table T { F:string; }"
2347 "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}",
2348 "illegal UTF-8 sequence");
2349 // "7 byte" pattern, over max length of 4 bytes
2351 "table T { F:string; }"
2353 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}",
2354 "illegal UTF-8 sequence");
2356 // Three invalid encodings for U+000A (\n, aka NEWLINE)
2358 "table T { F:string; }"
2360 "{ F:\"\xC0\x8A\"}",
2361 "illegal UTF-8 sequence");
2363 "table T { F:string; }"
2365 "{ F:\"\xE0\x80\x8A\"}",
2366 "illegal UTF-8 sequence");
2368 "table T { F:string; }"
2370 "{ F:\"\xF0\x80\x80\x8A\"}",
2371 "illegal UTF-8 sequence");
2373 // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
2375 "table T { F:string; }"
2377 "{ F:\"\xE0\x81\xA9\"}",
2378 "illegal UTF-8 sequence");
2380 "table T { F:string; }"
2382 "{ F:\"\xF0\x80\x81\xA9\"}",
2383 "illegal UTF-8 sequence");
2385 // Invalid encoding for U+20AC (EURO SYMBOL)
2387 "table T { F:string; }"
2389 "{ F:\"\xF0\x82\x82\xAC\"}",
2390 "illegal UTF-8 sequence");
2392 // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in
2395 "table T { F:string; }"
2397 // U+10400 "encoded" as U+D801 U+DC00
2398 "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}",
2399 "illegal UTF-8 sequence");
2401 // Check independence of identifier from locale.
2402 std::string locale_ident;
2403 locale_ident += "table T { F";
2404 locale_ident += static_cast<char>(-32); // unsigned 0xE0
2405 locale_ident += " :string; }";
2406 locale_ident += "root_type T;";
2407 locale_ident += "{}";
2408 TestError(locale_ident.c_str(), "");
2411 void UnknownFieldsTest() {
2412 flatbuffers::IDLOptions opts;
2413 opts.skip_unexpected_fields_in_json = true;
2414 flatbuffers::Parser parser(opts);
2416 TEST_EQ(parser.Parse("table T { str:string; i:int;}"
2419 "unknown_string:\"test\","
2420 "\"unknown_string\":\"test\","
2422 "unknown_float:1.0,"
2423 "unknown_array: [ 1, 2, 3, 4],"
2424 "unknown_object: { i: 10 },"
2425 "\"unknown_object\": { \"i\": 10 },"
2429 std::string jsongen;
2430 parser.opts.indent_step = -1;
2432 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2433 TEST_EQ(result, true);
2434 TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
2437 void ParseUnionTest() {
2438 // Unions must be parseable with the type field following the object.
2439 flatbuffers::Parser parser;
2440 TEST_EQ(parser.Parse("table T { A:int; }"
2444 "{ X:{ A:1 }, X_type: T }"),
2446 // Unions must be parsable with prefixed namespace.
2447 flatbuffers::Parser parser2;
2448 TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
2449 "table B { e:U; } root_type B;"
2450 "{ e_type: N_A, e: {} }"),
2454 void InvalidNestedFlatbufferTest() {
2455 // First, load and parse FlatBuffer schema (.fbs)
2456 std::string schemafile;
2457 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2458 false, &schemafile),
2460 auto include_test_path =
2461 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2462 const char *include_directories[] = { test_data_path.c_str(),
2463 include_test_path.c_str(), nullptr };
2464 flatbuffers::Parser parser1;
2465 TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
2467 // "color" inside nested flatbuffer contains invalid enum value
2468 TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
2469 "\"Leela\", color: \"nonexistent\"}}"),
2473 void EvolutionTest() {
2474 // VS10 does not support typed enums, exclude from tests
2475 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2476 const int NUM_VERSIONS = 2;
2477 std::string schemas[NUM_VERSIONS];
2478 std::string jsonfiles[NUM_VERSIONS];
2479 std::vector<uint8_t> binaries[NUM_VERSIONS];
2481 flatbuffers::IDLOptions idl_opts;
2482 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2483 flatbuffers::Parser parser(idl_opts);
2485 // Load all the schema versions and their associated data.
2486 for (int i = 0; i < NUM_VERSIONS; ++i) {
2487 std::string schema = test_data_path + "evolution_test/evolution_v" +
2488 flatbuffers::NumToString(i + 1) + ".fbs";
2489 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2490 std::string json = test_data_path + "evolution_test/evolution_v" +
2491 flatbuffers::NumToString(i + 1) + ".json";
2492 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2494 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2495 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2497 auto bufLen = parser.builder_.GetSize();
2498 auto buf = parser.builder_.GetBufferPointer();
2499 binaries[i].reserve(bufLen);
2500 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2503 // Assert that all the verifiers for the different schema versions properly
2504 // verify any version data.
2505 for (int i = 0; i < NUM_VERSIONS; ++i) {
2506 flatbuffers::Verifier verifier(&binaries[i].front(), binaries[i].size());
2507 TEST_ASSERT(Evolution::V1::VerifyRootBuffer(verifier));
2508 TEST_ASSERT(Evolution::V2::VerifyRootBuffer(verifier));
2511 // Test backwards compatibility by reading old data with an evolved schema.
2512 auto root_v1_viewed_from_v2 = Evolution::V2::GetRoot(&binaries[0].front());
2513 // field 'k' is new in version 2, so it should be null.
2514 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->k());
2515 // field 'l' is new in version 2 with a default of 56.
2516 TEST_EQ(root_v1_viewed_from_v2->l(), 56);
2517 // field 'c' of 'TableA' is new in version 2, so it should be null.
2518 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->e()->c());
2519 // 'TableC' was added to field 'c' union in version 2, so it should be null.
2520 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->c_as_TableC());
2521 // The field 'c' union should be of type 'TableB' regardless of schema version
2522 TEST_ASSERT(root_v1_viewed_from_v2->c_type() == Evolution::V2::Union::TableB);
2523 // The field 'f' was renamed to 'ff' in version 2, it should still be
2525 TEST_EQ(root_v1_viewed_from_v2->ff()->a(), 16);
2527 // Test forwards compatibility by reading new data with an old schema.
2528 auto root_v2_viewed_from_v1 = Evolution::V1::GetRoot(&binaries[1].front());
2529 // The field 'c' union in version 2 is a new table (index = 3) and should
2530 // still be accessible, but not interpretable.
2531 TEST_EQ(static_cast<uint8_t>(root_v2_viewed_from_v1->c_type()), 3);
2532 TEST_NOTNULL(root_v2_viewed_from_v1->c());
2533 // The field 'd' enum in verison 2 has new members and should still be
2534 // accessible, but not interpretable.
2535 TEST_EQ(static_cast<int8_t>(root_v2_viewed_from_v1->d()), 3);
2536 // The field 'a' in version 2 is deprecated and should return the default
2537 // value (0) instead of the value stored in the in the buffer (42).
2538 TEST_EQ(root_v2_viewed_from_v1->a(), 0);
2539 // The field 'ff' was originally named 'f' in version 1, it should still be
2541 TEST_EQ(root_v2_viewed_from_v1->f()->a(), 35);
2545 void UnionDeprecationTest() {
2546 const int NUM_VERSIONS = 2;
2547 std::string schemas[NUM_VERSIONS];
2548 std::string jsonfiles[NUM_VERSIONS];
2549 std::vector<uint8_t> binaries[NUM_VERSIONS];
2551 flatbuffers::IDLOptions idl_opts;
2552 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2553 flatbuffers::Parser parser(idl_opts);
2555 // Load all the schema versions and their associated data.
2556 for (int i = 0; i < NUM_VERSIONS; ++i) {
2557 std::string schema = test_data_path + "evolution_test/evolution_v" +
2558 flatbuffers::NumToString(i + 1) + ".fbs";
2559 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2560 std::string json = test_data_path + "evolution_test/evolution_v" +
2561 flatbuffers::NumToString(i + 1) + ".json";
2562 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2564 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2565 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2567 auto bufLen = parser.builder_.GetSize();
2568 auto buf = parser.builder_.GetBufferPointer();
2569 binaries[i].reserve(bufLen);
2570 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2573 auto v2 = parser.LookupStruct("Evolution.V2.Root");
2575 auto j_type_field = v2->fields.Lookup("j_type");
2576 TEST_NOTNULL(j_type_field);
2577 TEST_ASSERT(j_type_field->deprecated);
2580 void UnionVectorTest() {
2581 // load FlatBuffer fbs schema and json.
2582 std::string schemafile, jsonfile;
2583 TEST_EQ(flatbuffers::LoadFile(
2584 (test_data_path + "union_vector/union_vector.fbs").c_str(), false,
2587 TEST_EQ(flatbuffers::LoadFile(
2588 (test_data_path + "union_vector/union_vector.json").c_str(),
2593 flatbuffers::IDLOptions idl_opts;
2594 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2595 flatbuffers::Parser parser(idl_opts);
2596 TEST_EQ(parser.Parse(schemafile.c_str()), true);
2598 flatbuffers::FlatBufferBuilder fbb;
2601 std::vector<uint8_t> types;
2602 types.push_back(static_cast<uint8_t>(Character_Belle));
2603 types.push_back(static_cast<uint8_t>(Character_MuLan));
2604 types.push_back(static_cast<uint8_t>(Character_BookFan));
2605 types.push_back(static_cast<uint8_t>(Character_Other));
2606 types.push_back(static_cast<uint8_t>(Character_Unused));
2609 std::vector<flatbuffers::Offset<void>> characters;
2610 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
2611 characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
2612 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
2613 characters.push_back(fbb.CreateString("Other").Union());
2614 characters.push_back(fbb.CreateString("Unused").Union());
2617 const auto movie_offset =
2618 CreateMovie(fbb, Character_Rapunzel,
2619 fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
2620 fbb.CreateVector(types), fbb.CreateVector(characters));
2621 FinishMovieBuffer(fbb, movie_offset);
2623 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
2624 TEST_EQ(VerifyMovieBuffer(verifier), true);
2626 auto flat_movie = GetMovie(fbb.GetBufferPointer());
2628 auto TestMovie = [](const Movie *movie) {
2629 TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
2631 auto cts = movie->characters_type();
2632 TEST_EQ(movie->characters_type()->size(), 5);
2633 TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
2634 TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
2635 TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
2636 TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
2637 TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
2639 auto rapunzel = movie->main_character_as_Rapunzel();
2640 TEST_NOTNULL(rapunzel);
2641 TEST_EQ(rapunzel->hair_length(), 6);
2643 auto cs = movie->characters();
2644 TEST_EQ(cs->size(), 5);
2645 auto belle = cs->GetAs<BookReader>(0);
2646 TEST_EQ(belle->books_read(), 7);
2647 auto mu_lan = cs->GetAs<Attacker>(1);
2648 TEST_EQ(mu_lan->sword_attack_damage(), 5);
2649 auto book_fan = cs->GetAs<BookReader>(2);
2650 TEST_EQ(book_fan->books_read(), 2);
2651 auto other = cs->GetAsString(3);
2652 TEST_EQ_STR(other->c_str(), "Other");
2653 auto unused = cs->GetAsString(4);
2654 TEST_EQ_STR(unused->c_str(), "Unused");
2657 TestMovie(flat_movie);
2659 // Also test the JSON we loaded above.
2660 TEST_EQ(parser.Parse(jsonfile.c_str()), true);
2661 auto jbuf = parser.builder_.GetBufferPointer();
2662 flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
2663 TEST_EQ(VerifyMovieBuffer(jverifier), true);
2664 TestMovie(GetMovie(jbuf));
2666 auto movie_object = flat_movie->UnPack();
2667 TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
2668 TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
2669 TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
2670 TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
2671 TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
2672 TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
2675 fbb.Finish(Movie::Pack(fbb, movie_object));
2677 delete movie_object;
2679 auto repacked_movie = GetMovie(fbb.GetBufferPointer());
2681 TestMovie(repacked_movie);
2683 // Generate text using mini-reflection.
2685 flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
2688 "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
2689 "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
2690 "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
2691 "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
2693 flatbuffers::ToStringVisitor visitor("\n", true, " ");
2694 IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
2695 TEST_EQ_STR(visitor.s.c_str(),
2697 " \"main_character_type\": \"Rapunzel\",\n"
2698 " \"main_character\": {\n"
2699 " \"hair_length\": 6\n"
2701 " \"characters_type\": [\n"
2708 " \"characters\": [\n"
2710 " \"books_read\": 7\n"
2713 " \"sword_attack_damage\": 5\n"
2716 " \"books_read\": 2\n"
2723 // Generate text using parsed schema.
2724 std::string jsongen;
2725 auto result = GenerateText(parser, fbb.GetBufferPointer(), &jsongen);
2726 TEST_EQ(result, true);
2727 TEST_EQ_STR(jsongen.c_str(),
2729 " main_character_type: \"Rapunzel\",\n"
2730 " main_character: {\n"
2733 " characters_type: [\n"
2745 " sword_attack_damage: 5\n"
2755 // Simple test with reflection.
2757 auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
2758 auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
2759 fbb.GetBufferPointer(), fbb.GetSize());
2762 flatbuffers::Parser parser2(idl_opts);
2763 TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
2764 "union Any { Bool }"
2765 "table Root { a:Any; }"
2768 TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
2771 void ConformTest() {
2772 flatbuffers::Parser parser;
2773 TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
2775 auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
2776 const char *expected_err) {
2777 flatbuffers::Parser parser2;
2778 TEST_EQ(parser2.Parse(test), true);
2779 auto err = parser2.ConformTo(parser1);
2780 TEST_NOTNULL(strstr(err.c_str(), expected_err));
2783 test_conform(parser, "table T { A:byte; }", "types differ for field");
2784 test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
2785 test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
2786 test_conform(parser, "table T { B:float; }",
2787 "field renamed to different type");
2788 test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
2791 void ParseProtoBufAsciiTest() {
2792 // We can put the parser in a mode where it will accept JSON that looks more
2793 // like Protobuf ASCII, for users that have data in that format.
2794 // This uses no "" for field names (which we already support by default,
2795 // omits `,`, `:` before `{` and a couple of other features.
2796 flatbuffers::Parser parser;
2797 parser.opts.protobuf_ascii_alike = true;
2799 parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
2801 TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
2802 // Similarly, in text output, it should omit these.
2804 auto ok = flatbuffers::GenerateText(
2805 parser, parser.builder_.GetBufferPointer(), &text);
2807 TEST_EQ_STR(text.c_str(),
2808 "{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n");
2811 void FlexBuffersTest() {
2812 flexbuffers::Builder slb(512,
2813 flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
2815 // Write the equivalent of:
2816 // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ],
2817 // foo: 100, bool: true, mymap: { foo: "Fred" } }
2819 #ifndef FLATBUFFERS_CPP98_STL
2820 // It's possible to do this without std::function support as well.
2822 slb.Vector("vec", [&]() {
2823 slb += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2825 slb.IndirectFloat(4.0f);
2826 auto i_f = slb.LastValue();
2827 uint8_t blob[] = { 77 };
2830 slb.ReuseValue(i_f);
2832 int ints[] = { 1, 2, 3 };
2833 slb.Vector("bar", ints, 3);
2834 slb.FixedTypedVector("bar3", ints, 3);
2835 bool bools[] = {true, false, true, false};
2836 slb.Vector("bools", bools, 4);
2837 slb.Bool("bool", true);
2838 slb.Double("foo", 100);
2839 slb.Map("mymap", [&]() {
2840 slb.String("foo", "Fred"); // Testing key and string reuse.
2845 // It's possible to do this without std::function support as well.
2846 slb.Map([](flexbuffers::Builder& slb2) {
2847 slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
2848 slb3 += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2850 slb3.IndirectFloat(4.0f);
2851 auto i_f = slb3.LastValue();
2852 uint8_t blob[] = { 77 };
2855 slb3.ReuseValue(i_f);
2857 int ints[] = { 1, 2, 3 };
2858 slb2.Vector("bar", ints, 3);
2859 slb2.FixedTypedVector("bar3", ints, 3);
2860 slb2.Bool("bool", true);
2861 slb2.Double("foo", 100);
2862 slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
2863 slb3.String("foo", "Fred"); // Testing key and string reuse.
2867 #endif // FLATBUFFERS_CPP98_STL
2869 #ifdef FLATBUFFERS_TEST_VERBOSE
2870 for (size_t i = 0; i < slb.GetBuffer().size(); i++)
2871 printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
2876 auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
2877 TEST_EQ(map.size(), 7);
2878 auto vec = map["vec"].AsVector();
2879 TEST_EQ(vec.size(), 6);
2880 TEST_EQ(vec[0].AsInt64(), -100);
2881 TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
2882 TEST_EQ(vec[1].AsInt64(), 0); // Number parsing failed.
2883 TEST_EQ(vec[2].AsDouble(), 4.0);
2884 TEST_EQ(vec[2].AsString().IsTheEmptyString(), true); // Wrong Type.
2885 TEST_EQ_STR(vec[2].AsString().c_str(), ""); // This still works though.
2886 TEST_EQ_STR(vec[2].ToString().c_str(), "4.0"); // Or have it converted.
2887 // Few tests for templated version of As.
2888 TEST_EQ(vec[0].As<int64_t>(), -100);
2889 TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
2890 TEST_EQ(vec[1].As<int64_t>(), 0); // Number parsing failed.
2891 TEST_EQ(vec[2].As<double>(), 4.0);
2892 // Test that the blob can be accessed.
2893 TEST_EQ(vec[3].IsBlob(), true);
2894 auto blob = vec[3].AsBlob();
2895 TEST_EQ(blob.size(), 1);
2896 TEST_EQ(blob.data()[0], 77);
2897 TEST_EQ(vec[4].IsBool(), true); // Check if type is a bool
2898 TEST_EQ(vec[4].AsBool(), false); // Check if value is false
2899 TEST_EQ(vec[5].AsDouble(), 4.0); // This is shared with vec[2] !
2900 auto tvec = map["bar"].AsTypedVector();
2901 TEST_EQ(tvec.size(), 3);
2902 TEST_EQ(tvec[2].AsInt8(), 3);
2903 auto tvec3 = map["bar3"].AsFixedTypedVector();
2904 TEST_EQ(tvec3.size(), 3);
2905 TEST_EQ(tvec3[2].AsInt8(), 3);
2906 TEST_EQ(map["bool"].AsBool(), true);
2907 auto tvecb = map["bools"].AsTypedVector();
2908 TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
2909 TEST_EQ(map["foo"].AsUInt8(), 100);
2910 TEST_EQ(map["unknown"].IsNull(), true);
2911 auto mymap = map["mymap"].AsMap();
2912 // These should be equal by pointer equality, since key and value are shared.
2913 TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
2914 TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
2915 // We can mutate values in the buffer.
2916 TEST_EQ(vec[0].MutateInt(-99), true);
2917 TEST_EQ(vec[0].AsInt64(), -99);
2918 TEST_EQ(vec[1].MutateString("John"), true); // Size must match.
2919 TEST_EQ_STR(vec[1].AsString().c_str(), "John");
2920 TEST_EQ(vec[1].MutateString("Alfred"), false); // Too long.
2921 TEST_EQ(vec[2].MutateFloat(2.0f), true);
2922 TEST_EQ(vec[2].AsFloat(), 2.0f);
2923 TEST_EQ(vec[2].MutateFloat(3.14159), false); // Double does not fit in float.
2924 TEST_EQ(vec[4].AsBool(), false); // Is false before change
2925 TEST_EQ(vec[4].MutateBool(true), true); // Can change a bool
2926 TEST_EQ(vec[4].AsBool(), true); // Changed bool is now true
2929 flatbuffers::Parser parser;
2931 auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
2932 TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
2933 auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
2934 auto jmap = jroot.AsMap();
2935 auto jvec = jmap["a"].AsVector();
2936 TEST_EQ(jvec[0].AsInt64(), 123);
2937 TEST_EQ(jvec[1].AsDouble(), 456.0);
2938 TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
2939 TEST_EQ(jmap["c"].IsBool(), true); // Parsed correctly to a bool
2940 TEST_EQ(jmap["c"].AsBool(), true); // Parsed correctly to true
2941 TEST_EQ(jmap["d"].IsBool(), true); // Parsed correctly to a bool
2942 TEST_EQ(jmap["d"].AsBool(), false); // Parsed correctly to false
2943 // And from FlexBuffer back to JSON:
2944 auto jsonback = jroot.ToString();
2945 TEST_EQ_STR(jsontest, jsonback.c_str());
2949 for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
2951 for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
2956 TEST_EQ(slb.GetSize(), 664);
2959 void FlexBuffersDeprecatedTest() {
2960 // FlexBuffers as originally designed had a flaw involving the
2961 // FBT_VECTOR_STRING datatype, and this test documents/tests the fix for it.
2962 // Discussion: https://github.com/google/flatbuffers/issues/5627
2963 flexbuffers::Builder slb;
2964 // FBT_VECTOR_* are "typed vectors" where all elements are of the same type.
2965 // Problem is, when storing FBT_STRING elements, it relies on that type to
2966 // get the bit-width for the size field of the string, which in this case
2967 // isn't present, and instead defaults to 8-bit. This means that any strings
2968 // stored inside such a vector, when accessed thru the old API that returns
2969 // a String reference, will appear to be truncated if the string stored is
2970 // actually >=256 bytes.
2971 std::string test_data(300, 'A');
2972 auto start = slb.StartVector();
2973 // This one will have a 16-bit size field.
2974 slb.String(test_data);
2975 // This one will have an 8-bit size field.
2976 slb.String("hello");
2977 // We're asking this to be serialized as a typed vector (true), but not
2978 // fixed size (false). The type will be FBT_VECTOR_STRING with a bit-width
2979 // of whatever the offsets in the vector need, the bit-widths of the strings
2980 // are not stored(!) <- the actual design flaw.
2981 // Note that even in the fixed code, we continue to serialize the elements of
2982 // FBT_VECTOR_STRING as FBT_STRING, since there may be old code out there
2983 // reading new data that we want to continue to function.
2984 // Thus, FBT_VECTOR_STRING, while deprecated, will always be represented the
2985 // same way, the fix lies on the reading side.
2986 slb.EndVector(start, true, false);
2988 // So now lets read this data back.
2989 // For existing data, since we have no way of knowing what the actual
2990 // bit-width of the size field of the string is, we are going to ignore this
2991 // field, and instead treat these strings as FBT_KEY (null-terminated), so we
2992 // can deal with strings of arbitrary length. This of course truncates strings
2993 // with embedded nulls, but we think that that is preferrable over truncating
2994 // strings >= 256 bytes.
2995 auto vec = flexbuffers::GetRoot(slb.GetBuffer()).AsTypedVector();
2996 // Even though this was serialized as FBT_VECTOR_STRING, it is read as
2998 TEST_EQ(vec.ElementType(), flexbuffers::FBT_KEY);
2999 // Access the long string. Previously, this would return a string of size 1,
3000 // since it would read the high-byte of the 16-bit length.
3001 // This should now correctly test the full 300 bytes, using AsKey():
3002 TEST_EQ_STR(vec[0].AsKey(), test_data.c_str());
3003 // Old code that called AsString will continue to work, as the String
3004 // accessor objects now use a cached size that can come from a key as well.
3005 TEST_EQ_STR(vec[0].AsString().c_str(), test_data.c_str());
3006 // Short strings work as before:
3007 TEST_EQ_STR(vec[1].AsKey(), "hello");
3008 TEST_EQ_STR(vec[1].AsString().c_str(), "hello");
3009 // So, while existing code and data mostly "just work" with the fixes applied
3010 // to AsTypedVector and AsString, what do you do going forward?
3011 // Code accessing existing data doesn't necessarily need to change, though
3012 // you could consider using AsKey instead of AsString for a) documenting
3013 // that you are accessing keys, or b) a speedup if you don't actually use
3015 // For new data, or data that doesn't need to be backwards compatible,
3016 // instead serialize as FBT_VECTOR (call EndVector with typed = false, then
3017 // read elements with AsString), or, for maximum compactness, use
3018 // FBT_VECTOR_KEY (call slb.Key above instead, read with AsKey or AsString).
3021 void TypeAliasesTest() {
3022 flatbuffers::FlatBufferBuilder builder;
3024 builder.Finish(CreateTypeAliases(
3025 builder, flatbuffers::numeric_limits<int8_t>::min(),
3026 flatbuffers::numeric_limits<uint8_t>::max(),
3027 flatbuffers::numeric_limits<int16_t>::min(),
3028 flatbuffers::numeric_limits<uint16_t>::max(),
3029 flatbuffers::numeric_limits<int32_t>::min(),
3030 flatbuffers::numeric_limits<uint32_t>::max(),
3031 flatbuffers::numeric_limits<int64_t>::min(),
3032 flatbuffers::numeric_limits<uint64_t>::max(), 2.3f, 2.3));
3034 auto p = builder.GetBufferPointer();
3035 auto ta = flatbuffers::GetRoot<TypeAliases>(p);
3037 TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
3038 TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
3039 TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
3040 TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
3041 TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
3042 TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
3043 TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
3044 TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
3045 TEST_EQ(ta->f32(), 2.3f);
3046 TEST_EQ(ta->f64(), 2.3);
3047 using namespace flatbuffers; // is_same
3048 static_assert(is_same<decltype(ta->i8()), int8_t>::value, "invalid type");
3049 static_assert(is_same<decltype(ta->i16()), int16_t>::value, "invalid type");
3050 static_assert(is_same<decltype(ta->i32()), int32_t>::value, "invalid type");
3051 static_assert(is_same<decltype(ta->i64()), int64_t>::value, "invalid type");
3052 static_assert(is_same<decltype(ta->u8()), uint8_t>::value, "invalid type");
3053 static_assert(is_same<decltype(ta->u16()), uint16_t>::value, "invalid type");
3054 static_assert(is_same<decltype(ta->u32()), uint32_t>::value, "invalid type");
3055 static_assert(is_same<decltype(ta->u64()), uint64_t>::value, "invalid type");
3056 static_assert(is_same<decltype(ta->f32()), float>::value, "invalid type");
3057 static_assert(is_same<decltype(ta->f64()), double>::value, "invalid type");
3060 void EndianSwapTest() {
3061 TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
3062 TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
3064 TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
3065 0xEFCDAB9078563412);
3066 TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
3069 void UninitializedVectorTest() {
3070 flatbuffers::FlatBufferBuilder builder;
3072 Test *buf = nullptr;
3073 auto vector_offset =
3074 builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
3076 buf[0] = Test(10, 20);
3077 buf[1] = Test(30, 40);
3079 auto required_name = builder.CreateString("myMonster");
3080 auto monster_builder = MonsterBuilder(builder);
3081 monster_builder.add_name(
3082 required_name); // required field mandated for monster.
3083 monster_builder.add_test4(vector_offset);
3084 builder.Finish(monster_builder.Finish());
3086 auto p = builder.GetBufferPointer();
3087 auto uvt = flatbuffers::GetRoot<Monster>(p);
3089 auto vec = uvt->test4();
3091 auto test_0 = vec->Get(0);
3092 auto test_1 = vec->Get(1);
3093 TEST_EQ(test_0->a(), 10);
3094 TEST_EQ(test_0->b(), 20);
3095 TEST_EQ(test_1->a(), 30);
3096 TEST_EQ(test_1->b(), 40);
3099 void EqualOperatorTest() {
3102 TEST_EQ(b == a, true);
3103 TEST_EQ(b != a, false);
3106 TEST_EQ(b == a, false);
3107 TEST_EQ(b != a, true);
3109 TEST_EQ(b == a, true);
3110 TEST_EQ(b != a, false);
3112 b.inventory.push_back(3);
3113 TEST_EQ(b == a, false);
3114 TEST_EQ(b != a, true);
3115 b.inventory.clear();
3116 TEST_EQ(b == a, true);
3117 TEST_EQ(b != a, false);
3119 b.test.type = Any_Monster;
3120 TEST_EQ(b == a, false);
3121 TEST_EQ(b != a, true);
3124 // For testing any binaries, e.g. from fuzzing.
3125 void LoadVerifyBinaryTest() {
3127 if (flatbuffers::LoadFile(
3128 (test_data_path + "fuzzer/your-filename-here").c_str(), true,
3130 flatbuffers::Verifier verifier(
3131 reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
3132 TEST_EQ(VerifyMonsterBuffer(verifier), true);
3136 void CreateSharedStringTest() {
3137 flatbuffers::FlatBufferBuilder builder;
3138 const auto one1 = builder.CreateSharedString("one");
3139 const auto two = builder.CreateSharedString("two");
3140 const auto one2 = builder.CreateSharedString("one");
3141 TEST_EQ(one1.o, one2.o);
3142 const auto onetwo = builder.CreateSharedString("onetwo");
3143 TEST_EQ(onetwo.o != one1.o, true);
3144 TEST_EQ(onetwo.o != two.o, true);
3146 // Support for embedded nulls
3147 const char chars_b[] = { 'a', '\0', 'b' };
3148 const char chars_c[] = { 'a', '\0', 'c' };
3149 const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3150 const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
3151 const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3152 TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
3153 TEST_EQ(null_b1.o, null_b2.o);
3155 // Put the strings into an array for round trip verification.
3156 const flatbuffers::Offset<flatbuffers::String> array[7] = {
3157 one1, two, one2, onetwo, null_b1, null_c, null_b2
3159 const auto vector_offset =
3160 builder.CreateVector(array, flatbuffers::uoffset_t(7));
3161 MonsterBuilder monster_builder(builder);
3162 monster_builder.add_name(two);
3163 monster_builder.add_testarrayofstring(vector_offset);
3164 builder.Finish(monster_builder.Finish());
3166 // Read the Monster back.
3167 const auto *monster =
3168 flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
3169 TEST_EQ_STR(monster->name()->c_str(), "two");
3170 const auto *testarrayofstring = monster->testarrayofstring();
3171 TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
3172 const auto &a = *testarrayofstring;
3173 TEST_EQ_STR(a[0]->c_str(), "one");
3174 TEST_EQ_STR(a[1]->c_str(), "two");
3175 TEST_EQ_STR(a[2]->c_str(), "one");
3176 TEST_EQ_STR(a[3]->c_str(), "onetwo");
3177 TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
3178 TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
3179 TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
3181 // Make sure String::operator< works, too, since it is related to
3182 // StringOffsetCompare.
3183 TEST_EQ((*a[0]) < (*a[1]), true);
3184 TEST_EQ((*a[1]) < (*a[0]), false);
3185 TEST_EQ((*a[1]) < (*a[2]), false);
3186 TEST_EQ((*a[2]) < (*a[1]), true);
3187 TEST_EQ((*a[4]) < (*a[3]), true);
3188 TEST_EQ((*a[5]) < (*a[4]), false);
3189 TEST_EQ((*a[5]) < (*a[4]), false);
3190 TEST_EQ((*a[6]) < (*a[5]), true);
3193 void FixedLengthArrayTest() {
3194 // VS10 does not support typed enums, exclude from tests
3195 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3196 // Generate an ArrayTable containing one ArrayStruct.
3197 flatbuffers::FlatBufferBuilder fbb;
3198 MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
3199 TEST_NOTNULL(nStruct0.mutable_a());
3200 nStruct0.mutable_a()->Mutate(0, 1);
3201 nStruct0.mutable_a()->Mutate(1, 2);
3202 TEST_NOTNULL(nStruct0.mutable_c());
3203 nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3204 nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3205 TEST_NOTNULL(nStruct0.mutable_d());
3206 nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
3207 nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
3208 MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
3209 TEST_NOTNULL(nStruct1.mutable_a());
3210 nStruct1.mutable_a()->Mutate(0, 3);
3211 nStruct1.mutable_a()->Mutate(1, 4);
3212 TEST_NOTNULL(nStruct1.mutable_c());
3213 nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3214 nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3215 TEST_NOTNULL(nStruct1.mutable_d());
3216 nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
3217 nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
3218 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
3219 TEST_NOTNULL(aStruct.b());
3220 TEST_NOTNULL(aStruct.mutable_b());
3221 TEST_NOTNULL(aStruct.mutable_d());
3222 TEST_NOTNULL(aStruct.mutable_f());
3223 for (int i = 0; i < aStruct.b()->size(); i++)
3224 aStruct.mutable_b()->Mutate(i, i + 1);
3225 aStruct.mutable_d()->Mutate(0, nStruct0);
3226 aStruct.mutable_d()->Mutate(1, nStruct1);
3227 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
3228 MyGame::Example::FinishArrayTableBuffer(fbb, aTable);
3230 // Verify correctness of the ArrayTable.
3231 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
3232 MyGame::Example::VerifyArrayTableBuffer(verifier);
3233 auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
3234 auto mArStruct = p->mutable_a();
3235 TEST_NOTNULL(mArStruct);
3236 TEST_NOTNULL(mArStruct->b());
3237 TEST_NOTNULL(mArStruct->d());
3238 TEST_NOTNULL(mArStruct->f());
3239 TEST_NOTNULL(mArStruct->mutable_b());
3240 TEST_NOTNULL(mArStruct->mutable_d());
3241 TEST_NOTNULL(mArStruct->mutable_f());
3242 mArStruct->mutable_b()->Mutate(14, -14);
3243 TEST_EQ(mArStruct->a(), 2);
3244 TEST_EQ(mArStruct->b()->size(), 15);
3245 TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14);
3246 TEST_EQ(mArStruct->c(), 12);
3247 TEST_NOTNULL(mArStruct->d()->Get(0));
3248 TEST_NOTNULL(mArStruct->d()->Get(0)->a());
3249 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
3250 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
3251 TEST_NOTNULL(mArStruct->d()->Get(1));
3252 TEST_NOTNULL(mArStruct->d()->Get(1)->a());
3253 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
3254 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
3255 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
3256 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
3257 mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
3258 TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
3259 TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
3260 TEST_NOTNULL(mArStruct->d()->Get(0)->c());
3261 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
3262 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
3263 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3264 mArStruct->d()->Get(0)->d()->Get(0));
3265 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3266 mArStruct->d()->Get(0)->d()->Get(1));
3267 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
3268 TEST_NOTNULL(mArStruct->d()->Get(1)->c());
3269 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
3270 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
3271 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3272 mArStruct->d()->Get(1)->d()->Get(0));
3273 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3274 mArStruct->d()->Get(1)->d()->Get(1));
3275 for (int i = 0; i < mArStruct->b()->size() - 1; i++)
3276 TEST_EQ(mArStruct->b()->Get(i), i + 1);
3278 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
3279 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
3281 // Check if default constructor set all memory zero
3282 const size_t arr_size = sizeof(MyGame::Example::ArrayStruct);
3283 char non_zero_memory[arr_size];
3284 // set memory chunk of size ArrayStruct to 1's
3285 std::memset(static_cast<void *>(non_zero_memory), 1, arr_size);
3286 // after placement-new it should be all 0's
3287 #if defined (_MSC_VER) && defined (_DEBUG)
3290 MyGame::Example::ArrayStruct *ap = new (non_zero_memory) MyGame::Example::ArrayStruct;
3291 #if defined (_MSC_VER) && defined (_DEBUG)
3292 #define new DEBUG_NEW
3295 for (size_t i = 0; i < arr_size; ++i) {
3296 TEST_EQ(non_zero_memory[i], 0);
3301 void NativeTypeTest() {
3304 Geometry::ApplicationDataT src_data;
3305 src_data.vectors.reserve(N);
3307 for (int i = 0; i < N; ++i) {
3308 src_data.vectors.push_back(
3309 Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
3312 flatbuffers::FlatBufferBuilder fbb;
3313 fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
3315 auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
3317 for (int i = 0; i < N; ++i) {
3318 Native::Vector3D &v = dstDataT->vectors[i];
3319 TEST_EQ(v.x, 10 * i + 0.1f);
3320 TEST_EQ(v.y, 10 * i + 0.2f);
3321 TEST_EQ(v.z, 10 * i + 0.3f);
3325 void FixedLengthArrayJsonTest(bool binary) {
3326 // VS10 does not support typed enums, exclude from tests
3327 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3328 // load FlatBuffer schema (.fbs) and JSON from disk
3329 std::string schemafile;
3330 std::string jsonfile;
3332 flatbuffers::LoadFile(
3333 (test_data_path + "arrays_test." + (binary ? "bfbs" : "fbs")).c_str(),
3334 binary, &schemafile),
3336 TEST_EQ(flatbuffers::LoadFile((test_data_path + "arrays_test.golden").c_str(),
3340 // parse schema first, so we can use it to parse the data after
3341 flatbuffers::Parser parserOrg, parserGen;
3343 flatbuffers::Verifier verifier(
3344 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
3346 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3347 TEST_EQ(parserOrg.Deserialize((const uint8_t *)schemafile.c_str(),
3350 TEST_EQ(parserGen.Deserialize((const uint8_t *)schemafile.c_str(),
3354 TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
3355 TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
3357 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3359 // First, verify it, just in case:
3360 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3361 parserOrg.builder_.GetSize());
3362 TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
3365 std::string jsonGen;
3367 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3371 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3373 // Verify buffer from generated JSON
3374 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3375 parserGen.builder_.GetSize());
3376 TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
3378 // Compare generated buffer to original
3379 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3380 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3381 parserGen.builder_.GetBufferPointer(),
3382 parserOrg.builder_.GetSize()),
3389 void TestEmbeddedBinarySchema() {
3390 // load JSON from disk
3391 std::string jsonfile;
3392 TEST_EQ(flatbuffers::LoadFile(
3393 (test_data_path + "monsterdata_test.golden").c_str(), false,
3397 // parse schema first, so we can use it to parse the data after
3398 flatbuffers::Parser parserOrg, parserGen;
3399 flatbuffers::Verifier verifier(MyGame::Example::MonsterBinarySchema::data(),
3400 MyGame::Example::MonsterBinarySchema::size());
3401 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3402 TEST_EQ(parserOrg.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3403 MyGame::Example::MonsterBinarySchema::size()),
3405 TEST_EQ(parserGen.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3406 MyGame::Example::MonsterBinarySchema::size()),
3408 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3410 // First, verify it, just in case:
3411 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3412 parserOrg.builder_.GetSize());
3413 TEST_EQ(VerifyMonsterBuffer(verifierOrg), true);
3416 std::string jsonGen;
3418 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3422 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3424 // Verify buffer from generated JSON
3425 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3426 parserGen.builder_.GetSize());
3427 TEST_EQ(VerifyMonsterBuffer(verifierGen), true);
3429 // Compare generated buffer to original
3430 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3431 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3432 parserGen.builder_.GetBufferPointer(),
3433 parserOrg.builder_.GetSize()),
3437 void OptionalScalarsTest() {
3438 // Simple schemas and a "has optional scalar" sentinal.
3439 std::vector<std::string> schemas;
3440 schemas.push_back("table Monster { mana : int; }");
3441 schemas.push_back("table Monster { mana : int = 42; }");
3442 schemas.push_back("table Monster { mana : int = null; }");
3443 schemas.push_back("table Monster { mana : long; }");
3444 schemas.push_back("table Monster { mana : long = 42; }");
3445 schemas.push_back("table Monster { mana : long = null; }");
3446 schemas.push_back("table Monster { mana : float; }");
3447 schemas.push_back("table Monster { mana : float = 42; }");
3448 schemas.push_back("table Monster { mana : float = null; }");
3449 schemas.push_back("table Monster { mana : double; }");
3450 schemas.push_back("table Monster { mana : double = 42; }");
3451 schemas.push_back("table Monster { mana : double = null; }");
3452 schemas.push_back("table Monster { mana : bool; }");
3453 schemas.push_back("table Monster { mana : bool = 42; }");
3454 schemas.push_back("table Monster { mana : bool = null; }");
3456 // Check the FieldDef is correctly set.
3457 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3458 const bool has_null = schema->find("null") != std::string::npos;
3459 flatbuffers::Parser parser;
3460 TEST_ASSERT(parser.Parse(schema->c_str()));
3461 const auto *mana = parser.structs_.Lookup("Monster")->fields.Lookup("mana");
3462 TEST_EQ(mana->optional, has_null);
3465 // Test if optional scalars are allowed for each language.
3466 const int kNumLanguages = 17;
3467 const auto supported = (flatbuffers::IDLOptions::kRust |
3468 flatbuffers::IDLOptions::kSwift |
3469 flatbuffers::IDLOptions::kLobster);
3470 for (int lang=0; lang<kNumLanguages; lang++) {
3471 flatbuffers::IDLOptions opts;
3472 opts.lang_to_generate |= 1 << lang;
3473 if (opts.lang_to_generate & supported) continue;
3474 for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3475 const bool has_null = schema->find("null") != std::string::npos;
3476 flatbuffers::Parser parser(opts);
3477 // Its not supported in any language yet so has_null means error.
3478 TEST_EQ(parser.Parse(schema->c_str()), !has_null);
3483 void ParseFlexbuffersFromJsonWithNullTest() {
3484 // Test nulls are handled appropriately through flexbuffers to exercise other
3485 // code paths of ParseSingleValue in the optional scalars change.
3486 // TODO(cneo): Json -> Flatbuffers test once some language can generate code
3487 // with optional scalars.
3489 char json[] = "{\"opt_field\": 123 }";
3490 flatbuffers::Parser parser;
3491 flexbuffers::Builder flexbuild;
3492 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3493 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3494 TEST_EQ(root.AsMap()["opt_field"].AsInt64(), 123);
3497 char json[] = "{\"opt_field\": 123.4 }";
3498 flatbuffers::Parser parser;
3499 flexbuffers::Builder flexbuild;
3500 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3501 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3502 TEST_EQ(root.AsMap()["opt_field"].AsDouble(), 123.4);
3505 char json[] = "{\"opt_field\": null }";
3506 flatbuffers::Parser parser;
3507 flexbuffers::Builder flexbuild;
3508 parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3509 auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3510 TEST_ASSERT(!root.AsMap().IsTheEmptyMap());
3511 TEST_ASSERT(root.AsMap()["opt_field"].IsNull());
3512 TEST_EQ(root.ToString(), std::string("{ opt_field: null }"));
3516 int FlatBufferTests() {
3519 // Run our various test suites:
3522 auto flatbuf1 = CreateFlatBufferTest(rawbuf);
3523 #if !defined(FLATBUFFERS_CPP98_STL)
3524 auto flatbuf = std::move(flatbuf1); // Test move assignment.
3526 auto &flatbuf = flatbuf1;
3527 #endif // !defined(FLATBUFFERS_CPP98_STL)
3529 TriviallyCopyableTest();
3531 AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
3533 AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
3535 MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
3537 ObjectFlatBuffersTest(flatbuf.data());
3539 MiniReflectFlatBuffersTest(flatbuf.data());
3543 #ifndef FLATBUFFERS_NO_FILE_TESTS
3544 #ifdef FLATBUFFERS_TEST_PATH_PREFIX
3545 test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
3548 ParseAndGenerateTextTest(false);
3549 ParseAndGenerateTextTest(true);
3550 FixedLengthArrayJsonTest(false);
3551 FixedLengthArrayJsonTest(true);
3552 ReflectionTest(flatbuf.data(), flatbuf.size());
3554 ParseProtoTestWithSuffix();
3555 ParseProtoTestWithIncludes();
3557 UnionDeprecationTest();
3559 LoadVerifyBinaryTest();
3560 GenerateTableTextTest();
3561 TestEmbeddedBinarySchema();
3573 EnumOutOfRangeTest();
3574 IntegerOutOfRangeTest();
3575 IntegerBoundaryTest();
3577 UnicodeTestAllowNonUTF8();
3578 UnicodeTestGenerateTextFailsOnNonUTF8();
3579 UnicodeSurrogatesTest();
3580 UnicodeInvalidSurrogatesTest();
3582 UnknownFieldsTest();
3584 InvalidNestedFlatbufferTest();
3586 ParseProtoBufAsciiTest();
3589 CreateSharedStringTest();
3593 FlexBuffersDeprecatedTest();
3594 UninitializedVectorTest();
3595 EqualOperatorTest();
3600 TestMonsterExtraFloats();
3601 FixedLengthArrayTest();
3603 OptionalScalarsTest();
3604 ParseFlexbuffersFromJsonWithNullTest();
3608 int main(int /*argc*/, const char * /*argv*/[]) {
3611 std::string req_locale;
3612 if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
3614 TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
3615 req_locale.c_str());
3616 req_locale = flatbuffers::RemoveStringQuotes(req_locale);
3617 std::string the_locale;
3619 flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
3620 TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
3624 FlatBufferBuilderTest();
3626 if (!testing_fails) {
3627 TEST_OUTPUT_LINE("ALL TESTS PASSED");
3629 TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
3631 return CloseTestEngine();