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"
50 // Check that char* and uint8_t* are interoperable types.
51 // The reinterpret_cast<> between the pointers are used to simplify data loading.
52 static_assert(flatbuffers::is_same<uint8_t, char>::value ||
53 flatbuffers::is_same<uint8_t, unsigned char>::value,
54 "unexpected uint8_t type");
56 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
57 // Ensure IEEE-754 support if tests of floats with NaN/Inf will run.
58 static_assert(std::numeric_limits<float>::is_iec559 &&
59 std::numeric_limits<double>::is_iec559,
60 "IEC-559 (IEEE-754) standard required");
64 // Shortcuts for the infinity.
65 static const auto infinityf = std::numeric_limits<float>::infinity();
66 static const auto infinityd = std::numeric_limits<double>::infinity();
68 using namespace MyGame::Example;
70 void FlatBufferBuilderTest();
72 // Include simple random number generator to ensure results will be the
73 // same cross platform.
74 // http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
75 uint32_t lcg_seed = 48271;
78 (static_cast<uint64_t>(lcg_seed) * 279470273UL) % 4294967291UL;
80 void lcg_reset() { lcg_seed = 48271; }
82 std::string test_data_path =
83 #ifdef BAZEL_TEST_DATA_PATH
84 "../com_github_google_flatbuffers/tests/";
89 // example of how to build up a serialized buffer algorithmically:
90 flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) {
91 flatbuffers::FlatBufferBuilder builder;
93 auto vec = Vec3(1, 2, 3, 0, Color_Red, Test(10, 20));
95 auto name = builder.CreateString("MyMonster");
97 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
98 auto inventory = builder.CreateVector(inv_data, 10);
100 // Alternatively, create the vector first, and fill in data later:
101 // unsigned char *inv_buf = nullptr;
102 // auto inventory = builder.CreateUninitializedVector<unsigned char>(
104 // memcpy(inv_buf, inv_data, 10);
106 Test tests[] = { Test(10, 20), Test(30, 40) };
107 auto testv = builder.CreateVectorOfStructs(tests, 2);
110 #ifndef FLATBUFFERS_CPP98_STL
111 // Create a vector of structures from a lambda.
112 auto testv2 = builder.CreateVectorOfStructs<Test>(
113 2, [&](size_t i, Test* s) -> void {
117 // Create a vector of structures using a plain old C++ function.
118 auto testv2 = builder.CreateVectorOfStructs<Test>(
119 2, [](size_t i, Test* s, void *state) -> void {
120 *s = (reinterpret_cast<Test*>(state))[i];
122 #endif // FLATBUFFERS_CPP98_STL
125 // create monster with very few fields set:
126 // (same functionality as CreateMonster below, but sets fields manually)
127 flatbuffers::Offset<Monster> mlocs[3];
128 auto fred = builder.CreateString("Fred");
129 auto barney = builder.CreateString("Barney");
130 auto wilma = builder.CreateString("Wilma");
131 MonsterBuilder mb1(builder);
133 mlocs[0] = mb1.Finish();
134 MonsterBuilder mb2(builder);
135 mb2.add_name(barney);
137 mlocs[1] = mb2.Finish();
138 MonsterBuilder mb3(builder);
140 mlocs[2] = mb3.Finish();
142 // Create an array of strings. Also test string pooling, and lambdas.
144 builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(
146 [](size_t i, flatbuffers::FlatBufferBuilder *b)
147 -> flatbuffers::Offset<flatbuffers::String> {
148 static const char *names[] = { "bob", "fred", "bob", "fred" };
149 return b->CreateSharedString(names[i]);
153 // Creating vectors of strings in one convenient call.
154 std::vector<std::string> names2;
155 names2.push_back("jane");
156 names2.push_back("mary");
157 auto vecofstrings2 = builder.CreateVectorOfStrings(names2);
159 // Create an array of sorted tables, can be used with binary search when read:
160 auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3);
162 // Create an array of sorted structs,
163 // can be used with binary search when read:
164 std::vector<Ability> abilities;
165 abilities.push_back(Ability(4, 40));
166 abilities.push_back(Ability(3, 30));
167 abilities.push_back(Ability(2, 20));
168 abilities.push_back(Ability(1, 10));
169 auto vecofstructs = builder.CreateVectorOfSortedStructs(&abilities);
171 // Create a nested FlatBuffer.
172 // Nested FlatBuffers are stored in a ubyte vector, which can be convenient
173 // since they can be memcpy'd around much easier than other FlatBuffer
174 // values. They have little overhead compared to storing the table directly.
175 // As a test, create a mostly empty Monster buffer:
176 flatbuffers::FlatBufferBuilder nested_builder;
177 auto nmloc = CreateMonster(nested_builder, nullptr, 0, 0,
178 nested_builder.CreateString("NestedMonster"));
179 FinishMonsterBuffer(nested_builder, nmloc);
180 // Now we can store the buffer in the parent. Note that by default, vectors
181 // are only aligned to their elements or size field, so in this case if the
182 // buffer contains 64-bit elements, they may not be correctly aligned. We fix
184 builder.ForceVectorAlignment(nested_builder.GetSize(), sizeof(uint8_t),
185 nested_builder.GetBufferMinAlignment());
186 // If for whatever reason you don't have the nested_builder available, you
187 // can substitute flatbuffers::largest_scalar_t (64-bit) for the alignment, or
188 // the largest force_align value in your schema if you're using it.
189 auto nested_flatbuffer_vector = builder.CreateVector(
190 nested_builder.GetBufferPointer(), nested_builder.GetSize());
192 // Test a nested FlexBuffer:
193 flexbuffers::Builder flexbuild;
196 auto flex = builder.CreateVector(flexbuild.GetBuffer());
198 // Test vector of enums.
199 Color colors[] = { Color_Blue, Color_Green };
200 // We use this special creation function because we have an array of
201 // pre-C++11 (enum class) enums whose size likely is int, yet its declared
202 // type in the schema is byte.
203 auto vecofcolors = builder.CreateVectorScalarCast<uint8_t, Color>(colors, 2);
205 // shortcut for creating monster with all fields set:
206 auto mloc = CreateMonster(
207 builder, &vec, 150, 80, name, inventory, Color_Blue, Any_Monster,
208 mlocs[1].Union(), // Store a union.
209 testv, vecofstrings, vecoftables, 0, nested_flatbuffer_vector, 0, false,
210 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f, vecofstrings2,
211 vecofstructs, flex, testv2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
212 AnyUniqueAliases_NONE, 0, AnyAmbiguousAliases_NONE, 0, vecofcolors);
214 FinishMonsterBuffer(builder, mloc);
217 #ifdef FLATBUFFERS_TEST_VERBOSE
218 // print byte data for debugging:
219 auto p = builder.GetBufferPointer();
220 for (flatbuffers::uoffset_t i = 0; i < builder.GetSize(); i++)
225 // return the buffer for the caller to use.
227 reinterpret_cast<const char *>(builder.GetBufferPointer());
228 buffer.assign(bufferpointer, bufferpointer + builder.GetSize());
230 return builder.Release();
233 // example of accessing a buffer loaded in memory:
234 void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
235 bool pooled = true) {
236 // First, verify the buffers integrity (optional)
237 flatbuffers::Verifier verifier(flatbuf, length);
238 TEST_EQ(VerifyMonsterBuffer(verifier), true);
241 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
242 std::vector<uint8_t> test_buff;
243 test_buff.resize(length * 2);
244 std::memcpy(&test_buff[0], flatbuf, length);
245 std::memcpy(&test_buff[length], flatbuf, length);
247 flatbuffers::Verifier verifier1(&test_buff[0], length);
248 TEST_EQ(VerifyMonsterBuffer(verifier1), true);
249 TEST_EQ(verifier1.GetComputedSize(), length);
251 flatbuffers::Verifier verifier2(&test_buff[length], length);
252 TEST_EQ(VerifyMonsterBuffer(verifier2), true);
253 TEST_EQ(verifier2.GetComputedSize(), length);
257 TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0);
258 TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true);
259 TEST_EQ(strcmp(MonsterExtension(), "mon"), 0);
261 // Access the buffer from the root.
262 auto monster = GetMonster(flatbuf);
264 TEST_EQ(monster->hp(), 80);
265 TEST_EQ(monster->mana(), 150); // default
266 TEST_EQ_STR(monster->name()->c_str(), "MyMonster");
267 // Can't access the following field, it is deprecated in the schema,
268 // which means accessors are not generated:
269 // monster.friendly()
271 auto pos = monster->pos();
273 TEST_EQ(pos->z(), 3);
274 TEST_EQ(pos->test3().a(), 10);
275 TEST_EQ(pos->test3().b(), 20);
277 auto inventory = monster->inventory();
278 TEST_EQ(VectorLength(inventory), 10UL); // Works even if inventory is null.
279 TEST_NOTNULL(inventory);
280 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
281 // Check compatibilty of iterators with STL.
282 std::vector<unsigned char> inv_vec(inventory->begin(), inventory->end());
284 for (auto it = inventory->begin(); it != inventory->end(); ++it, ++n) {
285 auto indx = it - inventory->begin();
286 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
287 TEST_EQ(*it, inv_data[indx]);
289 TEST_EQ(n, inv_vec.size());
292 for (auto it = inventory->cbegin(); it != inventory->cend(); ++it, ++n) {
293 auto indx = it - inventory->cbegin();
294 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
295 TEST_EQ(*it, inv_data[indx]);
297 TEST_EQ(n, inv_vec.size());
300 for (auto it = inventory->rbegin(); it != inventory->rend(); ++it, ++n) {
301 auto indx = inventory->rend() - it - 1;
302 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
303 TEST_EQ(*it, inv_data[indx]);
305 TEST_EQ(n, inv_vec.size());
308 for (auto it = inventory->crbegin(); it != inventory->crend(); ++it, ++n) {
309 auto indx = inventory->crend() - it - 1;
310 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
311 TEST_EQ(*it, inv_data[indx]);
313 TEST_EQ(n, inv_vec.size());
315 TEST_EQ(monster->color(), Color_Blue);
317 // Example of accessing a union:
318 TEST_EQ(monster->test_type(), Any_Monster); // First make sure which it is.
319 auto monster2 = reinterpret_cast<const Monster *>(monster->test());
320 TEST_NOTNULL(monster2);
321 TEST_EQ_STR(monster2->name()->c_str(), "Fred");
323 // Example of accessing a vector of strings:
324 auto vecofstrings = monster->testarrayofstring();
325 TEST_EQ(vecofstrings->size(), 4U);
326 TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
327 TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
329 // These should have pointer equality because of string pooling.
330 TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
331 TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
334 auto vecofstrings2 = monster->testarrayofstring2();
336 TEST_EQ(vecofstrings2->size(), 2U);
337 TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
338 TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
341 // Example of accessing a vector of tables:
342 auto vecoftables = monster->testarrayoftables();
343 TEST_EQ(vecoftables->size(), 3U);
344 for (auto it = vecoftables->begin(); it != vecoftables->end(); ++it) {
345 TEST_EQ(strlen(it->name()->c_str()) >= 4, true);
347 TEST_EQ_STR(vecoftables->Get(0)->name()->c_str(), "Barney");
348 TEST_EQ(vecoftables->Get(0)->hp(), 1000);
349 TEST_EQ_STR(vecoftables->Get(1)->name()->c_str(), "Fred");
350 TEST_EQ_STR(vecoftables->Get(2)->name()->c_str(), "Wilma");
351 TEST_NOTNULL(vecoftables->LookupByKey("Barney"));
352 TEST_NOTNULL(vecoftables->LookupByKey("Fred"));
353 TEST_NOTNULL(vecoftables->LookupByKey("Wilma"));
355 // Test accessing a vector of sorted structs
356 auto vecofstructs = monster->testarrayofsortedstruct();
357 if (vecofstructs) { // not filled in monster_test.bfbs
358 for (flatbuffers::uoffset_t i = 0; i < vecofstructs->size() - 1; i++) {
359 auto left = vecofstructs->Get(i);
360 auto right = vecofstructs->Get(i + 1);
361 TEST_EQ(true, (left->KeyCompareLessThan(right)));
363 TEST_NOTNULL(vecofstructs->LookupByKey(3));
364 TEST_EQ(static_cast<const Ability *>(nullptr),
365 vecofstructs->LookupByKey(5));
368 // Test nested FlatBuffers if available:
369 auto nested_buffer = monster->testnestedflatbuffer();
371 // nested_buffer is a vector of bytes you can memcpy. However, if you
372 // actually want to access the nested data, this is a convenient
373 // accessor that directly gives you the root table:
374 auto nested_monster = monster->testnestedflatbuffer_nested_root();
375 TEST_EQ_STR(nested_monster->name()->c_str(), "NestedMonster");
378 // Test flexbuffer if available:
379 auto flex = monster->flex();
380 // flex is a vector of bytes you can memcpy etc.
381 TEST_EQ(flex->size(), 4); // Encoded FlexBuffer bytes.
382 // However, if you actually want to access the nested data, this is a
383 // convenient accessor that directly gives you the root value:
384 TEST_EQ(monster->flex_flexbuffer_root().AsInt16(), 1234);
386 // Test vector of enums:
387 auto colors = monster->vector_of_enums();
389 TEST_EQ(colors->size(), 2);
390 TEST_EQ(colors->Get(0), Color_Blue);
391 TEST_EQ(colors->Get(1), Color_Green);
394 // Since Flatbuffers uses explicit mechanisms to override the default
395 // compiler alignment, double check that the compiler indeed obeys them:
396 // (Test consists of a short and byte):
397 TEST_EQ(flatbuffers::AlignOf<Test>(), 2UL);
398 TEST_EQ(sizeof(Test), 4UL);
400 const flatbuffers::Vector<const Test *> *tests_array[] = {
404 for (size_t i = 0; i < sizeof(tests_array) / sizeof(tests_array[0]); ++i) {
405 auto tests = tests_array[i];
407 auto test_0 = tests->Get(0);
408 auto test_1 = tests->Get(1);
409 TEST_EQ(test_0->a(), 10);
410 TEST_EQ(test_0->b(), 20);
411 TEST_EQ(test_1->a(), 30);
412 TEST_EQ(test_1->b(), 40);
413 for (auto it = tests->begin(); it != tests->end(); ++it) {
414 TEST_EQ(it->a() == 10 || it->a() == 30, true); // Just testing iterators.
418 // Checking for presence of fields:
419 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
420 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
422 // Obtaining a buffer from a root:
423 TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
426 // Change a FlatBuffer in-place, after it has been constructed.
427 void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
428 // Get non-const pointer to root.
429 auto monster = GetMutableMonster(flatbuf);
431 // Each of these tests mutates, then tests, then set back to the original,
432 // so we can test that the buffer in the end still passes our original test.
433 auto hp_ok = monster->mutate_hp(10);
434 TEST_EQ(hp_ok, true); // Field was present.
435 TEST_EQ(monster->hp(), 10);
436 // Mutate to default value
437 auto hp_ok_default = monster->mutate_hp(100);
438 TEST_EQ(hp_ok_default, true); // Field was present.
439 TEST_EQ(monster->hp(), 100);
440 // Test that mutate to default above keeps field valid for further mutations
441 auto hp_ok_2 = monster->mutate_hp(20);
442 TEST_EQ(hp_ok_2, true);
443 TEST_EQ(monster->hp(), 20);
444 monster->mutate_hp(80);
446 // Monster originally at 150 mana (default value)
447 auto mana_default_ok = monster->mutate_mana(150); // Mutate to default value.
448 TEST_EQ(mana_default_ok,
449 true); // Mutation should succeed, because default value.
450 TEST_EQ(monster->mana(), 150);
451 auto mana_ok = monster->mutate_mana(10);
452 TEST_EQ(mana_ok, false); // Field was NOT present, because default value.
453 TEST_EQ(monster->mana(), 150);
456 auto pos = monster->mutable_pos();
457 auto test3 = pos->mutable_test3(); // Struct inside a struct.
458 test3.mutate_a(50); // Struct fields never fail.
459 TEST_EQ(test3.a(), 50);
463 auto inventory = monster->mutable_inventory();
464 inventory->Mutate(9, 100);
465 TEST_EQ(inventory->Get(9), 100);
466 inventory->Mutate(9, 9);
468 auto tables = monster->mutable_testarrayoftables();
469 auto first = tables->GetMutableObject(0);
470 TEST_EQ(first->hp(), 1000);
472 TEST_EQ(first->hp(), 0);
473 first->mutate_hp(1000);
475 // Run the verifier and the regular test to make sure we didn't trample on
477 AccessFlatBufferTest(flatbuf, length);
480 // Unpack a FlatBuffer into objects.
481 void ObjectFlatBuffersTest(uint8_t *flatbuf) {
482 // Optional: we can specify resolver and rehasher functions to turn hashed
483 // strings into object pointers and back, to implement remote references
485 auto resolver = flatbuffers::resolver_function_t(
486 [](void **pointer_adr, flatbuffers::hash_value_t hash) {
489 // Don't actually do anything, leave variable null.
491 auto rehasher = flatbuffers::rehasher_function_t(
492 [](void *pointer) -> flatbuffers::hash_value_t {
497 // Turn a buffer into C++ objects.
498 auto monster1 = UnPackMonster(flatbuf, &resolver);
500 // Re-serialize the data.
501 flatbuffers::FlatBufferBuilder fbb1;
502 fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
503 MonsterIdentifier());
505 // Unpack again, and re-serialize again.
506 auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
507 flatbuffers::FlatBufferBuilder fbb2;
508 fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
509 MonsterIdentifier());
511 // Now we've gone full round-trip, the two buffers should match.
512 auto len1 = fbb1.GetSize();
513 auto len2 = fbb2.GetSize();
515 TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), len1), 0);
517 // Test it with the original buffer test to make sure all data survived.
518 AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
520 // Test accessing fields, similar to AccessFlatBufferTest above.
521 TEST_EQ(monster2->hp, 80);
522 TEST_EQ(monster2->mana, 150); // default
523 TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
525 auto &pos = monster2->pos;
527 TEST_EQ(pos->z(), 3);
528 TEST_EQ(pos->test3().a(), 10);
529 TEST_EQ(pos->test3().b(), 20);
531 auto &inventory = monster2->inventory;
532 TEST_EQ(inventory.size(), 10UL);
533 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
534 for (auto it = inventory.begin(); it != inventory.end(); ++it)
535 TEST_EQ(*it, inv_data[it - inventory.begin()]);
537 TEST_EQ(monster2->color, Color_Blue);
539 auto monster3 = monster2->test.AsMonster();
540 TEST_NOTNULL(monster3);
541 TEST_EQ_STR(monster3->name.c_str(), "Fred");
543 auto &vecofstrings = monster2->testarrayofstring;
544 TEST_EQ(vecofstrings.size(), 4U);
545 TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
546 TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
548 auto &vecofstrings2 = monster2->testarrayofstring2;
549 TEST_EQ(vecofstrings2.size(), 2U);
550 TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
551 TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
553 auto &vecoftables = monster2->testarrayoftables;
554 TEST_EQ(vecoftables.size(), 3U);
555 TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
556 TEST_EQ(vecoftables[0]->hp, 1000);
557 TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
558 TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
560 auto &tests = monster2->test4;
561 TEST_EQ(tests[0].a(), 10);
562 TEST_EQ(tests[0].b(), 20);
563 TEST_EQ(tests[1].a(), 30);
564 TEST_EQ(tests[1].b(), 40);
567 // Prefix a FlatBuffer with a size field.
568 void SizePrefixedTest() {
569 // Create size prefixed buffer.
570 flatbuffers::FlatBufferBuilder fbb;
571 FinishSizePrefixedMonsterBuffer(
572 fbb, CreateMonster(fbb, 0, 200, 300, fbb.CreateString("bob")));
575 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
576 TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier), true);
579 auto m = GetSizePrefixedMonster(fbb.GetBufferPointer());
580 TEST_EQ(m->mana(), 200);
581 TEST_EQ(m->hp(), 300);
582 TEST_EQ_STR(m->name()->c_str(), "bob");
585 void TriviallyCopyableTest() {
587 #if __GNUG__ && __GNUC__ < 5
588 TEST_EQ(__has_trivial_copy(Vec3), true);
590 #if __cplusplus >= 201103L
591 TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
597 // Check stringify of an default enum value to json
598 void JsonDefaultTest() {
599 // load FlatBuffer schema (.fbs) from disk
600 std::string schemafile;
601 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
604 // parse schema first, so we can use it to parse the data after
605 flatbuffers::Parser parser;
606 auto include_test_path =
607 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
608 const char *include_directories[] = { test_data_path.c_str(),
609 include_test_path.c_str(), nullptr };
611 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
612 // create incomplete monster and store to json
613 parser.opts.output_default_scalars_in_json = true;
614 parser.opts.output_enum_identifiers = true;
615 flatbuffers::FlatBufferBuilder builder;
616 auto name = builder.CreateString("default_enum");
617 MonsterBuilder color_monster(builder);
618 color_monster.add_name(name);
619 FinishMonsterBuffer(builder, color_monster.Finish());
621 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
622 TEST_EQ(result, true);
623 // default value of the "color" field is Blue
624 TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true);
625 // default value of the "testf" field is 3.14159
626 TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true);
629 void JsonEnumsTest() {
630 // load FlatBuffer schema (.fbs) from disk
631 std::string schemafile;
632 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
635 // parse schema first, so we can use it to parse the data after
636 flatbuffers::Parser parser;
637 auto include_test_path =
638 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
639 const char *include_directories[] = { test_data_path.c_str(),
640 include_test_path.c_str(), nullptr };
641 parser.opts.output_enum_identifiers = true;
642 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
643 flatbuffers::FlatBufferBuilder builder;
644 auto name = builder.CreateString("bitflag_enum");
645 MonsterBuilder color_monster(builder);
646 color_monster.add_name(name);
647 color_monster.add_color(Color(Color_Blue | Color_Red));
648 FinishMonsterBuffer(builder, color_monster.Finish());
650 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
651 TEST_EQ(result, true);
652 TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true);
655 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
656 // The IEEE-754 quiet_NaN is not simple binary constant.
657 // All binary NaN bit strings have all the bits of the biased exponent field E
658 // set to 1. A quiet NaN bit string should be encoded with the first bit d[1]
659 // of the trailing significand field T being 1 (d[0] is implicit bit).
660 // It is assumed that endianness of floating-point is same as integer.
661 template<typename T, typename U, U qnan_base> bool is_quiet_nan_impl(T v) {
662 static_assert(sizeof(T) == sizeof(U), "unexpected");
664 std::memcpy(&b, &v, sizeof(T));
665 return ((b & qnan_base) == qnan_base);
667 static bool is_quiet_nan(float v) {
668 return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v);
670 static bool is_quiet_nan(double v) {
671 return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v);
674 void TestMonsterExtraFloats() {
675 TEST_EQ(is_quiet_nan(1.0), false);
676 TEST_EQ(is_quiet_nan(infinityd), false);
677 TEST_EQ(is_quiet_nan(-infinityf), false);
678 TEST_EQ(is_quiet_nan(std::numeric_limits<float>::quiet_NaN()), true);
679 TEST_EQ(is_quiet_nan(std::numeric_limits<double>::quiet_NaN()), true);
681 using namespace flatbuffers;
682 using namespace MyGame;
683 // Load FlatBuffer schema (.fbs) from disk.
684 std::string schemafile;
685 TEST_EQ(LoadFile((test_data_path + "monster_extra.fbs").c_str(), false,
688 // Parse schema first, so we can use it to parse the data after.
690 auto include_test_path = ConCatPathFileName(test_data_path, "include_test");
691 const char *include_directories[] = { test_data_path.c_str(),
692 include_test_path.c_str(), nullptr };
693 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
694 // Create empty extra and store to json.
695 parser.opts.output_default_scalars_in_json = true;
696 parser.opts.output_enum_identifiers = true;
697 FlatBufferBuilder builder;
698 const auto def_root = MonsterExtraBuilder(builder).Finish();
699 FinishMonsterExtraBuffer(builder, def_root);
700 const auto def_obj = builder.GetBufferPointer();
701 const auto def_extra = GetMonsterExtra(def_obj);
702 TEST_NOTNULL(def_extra);
703 TEST_EQ(is_quiet_nan(def_extra->f0()), true);
704 TEST_EQ(is_quiet_nan(def_extra->f1()), true);
705 TEST_EQ(def_extra->f2(), +infinityf);
706 TEST_EQ(def_extra->f3(), -infinityf);
707 TEST_EQ(is_quiet_nan(def_extra->d0()), true);
708 TEST_EQ(is_quiet_nan(def_extra->d1()), true);
709 TEST_EQ(def_extra->d2(), +infinityd);
710 TEST_EQ(def_extra->d3(), -infinityd);
712 auto result = GenerateText(parser, def_obj, &jsongen);
713 TEST_EQ(result, true);
714 // Check expected default values.
715 TEST_EQ(std::string::npos != jsongen.find("f0: nan"), true);
716 TEST_EQ(std::string::npos != jsongen.find("f1: nan"), true);
717 TEST_EQ(std::string::npos != jsongen.find("f2: inf"), true);
718 TEST_EQ(std::string::npos != jsongen.find("f3: -inf"), true);
719 TEST_EQ(std::string::npos != jsongen.find("d0: nan"), true);
720 TEST_EQ(std::string::npos != jsongen.find("d1: nan"), true);
721 TEST_EQ(std::string::npos != jsongen.find("d2: inf"), true);
722 TEST_EQ(std::string::npos != jsongen.find("d3: -inf"), true);
723 // Parse 'mosterdata_extra.json'.
724 const auto extra_base = test_data_path + "monsterdata_extra";
726 TEST_EQ(LoadFile((extra_base + ".json").c_str(), false, &jsongen), true);
727 TEST_EQ(parser.Parse(jsongen.c_str()), true);
728 const auto test_file = parser.builder_.GetBufferPointer();
729 const auto test_size = parser.builder_.GetSize();
730 Verifier verifier(test_file, test_size);
731 TEST_ASSERT(VerifyMonsterExtraBuffer(verifier));
732 const auto extra = GetMonsterExtra(test_file);
734 TEST_EQ(is_quiet_nan(extra->f0()), true);
735 TEST_EQ(is_quiet_nan(extra->f1()), true);
736 TEST_EQ(extra->f2(), +infinityf);
737 TEST_EQ(extra->f3(), -infinityf);
738 TEST_EQ(is_quiet_nan(extra->d0()), true);
739 TEST_EQ(extra->d1(), +infinityd);
740 TEST_EQ(extra->d2(), -infinityd);
741 TEST_EQ(is_quiet_nan(extra->d3()), true);
742 TEST_NOTNULL(extra->fvec());
743 TEST_EQ(extra->fvec()->size(), 4);
744 TEST_EQ(extra->fvec()->Get(0), 1.0f);
745 TEST_EQ(extra->fvec()->Get(1), -infinityf);
746 TEST_EQ(extra->fvec()->Get(2), +infinityf);
747 TEST_EQ(is_quiet_nan(extra->fvec()->Get(3)), true);
748 TEST_NOTNULL(extra->dvec());
749 TEST_EQ(extra->dvec()->size(), 4);
750 TEST_EQ(extra->dvec()->Get(0), 2.0);
751 TEST_EQ(extra->dvec()->Get(1), +infinityd);
752 TEST_EQ(extra->dvec()->Get(2), -infinityd);
753 TEST_EQ(is_quiet_nan(extra->dvec()->Get(3)), true);
756 void TestMonsterExtraFloats() {}
759 // example of parsing text straight into a buffer, and generating
760 // text back from it:
761 void ParseAndGenerateTextTest(bool binary) {
762 // load FlatBuffer schema (.fbs) and JSON from disk
763 std::string schemafile;
764 std::string jsonfile;
765 TEST_EQ(flatbuffers::LoadFile(
766 (test_data_path + "monster_test." + (binary ? "bfbs" : "fbs"))
768 binary, &schemafile),
770 TEST_EQ(flatbuffers::LoadFile(
771 (test_data_path + "monsterdata_test.golden").c_str(), false,
775 auto include_test_path =
776 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
777 const char *include_directories[] = { test_data_path.c_str(),
778 include_test_path.c_str(), nullptr };
780 // parse schema first, so we can use it to parse the data after
781 flatbuffers::Parser parser;
783 flatbuffers::Verifier verifier(
784 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
786 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
787 // auto schema = reflection::GetSchema(schemafile.c_str());
788 TEST_EQ(parser.Deserialize((const uint8_t *)schemafile.c_str(),
792 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
794 TEST_EQ(parser.Parse(jsonfile.c_str(), include_directories), true);
796 // here, parser.builder_ contains a binary buffer that is the parsed data.
798 // First, verify it, just in case:
799 flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
800 parser.builder_.GetSize());
801 TEST_EQ(VerifyMonsterBuffer(verifier), true);
803 AccessFlatBufferTest(parser.builder_.GetBufferPointer(),
804 parser.builder_.GetSize(), false);
806 // to ensure it is correct, we now generate text back from the binary,
807 // and compare the two:
810 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
811 TEST_EQ(result, true);
812 TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
814 // We can also do the above using the convenient Registry that knows about
815 // a set of file_identifiers mapped to schemas.
816 flatbuffers::Registry registry;
817 // Make sure schemas can find their includes.
818 registry.AddIncludeDirectory(test_data_path.c_str());
819 registry.AddIncludeDirectory(include_test_path.c_str());
820 // Call this with many schemas if possible.
821 registry.Register(MonsterIdentifier(),
822 (test_data_path + "monster_test.fbs").c_str());
823 // Now we got this set up, we can parse by just specifying the identifier,
824 // the correct schema will be loaded on the fly:
825 auto buf = registry.TextToFlatBuffer(jsonfile.c_str(), MonsterIdentifier());
826 // If this fails, check registry.lasterror_.
827 TEST_NOTNULL(buf.data());
828 // Test the buffer, to be sure:
829 AccessFlatBufferTest(buf.data(), buf.size(), false);
830 // We can use the registry to turn this back into text, in this case it
831 // will get the file_identifier from the binary:
833 auto ok = registry.FlatBufferToText(buf.data(), buf.size(), &text);
834 // If this fails, check registry.lasterror_.
836 TEST_EQ_STR(text.c_str(), jsonfile.c_str());
838 // Generate text for UTF-8 strings without escapes.
839 std::string jsonfile_utf8;
840 TEST_EQ(flatbuffers::LoadFile((test_data_path + "unicode_test.json").c_str(),
841 false, &jsonfile_utf8),
843 TEST_EQ(parser.Parse(jsonfile_utf8.c_str(), include_directories), true);
844 // To ensure it is correct, generate utf-8 text back from the binary.
845 std::string jsongen_utf8;
846 // request natural printing for utf-8 strings
847 parser.opts.natural_utf8 = true;
848 parser.opts.strict_json = true;
850 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen_utf8),
852 TEST_EQ_STR(jsongen_utf8.c_str(), jsonfile_utf8.c_str());
855 void ReflectionTest(uint8_t *flatbuf, size_t length) {
856 // Load a binary schema.
857 std::string bfbsfile;
858 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.bfbs").c_str(),
862 // Verify it, just in case:
863 flatbuffers::Verifier verifier(
864 reinterpret_cast<const uint8_t *>(bfbsfile.c_str()), bfbsfile.length());
865 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
867 // Make sure the schema is what we expect it to be.
868 auto &schema = *reflection::GetSchema(bfbsfile.c_str());
869 auto root_table = schema.root_table();
870 TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
871 auto fields = root_table->fields();
872 auto hp_field_ptr = fields->LookupByKey("hp");
873 TEST_NOTNULL(hp_field_ptr);
874 auto &hp_field = *hp_field_ptr;
875 TEST_EQ_STR(hp_field.name()->c_str(), "hp");
876 TEST_EQ(hp_field.id(), 2);
877 TEST_EQ(hp_field.type()->base_type(), reflection::Short);
878 auto friendly_field_ptr = fields->LookupByKey("friendly");
879 TEST_NOTNULL(friendly_field_ptr);
880 TEST_NOTNULL(friendly_field_ptr->attributes());
881 TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
883 // Make sure the table index is what we expect it to be.
884 auto pos_field_ptr = fields->LookupByKey("pos");
885 TEST_NOTNULL(pos_field_ptr);
886 TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
887 auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
888 TEST_NOTNULL(pos_table_ptr);
889 TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
891 // Now use it to dynamically access a buffer.
892 auto &root = *flatbuffers::GetAnyRoot(flatbuf);
894 // Verify the buffer first using reflection based verification
895 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
898 auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
901 // Rather than needing to know the type, we can also get the value of
902 // any field as an int64_t/double/string, regardless of what it actually is.
903 auto hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
904 TEST_EQ(hp_int64, 80);
905 auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
906 TEST_EQ(hp_double, 80.0);
907 auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
908 TEST_EQ_STR(hp_string.c_str(), "80");
910 // Get struct field through reflection
911 auto pos_struct = flatbuffers::GetFieldStruct(root, *pos_field_ptr);
912 TEST_NOTNULL(pos_struct);
913 TEST_EQ(flatbuffers::GetAnyFieldF(*pos_struct,
914 *pos_table_ptr->fields()->LookupByKey("z")),
917 auto test3_field = pos_table_ptr->fields()->LookupByKey("test3");
918 auto test3_struct = flatbuffers::GetFieldStruct(*pos_struct, *test3_field);
919 TEST_NOTNULL(test3_struct);
920 auto test3_object = schema.objects()->Get(test3_field->type()->index());
922 TEST_EQ(flatbuffers::GetAnyFieldF(*test3_struct,
923 *test3_object->fields()->LookupByKey("a")),
926 // We can also modify it.
927 flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
928 hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
931 // We can also set fields generically:
932 flatbuffers::SetAnyFieldI(&root, hp_field, 300);
933 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
934 TEST_EQ(hp_int64, 300);
935 flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
936 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
937 TEST_EQ(hp_int64, 300);
938 flatbuffers::SetAnyFieldS(&root, hp_field, "300");
939 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
940 TEST_EQ(hp_int64, 300);
942 // Test buffer is valid after the modifications
943 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
946 // Reset it, for further tests.
947 flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
949 // More advanced functionality: changing the size of items in-line!
950 // First we put the FlatBuffer inside an std::vector.
951 std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
952 // Find the field we want to modify.
953 auto &name_field = *fields->LookupByKey("name");
955 // This time we wrap the result from GetAnyRoot in a smartpointer that
956 // will keep rroot valid as resizingbuf resizes.
957 auto rroot = flatbuffers::piv(
958 flatbuffers::GetAnyRoot(flatbuffers::vector_data(resizingbuf)),
960 SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
962 // Here resizingbuf has changed, but rroot is still valid.
963 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
964 // Now lets extend a vector by 100 elements (10 -> 110).
965 auto &inventory_field = *fields->LookupByKey("inventory");
966 auto rinventory = flatbuffers::piv(
967 flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field), resizingbuf);
968 flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
970 // rinventory still valid, so lets read from it.
971 TEST_EQ(rinventory->Get(10), 50);
973 // For reflection uses not covered already, there is a more powerful way:
974 // we can simply generate whatever object we want to add/modify in a
975 // FlatBuffer of its own, then add that to an existing FlatBuffer:
976 // As an example, let's add a string to an array of strings.
977 // First, find our field:
978 auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
979 // Find the vector value:
980 auto rtestarrayofstring = flatbuffers::piv(
981 flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
982 **rroot, testarrayofstring_field),
984 // It's a vector of 2 strings, to which we add one more, initialized to
986 flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
987 schema, 3, 0, *rtestarrayofstring, &resizingbuf);
988 // Here we just create a buffer that contans a single string, but this
989 // could also be any complex set of tables and other values.
990 flatbuffers::FlatBufferBuilder stringfbb;
991 stringfbb.Finish(stringfbb.CreateString("hank"));
992 // Add the contents of it to our existing FlatBuffer.
993 // We do this last, so the pointer doesn't get invalidated (since it is
994 // at the end of the buffer):
995 auto string_ptr = flatbuffers::AddFlatBuffer(
996 resizingbuf, stringfbb.GetBufferPointer(), stringfbb.GetSize());
997 // Finally, set the new value in the vector.
998 rtestarrayofstring->MutateOffset(2, string_ptr);
999 TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
1000 TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
1001 // Test integrity of all resize operations above.
1002 flatbuffers::Verifier resize_verifier(
1003 reinterpret_cast<const uint8_t *>(flatbuffers::vector_data(resizingbuf)),
1004 resizingbuf.size());
1005 TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
1007 // Test buffer is valid using reflection as well
1008 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1009 flatbuffers::vector_data(resizingbuf),
1010 resizingbuf.size()),
1013 // As an additional test, also set it on the name field.
1014 // Note: unlike the name change above, this just overwrites the offset,
1015 // rather than changing the string in-place.
1016 SetFieldT(*rroot, name_field, string_ptr);
1017 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
1019 // Using reflection, rather than mutating binary FlatBuffers, we can also copy
1020 // tables and other things out of other FlatBuffers into a FlatBufferBuilder,
1021 // either part or whole.
1022 flatbuffers::FlatBufferBuilder fbb;
1023 auto root_offset = flatbuffers::CopyTable(
1024 fbb, schema, *root_table, *flatbuffers::GetAnyRoot(flatbuf), true);
1025 fbb.Finish(root_offset, MonsterIdentifier());
1026 // Test that it was copied correctly:
1027 AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
1029 // Test buffer is valid using reflection as well
1030 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1031 fbb.GetBufferPointer(), fbb.GetSize()),
1035 void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
1037 flatbuffers::FlatBufferToString(flatbuf, Monster::MiniReflectTypeTable());
1041 "pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
1042 "{ a: 10, b: 20 } }, "
1044 "name: \"MyMonster\", "
1045 "inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
1046 "test_type: Monster, "
1047 "test: { name: \"Fred\" }, "
1048 "test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1049 "testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
1050 "testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" "
1052 "{ name: \"Wilma\" } ], "
1053 // TODO(wvo): should really print this nested buffer correctly.
1054 "testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, "
1056 "4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
1057 "101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
1058 "testarrayofstring2: [ \"jane\", \"mary\" ], "
1059 "testarrayofsortedstruct: [ { id: 1, distance: 10 }, "
1060 "{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
1061 "{ id: 4, distance: 40 } ], "
1062 "flex: [ 210, 4, 5, 2 ], "
1063 "test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1064 "vector_of_enums: [ Blue, Green ] "
1068 Vec3 vec(1, 2, 3, 1.5, Color_Red, test);
1069 flatbuffers::FlatBufferBuilder vec_builder;
1070 vec_builder.Finish(vec_builder.CreateStruct(vec));
1071 auto vec_buffer = vec_builder.Release();
1072 auto vec_str = flatbuffers::FlatBufferToString(vec_buffer.data(),
1073 Vec3::MiniReflectTypeTable());
1074 TEST_EQ_STR(vec_str.c_str(),
1075 "{ x: 1.0, y: 2.0, z: 3.0, test1: 1.5, test2: Red, test3: { a: "
1079 // Parse a .proto schema, output as .fbs
1080 void ParseProtoTest() {
1081 // load the .proto and the golden file from disk
1082 std::string protofile;
1083 std::string goldenfile;
1084 std::string goldenunionfile;
1086 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1090 flatbuffers::LoadFile((test_data_path + "prototest/test.golden").c_str(),
1091 false, &goldenfile),
1093 TEST_EQ(flatbuffers::LoadFile(
1094 (test_data_path + "prototest/test_union.golden").c_str(), false,
1098 flatbuffers::IDLOptions opts;
1099 opts.include_dependence_headers = false;
1100 opts.proto_mode = true;
1103 flatbuffers::Parser parser(opts);
1104 auto protopath = test_data_path + "prototest/";
1105 const char *include_directories[] = { protopath.c_str(), nullptr };
1106 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1109 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1111 // Ensure generated file is parsable.
1112 flatbuffers::Parser parser2;
1113 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1114 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1116 // Parse proto with --oneof-union option.
1117 opts.proto_oneof_union = true;
1118 flatbuffers::Parser parser3(opts);
1119 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1122 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1124 // Ensure generated file is parsable.
1125 flatbuffers::Parser parser4;
1126 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1127 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1130 // Parse a .proto schema, output as .fbs
1131 void ParseProtoTestWithIncludes() {
1132 // load the .proto and the golden file from disk
1133 std::string protofile;
1134 std::string goldenfile;
1135 std::string goldenunionfile;
1136 std::string importprotofile;
1138 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1142 flatbuffers::LoadFile((test_data_path + "prototest/imported.proto").c_str(),
1143 false, &importprotofile),
1146 flatbuffers::LoadFile((test_data_path + "prototest/test_include.golden").c_str(),
1147 false, &goldenfile),
1149 TEST_EQ(flatbuffers::LoadFile(
1150 (test_data_path + "prototest/test_union_include.golden").c_str(), false,
1154 flatbuffers::IDLOptions opts;
1155 opts.include_dependence_headers = true;
1156 opts.proto_mode = true;
1159 flatbuffers::Parser parser(opts);
1160 auto protopath = test_data_path + "prototest/";
1161 const char *include_directories[] = { protopath.c_str(), nullptr };
1162 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1165 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1167 // Generate fbs from import.proto
1168 flatbuffers::Parser import_parser(opts);
1169 TEST_EQ(import_parser.Parse(importprotofile.c_str(), include_directories), true);
1170 auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test");
1172 // Ensure generated file is parsable.
1173 flatbuffers::Parser parser2;
1174 TEST_EQ(parser2.Parse(import_fbs.c_str(), include_directories, "imported.fbs"), true);
1175 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1176 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1178 // Parse proto with --oneof-union option.
1179 opts.proto_oneof_union = true;
1180 flatbuffers::Parser parser3(opts);
1181 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1184 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1186 // Ensure generated file is parsable.
1187 flatbuffers::Parser parser4;
1188 TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, "imported.fbs"), true);
1189 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1190 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1193 template<typename T>
1194 void CompareTableFieldValue(flatbuffers::Table *table,
1195 flatbuffers::voffset_t voffset, T val) {
1196 T read = table->GetField(voffset, static_cast<T>(0));
1200 // Low level stress/fuzz test: serialize/deserialize a variety of
1201 // different kinds of data in different combinations
1203 // Values we're testing against: chosen to ensure no bits get chopped
1204 // off anywhere, and also be different from eachother.
1205 const uint8_t bool_val = true;
1206 const int8_t char_val = -127; // 0x81
1207 const uint8_t uchar_val = 0xFF;
1208 const int16_t short_val = -32222; // 0x8222;
1209 const uint16_t ushort_val = 0xFEEE;
1210 const int32_t int_val = 0x83333333;
1211 const uint32_t uint_val = 0xFDDDDDDD;
1212 const int64_t long_val = 0x8444444444444444LL;
1213 const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
1214 const float float_val = 3.14159f;
1215 const double double_val = 3.14159265359;
1217 const int test_values_max = 11;
1218 const flatbuffers::voffset_t fields_per_object = 4;
1219 const int num_fuzz_objects = 10000; // The higher, the more thorough :)
1221 flatbuffers::FlatBufferBuilder builder;
1223 lcg_reset(); // Keep it deterministic.
1225 flatbuffers::uoffset_t objects[num_fuzz_objects];
1227 // Generate num_fuzz_objects random objects each consisting of
1228 // fields_per_object fields, each of a random type.
1229 for (int i = 0; i < num_fuzz_objects; i++) {
1230 auto start = builder.StartTable();
1231 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1232 int choice = lcg_rand() % test_values_max;
1233 auto off = flatbuffers::FieldIndexToOffset(f);
1235 case 0: builder.AddElement<uint8_t>(off, bool_val, 0); break;
1236 case 1: builder.AddElement<int8_t>(off, char_val, 0); break;
1237 case 2: builder.AddElement<uint8_t>(off, uchar_val, 0); break;
1238 case 3: builder.AddElement<int16_t>(off, short_val, 0); break;
1239 case 4: builder.AddElement<uint16_t>(off, ushort_val, 0); break;
1240 case 5: builder.AddElement<int32_t>(off, int_val, 0); break;
1241 case 6: builder.AddElement<uint32_t>(off, uint_val, 0); break;
1242 case 7: builder.AddElement<int64_t>(off, long_val, 0); break;
1243 case 8: builder.AddElement<uint64_t>(off, ulong_val, 0); break;
1244 case 9: builder.AddElement<float>(off, float_val, 0); break;
1245 case 10: builder.AddElement<double>(off, double_val, 0); break;
1248 objects[i] = builder.EndTable(start);
1250 builder.PreAlign<flatbuffers::largest_scalar_t>(0); // Align whole buffer.
1252 lcg_reset(); // Reset.
1254 uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
1256 // Test that all objects we generated are readable and return the
1257 // expected values. We generate random objects in the same order
1258 // so this is deterministic.
1259 for (int i = 0; i < num_fuzz_objects; i++) {
1260 auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
1261 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1262 int choice = lcg_rand() % test_values_max;
1263 flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
1265 case 0: CompareTableFieldValue(table, off, bool_val); break;
1266 case 1: CompareTableFieldValue(table, off, char_val); break;
1267 case 2: CompareTableFieldValue(table, off, uchar_val); break;
1268 case 3: CompareTableFieldValue(table, off, short_val); break;
1269 case 4: CompareTableFieldValue(table, off, ushort_val); break;
1270 case 5: CompareTableFieldValue(table, off, int_val); break;
1271 case 6: CompareTableFieldValue(table, off, uint_val); break;
1272 case 7: CompareTableFieldValue(table, off, long_val); break;
1273 case 8: CompareTableFieldValue(table, off, ulong_val); break;
1274 case 9: CompareTableFieldValue(table, off, float_val); break;
1275 case 10: CompareTableFieldValue(table, off, double_val); break;
1281 // High level stress/fuzz test: generate a big schema and
1282 // matching json data in random combinations, then parse both,
1283 // generate json back from the binary, and compare with the original.
1285 lcg_reset(); // Keep it deterministic.
1287 const int num_definitions = 30;
1288 const int num_struct_definitions = 5; // Subset of num_definitions.
1289 const int fields_per_definition = 15;
1290 const int instances_per_definition = 5;
1291 const int deprecation_rate = 10; // 1 in deprecation_rate fields will
1294 std::string schema = "namespace test;\n\n";
1297 std::string instances[instances_per_definition];
1299 // Since we're generating schema and corresponding data in tandem,
1300 // this convenience function adds strings to both at once.
1301 static void Add(RndDef (&definitions_l)[num_definitions],
1302 std::string &schema_l, const int instances_per_definition_l,
1303 const char *schema_add, const char *instance_add,
1305 schema_l += schema_add;
1306 for (int i = 0; i < instances_per_definition_l; i++)
1307 definitions_l[definition].instances[i] += instance_add;
1312 #define AddToSchemaAndInstances(schema_add, instance_add) \
1313 RndDef::Add(definitions, schema, instances_per_definition, \
1314 schema_add, instance_add, definition)
1317 RndDef::Add(definitions, schema, instances_per_definition, \
1318 "byte", "1", definition)
1321 RndDef definitions[num_definitions];
1323 // We are going to generate num_definitions, the first
1324 // num_struct_definitions will be structs, the rest tables. For each
1325 // generate random fields, some of which may be struct/table types
1326 // referring to previously generated structs/tables.
1327 // Simultanenously, we generate instances_per_definition JSON data
1328 // definitions, which will have identical structure to the schema
1329 // being generated. We generate multiple instances such that when creating
1330 // hierarchy, we get some variety by picking one randomly.
1331 for (int definition = 0; definition < num_definitions; definition++) {
1332 std::string definition_name = "D" + flatbuffers::NumToString(definition);
1334 bool is_struct = definition < num_struct_definitions;
1336 AddToSchemaAndInstances(
1337 ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
1340 for (int field = 0; field < fields_per_definition; field++) {
1341 const bool is_last_field = field == fields_per_definition - 1;
1343 // Deprecate 1 in deprecation_rate fields. Only table fields can be
1345 // Don't deprecate the last field to avoid dangling commas in JSON.
1346 const bool deprecated =
1347 !is_struct && !is_last_field && (lcg_rand() % deprecation_rate == 0);
1349 std::string field_name = "f" + flatbuffers::NumToString(field);
1350 AddToSchemaAndInstances((" " + field_name + ":").c_str(),
1351 deprecated ? "" : (field_name + ": ").c_str());
1352 // Pick random type:
1353 auto base_type = static_cast<flatbuffers::BaseType>(
1354 lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
1355 switch (base_type) {
1356 case flatbuffers::BASE_TYPE_STRING:
1358 Dummy(); // No strings in structs.
1360 AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
1363 case flatbuffers::BASE_TYPE_VECTOR:
1365 Dummy(); // No vectors in structs.
1367 AddToSchemaAndInstances("[ubyte]",
1368 deprecated ? "" : "[\n0,\n1,\n255\n]");
1371 case flatbuffers::BASE_TYPE_NONE:
1372 case flatbuffers::BASE_TYPE_UTYPE:
1373 case flatbuffers::BASE_TYPE_STRUCT:
1374 case flatbuffers::BASE_TYPE_UNION:
1376 // Pick a random previous definition and random data instance of
1378 int defref = lcg_rand() % definition;
1379 int instance = lcg_rand() % instances_per_definition;
1380 AddToSchemaAndInstances(
1381 ("D" + flatbuffers::NumToString(defref)).c_str(),
1383 : definitions[defref].instances[instance].c_str());
1385 // If this is the first definition, we have no definition we can
1390 case flatbuffers::BASE_TYPE_BOOL:
1391 AddToSchemaAndInstances(
1392 "bool", deprecated ? "" : (lcg_rand() % 2 ? "true" : "false"));
1394 case flatbuffers::BASE_TYPE_ARRAY:
1396 AddToSchemaAndInstances(
1398 deprecated ? "" : "255"); // No fixed-length arrays in tables.
1400 AddToSchemaAndInstances("[int:3]", deprecated ? "" : "[\n,\n,\n]");
1404 // All the scalar types.
1405 schema += flatbuffers::kTypeNames[base_type];
1408 // We want each instance to use its own random value.
1409 for (int inst = 0; inst < instances_per_definition; inst++)
1410 definitions[definition].instances[inst] +=
1411 flatbuffers::IsFloat(base_type)
1412 ? flatbuffers::NumToString<double>(lcg_rand() % 128)
1414 : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
1417 AddToSchemaAndInstances(deprecated ? "(deprecated);\n" : ";\n",
1418 deprecated ? "" : is_last_field ? "\n" : ",\n");
1420 AddToSchemaAndInstances("}\n\n", "}");
1423 schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
1426 flatbuffers::Parser parser;
1428 // Will not compare against the original if we don't write defaults
1429 parser.builder_.ForceDefaults(true);
1431 // Parse the schema, parse the generated data, then generate text back
1432 // from the binary and compare against the original.
1433 TEST_EQ(parser.Parse(schema.c_str()), true);
1435 const std::string &json =
1436 definitions[num_definitions - 1].instances[0] + "\n";
1438 TEST_EQ(parser.Parse(json.c_str()), true);
1440 std::string jsongen;
1441 parser.opts.indent_step = 0;
1443 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
1444 TEST_EQ(result, true);
1446 if (jsongen != json) {
1447 // These strings are larger than a megabyte, so we show the bytes around
1448 // the first bytes that are different rather than the whole string.
1449 size_t len = std::min(json.length(), jsongen.length());
1450 for (size_t i = 0; i < len; i++) {
1451 if (json[i] != jsongen[i]) {
1452 i -= std::min(static_cast<size_t>(10), i); // show some context;
1453 size_t end = std::min(len, i + 20);
1454 for (; i < end; i++)
1455 TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
1456 static_cast<int>(i), jsongen[i], json[i]);
1460 TEST_NOTNULL(nullptr); //-V501 (this comment supresses CWE-570 warning)
1464 #ifdef FLATBUFFERS_TEST_VERBOSE
1465 TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
1466 static_cast<int>(schema.length() / 1024),
1467 static_cast<int>(json.length() / 1024));
1472 // Test that parser errors are actually generated.
1473 void TestError_(const char *src, const char *error_substr, bool strict_json,
1474 const char *file, int line, const char *func) {
1475 flatbuffers::IDLOptions opts;
1476 opts.strict_json = strict_json;
1477 flatbuffers::Parser parser(opts);
1478 if (parser.Parse(src)) {
1479 TestFail("true", "false",
1480 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1482 } else if (!strstr(parser.error_.c_str(), error_substr)) {
1483 TestFail(parser.error_.c_str(), error_substr,
1484 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1489 void TestError_(const char *src, const char *error_substr, const char *file,
1490 int line, const char *func) {
1491 TestError_(src, error_substr, false, file, line, func);
1495 # define TestError(src, ...) \
1496 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
1498 # define TestError(src, ...) \
1499 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1502 // Test that parsing errors occur as we'd expect.
1503 // Also useful for coverage, making sure these paths are run.
1505 // In order they appear in idl_parser.cpp
1506 TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
1507 TestError("\"\0", "illegal");
1508 TestError("\"\\q", "escape code");
1509 TestError("table ///", "documentation");
1510 TestError("@", "illegal");
1511 TestError("table 1", "expecting");
1512 TestError("table X { Y:[[int]]; }", "nested vector");
1513 TestError("table X { Y:1; }", "illegal type");
1514 TestError("table X { Y:int; Y:int; }", "field already");
1515 TestError("table Y {} table X { Y:int; }", "same as table");
1516 TestError("struct X { Y:string; }", "only scalar");
1517 TestError("table X { Y:string = \"\"; }", "default values");
1518 TestError("struct X { a:uint = 42; }", "default values");
1519 TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
1520 TestError("struct X { Y:int (deprecated); }", "deprecate");
1521 TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
1522 "missing type field");
1523 TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
1525 TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
1526 TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
1527 TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
1530 "struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
1533 TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
1534 "unknown enum value");
1535 TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
1536 TestError("enum X:byte { Y } enum X {", "enum already");
1537 TestError("enum X:float {}", "underlying");
1538 TestError("enum X:byte { Y, Y }", "value already");
1539 TestError("enum X:byte { Y=2, Z=1 }", "ascending");
1540 TestError("table X { Y:int; } table X {", "datatype already");
1541 TestError("struct X (force_align: 7) { Y:int; }", "force_align");
1542 TestError("struct X {}", "size 0");
1543 TestError("{}", "no root");
1544 TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
1545 TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
1547 TestError("root_type X;", "unknown root");
1548 TestError("struct X { Y:int; } root_type X;", "a table");
1549 TestError("union X { Y }", "referenced");
1550 TestError("union Z { X } struct X { Y:int; }", "only tables");
1551 TestError("table X { Y:[int]; YLength:int; }", "clash");
1552 TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
1553 // float to integer conversion is forbidden
1554 TestError("table X { Y:int; } root_type X; { Y:1.0 }", "float");
1555 TestError("table X { Y:bool; } root_type X; { Y:1.0 }", "float");
1556 TestError("enum X:bool { Y = true }", "must be integral");
1559 template<typename T>
1560 T TestValue(const char *json, const char *type_name,
1561 const char *decls = nullptr) {
1562 flatbuffers::Parser parser;
1563 parser.builder_.ForceDefaults(true); // return defaults
1564 auto check_default = json ? false : true;
1565 if (check_default) { parser.opts.output_default_scalars_in_json = true; }
1567 std::string schema = std::string(decls ? decls : "") + "\n" +
1568 "table X { Y:" + std::string(type_name) +
1570 auto schema_done = parser.Parse(schema.c_str());
1571 TEST_EQ_STR(parser.error_.c_str(), "");
1572 TEST_EQ(schema_done, true);
1574 auto done = parser.Parse(check_default ? "{}" : json);
1575 TEST_EQ_STR(parser.error_.c_str(), "");
1576 TEST_EQ(done, true);
1578 // Check with print.
1579 std::string print_back;
1580 parser.opts.indent_step = -1;
1581 TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back),
1583 // restore value from its default
1584 if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); }
1586 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
1587 parser.builder_.GetBufferPointer());
1588 return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
1591 bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
1593 // Additional parser testing not covered elsewhere.
1595 // Test scientific notation numbers.
1597 FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"), 3.14159f),
1600 TEST_EQ(FloatCompare(TestValue<float>("{ Y:\"0.0314159e+2\" }", "float"),
1604 // Test conversion functions.
1605 TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }", "float"), -1),
1608 // int embedded to string
1609 TEST_EQ(TestValue<int>("{ Y:\"-876\" }", "int=-123"), -876);
1610 TEST_EQ(TestValue<int>("{ Y:\"876\" }", "int=-123"), 876);
1612 // Test negative hex constant.
1613 TEST_EQ(TestValue<int>("{ Y:-0x8ea0 }", "int=-0x8ea0"), -36512);
1614 TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
1616 // positive hex constant
1617 TEST_EQ(TestValue<int>("{ Y:0x1abcdef }", "int=0x1"), 0x1abcdef);
1618 // with optional '+' sign
1619 TEST_EQ(TestValue<int>("{ Y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
1621 TEST_EQ(TestValue<int>("{ Y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
1623 // Make sure we do unsigned 64bit correctly.
1624 TEST_EQ(TestValue<uint64_t>("{ Y:12335089644688340133 }", "ulong"),
1625 12335089644688340133ULL);
1628 TEST_EQ(TestValue<bool>("{ Y:\"false\" }", "bool=true"), false);
1629 TEST_EQ(TestValue<bool>("{ Y:\"true\" }", "bool=\"true\""), true);
1630 TEST_EQ(TestValue<bool>("{ Y:'false' }", "bool=true"), false);
1631 TEST_EQ(TestValue<bool>("{ Y:'true' }", "bool=\"true\""), true);
1633 // check comments before and after json object
1634 TEST_EQ(TestValue<int>("/*before*/ { Y:1 } /*after*/", "int"), 1);
1635 TEST_EQ(TestValue<int>("//before \n { Y:1 } //after", "int"), 1);
1638 void NestedListTest() {
1639 flatbuffers::Parser parser1;
1640 TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
1642 "{ F:[ [10,20], [30,40]] }"),
1646 void EnumStringsTest() {
1647 flatbuffers::Parser parser1;
1648 TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
1650 "{ F:[ A, B, \"C\", \"A B C\" ] }"),
1652 flatbuffers::Parser parser2;
1653 TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
1655 "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"),
1657 // unsigned bit_flags
1658 flatbuffers::Parser parser3;
1660 parser3.Parse("enum E:uint16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }"
1661 " table T { F: E = \"F15 F08\"; }"
1666 void EnumNamesTest() {
1667 TEST_EQ_STR("Red", EnumNameColor(Color_Red));
1668 TEST_EQ_STR("Green", EnumNameColor(Color_Green));
1669 TEST_EQ_STR("Blue", EnumNameColor(Color_Blue));
1670 // Check that Color to string don't crash while decode a mixture of Colors.
1671 // 1) Example::Color enum is enum with unfixed underlying type.
1672 // 2) Valid enum range: [0; 2^(ceil(log2(Color_ANY))) - 1].
1673 // Consequence: A value is out of this range will lead to UB (since C++17).
1674 // For details see C++17 standard or explanation on the SO:
1675 // stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class
1676 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(0)));
1677 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY - 1)));
1678 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY + 1)));
1681 void EnumOutOfRangeTest() {
1682 TestError("enum X:byte { Y = 128 }", "enum value does not fit");
1683 TestError("enum X:byte { Y = -129 }", "enum value does not fit");
1684 TestError("enum X:byte { Y = 126, Z0, Z1 }", "enum value does not fit");
1685 TestError("enum X:ubyte { Y = -1 }", "enum value does not fit");
1686 TestError("enum X:ubyte { Y = 256 }", "enum value does not fit");
1687 TestError("enum X:ubyte { Y = 255, Z }", "enum value does not fit");
1688 // Unions begin with an implicit "NONE = 0".
1689 TestError("table Y{} union X { Y = -1 }",
1690 "enum values must be specified in ascending order");
1691 TestError("table Y{} union X { Y = 256 }", "enum value does not fit");
1692 TestError("table Y{} union X { Y = 255, Z:Y }", "enum value does not fit");
1693 TestError("enum X:int { Y = -2147483649 }", "enum value does not fit");
1694 TestError("enum X:int { Y = 2147483648 }", "enum value does not fit");
1695 TestError("enum X:uint { Y = -1 }", "enum value does not fit");
1696 TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit");
1697 TestError("enum X:long { Y = 9223372036854775808 }", "does not fit");
1698 TestError("enum X:long { Y = 9223372036854775807, Z }",
1699 "enum value does not fit");
1700 TestError("enum X:ulong { Y = -1 }", "does not fit");
1701 TestError("enum X:ubyte (bit_flags) { Y=8 }", "bit flag out");
1702 TestError("enum X:byte (bit_flags) { Y=7 }", "must be unsigned"); // -128
1703 // bit_flgs out of range
1704 TestError("enum X:ubyte (bit_flags) { Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8 }",
1708 void EnumValueTest() {
1709 // json: "{ Y:0 }", schema: table X { Y : "E"}
1710 // 0 in enum (V=0) E then Y=0 is valid.
1711 TEST_EQ(TestValue<int>("{ Y:0 }", "E", "enum E:int { V }"), 0);
1712 TEST_EQ(TestValue<int>("{ Y:V }", "E", "enum E:int { V }"), 0);
1713 // A default value of Y is 0.
1714 TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
1715 TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { V=5 }"), 5);
1716 // Generate json with defaults and check.
1717 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
1719 TEST_EQ(TestValue<int>("{ Y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
1720 TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
1721 // Generate json with defaults and check.
1722 TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
1723 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
1725 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1726 "enum E:ulong { V = 13835058055282163712 }"),
1727 13835058055282163712ULL);
1728 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1729 "enum E:ulong { V = 18446744073709551615 }"),
1730 18446744073709551615ULL);
1731 // Assign non-enum value to enum field. Is it right?
1732 TEST_EQ(TestValue<int>("{ Y:7 }", "E", "enum E:int { V = 0 }"), 7);
1735 void IntegerOutOfRangeTest() {
1736 TestError("table T { F:byte; } root_type T; { F:128 }",
1737 "constant does not fit");
1738 TestError("table T { F:byte; } root_type T; { F:-129 }",
1739 "constant does not fit");
1740 TestError("table T { F:ubyte; } root_type T; { F:256 }",
1741 "constant does not fit");
1742 TestError("table T { F:ubyte; } root_type T; { F:-1 }",
1743 "constant does not fit");
1744 TestError("table T { F:short; } root_type T; { F:32768 }",
1745 "constant does not fit");
1746 TestError("table T { F:short; } root_type T; { F:-32769 }",
1747 "constant does not fit");
1748 TestError("table T { F:ushort; } root_type T; { F:65536 }",
1749 "constant does not fit");
1750 TestError("table T { F:ushort; } root_type T; { F:-1 }",
1751 "constant does not fit");
1752 TestError("table T { F:int; } root_type T; { F:2147483648 }",
1753 "constant does not fit");
1754 TestError("table T { F:int; } root_type T; { F:-2147483649 }",
1755 "constant does not fit");
1756 TestError("table T { F:uint; } root_type T; { F:4294967296 }",
1757 "constant does not fit");
1758 TestError("table T { F:uint; } root_type T; { F:-1 }",
1759 "constant does not fit");
1760 // Check fixed width aliases
1761 TestError("table X { Y:uint8; } root_type X; { Y: -1 }", "does not fit");
1762 TestError("table X { Y:uint8; } root_type X; { Y: 256 }", "does not fit");
1763 TestError("table X { Y:uint16; } root_type X; { Y: -1 }", "does not fit");
1764 TestError("table X { Y:uint16; } root_type X; { Y: 65536 }", "does not fit");
1765 TestError("table X { Y:uint32; } root_type X; { Y: -1 }", "");
1766 TestError("table X { Y:uint32; } root_type X; { Y: 4294967296 }",
1768 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1769 TestError("table X { Y:uint64; } root_type X; { Y: -9223372036854775809 }",
1771 TestError("table X { Y:uint64; } root_type X; { Y: 18446744073709551616 }",
1774 TestError("table X { Y:int8; } root_type X; { Y: -129 }", "does not fit");
1775 TestError("table X { Y:int8; } root_type X; { Y: 128 }", "does not fit");
1776 TestError("table X { Y:int16; } root_type X; { Y: -32769 }", "does not fit");
1777 TestError("table X { Y:int16; } root_type X; { Y: 32768 }", "does not fit");
1778 TestError("table X { Y:int32; } root_type X; { Y: -2147483649 }", "");
1779 TestError("table X { Y:int32; } root_type X; { Y: 2147483648 }",
1781 TestError("table X { Y:int64; } root_type X; { Y: -9223372036854775809 }",
1783 TestError("table X { Y:int64; } root_type X; { Y: 9223372036854775808 }",
1785 // check out-of-int64 as int8
1786 TestError("table X { Y:int8; } root_type X; { Y: -9223372036854775809 }",
1788 TestError("table X { Y:int8; } root_type X; { Y: 9223372036854775808 }",
1791 // Check default values
1792 TestError("table X { Y:int64=-9223372036854775809; } root_type X; {}",
1794 TestError("table X { Y:int64= 9223372036854775808; } root_type X; {}",
1796 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1797 TestError("table X { Y:uint64=-9223372036854775809; } root_type X; {}",
1799 TestError("table X { Y:uint64= 18446744073709551616; } root_type X; {}",
1803 void IntegerBoundaryTest() {
1804 // Check numerical compatibility with non-C++ languages.
1805 // By the C++ standard, std::numerical_limits<int64_t>::min() ==
1806 // -9223372036854775807 (-2^63+1) or less* The Flatbuffers grammar and most of
1807 // the languages (C#, Java, Rust) expect that minimum values are: -128,
1808 // -32768,.., -9223372036854775808. Since C++20,
1809 // static_cast<int64>(0x8000000000000000ULL) is well-defined two's complement
1810 // cast. Therefore -9223372036854775808 should be valid negative value.
1811 TEST_EQ(flatbuffers::numeric_limits<int8_t>::min(), -128);
1812 TEST_EQ(flatbuffers::numeric_limits<int8_t>::max(), 127);
1813 TEST_EQ(flatbuffers::numeric_limits<int16_t>::min(), -32768);
1814 TEST_EQ(flatbuffers::numeric_limits<int16_t>::max(), 32767);
1815 TEST_EQ(flatbuffers::numeric_limits<int32_t>::min() + 1, -2147483647);
1816 TEST_EQ(flatbuffers::numeric_limits<int32_t>::max(), 2147483647ULL);
1817 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min() + 1LL,
1818 -9223372036854775807LL);
1819 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(), 9223372036854775807ULL);
1820 TEST_EQ(flatbuffers::numeric_limits<uint8_t>::max(), 255);
1821 TEST_EQ(flatbuffers::numeric_limits<uint16_t>::max(), 65535);
1822 TEST_EQ(flatbuffers::numeric_limits<uint32_t>::max(), 4294967295ULL);
1823 TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
1824 18446744073709551615ULL);
1826 TEST_EQ(TestValue<int8_t>("{ Y:127 }", "byte"), 127);
1827 TEST_EQ(TestValue<int8_t>("{ Y:-128 }", "byte"), -128);
1828 TEST_EQ(TestValue<uint8_t>("{ Y:255 }", "ubyte"), 255);
1829 TEST_EQ(TestValue<uint8_t>("{ Y:0 }", "ubyte"), 0);
1830 TEST_EQ(TestValue<int16_t>("{ Y:32767 }", "short"), 32767);
1831 TEST_EQ(TestValue<int16_t>("{ Y:-32768 }", "short"), -32768);
1832 TEST_EQ(TestValue<uint16_t>("{ Y:65535 }", "ushort"), 65535);
1833 TEST_EQ(TestValue<uint16_t>("{ Y:0 }", "ushort"), 0);
1834 TEST_EQ(TestValue<int32_t>("{ Y:2147483647 }", "int"), 2147483647);
1835 TEST_EQ(TestValue<int32_t>("{ Y:-2147483648 }", "int") + 1, -2147483647);
1836 TEST_EQ(TestValue<uint32_t>("{ Y:4294967295 }", "uint"), 4294967295);
1837 TEST_EQ(TestValue<uint32_t>("{ Y:0 }", "uint"), 0);
1838 TEST_EQ(TestValue<int64_t>("{ Y:9223372036854775807 }", "long"),
1839 9223372036854775807LL);
1840 TEST_EQ(TestValue<int64_t>("{ Y:-9223372036854775808 }", "long") + 1LL,
1841 -9223372036854775807LL);
1842 TEST_EQ(TestValue<uint64_t>("{ Y:18446744073709551615 }", "ulong"),
1843 18446744073709551615ULL);
1844 TEST_EQ(TestValue<uint64_t>("{ Y:0 }", "ulong"), 0);
1845 TEST_EQ(TestValue<uint64_t>("{ Y: 18446744073709551615 }", "uint64"),
1846 18446744073709551615ULL);
1847 // check that the default works
1848 TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
1849 18446744073709551615ULL);
1852 void ValidFloatTest() {
1853 // check rounding to infinity
1854 TEST_EQ(TestValue<float>("{ Y:+3.4029e+38 }", "float"), +infinityf);
1855 TEST_EQ(TestValue<float>("{ Y:-3.4029e+38 }", "float"), -infinityf);
1856 TEST_EQ(TestValue<double>("{ Y:+1.7977e+308 }", "double"), +infinityd);
1857 TEST_EQ(TestValue<double>("{ Y:-1.7977e+308 }", "double"), -infinityd);
1860 FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"), 3.14159f),
1863 TEST_EQ(FloatCompare(TestValue<float>("{ Y:\" 0.0314159e+2 \" }", "float"),
1867 TEST_EQ(TestValue<float>("{ Y:1 }", "float"), 1.0f);
1868 TEST_EQ(TestValue<float>("{ Y:1.0 }", "float"), 1.0f);
1869 TEST_EQ(TestValue<float>("{ Y:1. }", "float"), 1.0f);
1870 TEST_EQ(TestValue<float>("{ Y:+1. }", "float"), 1.0f);
1871 TEST_EQ(TestValue<float>("{ Y:-1. }", "float"), -1.0f);
1872 TEST_EQ(TestValue<float>("{ Y:1.e0 }", "float"), 1.0f);
1873 TEST_EQ(TestValue<float>("{ Y:1.e+0 }", "float"), 1.0f);
1874 TEST_EQ(TestValue<float>("{ Y:1.e-0 }", "float"), 1.0f);
1875 TEST_EQ(TestValue<float>("{ Y:0.125 }", "float"), 0.125f);
1876 TEST_EQ(TestValue<float>("{ Y:.125 }", "float"), 0.125f);
1877 TEST_EQ(TestValue<float>("{ Y:-.125 }", "float"), -0.125f);
1878 TEST_EQ(TestValue<float>("{ Y:+.125 }", "float"), +0.125f);
1879 TEST_EQ(TestValue<float>("{ Y:5 }", "float"), 5.0f);
1880 TEST_EQ(TestValue<float>("{ Y:\"5\" }", "float"), 5.0f);
1882 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
1883 // Old MSVC versions may have problem with this check.
1884 // https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
1885 TEST_EQ(TestValue<double>("{ Y:6.9294956446009195e15 }", "double"),
1886 6929495644600920.0);
1888 TEST_EQ(std::isnan(TestValue<double>("{ Y:nan }", "double")), true);
1889 TEST_EQ(std::isnan(TestValue<float>("{ Y:nan }", "float")), true);
1890 TEST_EQ(std::isnan(TestValue<float>("{ Y:\"nan\" }", "float")), true);
1891 TEST_EQ(std::isnan(TestValue<float>("{ Y:+nan }", "float")), true);
1892 TEST_EQ(std::isnan(TestValue<float>("{ Y:-nan }", "float")), true);
1893 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
1894 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
1896 TEST_EQ(TestValue<float>("{ Y:inf }", "float"), infinityf);
1897 TEST_EQ(TestValue<float>("{ Y:\"inf\" }", "float"), infinityf);
1898 TEST_EQ(TestValue<float>("{ Y:+inf }", "float"), infinityf);
1899 TEST_EQ(TestValue<float>("{ Y:-inf }", "float"), -infinityf);
1900 TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinityf);
1901 TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinityf);
1903 "{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
1907 "{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
1911 // Test binary format of float point.
1912 // https://en.cppreference.com/w/cpp/language/floating_literal
1913 // 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
1914 TEST_EQ(TestValue<double>("{ Y:0x12.34p-1 }", "double"), 9.1015625);
1915 // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
1916 TEST_EQ(TestValue<float>("{ Y:-0x0.2p0 }", "float"), -0.125f);
1917 TEST_EQ(TestValue<float>("{ Y:-0x.2p1 }", "float"), -0.25f);
1918 TEST_EQ(TestValue<float>("{ Y:0x1.2p3 }", "float"), 9.0f);
1919 TEST_EQ(TestValue<float>("{ Y:0x10.1p0 }", "float"), 16.0625f);
1920 TEST_EQ(TestValue<double>("{ Y:0x1.2p3 }", "double"), 9.0);
1921 TEST_EQ(TestValue<double>("{ Y:0x10.1p0 }", "double"), 16.0625);
1922 TEST_EQ(TestValue<double>("{ Y:0xC.68p+2 }", "double"), 49.625);
1923 TestValue<double>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
1924 TestValue<float>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
1926 #else // FLATBUFFERS_HAS_NEW_STRTOD
1927 TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");
1928 #endif // !FLATBUFFERS_HAS_NEW_STRTOD
1931 void InvalidFloatTest() {
1932 auto invalid_msg = "invalid number";
1933 auto comma_msg = "expecting: ,";
1934 TestError("table T { F:float; } root_type T; { F:1,0 }", "");
1935 TestError("table T { F:float; } root_type T; { F:. }", "");
1936 TestError("table T { F:float; } root_type T; { F:- }", invalid_msg);
1937 TestError("table T { F:float; } root_type T; { F:+ }", invalid_msg);
1938 TestError("table T { F:float; } root_type T; { F:-. }", invalid_msg);
1939 TestError("table T { F:float; } root_type T; { F:+. }", invalid_msg);
1940 TestError("table T { F:float; } root_type T; { F:.e }", "");
1941 TestError("table T { F:float; } root_type T; { F:-e }", invalid_msg);
1942 TestError("table T { F:float; } root_type T; { F:+e }", invalid_msg);
1943 TestError("table T { F:float; } root_type T; { F:-.e }", invalid_msg);
1944 TestError("table T { F:float; } root_type T; { F:+.e }", invalid_msg);
1945 TestError("table T { F:float; } root_type T; { F:-e1 }", invalid_msg);
1946 TestError("table T { F:float; } root_type T; { F:+e1 }", invalid_msg);
1947 TestError("table T { F:float; } root_type T; { F:1.0e+ }", invalid_msg);
1948 TestError("table T { F:float; } root_type T; { F:1.0e- }", invalid_msg);
1949 // exponent pP is mandatory for hex-float
1950 TestError("table T { F:float; } root_type T; { F:0x0 }", invalid_msg);
1951 TestError("table T { F:float; } root_type T; { F:-0x. }", invalid_msg);
1952 TestError("table T { F:float; } root_type T; { F:0x. }", invalid_msg);
1953 // eE not exponent in hex-float!
1954 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
1955 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
1956 TestError("table T { F:float; } root_type T; { F:0x0.0p }", invalid_msg);
1957 TestError("table T { F:float; } root_type T; { F:0x0.0p+ }", invalid_msg);
1958 TestError("table T { F:float; } root_type T; { F:0x0.0p- }", invalid_msg);
1959 TestError("table T { F:float; } root_type T; { F:0x0.0pa1 }", invalid_msg);
1960 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
1961 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
1962 TestError("table T { F:float; } root_type T; { F:0x0.0e+0 }", invalid_msg);
1963 TestError("table T { F:float; } root_type T; { F:0x0.0e-0 }", invalid_msg);
1964 TestError("table T { F:float; } root_type T; { F:0x0.0ep+ }", invalid_msg);
1965 TestError("table T { F:float; } root_type T; { F:0x0.0ep- }", invalid_msg);
1966 TestError("table T { F:float; } root_type T; { F:1.2.3 }", invalid_msg);
1967 TestError("table T { F:float; } root_type T; { F:1.2.e3 }", invalid_msg);
1968 TestError("table T { F:float; } root_type T; { F:1.2e.3 }", invalid_msg);
1969 TestError("table T { F:float; } root_type T; { F:1.2e0.3 }", invalid_msg);
1970 TestError("table T { F:float; } root_type T; { F:1.2e3. }", invalid_msg);
1971 TestError("table T { F:float; } root_type T; { F:1.2e3.0 }", invalid_msg);
1972 TestError("table T { F:float; } root_type T; { F:+-1.0 }", invalid_msg);
1973 TestError("table T { F:float; } root_type T; { F:1.0e+-1 }", invalid_msg);
1974 TestError("table T { F:float; } root_type T; { F:\"1.0e+-1\" }", invalid_msg);
1975 TestError("table T { F:float; } root_type T; { F:1.e0e }", comma_msg);
1976 TestError("table T { F:float; } root_type T; { F:0x1.p0e }", comma_msg);
1977 TestError("table T { F:float; } root_type T; { F:\" 0x10 \" }", invalid_msg);
1979 TestError("table T { F:float; } root_type T; { F:\"1,2.\" }", invalid_msg);
1980 TestError("table T { F:float; } root_type T; { F:\"1.2e3.\" }", invalid_msg);
1981 TestError("table T { F:float; } root_type T; { F:\"0x1.p0e\" }", invalid_msg);
1982 TestError("table T { F:float; } root_type T; { F:\"0x1.0\" }", invalid_msg);
1983 TestError("table T { F:float; } root_type T; { F:\" 0x1.0\" }", invalid_msg);
1984 TestError("table T { F:float; } root_type T; { F:\"+ 0\" }", invalid_msg);
1985 // disable escapes for "number-in-string"
1986 TestError("table T { F:float; } root_type T; { F:\"\\f1.2e3.\" }", "invalid");
1987 TestError("table T { F:float; } root_type T; { F:\"\\t1.2e3.\" }", "invalid");
1988 TestError("table T { F:float; } root_type T; { F:\"\\n1.2e3.\" }", "invalid");
1989 TestError("table T { F:float; } root_type T; { F:\"\\r1.2e3.\" }", "invalid");
1990 TestError("table T { F:float; } root_type T; { F:\"4\\x005\" }", "invalid");
1991 TestError("table T { F:float; } root_type T; { F:\"\'12\'\" }", invalid_msg);
1992 // null is not a number constant!
1993 TestError("table T { F:float; } root_type T; { F:\"null\" }", invalid_msg);
1994 TestError("table T { F:float; } root_type T; { F:null }", invalid_msg);
1997 void GenerateTableTextTest() {
1998 std::string schemafile;
1999 std::string jsonfile;
2001 flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2002 false, &schemafile) &&
2003 flatbuffers::LoadFile((test_data_path + "monsterdata_test.json").c_str(),
2006 auto include_test_path =
2007 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2008 const char *include_directories[] = { test_data_path.c_str(),
2009 include_test_path.c_str(), nullptr };
2010 flatbuffers::IDLOptions opt;
2011 opt.indent_step = -1;
2012 flatbuffers::Parser parser(opt);
2013 ok = parser.Parse(schemafile.c_str(), include_directories) &&
2014 parser.Parse(jsonfile.c_str(), include_directories);
2017 const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
2018 std::string jsongen;
2019 auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster",
2021 TEST_EQ(result, true);
2023 const Vec3 *pos = monster->pos();
2025 result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
2026 TEST_EQ(result, true);
2029 "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
2030 const Test &test3 = pos->test3();
2033 GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
2034 TEST_EQ(result, true);
2035 TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
2036 const Test *test4 = monster->test4()->Get(0);
2039 GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
2040 TEST_EQ(result, true);
2041 TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
2044 template<typename T>
2045 void NumericUtilsTestInteger(const char *lower, const char *upper) {
2047 TEST_EQ(flatbuffers::StringToNumber("1q", &x), false);
2049 TEST_EQ(flatbuffers::StringToNumber(upper, &x), false);
2050 TEST_EQ(x, flatbuffers::numeric_limits<T>::max());
2051 TEST_EQ(flatbuffers::StringToNumber(lower, &x), false);
2052 auto expval = flatbuffers::is_unsigned<T>::value
2053 ? flatbuffers::numeric_limits<T>::max()
2054 : flatbuffers::numeric_limits<T>::lowest();
2058 template<typename T>
2059 void NumericUtilsTestFloat(const char *lower, const char *upper) {
2061 TEST_EQ(flatbuffers::StringToNumber("", &f), false);
2062 TEST_EQ(flatbuffers::StringToNumber("1q", &f), false);
2064 TEST_EQ(flatbuffers::StringToNumber(upper, &f), true);
2065 TEST_EQ(f, +flatbuffers::numeric_limits<T>::infinity());
2066 TEST_EQ(flatbuffers::StringToNumber(lower, &f), true);
2067 TEST_EQ(f, -flatbuffers::numeric_limits<T>::infinity());
2070 void NumericUtilsTest() {
2071 NumericUtilsTestInteger<uint64_t>("-1", "18446744073709551616");
2072 NumericUtilsTestInteger<uint8_t>("-1", "256");
2073 NumericUtilsTestInteger<int64_t>("-9223372036854775809",
2074 "9223372036854775808");
2075 NumericUtilsTestInteger<int8_t>("-129", "128");
2076 NumericUtilsTestFloat<float>("-3.4029e+38", "+3.4029e+38");
2077 NumericUtilsTestFloat<float>("-1.7977e+308", "+1.7977e+308");
2080 void IsAsciiUtilsTest() {
2082 for (int cnt = 0; cnt < 256; cnt++) {
2083 auto alpha = (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
2084 auto dec = (('0' <= c) && (c <= '9'));
2085 auto hex = (('a' <= c) && (c <= 'f')) || (('A' <= c) && (c <= 'F'));
2086 TEST_EQ(flatbuffers::is_alpha(c), alpha);
2087 TEST_EQ(flatbuffers::is_alnum(c), alpha || dec);
2088 TEST_EQ(flatbuffers::is_digit(c), dec);
2089 TEST_EQ(flatbuffers::is_xdigit(c), dec || hex);
2094 void UnicodeTest() {
2095 flatbuffers::Parser parser;
2096 // Without setting allow_non_utf8 = true, we treat \x sequences as byte
2097 // sequences which are then validated as UTF-8.
2098 TEST_EQ(parser.Parse("table T { F:string; }"
2100 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2101 "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD8"
2104 std::string jsongen;
2105 parser.opts.indent_step = -1;
2107 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2108 TEST_EQ(result, true);
2109 TEST_EQ_STR(jsongen.c_str(),
2110 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2111 "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
2114 void UnicodeTestAllowNonUTF8() {
2115 flatbuffers::Parser parser;
2116 parser.opts.allow_non_utf8 = true;
2119 "table T { F:string; }"
2121 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2122 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2124 std::string jsongen;
2125 parser.opts.indent_step = -1;
2127 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2128 TEST_EQ(result, true);
2131 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2132 "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
2135 void UnicodeTestGenerateTextFailsOnNonUTF8() {
2136 flatbuffers::Parser parser;
2137 // Allow non-UTF-8 initially to model what happens when we load a binary
2138 // flatbuffer from disk which contains non-UTF-8 strings.
2139 parser.opts.allow_non_utf8 = true;
2142 "table T { F:string; }"
2144 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2145 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2147 std::string jsongen;
2148 parser.opts.indent_step = -1;
2149 // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates
2151 parser.opts.allow_non_utf8 = false;
2153 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2154 TEST_EQ(result, false);
2157 void UnicodeSurrogatesTest() {
2158 flatbuffers::Parser parser;
2160 TEST_EQ(parser.Parse("table T { F:string (id: 0); }"
2162 "{ F:\"\\uD83D\\uDCA9\"}"),
2164 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
2165 parser.builder_.GetBufferPointer());
2166 auto string = root->GetPointer<flatbuffers::String *>(
2167 flatbuffers::FieldIndexToOffset(0));
2168 TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
2171 void UnicodeInvalidSurrogatesTest() {
2173 "table T { F:string; }"
2176 "unpaired high surrogate");
2178 "table T { F:string; }"
2180 "{ F:\"\\uD800abcd\"}",
2181 "unpaired high surrogate");
2183 "table T { F:string; }"
2185 "{ F:\"\\uD800\\n\"}",
2186 "unpaired high surrogate");
2188 "table T { F:string; }"
2190 "{ F:\"\\uD800\\uD800\"}",
2191 "multiple high surrogates");
2193 "table T { F:string; }"
2196 "unpaired low surrogate");
2199 void InvalidUTF8Test() {
2200 // "1 byte" pattern, under min length of 2 bytes
2202 "table T { F:string; }"
2205 "illegal UTF-8 sequence");
2206 // 2 byte pattern, string too short
2208 "table T { F:string; }"
2211 "illegal UTF-8 sequence");
2212 // 3 byte pattern, string too short
2214 "table T { F:string; }"
2216 "{ F:\"\xEF\xBF\"}",
2217 "illegal UTF-8 sequence");
2218 // 4 byte pattern, string too short
2220 "table T { F:string; }"
2222 "{ F:\"\xF7\xBF\xBF\"}",
2223 "illegal UTF-8 sequence");
2224 // "5 byte" pattern, string too short
2226 "table T { F:string; }"
2228 "{ F:\"\xFB\xBF\xBF\xBF\"}",
2229 "illegal UTF-8 sequence");
2230 // "6 byte" pattern, string too short
2232 "table T { F:string; }"
2234 "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}",
2235 "illegal UTF-8 sequence");
2236 // "7 byte" pattern, string too short
2238 "table T { F:string; }"
2240 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}",
2241 "illegal UTF-8 sequence");
2242 // "5 byte" pattern, over max length of 4 bytes
2244 "table T { F:string; }"
2246 "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}",
2247 "illegal UTF-8 sequence");
2248 // "6 byte" pattern, over max length of 4 bytes
2250 "table T { F:string; }"
2252 "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}",
2253 "illegal UTF-8 sequence");
2254 // "7 byte" pattern, over max length of 4 bytes
2256 "table T { F:string; }"
2258 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}",
2259 "illegal UTF-8 sequence");
2261 // Three invalid encodings for U+000A (\n, aka NEWLINE)
2263 "table T { F:string; }"
2265 "{ F:\"\xC0\x8A\"}",
2266 "illegal UTF-8 sequence");
2268 "table T { F:string; }"
2270 "{ F:\"\xE0\x80\x8A\"}",
2271 "illegal UTF-8 sequence");
2273 "table T { F:string; }"
2275 "{ F:\"\xF0\x80\x80\x8A\"}",
2276 "illegal UTF-8 sequence");
2278 // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
2280 "table T { F:string; }"
2282 "{ F:\"\xE0\x81\xA9\"}",
2283 "illegal UTF-8 sequence");
2285 "table T { F:string; }"
2287 "{ F:\"\xF0\x80\x81\xA9\"}",
2288 "illegal UTF-8 sequence");
2290 // Invalid encoding for U+20AC (EURO SYMBOL)
2292 "table T { F:string; }"
2294 "{ F:\"\xF0\x82\x82\xAC\"}",
2295 "illegal UTF-8 sequence");
2297 // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in
2300 "table T { F:string; }"
2302 // U+10400 "encoded" as U+D801 U+DC00
2303 "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}",
2304 "illegal UTF-8 sequence");
2306 // Check independence of identifier from locale.
2307 std::string locale_ident;
2308 locale_ident += "table T { F";
2309 locale_ident += static_cast<char>(-32); // unsigned 0xE0
2310 locale_ident += " :string; }";
2311 locale_ident += "root_type T;";
2312 locale_ident += "{}";
2313 TestError(locale_ident.c_str(), "");
2316 void UnknownFieldsTest() {
2317 flatbuffers::IDLOptions opts;
2318 opts.skip_unexpected_fields_in_json = true;
2319 flatbuffers::Parser parser(opts);
2321 TEST_EQ(parser.Parse("table T { str:string; i:int;}"
2324 "unknown_string:\"test\","
2325 "\"unknown_string\":\"test\","
2327 "unknown_float:1.0,"
2328 "unknown_array: [ 1, 2, 3, 4],"
2329 "unknown_object: { i: 10 },"
2330 "\"unknown_object\": { \"i\": 10 },"
2334 std::string jsongen;
2335 parser.opts.indent_step = -1;
2337 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2338 TEST_EQ(result, true);
2339 TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
2342 void ParseUnionTest() {
2343 // Unions must be parseable with the type field following the object.
2344 flatbuffers::Parser parser;
2345 TEST_EQ(parser.Parse("table T { A:int; }"
2349 "{ X:{ A:1 }, X_type: T }"),
2351 // Unions must be parsable with prefixed namespace.
2352 flatbuffers::Parser parser2;
2353 TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
2354 "table B { e:U; } root_type B;"
2355 "{ e_type: N_A, e: {} }"),
2359 void InvalidNestedFlatbufferTest() {
2360 // First, load and parse FlatBuffer schema (.fbs)
2361 std::string schemafile;
2362 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2363 false, &schemafile),
2365 auto include_test_path =
2366 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2367 const char *include_directories[] = { test_data_path.c_str(),
2368 include_test_path.c_str(), nullptr };
2369 flatbuffers::Parser parser1;
2370 TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
2372 // "color" inside nested flatbuffer contains invalid enum value
2373 TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
2374 "\"Leela\", color: \"nonexistent\"}}"),
2378 void EvolutionTest() {
2379 // VS10 does not support typed enums, exclude from tests
2380 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2381 const int NUM_VERSIONS = 2;
2382 std::string schemas[NUM_VERSIONS];
2383 std::string jsonfiles[NUM_VERSIONS];
2384 std::vector<uint8_t> binaries[NUM_VERSIONS];
2386 flatbuffers::IDLOptions idl_opts;
2387 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2388 flatbuffers::Parser parser(idl_opts);
2390 // Load all the schema versions and their associated data.
2391 for (int i = 0; i < NUM_VERSIONS; ++i) {
2392 std::string schema = test_data_path + "evolution_test/evolution_v" +
2393 flatbuffers::NumToString(i + 1) + ".fbs";
2394 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2395 std::string json = test_data_path + "evolution_test/evolution_v" +
2396 flatbuffers::NumToString(i + 1) + ".json";
2397 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2399 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2400 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2402 auto bufLen = parser.builder_.GetSize();
2403 auto buf = parser.builder_.GetBufferPointer();
2404 binaries[i].reserve(bufLen);
2405 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2408 // Assert that all the verifiers for the different schema versions properly verify any version data.
2409 for (int i = 0; i < NUM_VERSIONS; ++i) {
2410 flatbuffers::Verifier verifier(&binaries[i].front(), binaries[i].size());
2411 TEST_ASSERT(Evolution::V1::VerifyRootBuffer(verifier));
2412 TEST_ASSERT(Evolution::V2::VerifyRootBuffer(verifier));
2415 // Test backwards compatibility by reading old data with an evolved schema.
2416 auto root_v1_viewed_from_v2 = Evolution::V2::GetRoot(&binaries[0].front());
2417 // field 'j' is new in version 2, so it should be null.
2418 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->j());
2419 // field 'k' is new in version 2 with a default of 56.
2420 TEST_EQ(root_v1_viewed_from_v2->k(), 56);
2421 // field 'c' of 'TableA' is new in version 2, so it should be null.
2422 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->e()->c());
2423 // 'TableC' was added to field 'c' union in version 2, so it should be null.
2424 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->c_as_TableC());
2425 // The field 'c' union should be of type 'TableB' regardless of schema version
2426 TEST_ASSERT(root_v1_viewed_from_v2->c_type() == Evolution::V2::Union::TableB);
2427 // The field 'f' was renamed to 'ff' in version 2, it should still be readable.
2428 TEST_EQ(root_v1_viewed_from_v2->ff()->a(), 16);
2430 // Test forwards compatibility by reading new data with an old schema.
2431 auto root_v2_viewed_from_v1 = Evolution::V1::GetRoot(&binaries[1].front());
2432 // The field 'c' union in version 2 is a new table (index = 3) and should still be accessible,
2433 // but not interpretable.
2434 TEST_EQ(static_cast<uint8_t>(root_v2_viewed_from_v1->c_type()), 3);
2435 TEST_NOTNULL(root_v2_viewed_from_v1->c());
2436 // The field 'd' enum in verison 2 has new members and should still be accessible, but not interpretable.
2437 TEST_EQ(static_cast<int8_t>(root_v2_viewed_from_v1->d()), 3);
2438 // The field 'a' in version 2 is deprecated and should return the default value (0) instead of the value stored in
2439 // the in the buffer (42).
2440 TEST_EQ(root_v2_viewed_from_v1->a(), 0);
2441 // The field 'ff' was originally named 'f' in version 1, it should still be readable.
2442 TEST_EQ(root_v2_viewed_from_v1->f()->a(), 35);
2446 void UnionVectorTest() {
2447 // load FlatBuffer fbs schema and json.
2448 std::string schemafile, jsonfile;
2449 TEST_EQ(flatbuffers::LoadFile(
2450 (test_data_path + "union_vector/union_vector.fbs").c_str(), false,
2453 TEST_EQ(flatbuffers::LoadFile(
2454 (test_data_path + "union_vector/union_vector.json").c_str(),
2459 flatbuffers::IDLOptions idl_opts;
2460 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2461 flatbuffers::Parser parser(idl_opts);
2462 TEST_EQ(parser.Parse(schemafile.c_str()), true);
2464 flatbuffers::FlatBufferBuilder fbb;
2467 std::vector<uint8_t> types;
2468 types.push_back(static_cast<uint8_t>(Character_Belle));
2469 types.push_back(static_cast<uint8_t>(Character_MuLan));
2470 types.push_back(static_cast<uint8_t>(Character_BookFan));
2471 types.push_back(static_cast<uint8_t>(Character_Other));
2472 types.push_back(static_cast<uint8_t>(Character_Unused));
2475 std::vector<flatbuffers::Offset<void>> characters;
2476 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
2477 characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
2478 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
2479 characters.push_back(fbb.CreateString("Other").Union());
2480 characters.push_back(fbb.CreateString("Unused").Union());
2483 const auto movie_offset =
2484 CreateMovie(fbb, Character_Rapunzel,
2485 fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
2486 fbb.CreateVector(types), fbb.CreateVector(characters));
2487 FinishMovieBuffer(fbb, movie_offset);
2489 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
2490 TEST_EQ(VerifyMovieBuffer(verifier), true);
2492 auto flat_movie = GetMovie(fbb.GetBufferPointer());
2494 auto TestMovie = [](const Movie *movie) {
2495 TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
2497 auto cts = movie->characters_type();
2498 TEST_EQ(movie->characters_type()->size(), 5);
2499 TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
2500 TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
2501 TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
2502 TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
2503 TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
2505 auto rapunzel = movie->main_character_as_Rapunzel();
2506 TEST_NOTNULL(rapunzel);
2507 TEST_EQ(rapunzel->hair_length(), 6);
2509 auto cs = movie->characters();
2510 TEST_EQ(cs->size(), 5);
2511 auto belle = cs->GetAs<BookReader>(0);
2512 TEST_EQ(belle->books_read(), 7);
2513 auto mu_lan = cs->GetAs<Attacker>(1);
2514 TEST_EQ(mu_lan->sword_attack_damage(), 5);
2515 auto book_fan = cs->GetAs<BookReader>(2);
2516 TEST_EQ(book_fan->books_read(), 2);
2517 auto other = cs->GetAsString(3);
2518 TEST_EQ_STR(other->c_str(), "Other");
2519 auto unused = cs->GetAsString(4);
2520 TEST_EQ_STR(unused->c_str(), "Unused");
2523 TestMovie(flat_movie);
2525 // Also test the JSON we loaded above.
2526 TEST_EQ(parser.Parse(jsonfile.c_str()), true);
2527 auto jbuf = parser.builder_.GetBufferPointer();
2528 flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
2529 TEST_EQ(VerifyMovieBuffer(jverifier), true);
2530 TestMovie(GetMovie(jbuf));
2532 auto movie_object = flat_movie->UnPack();
2533 TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
2534 TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
2535 TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
2536 TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
2537 TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
2538 TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
2541 fbb.Finish(Movie::Pack(fbb, movie_object));
2543 delete movie_object;
2545 auto repacked_movie = GetMovie(fbb.GetBufferPointer());
2547 TestMovie(repacked_movie);
2549 // Generate text using mini-reflection.
2551 flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
2554 "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
2555 "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
2556 "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
2557 "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
2559 flatbuffers::ToStringVisitor visitor("\n", true, " ");
2560 IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
2561 TEST_EQ_STR(visitor.s.c_str(),
2563 " \"main_character_type\": \"Rapunzel\",\n"
2564 " \"main_character\": {\n"
2565 " \"hair_length\": 6\n"
2567 " \"characters_type\": [\n"
2574 " \"characters\": [\n"
2576 " \"books_read\": 7\n"
2579 " \"sword_attack_damage\": 5\n"
2582 " \"books_read\": 2\n"
2589 // Generate text using parsed schema.
2590 std::string jsongen;
2591 auto result = GenerateText(parser, fbb.GetBufferPointer(), &jsongen);
2592 TEST_EQ(result, true);
2593 TEST_EQ_STR(jsongen.c_str(),
2595 " main_character_type: \"Rapunzel\",\n"
2596 " main_character: {\n"
2599 " characters_type: [\n"
2611 " sword_attack_damage: 5\n"
2621 // Simple test with reflection.
2623 auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
2624 auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
2625 fbb.GetBufferPointer(), fbb.GetSize());
2628 flatbuffers::Parser parser2(idl_opts);
2629 TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
2630 "union Any { Bool }"
2631 "table Root { a:Any; }"
2634 TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
2637 void ConformTest() {
2638 flatbuffers::Parser parser;
2639 TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
2641 auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
2642 const char *expected_err) {
2643 flatbuffers::Parser parser2;
2644 TEST_EQ(parser2.Parse(test), true);
2645 auto err = parser2.ConformTo(parser1);
2646 TEST_NOTNULL(strstr(err.c_str(), expected_err));
2649 test_conform(parser, "table T { A:byte; }", "types differ for field");
2650 test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
2651 test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
2652 test_conform(parser, "table T { B:float; }",
2653 "field renamed to different type");
2654 test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
2657 void ParseProtoBufAsciiTest() {
2658 // We can put the parser in a mode where it will accept JSON that looks more
2659 // like Protobuf ASCII, for users that have data in that format.
2660 // This uses no "" for field names (which we already support by default,
2661 // omits `,`, `:` before `{` and a couple of other features.
2662 flatbuffers::Parser parser;
2663 parser.opts.protobuf_ascii_alike = true;
2665 parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
2667 TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
2668 // Similarly, in text output, it should omit these.
2670 auto ok = flatbuffers::GenerateText(
2671 parser, parser.builder_.GetBufferPointer(), &text);
2673 TEST_EQ_STR(text.c_str(),
2674 "{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n");
2677 void FlexBuffersTest() {
2678 flexbuffers::Builder slb(512,
2679 flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
2681 // Write the equivalent of:
2682 // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ],
2683 // foo: 100, bool: true, mymap: { foo: "Fred" } }
2685 #ifndef FLATBUFFERS_CPP98_STL
2686 // It's possible to do this without std::function support as well.
2688 slb.Vector("vec", [&]() {
2689 slb += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2691 slb.IndirectFloat(4.0f);
2692 auto i_f = slb.LastValue();
2693 uint8_t blob[] = { 77 };
2696 slb.ReuseValue(i_f);
2698 int ints[] = { 1, 2, 3 };
2699 slb.Vector("bar", ints, 3);
2700 slb.FixedTypedVector("bar3", ints, 3);
2701 bool bools[] = {true, false, true, false};
2702 slb.Vector("bools", bools, 4);
2703 slb.Bool("bool", true);
2704 slb.Double("foo", 100);
2705 slb.Map("mymap", [&]() {
2706 slb.String("foo", "Fred"); // Testing key and string reuse.
2711 // It's possible to do this without std::function support as well.
2712 slb.Map([](flexbuffers::Builder& slb2) {
2713 slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
2714 slb3 += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2716 slb3.IndirectFloat(4.0f);
2717 auto i_f = slb3.LastValue();
2718 uint8_t blob[] = { 77 };
2721 slb3.ReuseValue(i_f);
2723 int ints[] = { 1, 2, 3 };
2724 slb2.Vector("bar", ints, 3);
2725 slb2.FixedTypedVector("bar3", ints, 3);
2726 slb2.Bool("bool", true);
2727 slb2.Double("foo", 100);
2728 slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
2729 slb3.String("foo", "Fred"); // Testing key and string reuse.
2733 #endif // FLATBUFFERS_CPP98_STL
2735 #ifdef FLATBUFFERS_TEST_VERBOSE
2736 for (size_t i = 0; i < slb.GetBuffer().size(); i++)
2737 printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
2742 auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
2743 TEST_EQ(map.size(), 7);
2744 auto vec = map["vec"].AsVector();
2745 TEST_EQ(vec.size(), 6);
2746 TEST_EQ(vec[0].AsInt64(), -100);
2747 TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
2748 TEST_EQ(vec[1].AsInt64(), 0); // Number parsing failed.
2749 TEST_EQ(vec[2].AsDouble(), 4.0);
2750 TEST_EQ(vec[2].AsString().IsTheEmptyString(), true); // Wrong Type.
2751 TEST_EQ_STR(vec[2].AsString().c_str(), ""); // This still works though.
2752 TEST_EQ_STR(vec[2].ToString().c_str(), "4.0"); // Or have it converted.
2753 // Few tests for templated version of As.
2754 TEST_EQ(vec[0].As<int64_t>(), -100);
2755 TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
2756 TEST_EQ(vec[1].As<int64_t>(), 0); // Number parsing failed.
2757 TEST_EQ(vec[2].As<double>(), 4.0);
2758 // Test that the blob can be accessed.
2759 TEST_EQ(vec[3].IsBlob(), true);
2760 auto blob = vec[3].AsBlob();
2761 TEST_EQ(blob.size(), 1);
2762 TEST_EQ(blob.data()[0], 77);
2763 TEST_EQ(vec[4].IsBool(), true); // Check if type is a bool
2764 TEST_EQ(vec[4].AsBool(), false); // Check if value is false
2765 TEST_EQ(vec[5].AsDouble(), 4.0); // This is shared with vec[2] !
2766 auto tvec = map["bar"].AsTypedVector();
2767 TEST_EQ(tvec.size(), 3);
2768 TEST_EQ(tvec[2].AsInt8(), 3);
2769 auto tvec3 = map["bar3"].AsFixedTypedVector();
2770 TEST_EQ(tvec3.size(), 3);
2771 TEST_EQ(tvec3[2].AsInt8(), 3);
2772 TEST_EQ(map["bool"].AsBool(), true);
2773 auto tvecb = map["bools"].AsTypedVector();
2774 TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
2775 TEST_EQ(map["foo"].AsUInt8(), 100);
2776 TEST_EQ(map["unknown"].IsNull(), true);
2777 auto mymap = map["mymap"].AsMap();
2778 // These should be equal by pointer equality, since key and value are shared.
2779 TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
2780 TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
2781 // We can mutate values in the buffer.
2782 TEST_EQ(vec[0].MutateInt(-99), true);
2783 TEST_EQ(vec[0].AsInt64(), -99);
2784 TEST_EQ(vec[1].MutateString("John"), true); // Size must match.
2785 TEST_EQ_STR(vec[1].AsString().c_str(), "John");
2786 TEST_EQ(vec[1].MutateString("Alfred"), false); // Too long.
2787 TEST_EQ(vec[2].MutateFloat(2.0f), true);
2788 TEST_EQ(vec[2].AsFloat(), 2.0f);
2789 TEST_EQ(vec[2].MutateFloat(3.14159), false); // Double does not fit in float.
2790 TEST_EQ(vec[4].AsBool(), false); // Is false before change
2791 TEST_EQ(vec[4].MutateBool(true), true); // Can change a bool
2792 TEST_EQ(vec[4].AsBool(), true); // Changed bool is now true
2795 flatbuffers::Parser parser;
2797 auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
2798 TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
2799 auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
2800 auto jmap = jroot.AsMap();
2801 auto jvec = jmap["a"].AsVector();
2802 TEST_EQ(jvec[0].AsInt64(), 123);
2803 TEST_EQ(jvec[1].AsDouble(), 456.0);
2804 TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
2805 TEST_EQ(jmap["c"].IsBool(), true); // Parsed correctly to a bool
2806 TEST_EQ(jmap["c"].AsBool(), true); // Parsed correctly to true
2807 TEST_EQ(jmap["d"].IsBool(), true); // Parsed correctly to a bool
2808 TEST_EQ(jmap["d"].AsBool(), false); // Parsed correctly to false
2809 // And from FlexBuffer back to JSON:
2810 auto jsonback = jroot.ToString();
2811 TEST_EQ_STR(jsontest, jsonback.c_str());
2814 void FlexBuffersDeprecatedTest() {
2815 // FlexBuffers as originally designed had a flaw involving the
2816 // FBT_VECTOR_STRING datatype, and this test documents/tests the fix for it.
2817 // Discussion: https://github.com/google/flatbuffers/issues/5627
2818 flexbuffers::Builder slb;
2819 // FBT_VECTOR_* are "typed vectors" where all elements are of the same type.
2820 // Problem is, when storing FBT_STRING elements, it relies on that type to
2821 // get the bit-width for the size field of the string, which in this case
2822 // isn't present, and instead defaults to 8-bit. This means that any strings
2823 // stored inside such a vector, when accessed thru the old API that returns
2824 // a String reference, will appear to be truncated if the string stored is
2825 // actually >=256 bytes.
2826 std::string test_data(300, 'A');
2827 auto start = slb.StartVector();
2828 // This one will have a 16-bit size field.
2829 slb.String(test_data);
2830 // This one will have an 8-bit size field.
2831 slb.String("hello");
2832 // We're asking this to be serialized as a typed vector (true), but not
2833 // fixed size (false). The type will be FBT_VECTOR_STRING with a bit-width
2834 // of whatever the offsets in the vector need, the bit-widths of the strings
2835 // are not stored(!) <- the actual design flaw.
2836 // Note that even in the fixed code, we continue to serialize the elements of
2837 // FBT_VECTOR_STRING as FBT_STRING, since there may be old code out there
2838 // reading new data that we want to continue to function.
2839 // Thus, FBT_VECTOR_STRING, while deprecated, will always be represented the
2840 // same way, the fix lies on the reading side.
2841 slb.EndVector(start, true, false);
2843 // So now lets read this data back.
2844 // For existing data, since we have no way of knowing what the actual
2845 // bit-width of the size field of the string is, we are going to ignore this
2846 // field, and instead treat these strings as FBT_KEY (null-terminated), so we
2847 // can deal with strings of arbitrary length. This of course truncates strings
2848 // with embedded nulls, but we think that that is preferrable over truncating
2849 // strings >= 256 bytes.
2850 auto vec = flexbuffers::GetRoot(slb.GetBuffer()).AsTypedVector();
2851 // Even though this was serialized as FBT_VECTOR_STRING, it is read as
2853 TEST_EQ(vec.ElementType(), flexbuffers::FBT_KEY);
2854 // Access the long string. Previously, this would return a string of size 1,
2855 // since it would read the high-byte of the 16-bit length.
2856 // This should now correctly test the full 300 bytes, using AsKey():
2857 TEST_EQ_STR(vec[0].AsKey(), test_data.c_str());
2858 // Old code that called AsString will continue to work, as the String
2859 // accessor objects now use a cached size that can come from a key as well.
2860 TEST_EQ_STR(vec[0].AsString().c_str(), test_data.c_str());
2861 // Short strings work as before:
2862 TEST_EQ_STR(vec[1].AsKey(), "hello");
2863 TEST_EQ_STR(vec[1].AsString().c_str(), "hello");
2864 // So, while existing code and data mostly "just work" with the fixes applied
2865 // to AsTypedVector and AsString, what do you do going forward?
2866 // Code accessing existing data doesn't necessarily need to change, though
2867 // you could consider using AsKey instead of AsString for a) documenting
2868 // that you are accessing keys, or b) a speedup if you don't actually use
2870 // For new data, or data that doesn't need to be backwards compatible,
2871 // instead serialize as FBT_VECTOR (call EndVector with typed = false, then
2872 // read elements with AsString), or, for maximum compactness, use
2873 // FBT_VECTOR_KEY (call slb.Key above instead, read with AsKey or AsString).
2876 void TypeAliasesTest() {
2877 flatbuffers::FlatBufferBuilder builder;
2879 builder.Finish(CreateTypeAliases(
2880 builder, flatbuffers::numeric_limits<int8_t>::min(),
2881 flatbuffers::numeric_limits<uint8_t>::max(),
2882 flatbuffers::numeric_limits<int16_t>::min(),
2883 flatbuffers::numeric_limits<uint16_t>::max(),
2884 flatbuffers::numeric_limits<int32_t>::min(),
2885 flatbuffers::numeric_limits<uint32_t>::max(),
2886 flatbuffers::numeric_limits<int64_t>::min(),
2887 flatbuffers::numeric_limits<uint64_t>::max(), 2.3f, 2.3));
2889 auto p = builder.GetBufferPointer();
2890 auto ta = flatbuffers::GetRoot<TypeAliases>(p);
2892 TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
2893 TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
2894 TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
2895 TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
2896 TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
2897 TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
2898 TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
2899 TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
2900 TEST_EQ(ta->f32(), 2.3f);
2901 TEST_EQ(ta->f64(), 2.3);
2902 using namespace flatbuffers; // is_same
2903 static_assert(is_same<decltype(ta->i8()), int8_t>::value, "invalid type");
2904 static_assert(is_same<decltype(ta->i16()), int16_t>::value, "invalid type");
2905 static_assert(is_same<decltype(ta->i32()), int32_t>::value, "invalid type");
2906 static_assert(is_same<decltype(ta->i64()), int64_t>::value, "invalid type");
2907 static_assert(is_same<decltype(ta->u8()), uint8_t>::value, "invalid type");
2908 static_assert(is_same<decltype(ta->u16()), uint16_t>::value, "invalid type");
2909 static_assert(is_same<decltype(ta->u32()), uint32_t>::value, "invalid type");
2910 static_assert(is_same<decltype(ta->u64()), uint64_t>::value, "invalid type");
2911 static_assert(is_same<decltype(ta->f32()), float>::value, "invalid type");
2912 static_assert(is_same<decltype(ta->f64()), double>::value, "invalid type");
2915 void EndianSwapTest() {
2916 TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
2917 TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
2919 TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
2920 0xEFCDAB9078563412);
2921 TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
2924 void UninitializedVectorTest() {
2925 flatbuffers::FlatBufferBuilder builder;
2927 Test *buf = nullptr;
2928 auto vector_offset =
2929 builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
2931 buf[0] = Test(10, 20);
2932 buf[1] = Test(30, 40);
2934 auto required_name = builder.CreateString("myMonster");
2935 auto monster_builder = MonsterBuilder(builder);
2936 monster_builder.add_name(
2937 required_name); // required field mandated for monster.
2938 monster_builder.add_test4(vector_offset);
2939 builder.Finish(monster_builder.Finish());
2941 auto p = builder.GetBufferPointer();
2942 auto uvt = flatbuffers::GetRoot<Monster>(p);
2944 auto vec = uvt->test4();
2946 auto test_0 = vec->Get(0);
2947 auto test_1 = vec->Get(1);
2948 TEST_EQ(test_0->a(), 10);
2949 TEST_EQ(test_0->b(), 20);
2950 TEST_EQ(test_1->a(), 30);
2951 TEST_EQ(test_1->b(), 40);
2954 void EqualOperatorTest() {
2957 TEST_EQ(b == a, true);
2958 TEST_EQ(b != a, false);
2961 TEST_EQ(b == a, false);
2962 TEST_EQ(b != a, true);
2964 TEST_EQ(b == a, true);
2965 TEST_EQ(b != a, false);
2967 b.inventory.push_back(3);
2968 TEST_EQ(b == a, false);
2969 TEST_EQ(b != a, true);
2970 b.inventory.clear();
2971 TEST_EQ(b == a, true);
2972 TEST_EQ(b != a, false);
2974 b.test.type = Any_Monster;
2975 TEST_EQ(b == a, false);
2976 TEST_EQ(b != a, true);
2979 // For testing any binaries, e.g. from fuzzing.
2980 void LoadVerifyBinaryTest() {
2982 if (flatbuffers::LoadFile(
2983 (test_data_path + "fuzzer/your-filename-here").c_str(), true,
2985 flatbuffers::Verifier verifier(
2986 reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
2987 TEST_EQ(VerifyMonsterBuffer(verifier), true);
2991 void CreateSharedStringTest() {
2992 flatbuffers::FlatBufferBuilder builder;
2993 const auto one1 = builder.CreateSharedString("one");
2994 const auto two = builder.CreateSharedString("two");
2995 const auto one2 = builder.CreateSharedString("one");
2996 TEST_EQ(one1.o, one2.o);
2997 const auto onetwo = builder.CreateSharedString("onetwo");
2998 TEST_EQ(onetwo.o != one1.o, true);
2999 TEST_EQ(onetwo.o != two.o, true);
3001 // Support for embedded nulls
3002 const char chars_b[] = { 'a', '\0', 'b' };
3003 const char chars_c[] = { 'a', '\0', 'c' };
3004 const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3005 const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
3006 const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3007 TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
3008 TEST_EQ(null_b1.o, null_b2.o);
3010 // Put the strings into an array for round trip verification.
3011 const flatbuffers::Offset<flatbuffers::String> array[7] = {
3012 one1, two, one2, onetwo, null_b1, null_c, null_b2
3014 const auto vector_offset =
3015 builder.CreateVector(array, flatbuffers::uoffset_t(7));
3016 MonsterBuilder monster_builder(builder);
3017 monster_builder.add_name(two);
3018 monster_builder.add_testarrayofstring(vector_offset);
3019 builder.Finish(monster_builder.Finish());
3021 // Read the Monster back.
3022 const auto *monster =
3023 flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
3024 TEST_EQ_STR(monster->name()->c_str(), "two");
3025 const auto *testarrayofstring = monster->testarrayofstring();
3026 TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
3027 const auto &a = *testarrayofstring;
3028 TEST_EQ_STR(a[0]->c_str(), "one");
3029 TEST_EQ_STR(a[1]->c_str(), "two");
3030 TEST_EQ_STR(a[2]->c_str(), "one");
3031 TEST_EQ_STR(a[3]->c_str(), "onetwo");
3032 TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
3033 TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
3034 TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
3036 // Make sure String::operator< works, too, since it is related to
3037 // StringOffsetCompare.
3038 TEST_EQ((*a[0]) < (*a[1]), true);
3039 TEST_EQ((*a[1]) < (*a[0]), false);
3040 TEST_EQ((*a[1]) < (*a[2]), false);
3041 TEST_EQ((*a[2]) < (*a[1]), true);
3042 TEST_EQ((*a[4]) < (*a[3]), true);
3043 TEST_EQ((*a[5]) < (*a[4]), false);
3044 TEST_EQ((*a[5]) < (*a[4]), false);
3045 TEST_EQ((*a[6]) < (*a[5]), true);
3048 void FixedLengthArrayTest() {
3049 // VS10 does not support typed enums, exclude from tests
3050 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3051 // Generate an ArrayTable containing one ArrayStruct.
3052 flatbuffers::FlatBufferBuilder fbb;
3053 MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
3054 TEST_NOTNULL(nStruct0.mutable_a());
3055 nStruct0.mutable_a()->Mutate(0, 1);
3056 nStruct0.mutable_a()->Mutate(1, 2);
3057 TEST_NOTNULL(nStruct0.mutable_c());
3058 nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3059 nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3060 TEST_NOTNULL(nStruct0.mutable_d());
3061 nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
3062 nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
3063 MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
3064 TEST_NOTNULL(nStruct1.mutable_a());
3065 nStruct1.mutable_a()->Mutate(0, 3);
3066 nStruct1.mutable_a()->Mutate(1, 4);
3067 TEST_NOTNULL(nStruct1.mutable_c());
3068 nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3069 nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3070 TEST_NOTNULL(nStruct1.mutable_d());
3071 nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
3072 nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
3073 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
3074 TEST_NOTNULL(aStruct.b());
3075 TEST_NOTNULL(aStruct.mutable_b());
3076 TEST_NOTNULL(aStruct.mutable_d());
3077 TEST_NOTNULL(aStruct.mutable_f());
3078 for (int i = 0; i < aStruct.b()->size(); i++)
3079 aStruct.mutable_b()->Mutate(i, i + 1);
3080 aStruct.mutable_d()->Mutate(0, nStruct0);
3081 aStruct.mutable_d()->Mutate(1, nStruct1);
3082 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
3085 // Verify correctness of the ArrayTable.
3086 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
3087 MyGame::Example::VerifyArrayTableBuffer(verifier);
3088 auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
3089 auto mArStruct = p->mutable_a();
3090 TEST_NOTNULL(mArStruct);
3091 TEST_NOTNULL(mArStruct->b());
3092 TEST_NOTNULL(mArStruct->d());
3093 TEST_NOTNULL(mArStruct->f());
3094 TEST_NOTNULL(mArStruct->mutable_b());
3095 TEST_NOTNULL(mArStruct->mutable_d());
3096 TEST_NOTNULL(mArStruct->mutable_f());
3097 mArStruct->mutable_b()->Mutate(14, -14);
3098 TEST_EQ(mArStruct->a(), 2);
3099 TEST_EQ(mArStruct->b()->size(), 15);
3100 TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14);
3101 TEST_EQ(mArStruct->c(), 12);
3102 TEST_NOTNULL(mArStruct->d()->Get(0));
3103 TEST_NOTNULL(mArStruct->d()->Get(0)->a());
3104 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
3105 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
3106 TEST_NOTNULL(mArStruct->d()->Get(1));
3107 TEST_NOTNULL(mArStruct->d()->Get(1)->a());
3108 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
3109 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
3110 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
3111 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
3112 mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
3113 TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
3114 TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
3115 TEST_NOTNULL(mArStruct->d()->Get(0)->c());
3116 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
3117 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
3118 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3119 mArStruct->d()->Get(0)->d()->Get(0));
3120 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3121 mArStruct->d()->Get(0)->d()->Get(1));
3122 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
3123 TEST_NOTNULL(mArStruct->d()->Get(1)->c());
3124 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
3125 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
3126 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3127 mArStruct->d()->Get(1)->d()->Get(0));
3128 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3129 mArStruct->d()->Get(1)->d()->Get(1));
3130 for (int i = 0; i < mArStruct->b()->size() - 1; i++)
3131 TEST_EQ(mArStruct->b()->Get(i), i + 1);
3133 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
3134 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
3138 void NativeTypeTest() {
3141 Geometry::ApplicationDataT src_data;
3142 src_data.vectors.reserve(N);
3144 for (int i = 0; i < N; ++i) {
3145 src_data.vectors.push_back(
3146 Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
3149 flatbuffers::FlatBufferBuilder fbb;
3150 fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
3152 auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
3154 for (int i = 0; i < N; ++i) {
3155 Native::Vector3D &v = dstDataT->vectors[i];
3156 TEST_EQ(v.x, 10 * i + 0.1f);
3157 TEST_EQ(v.y, 10 * i + 0.2f);
3158 TEST_EQ(v.z, 10 * i + 0.3f);
3162 void FixedLengthArrayJsonTest(bool binary) {
3163 // VS10 does not support typed enums, exclude from tests
3164 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3165 // load FlatBuffer schema (.fbs) and JSON from disk
3166 std::string schemafile;
3167 std::string jsonfile;
3169 flatbuffers::LoadFile(
3170 (test_data_path + "arrays_test." + (binary ? "bfbs" : "fbs")).c_str(),
3171 binary, &schemafile),
3173 TEST_EQ(flatbuffers::LoadFile((test_data_path + "arrays_test.golden").c_str(),
3177 // parse schema first, so we can use it to parse the data after
3178 flatbuffers::Parser parserOrg, parserGen;
3180 flatbuffers::Verifier verifier(
3181 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
3183 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3184 TEST_EQ(parserOrg.Deserialize((const uint8_t *)schemafile.c_str(),
3187 TEST_EQ(parserGen.Deserialize((const uint8_t *)schemafile.c_str(),
3191 TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
3192 TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
3194 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3196 // First, verify it, just in case:
3197 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3198 parserOrg.builder_.GetSize());
3199 TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
3202 std::string jsonGen;
3204 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3208 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3210 // Verify buffer from generated JSON
3211 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3212 parserGen.builder_.GetSize());
3213 TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
3215 // Compare generated buffer to original
3216 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3217 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3218 parserGen.builder_.GetBufferPointer(),
3219 parserOrg.builder_.GetSize()),
3226 int FlatBufferTests() {
3229 // Run our various test suites:
3232 auto flatbuf1 = CreateFlatBufferTest(rawbuf);
3233 #if !defined(FLATBUFFERS_CPP98_STL)
3234 auto flatbuf = std::move(flatbuf1); // Test move assignment.
3236 auto &flatbuf = flatbuf1;
3237 #endif // !defined(FLATBUFFERS_CPP98_STL)
3239 TriviallyCopyableTest();
3241 AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
3243 AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
3245 MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
3247 ObjectFlatBuffersTest(flatbuf.data());
3249 MiniReflectFlatBuffersTest(flatbuf.data());
3253 #ifndef FLATBUFFERS_NO_FILE_TESTS
3254 #ifdef FLATBUFFERS_TEST_PATH_PREFIX
3255 test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
3258 ParseAndGenerateTextTest(false);
3259 ParseAndGenerateTextTest(true);
3260 FixedLengthArrayJsonTest(false);
3261 FixedLengthArrayJsonTest(true);
3262 ReflectionTest(flatbuf.data(), flatbuf.size());
3264 ParseProtoTestWithIncludes();
3267 LoadVerifyBinaryTest();
3268 GenerateTableTextTest();
3280 EnumOutOfRangeTest();
3281 IntegerOutOfRangeTest();
3282 IntegerBoundaryTest();
3284 UnicodeTestAllowNonUTF8();
3285 UnicodeTestGenerateTextFailsOnNonUTF8();
3286 UnicodeSurrogatesTest();
3287 UnicodeInvalidSurrogatesTest();
3289 UnknownFieldsTest();
3291 InvalidNestedFlatbufferTest();
3293 ParseProtoBufAsciiTest();
3296 CreateSharedStringTest();
3300 FlexBuffersDeprecatedTest();
3301 UninitializedVectorTest();
3302 EqualOperatorTest();
3307 TestMonsterExtraFloats();
3308 FixedLengthArrayTest();
3313 int main(int /*argc*/, const char * /*argv*/[]) {
3316 std::string req_locale;
3317 if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
3319 TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
3320 req_locale.c_str());
3321 req_locale = flatbuffers::RemoveStringQuotes(req_locale);
3322 std::string the_locale;
3324 flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
3325 TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
3329 FlatBufferBuilderTest();
3331 if (!testing_fails) {
3332 TEST_OUTPUT_LINE("ALL TESTS PASSED");
3334 TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
3336 return CloseTestEngine();