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 //printf("Golden\n%s\n", goldenfile.c_str());
1177 printf("FBS\n%s\n", fbs.c_str());
1178 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1180 // Parse proto with --oneof-union option.
1181 opts.proto_oneof_union = true;
1182 flatbuffers::Parser parser3(opts);
1183 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1186 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1188 // Ensure generated file is parsable.
1189 flatbuffers::Parser parser4;
1190 TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, "imported.fbs"), true);
1191 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1192 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1195 template<typename T>
1196 void CompareTableFieldValue(flatbuffers::Table *table,
1197 flatbuffers::voffset_t voffset, T val) {
1198 T read = table->GetField(voffset, static_cast<T>(0));
1202 // Low level stress/fuzz test: serialize/deserialize a variety of
1203 // different kinds of data in different combinations
1205 // Values we're testing against: chosen to ensure no bits get chopped
1206 // off anywhere, and also be different from eachother.
1207 const uint8_t bool_val = true;
1208 const int8_t char_val = -127; // 0x81
1209 const uint8_t uchar_val = 0xFF;
1210 const int16_t short_val = -32222; // 0x8222;
1211 const uint16_t ushort_val = 0xFEEE;
1212 const int32_t int_val = 0x83333333;
1213 const uint32_t uint_val = 0xFDDDDDDD;
1214 const int64_t long_val = 0x8444444444444444LL;
1215 const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
1216 const float float_val = 3.14159f;
1217 const double double_val = 3.14159265359;
1219 const int test_values_max = 11;
1220 const flatbuffers::voffset_t fields_per_object = 4;
1221 const int num_fuzz_objects = 10000; // The higher, the more thorough :)
1223 flatbuffers::FlatBufferBuilder builder;
1225 lcg_reset(); // Keep it deterministic.
1227 flatbuffers::uoffset_t objects[num_fuzz_objects];
1229 // Generate num_fuzz_objects random objects each consisting of
1230 // fields_per_object fields, each of a random type.
1231 for (int i = 0; i < num_fuzz_objects; i++) {
1232 auto start = builder.StartTable();
1233 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1234 int choice = lcg_rand() % test_values_max;
1235 auto off = flatbuffers::FieldIndexToOffset(f);
1237 case 0: builder.AddElement<uint8_t>(off, bool_val, 0); break;
1238 case 1: builder.AddElement<int8_t>(off, char_val, 0); break;
1239 case 2: builder.AddElement<uint8_t>(off, uchar_val, 0); break;
1240 case 3: builder.AddElement<int16_t>(off, short_val, 0); break;
1241 case 4: builder.AddElement<uint16_t>(off, ushort_val, 0); break;
1242 case 5: builder.AddElement<int32_t>(off, int_val, 0); break;
1243 case 6: builder.AddElement<uint32_t>(off, uint_val, 0); break;
1244 case 7: builder.AddElement<int64_t>(off, long_val, 0); break;
1245 case 8: builder.AddElement<uint64_t>(off, ulong_val, 0); break;
1246 case 9: builder.AddElement<float>(off, float_val, 0); break;
1247 case 10: builder.AddElement<double>(off, double_val, 0); break;
1250 objects[i] = builder.EndTable(start);
1252 builder.PreAlign<flatbuffers::largest_scalar_t>(0); // Align whole buffer.
1254 lcg_reset(); // Reset.
1256 uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
1258 // Test that all objects we generated are readable and return the
1259 // expected values. We generate random objects in the same order
1260 // so this is deterministic.
1261 for (int i = 0; i < num_fuzz_objects; i++) {
1262 auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
1263 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1264 int choice = lcg_rand() % test_values_max;
1265 flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
1267 case 0: CompareTableFieldValue(table, off, bool_val); break;
1268 case 1: CompareTableFieldValue(table, off, char_val); break;
1269 case 2: CompareTableFieldValue(table, off, uchar_val); break;
1270 case 3: CompareTableFieldValue(table, off, short_val); break;
1271 case 4: CompareTableFieldValue(table, off, ushort_val); break;
1272 case 5: CompareTableFieldValue(table, off, int_val); break;
1273 case 6: CompareTableFieldValue(table, off, uint_val); break;
1274 case 7: CompareTableFieldValue(table, off, long_val); break;
1275 case 8: CompareTableFieldValue(table, off, ulong_val); break;
1276 case 9: CompareTableFieldValue(table, off, float_val); break;
1277 case 10: CompareTableFieldValue(table, off, double_val); break;
1283 // High level stress/fuzz test: generate a big schema and
1284 // matching json data in random combinations, then parse both,
1285 // generate json back from the binary, and compare with the original.
1287 lcg_reset(); // Keep it deterministic.
1289 const int num_definitions = 30;
1290 const int num_struct_definitions = 5; // Subset of num_definitions.
1291 const int fields_per_definition = 15;
1292 const int instances_per_definition = 5;
1293 const int deprecation_rate = 10; // 1 in deprecation_rate fields will
1296 std::string schema = "namespace test;\n\n";
1299 std::string instances[instances_per_definition];
1301 // Since we're generating schema and corresponding data in tandem,
1302 // this convenience function adds strings to both at once.
1303 static void Add(RndDef (&definitions_l)[num_definitions],
1304 std::string &schema_l, const int instances_per_definition_l,
1305 const char *schema_add, const char *instance_add,
1307 schema_l += schema_add;
1308 for (int i = 0; i < instances_per_definition_l; i++)
1309 definitions_l[definition].instances[i] += instance_add;
1314 #define AddToSchemaAndInstances(schema_add, instance_add) \
1315 RndDef::Add(definitions, schema, instances_per_definition, \
1316 schema_add, instance_add, definition)
1319 RndDef::Add(definitions, schema, instances_per_definition, \
1320 "byte", "1", definition)
1323 RndDef definitions[num_definitions];
1325 // We are going to generate num_definitions, the first
1326 // num_struct_definitions will be structs, the rest tables. For each
1327 // generate random fields, some of which may be struct/table types
1328 // referring to previously generated structs/tables.
1329 // Simultanenously, we generate instances_per_definition JSON data
1330 // definitions, which will have identical structure to the schema
1331 // being generated. We generate multiple instances such that when creating
1332 // hierarchy, we get some variety by picking one randomly.
1333 for (int definition = 0; definition < num_definitions; definition++) {
1334 std::string definition_name = "D" + flatbuffers::NumToString(definition);
1336 bool is_struct = definition < num_struct_definitions;
1338 AddToSchemaAndInstances(
1339 ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
1342 for (int field = 0; field < fields_per_definition; field++) {
1343 const bool is_last_field = field == fields_per_definition - 1;
1345 // Deprecate 1 in deprecation_rate fields. Only table fields can be
1347 // Don't deprecate the last field to avoid dangling commas in JSON.
1348 const bool deprecated =
1349 !is_struct && !is_last_field && (lcg_rand() % deprecation_rate == 0);
1351 std::string field_name = "f" + flatbuffers::NumToString(field);
1352 AddToSchemaAndInstances((" " + field_name + ":").c_str(),
1353 deprecated ? "" : (field_name + ": ").c_str());
1354 // Pick random type:
1355 auto base_type = static_cast<flatbuffers::BaseType>(
1356 lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
1357 switch (base_type) {
1358 case flatbuffers::BASE_TYPE_STRING:
1360 Dummy(); // No strings in structs.
1362 AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
1365 case flatbuffers::BASE_TYPE_VECTOR:
1367 Dummy(); // No vectors in structs.
1369 AddToSchemaAndInstances("[ubyte]",
1370 deprecated ? "" : "[\n0,\n1,\n255\n]");
1373 case flatbuffers::BASE_TYPE_NONE:
1374 case flatbuffers::BASE_TYPE_UTYPE:
1375 case flatbuffers::BASE_TYPE_STRUCT:
1376 case flatbuffers::BASE_TYPE_UNION:
1378 // Pick a random previous definition and random data instance of
1380 int defref = lcg_rand() % definition;
1381 int instance = lcg_rand() % instances_per_definition;
1382 AddToSchemaAndInstances(
1383 ("D" + flatbuffers::NumToString(defref)).c_str(),
1385 : definitions[defref].instances[instance].c_str());
1387 // If this is the first definition, we have no definition we can
1392 case flatbuffers::BASE_TYPE_BOOL:
1393 AddToSchemaAndInstances(
1394 "bool", deprecated ? "" : (lcg_rand() % 2 ? "true" : "false"));
1396 case flatbuffers::BASE_TYPE_ARRAY:
1398 AddToSchemaAndInstances(
1400 deprecated ? "" : "255"); // No fixed-length arrays in tables.
1402 AddToSchemaAndInstances("[int:3]", deprecated ? "" : "[\n,\n,\n]");
1406 // All the scalar types.
1407 schema += flatbuffers::kTypeNames[base_type];
1410 // We want each instance to use its own random value.
1411 for (int inst = 0; inst < instances_per_definition; inst++)
1412 definitions[definition].instances[inst] +=
1413 flatbuffers::IsFloat(base_type)
1414 ? flatbuffers::NumToString<double>(lcg_rand() % 128)
1416 : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
1419 AddToSchemaAndInstances(deprecated ? "(deprecated);\n" : ";\n",
1420 deprecated ? "" : is_last_field ? "\n" : ",\n");
1422 AddToSchemaAndInstances("}\n\n", "}");
1425 schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
1428 flatbuffers::Parser parser;
1430 // Will not compare against the original if we don't write defaults
1431 parser.builder_.ForceDefaults(true);
1433 // Parse the schema, parse the generated data, then generate text back
1434 // from the binary and compare against the original.
1435 TEST_EQ(parser.Parse(schema.c_str()), true);
1437 const std::string &json =
1438 definitions[num_definitions - 1].instances[0] + "\n";
1440 TEST_EQ(parser.Parse(json.c_str()), true);
1442 std::string jsongen;
1443 parser.opts.indent_step = 0;
1445 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
1446 TEST_EQ(result, true);
1448 if (jsongen != json) {
1449 // These strings are larger than a megabyte, so we show the bytes around
1450 // the first bytes that are different rather than the whole string.
1451 size_t len = std::min(json.length(), jsongen.length());
1452 for (size_t i = 0; i < len; i++) {
1453 if (json[i] != jsongen[i]) {
1454 i -= std::min(static_cast<size_t>(10), i); // show some context;
1455 size_t end = std::min(len, i + 20);
1456 for (; i < end; i++)
1457 TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
1458 static_cast<int>(i), jsongen[i], json[i]);
1462 TEST_NOTNULL(nullptr);
1466 #ifdef FLATBUFFERS_TEST_VERBOSE
1467 TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
1468 static_cast<int>(schema.length() / 1024),
1469 static_cast<int>(json.length() / 1024));
1474 // Test that parser errors are actually generated.
1475 void TestError_(const char *src, const char *error_substr, bool strict_json,
1476 const char *file, int line, const char *func) {
1477 flatbuffers::IDLOptions opts;
1478 opts.strict_json = strict_json;
1479 flatbuffers::Parser parser(opts);
1480 if (parser.Parse(src)) {
1481 TestFail("true", "false",
1482 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1484 } else if (!strstr(parser.error_.c_str(), error_substr)) {
1485 TestFail(parser.error_.c_str(), error_substr,
1486 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1491 void TestError_(const char *src, const char *error_substr, const char *file,
1492 int line, const char *func) {
1493 TestError_(src, error_substr, false, file, line, func);
1497 # define TestError(src, ...) \
1498 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
1500 # define TestError(src, ...) \
1501 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1504 // Test that parsing errors occur as we'd expect.
1505 // Also useful for coverage, making sure these paths are run.
1507 // In order they appear in idl_parser.cpp
1508 TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
1509 TestError("\"\0", "illegal");
1510 TestError("\"\\q", "escape code");
1511 TestError("table ///", "documentation");
1512 TestError("@", "illegal");
1513 TestError("table 1", "expecting");
1514 TestError("table X { Y:[[int]]; }", "nested vector");
1515 TestError("table X { Y:1; }", "illegal type");
1516 TestError("table X { Y:int; Y:int; }", "field already");
1517 TestError("table Y {} table X { Y:int; }", "same as table");
1518 TestError("struct X { Y:string; }", "only scalar");
1519 TestError("table X { Y:string = \"\"; }", "default values");
1520 TestError("struct X { a:uint = 42; }", "default values");
1521 TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
1522 TestError("struct X { Y:int (deprecated); }", "deprecate");
1523 TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
1524 "missing type field");
1525 TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
1527 TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
1528 TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
1529 TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
1532 "struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
1535 TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
1536 "unknown enum value");
1537 TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
1538 TestError("enum X:byte { Y } enum X {", "enum already");
1539 TestError("enum X:float {}", "underlying");
1540 TestError("enum X:byte { Y, Y }", "value already");
1541 TestError("enum X:byte { Y=2, Z=1 }", "ascending");
1542 TestError("table X { Y:int; } table X {", "datatype already");
1543 TestError("struct X (force_align: 7) { Y:int; }", "force_align");
1544 TestError("struct X {}", "size 0");
1545 TestError("{}", "no root");
1546 TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
1547 TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
1549 TestError("root_type X;", "unknown root");
1550 TestError("struct X { Y:int; } root_type X;", "a table");
1551 TestError("union X { Y }", "referenced");
1552 TestError("union Z { X } struct X { Y:int; }", "only tables");
1553 TestError("table X { Y:[int]; YLength:int; }", "clash");
1554 TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
1555 // float to integer conversion is forbidden
1556 TestError("table X { Y:int; } root_type X; { Y:1.0 }", "float");
1557 TestError("table X { Y:bool; } root_type X; { Y:1.0 }", "float");
1558 TestError("enum X:bool { Y = true }", "must be integral");
1561 template<typename T>
1562 T TestValue(const char *json, const char *type_name,
1563 const char *decls = nullptr) {
1564 flatbuffers::Parser parser;
1565 parser.builder_.ForceDefaults(true); // return defaults
1566 auto check_default = json ? false : true;
1567 if (check_default) { parser.opts.output_default_scalars_in_json = true; }
1569 std::string schema = std::string(decls ? decls : "") + "\n" +
1570 "table X { Y:" + std::string(type_name) +
1572 auto schema_done = parser.Parse(schema.c_str());
1573 TEST_EQ_STR(parser.error_.c_str(), "");
1574 TEST_EQ(schema_done, true);
1576 auto done = parser.Parse(check_default ? "{}" : json);
1577 TEST_EQ_STR(parser.error_.c_str(), "");
1578 TEST_EQ(done, true);
1580 // Check with print.
1581 std::string print_back;
1582 parser.opts.indent_step = -1;
1583 TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back),
1585 // restore value from its default
1586 if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); }
1588 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
1589 parser.builder_.GetBufferPointer());
1590 return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
1593 bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
1595 // Additional parser testing not covered elsewhere.
1597 // Test scientific notation numbers.
1599 FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"), 3.14159f),
1602 TEST_EQ(FloatCompare(TestValue<float>("{ Y:\"0.0314159e+2\" }", "float"),
1606 // Test conversion functions.
1607 TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }", "float"), -1),
1610 // int embedded to string
1611 TEST_EQ(TestValue<int>("{ Y:\"-876\" }", "int=-123"), -876);
1612 TEST_EQ(TestValue<int>("{ Y:\"876\" }", "int=-123"), 876);
1614 // Test negative hex constant.
1615 TEST_EQ(TestValue<int>("{ Y:-0x8ea0 }", "int=-0x8ea0"), -36512);
1616 TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
1618 // positive hex constant
1619 TEST_EQ(TestValue<int>("{ Y:0x1abcdef }", "int=0x1"), 0x1abcdef);
1620 // with optional '+' sign
1621 TEST_EQ(TestValue<int>("{ Y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
1623 TEST_EQ(TestValue<int>("{ Y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
1625 // Make sure we do unsigned 64bit correctly.
1626 TEST_EQ(TestValue<uint64_t>("{ Y:12335089644688340133 }", "ulong"),
1627 12335089644688340133ULL);
1630 TEST_EQ(TestValue<bool>("{ Y:\"false\" }", "bool=true"), false);
1631 TEST_EQ(TestValue<bool>("{ Y:\"true\" }", "bool=\"true\""), true);
1632 TEST_EQ(TestValue<bool>("{ Y:'false' }", "bool=true"), false);
1633 TEST_EQ(TestValue<bool>("{ Y:'true' }", "bool=\"true\""), true);
1635 // check comments before and after json object
1636 TEST_EQ(TestValue<int>("/*before*/ { Y:1 } /*after*/", "int"), 1);
1637 TEST_EQ(TestValue<int>("//before \n { Y:1 } //after", "int"), 1);
1640 void NestedListTest() {
1641 flatbuffers::Parser parser1;
1642 TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
1644 "{ F:[ [10,20], [30,40]] }"),
1648 void EnumStringsTest() {
1649 flatbuffers::Parser parser1;
1650 TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
1652 "{ F:[ A, B, \"C\", \"A B C\" ] }"),
1654 flatbuffers::Parser parser2;
1655 TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
1657 "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"),
1659 // unsigned bit_flags
1660 flatbuffers::Parser parser3;
1662 parser3.Parse("enum E:uint16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }"
1663 " table T { F: E = \"F15 F08\"; }"
1668 void EnumNamesTest() {
1669 TEST_EQ_STR("Red", EnumNameColor(Color_Red));
1670 TEST_EQ_STR("Green", EnumNameColor(Color_Green));
1671 TEST_EQ_STR("Blue", EnumNameColor(Color_Blue));
1672 // Check that Color to string don't crash while decode a mixture of Colors.
1673 // 1) Example::Color enum is enum with unfixed underlying type.
1674 // 2) Valid enum range: [0; 2^(ceil(log2(Color_ANY))) - 1].
1675 // Consequence: A value is out of this range will lead to UB (since C++17).
1676 // For details see C++17 standard or explanation on the SO:
1677 // stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class
1678 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(0)));
1679 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY - 1)));
1680 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY + 1)));
1683 void EnumOutOfRangeTest() {
1684 TestError("enum X:byte { Y = 128 }", "enum value does not fit");
1685 TestError("enum X:byte { Y = -129 }", "enum value does not fit");
1686 TestError("enum X:byte { Y = 126, Z0, Z1 }", "enum value does not fit");
1687 TestError("enum X:ubyte { Y = -1 }", "enum value does not fit");
1688 TestError("enum X:ubyte { Y = 256 }", "enum value does not fit");
1689 TestError("enum X:ubyte { Y = 255, Z }", "enum value does not fit");
1690 // Unions begin with an implicit "NONE = 0".
1691 TestError("table Y{} union X { Y = -1 }",
1692 "enum values must be specified in ascending order");
1693 TestError("table Y{} union X { Y = 256 }", "enum value does not fit");
1694 TestError("table Y{} union X { Y = 255, Z:Y }", "enum value does not fit");
1695 TestError("enum X:int { Y = -2147483649 }", "enum value does not fit");
1696 TestError("enum X:int { Y = 2147483648 }", "enum value does not fit");
1697 TestError("enum X:uint { Y = -1 }", "enum value does not fit");
1698 TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit");
1699 TestError("enum X:long { Y = 9223372036854775808 }", "does not fit");
1700 TestError("enum X:long { Y = 9223372036854775807, Z }",
1701 "enum value does not fit");
1702 TestError("enum X:ulong { Y = -1 }", "does not fit");
1703 TestError("enum X:ubyte (bit_flags) { Y=8 }", "bit flag out");
1704 TestError("enum X:byte (bit_flags) { Y=7 }", "must be unsigned"); // -128
1705 // bit_flgs out of range
1706 TestError("enum X:ubyte (bit_flags) { Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8 }",
1710 void EnumValueTest() {
1711 // json: "{ Y:0 }", schema: table X { Y : "E"}
1712 // 0 in enum (V=0) E then Y=0 is valid.
1713 TEST_EQ(TestValue<int>("{ Y:0 }", "E", "enum E:int { V }"), 0);
1714 TEST_EQ(TestValue<int>("{ Y:V }", "E", "enum E:int { V }"), 0);
1715 // A default value of Y is 0.
1716 TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
1717 TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { V=5 }"), 5);
1718 // Generate json with defaults and check.
1719 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
1721 TEST_EQ(TestValue<int>("{ Y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
1722 TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
1723 // Generate json with defaults and check.
1724 TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
1725 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
1727 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1728 "enum E:ulong { V = 13835058055282163712 }"),
1729 13835058055282163712ULL);
1730 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1731 "enum E:ulong { V = 18446744073709551615 }"),
1732 18446744073709551615ULL);
1733 // Assign non-enum value to enum field. Is it right?
1734 TEST_EQ(TestValue<int>("{ Y:7 }", "E", "enum E:int { V = 0 }"), 7);
1737 void IntegerOutOfRangeTest() {
1738 TestError("table T { F:byte; } root_type T; { F:128 }",
1739 "constant does not fit");
1740 TestError("table T { F:byte; } root_type T; { F:-129 }",
1741 "constant does not fit");
1742 TestError("table T { F:ubyte; } root_type T; { F:256 }",
1743 "constant does not fit");
1744 TestError("table T { F:ubyte; } root_type T; { F:-1 }",
1745 "constant does not fit");
1746 TestError("table T { F:short; } root_type T; { F:32768 }",
1747 "constant does not fit");
1748 TestError("table T { F:short; } root_type T; { F:-32769 }",
1749 "constant does not fit");
1750 TestError("table T { F:ushort; } root_type T; { F:65536 }",
1751 "constant does not fit");
1752 TestError("table T { F:ushort; } root_type T; { F:-1 }",
1753 "constant does not fit");
1754 TestError("table T { F:int; } root_type T; { F:2147483648 }",
1755 "constant does not fit");
1756 TestError("table T { F:int; } root_type T; { F:-2147483649 }",
1757 "constant does not fit");
1758 TestError("table T { F:uint; } root_type T; { F:4294967296 }",
1759 "constant does not fit");
1760 TestError("table T { F:uint; } root_type T; { F:-1 }",
1761 "constant does not fit");
1762 // Check fixed width aliases
1763 TestError("table X { Y:uint8; } root_type X; { Y: -1 }", "does not fit");
1764 TestError("table X { Y:uint8; } root_type X; { Y: 256 }", "does not fit");
1765 TestError("table X { Y:uint16; } root_type X; { Y: -1 }", "does not fit");
1766 TestError("table X { Y:uint16; } root_type X; { Y: 65536 }", "does not fit");
1767 TestError("table X { Y:uint32; } root_type X; { Y: -1 }", "");
1768 TestError("table X { Y:uint32; } root_type X; { Y: 4294967296 }",
1770 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1771 TestError("table X { Y:uint64; } root_type X; { Y: -9223372036854775809 }",
1773 TestError("table X { Y:uint64; } root_type X; { Y: 18446744073709551616 }",
1776 TestError("table X { Y:int8; } root_type X; { Y: -129 }", "does not fit");
1777 TestError("table X { Y:int8; } root_type X; { Y: 128 }", "does not fit");
1778 TestError("table X { Y:int16; } root_type X; { Y: -32769 }", "does not fit");
1779 TestError("table X { Y:int16; } root_type X; { Y: 32768 }", "does not fit");
1780 TestError("table X { Y:int32; } root_type X; { Y: -2147483649 }", "");
1781 TestError("table X { Y:int32; } root_type X; { Y: 2147483648 }",
1783 TestError("table X { Y:int64; } root_type X; { Y: -9223372036854775809 }",
1785 TestError("table X { Y:int64; } root_type X; { Y: 9223372036854775808 }",
1787 // check out-of-int64 as int8
1788 TestError("table X { Y:int8; } root_type X; { Y: -9223372036854775809 }",
1790 TestError("table X { Y:int8; } root_type X; { Y: 9223372036854775808 }",
1793 // Check default values
1794 TestError("table X { Y:int64=-9223372036854775809; } root_type X; {}",
1796 TestError("table X { Y:int64= 9223372036854775808; } root_type X; {}",
1798 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1799 TestError("table X { Y:uint64=-9223372036854775809; } root_type X; {}",
1801 TestError("table X { Y:uint64= 18446744073709551616; } root_type X; {}",
1805 void IntegerBoundaryTest() {
1806 // Check numerical compatibility with non-C++ languages.
1807 // By the C++ standard, std::numerical_limits<int64_t>::min() ==
1808 // -9223372036854775807 (-2^63+1) or less* The Flatbuffers grammar and most of
1809 // the languages (C#, Java, Rust) expect that minimum values are: -128,
1810 // -32768,.., -9223372036854775808. Since C++20,
1811 // static_cast<int64>(0x8000000000000000ULL) is well-defined two's complement
1812 // cast. Therefore -9223372036854775808 should be valid negative value.
1813 TEST_EQ(flatbuffers::numeric_limits<int8_t>::min(), -128);
1814 TEST_EQ(flatbuffers::numeric_limits<int8_t>::max(), 127);
1815 TEST_EQ(flatbuffers::numeric_limits<int16_t>::min(), -32768);
1816 TEST_EQ(flatbuffers::numeric_limits<int16_t>::max(), 32767);
1817 TEST_EQ(flatbuffers::numeric_limits<int32_t>::min() + 1, -2147483647);
1818 TEST_EQ(flatbuffers::numeric_limits<int32_t>::max(), 2147483647ULL);
1819 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min() + 1LL,
1820 -9223372036854775807LL);
1821 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(), 9223372036854775807ULL);
1822 TEST_EQ(flatbuffers::numeric_limits<uint8_t>::max(), 255);
1823 TEST_EQ(flatbuffers::numeric_limits<uint16_t>::max(), 65535);
1824 TEST_EQ(flatbuffers::numeric_limits<uint32_t>::max(), 4294967295ULL);
1825 TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
1826 18446744073709551615ULL);
1828 TEST_EQ(TestValue<int8_t>("{ Y:127 }", "byte"), 127);
1829 TEST_EQ(TestValue<int8_t>("{ Y:-128 }", "byte"), -128);
1830 TEST_EQ(TestValue<uint8_t>("{ Y:255 }", "ubyte"), 255);
1831 TEST_EQ(TestValue<uint8_t>("{ Y:0 }", "ubyte"), 0);
1832 TEST_EQ(TestValue<int16_t>("{ Y:32767 }", "short"), 32767);
1833 TEST_EQ(TestValue<int16_t>("{ Y:-32768 }", "short"), -32768);
1834 TEST_EQ(TestValue<uint16_t>("{ Y:65535 }", "ushort"), 65535);
1835 TEST_EQ(TestValue<uint16_t>("{ Y:0 }", "ushort"), 0);
1836 TEST_EQ(TestValue<int32_t>("{ Y:2147483647 }", "int"), 2147483647);
1837 TEST_EQ(TestValue<int32_t>("{ Y:-2147483648 }", "int") + 1, -2147483647);
1838 TEST_EQ(TestValue<uint32_t>("{ Y:4294967295 }", "uint"), 4294967295);
1839 TEST_EQ(TestValue<uint32_t>("{ Y:0 }", "uint"), 0);
1840 TEST_EQ(TestValue<int64_t>("{ Y:9223372036854775807 }", "long"),
1841 9223372036854775807LL);
1842 TEST_EQ(TestValue<int64_t>("{ Y:-9223372036854775808 }", "long") + 1LL,
1843 -9223372036854775807LL);
1844 TEST_EQ(TestValue<uint64_t>("{ Y:18446744073709551615 }", "ulong"),
1845 18446744073709551615ULL);
1846 TEST_EQ(TestValue<uint64_t>("{ Y:0 }", "ulong"), 0);
1847 TEST_EQ(TestValue<uint64_t>("{ Y: 18446744073709551615 }", "uint64"),
1848 18446744073709551615ULL);
1849 // check that the default works
1850 TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
1851 18446744073709551615ULL);
1854 void ValidFloatTest() {
1855 // check rounding to infinity
1856 TEST_EQ(TestValue<float>("{ Y:+3.4029e+38 }", "float"), +infinityf);
1857 TEST_EQ(TestValue<float>("{ Y:-3.4029e+38 }", "float"), -infinityf);
1858 TEST_EQ(TestValue<double>("{ Y:+1.7977e+308 }", "double"), +infinityd);
1859 TEST_EQ(TestValue<double>("{ Y:-1.7977e+308 }", "double"), -infinityd);
1862 FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"), 3.14159f),
1865 TEST_EQ(FloatCompare(TestValue<float>("{ Y:\" 0.0314159e+2 \" }", "float"),
1869 TEST_EQ(TestValue<float>("{ Y:1 }", "float"), 1.0f);
1870 TEST_EQ(TestValue<float>("{ Y:1.0 }", "float"), 1.0f);
1871 TEST_EQ(TestValue<float>("{ Y:1. }", "float"), 1.0f);
1872 TEST_EQ(TestValue<float>("{ Y:+1. }", "float"), 1.0f);
1873 TEST_EQ(TestValue<float>("{ Y:-1. }", "float"), -1.0f);
1874 TEST_EQ(TestValue<float>("{ Y:1.e0 }", "float"), 1.0f);
1875 TEST_EQ(TestValue<float>("{ Y:1.e+0 }", "float"), 1.0f);
1876 TEST_EQ(TestValue<float>("{ Y:1.e-0 }", "float"), 1.0f);
1877 TEST_EQ(TestValue<float>("{ Y:0.125 }", "float"), 0.125f);
1878 TEST_EQ(TestValue<float>("{ Y:.125 }", "float"), 0.125f);
1879 TEST_EQ(TestValue<float>("{ Y:-.125 }", "float"), -0.125f);
1880 TEST_EQ(TestValue<float>("{ Y:+.125 }", "float"), +0.125f);
1881 TEST_EQ(TestValue<float>("{ Y:5 }", "float"), 5.0f);
1882 TEST_EQ(TestValue<float>("{ Y:\"5\" }", "float"), 5.0f);
1884 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
1885 // Old MSVC versions may have problem with this check.
1886 // https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
1887 TEST_EQ(TestValue<double>("{ Y:6.9294956446009195e15 }", "double"),
1888 6929495644600920.0);
1890 TEST_EQ(std::isnan(TestValue<double>("{ Y:nan }", "double")), 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>("{ Y:+nan }", "float")), true);
1894 TEST_EQ(std::isnan(TestValue<float>("{ Y:-nan }", "float")), true);
1895 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
1896 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
1898 TEST_EQ(TestValue<float>("{ Y:inf }", "float"), infinityf);
1899 TEST_EQ(TestValue<float>("{ Y:\"inf\" }", "float"), infinityf);
1900 TEST_EQ(TestValue<float>("{ Y:+inf }", "float"), infinityf);
1901 TEST_EQ(TestValue<float>("{ Y:-inf }", "float"), -infinityf);
1902 TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinityf);
1903 TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinityf);
1905 "{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
1909 "{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
1913 // Test binary format of float point.
1914 // https://en.cppreference.com/w/cpp/language/floating_literal
1915 // 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
1916 TEST_EQ(TestValue<double>("{ Y:0x12.34p-1 }", "double"), 9.1015625);
1917 // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
1918 TEST_EQ(TestValue<float>("{ Y:-0x0.2p0 }", "float"), -0.125f);
1919 TEST_EQ(TestValue<float>("{ Y:-0x.2p1 }", "float"), -0.25f);
1920 TEST_EQ(TestValue<float>("{ Y:0x1.2p3 }", "float"), 9.0f);
1921 TEST_EQ(TestValue<float>("{ Y:0x10.1p0 }", "float"), 16.0625f);
1922 TEST_EQ(TestValue<double>("{ Y:0x1.2p3 }", "double"), 9.0);
1923 TEST_EQ(TestValue<double>("{ Y:0x10.1p0 }", "double"), 16.0625);
1924 TEST_EQ(TestValue<double>("{ Y:0xC.68p+2 }", "double"), 49.625);
1925 TestValue<double>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
1926 TestValue<float>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
1928 #else // FLATBUFFERS_HAS_NEW_STRTOD
1929 TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");
1930 #endif // !FLATBUFFERS_HAS_NEW_STRTOD
1933 void InvalidFloatTest() {
1934 auto invalid_msg = "invalid number";
1935 auto comma_msg = "expecting: ,";
1936 TestError("table T { F:float; } root_type T; { F:1,0 }", "");
1937 TestError("table T { F:float; } root_type T; { F:. }", "");
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:-. }", invalid_msg);
1941 TestError("table T { F:float; } root_type T; { F:+. }", invalid_msg);
1942 TestError("table T { F:float; } root_type T; { F:.e }", "");
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:-.e }", invalid_msg);
1946 TestError("table T { F:float; } root_type T; { F:+.e }", invalid_msg);
1947 TestError("table T { F:float; } root_type T; { F:-e1 }", invalid_msg);
1948 TestError("table T { F:float; } root_type T; { F:+e1 }", invalid_msg);
1949 TestError("table T { F:float; } root_type T; { F:1.0e+ }", invalid_msg);
1950 TestError("table T { F:float; } root_type T; { F:1.0e- }", invalid_msg);
1951 // exponent pP is mandatory for hex-float
1952 TestError("table T { F:float; } root_type T; { F:0x0 }", invalid_msg);
1953 TestError("table T { F:float; } root_type T; { F:-0x. }", invalid_msg);
1954 TestError("table T { F:float; } root_type T; { F:0x. }", invalid_msg);
1955 // eE not exponent in hex-float!
1956 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
1957 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", 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.0p+ }", invalid_msg);
1960 TestError("table T { F:float; } root_type T; { F:0x0.0p- }", invalid_msg);
1961 TestError("table T { F:float; } root_type T; { F:0x0.0pa1 }", invalid_msg);
1962 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
1963 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
1964 TestError("table T { F:float; } root_type T; { F:0x0.0e+0 }", invalid_msg);
1965 TestError("table T { F:float; } root_type T; { F:0x0.0e-0 }", invalid_msg);
1966 TestError("table T { F:float; } root_type T; { F:0x0.0ep+ }", invalid_msg);
1967 TestError("table T { F:float; } root_type T; { F:0x0.0ep- }", invalid_msg);
1968 TestError("table T { F:float; } root_type T; { F:1.2.3 }", invalid_msg);
1969 TestError("table T { F:float; } root_type T; { F:1.2.e3 }", invalid_msg);
1970 TestError("table T { F:float; } root_type T; { F:1.2e.3 }", invalid_msg);
1971 TestError("table T { F:float; } root_type T; { F:1.2e0.3 }", invalid_msg);
1972 TestError("table T { F:float; } root_type T; { F:1.2e3. }", invalid_msg);
1973 TestError("table T { F:float; } root_type T; { F:1.2e3.0 }", invalid_msg);
1974 TestError("table T { F:float; } root_type T; { F:+-1.0 }", invalid_msg);
1975 TestError("table T { F:float; } root_type T; { F:1.0e+-1 }", invalid_msg);
1976 TestError("table T { F:float; } root_type T; { F:\"1.0e+-1\" }", invalid_msg);
1977 TestError("table T { F:float; } root_type T; { F:1.e0e }", comma_msg);
1978 TestError("table T { F:float; } root_type T; { F:0x1.p0e }", comma_msg);
1979 TestError("table T { F:float; } root_type T; { F:\" 0x10 \" }", invalid_msg);
1981 TestError("table T { F:float; } root_type T; { F:\"1,2.\" }", invalid_msg);
1982 TestError("table T { F:float; } root_type T; { F:\"1.2e3.\" }", invalid_msg);
1983 TestError("table T { F:float; } root_type T; { F:\"0x1.p0e\" }", invalid_msg);
1984 TestError("table T { F:float; } root_type T; { F:\"0x1.0\" }", invalid_msg);
1985 TestError("table T { F:float; } root_type T; { F:\" 0x1.0\" }", invalid_msg);
1986 TestError("table T { F:float; } root_type T; { F:\"+ 0\" }", invalid_msg);
1987 // disable escapes for "number-in-string"
1988 TestError("table T { F:float; } root_type T; { F:\"\\f1.2e3.\" }", "invalid");
1989 TestError("table T { F:float; } root_type T; { F:\"\\t1.2e3.\" }", "invalid");
1990 TestError("table T { F:float; } root_type T; { F:\"\\n1.2e3.\" }", "invalid");
1991 TestError("table T { F:float; } root_type T; { F:\"\\r1.2e3.\" }", "invalid");
1992 TestError("table T { F:float; } root_type T; { F:\"4\\x005\" }", "invalid");
1993 TestError("table T { F:float; } root_type T; { F:\"\'12\'\" }", invalid_msg);
1994 // null is not a number constant!
1995 TestError("table T { F:float; } root_type T; { F:\"null\" }", invalid_msg);
1996 TestError("table T { F:float; } root_type T; { F:null }", invalid_msg);
1999 void GenerateTableTextTest() {
2000 std::string schemafile;
2001 std::string jsonfile;
2003 flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2004 false, &schemafile) &&
2005 flatbuffers::LoadFile((test_data_path + "monsterdata_test.json").c_str(),
2008 auto include_test_path =
2009 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2010 const char *include_directories[] = { test_data_path.c_str(),
2011 include_test_path.c_str(), nullptr };
2012 flatbuffers::IDLOptions opt;
2013 opt.indent_step = -1;
2014 flatbuffers::Parser parser(opt);
2015 ok = parser.Parse(schemafile.c_str(), include_directories) &&
2016 parser.Parse(jsonfile.c_str(), include_directories);
2019 const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
2020 std::string jsongen;
2021 auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster",
2023 TEST_EQ(result, true);
2025 const Vec3 *pos = monster->pos();
2027 result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
2028 TEST_EQ(result, true);
2031 "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
2032 const Test &test3 = pos->test3();
2035 GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
2036 TEST_EQ(result, true);
2037 TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
2038 const Test *test4 = monster->test4()->Get(0);
2041 GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
2042 TEST_EQ(result, true);
2043 TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
2046 template<typename T>
2047 void NumericUtilsTestInteger(const char *lower, const char *upper) {
2049 TEST_EQ(flatbuffers::StringToNumber("1q", &x), false);
2051 TEST_EQ(flatbuffers::StringToNumber(upper, &x), false);
2052 TEST_EQ(x, flatbuffers::numeric_limits<T>::max());
2053 TEST_EQ(flatbuffers::StringToNumber(lower, &x), false);
2054 auto expval = flatbuffers::is_unsigned<T>::value
2055 ? flatbuffers::numeric_limits<T>::max()
2056 : flatbuffers::numeric_limits<T>::lowest();
2060 template<typename T>
2061 void NumericUtilsTestFloat(const char *lower, const char *upper) {
2063 TEST_EQ(flatbuffers::StringToNumber("", &f), false);
2064 TEST_EQ(flatbuffers::StringToNumber("1q", &f), false);
2066 TEST_EQ(flatbuffers::StringToNumber(upper, &f), true);
2067 TEST_EQ(f, +flatbuffers::numeric_limits<T>::infinity());
2068 TEST_EQ(flatbuffers::StringToNumber(lower, &f), true);
2069 TEST_EQ(f, -flatbuffers::numeric_limits<T>::infinity());
2072 void NumericUtilsTest() {
2073 NumericUtilsTestInteger<uint64_t>("-1", "18446744073709551616");
2074 NumericUtilsTestInteger<uint8_t>("-1", "256");
2075 NumericUtilsTestInteger<int64_t>("-9223372036854775809",
2076 "9223372036854775808");
2077 NumericUtilsTestInteger<int8_t>("-129", "128");
2078 NumericUtilsTestFloat<float>("-3.4029e+38", "+3.4029e+38");
2079 NumericUtilsTestFloat<float>("-1.7977e+308", "+1.7977e+308");
2082 void IsAsciiUtilsTest() {
2084 for (int cnt = 0; cnt < 256; cnt++) {
2085 auto alpha = (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
2086 auto dec = (('0' <= c) && (c <= '9'));
2087 auto hex = (('a' <= c) && (c <= 'f')) || (('A' <= c) && (c <= 'F'));
2088 TEST_EQ(flatbuffers::is_alpha(c), alpha);
2089 TEST_EQ(flatbuffers::is_alnum(c), alpha || dec);
2090 TEST_EQ(flatbuffers::is_digit(c), dec);
2091 TEST_EQ(flatbuffers::is_xdigit(c), dec || hex);
2096 void UnicodeTest() {
2097 flatbuffers::Parser parser;
2098 // Without setting allow_non_utf8 = true, we treat \x sequences as byte
2099 // sequences which are then validated as UTF-8.
2100 TEST_EQ(parser.Parse("table T { F:string; }"
2102 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2103 "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD8"
2106 std::string jsongen;
2107 parser.opts.indent_step = -1;
2109 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2110 TEST_EQ(result, true);
2111 TEST_EQ_STR(jsongen.c_str(),
2112 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2113 "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
2116 void UnicodeTestAllowNonUTF8() {
2117 flatbuffers::Parser parser;
2118 parser.opts.allow_non_utf8 = true;
2121 "table T { F:string; }"
2123 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2124 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2126 std::string jsongen;
2127 parser.opts.indent_step = -1;
2129 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2130 TEST_EQ(result, true);
2133 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2134 "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
2137 void UnicodeTestGenerateTextFailsOnNonUTF8() {
2138 flatbuffers::Parser parser;
2139 // Allow non-UTF-8 initially to model what happens when we load a binary
2140 // flatbuffer from disk which contains non-UTF-8 strings.
2141 parser.opts.allow_non_utf8 = true;
2144 "table T { F:string; }"
2146 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2147 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2149 std::string jsongen;
2150 parser.opts.indent_step = -1;
2151 // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates
2153 parser.opts.allow_non_utf8 = false;
2155 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2156 TEST_EQ(result, false);
2159 void UnicodeSurrogatesTest() {
2160 flatbuffers::Parser parser;
2162 TEST_EQ(parser.Parse("table T { F:string (id: 0); }"
2164 "{ F:\"\\uD83D\\uDCA9\"}"),
2166 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
2167 parser.builder_.GetBufferPointer());
2168 auto string = root->GetPointer<flatbuffers::String *>(
2169 flatbuffers::FieldIndexToOffset(0));
2170 TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
2173 void UnicodeInvalidSurrogatesTest() {
2175 "table T { F:string; }"
2178 "unpaired high surrogate");
2180 "table T { F:string; }"
2182 "{ F:\"\\uD800abcd\"}",
2183 "unpaired high surrogate");
2185 "table T { F:string; }"
2187 "{ F:\"\\uD800\\n\"}",
2188 "unpaired high surrogate");
2190 "table T { F:string; }"
2192 "{ F:\"\\uD800\\uD800\"}",
2193 "multiple high surrogates");
2195 "table T { F:string; }"
2198 "unpaired low surrogate");
2201 void InvalidUTF8Test() {
2202 // "1 byte" pattern, under min length of 2 bytes
2204 "table T { F:string; }"
2207 "illegal UTF-8 sequence");
2208 // 2 byte pattern, string too short
2210 "table T { F:string; }"
2213 "illegal UTF-8 sequence");
2214 // 3 byte pattern, string too short
2216 "table T { F:string; }"
2218 "{ F:\"\xEF\xBF\"}",
2219 "illegal UTF-8 sequence");
2220 // 4 byte pattern, string too short
2222 "table T { F:string; }"
2224 "{ F:\"\xF7\xBF\xBF\"}",
2225 "illegal UTF-8 sequence");
2226 // "5 byte" pattern, string too short
2228 "table T { F:string; }"
2230 "{ F:\"\xFB\xBF\xBF\xBF\"}",
2231 "illegal UTF-8 sequence");
2232 // "6 byte" pattern, string too short
2234 "table T { F:string; }"
2236 "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}",
2237 "illegal UTF-8 sequence");
2238 // "7 byte" pattern, string too short
2240 "table T { F:string; }"
2242 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}",
2243 "illegal UTF-8 sequence");
2244 // "5 byte" pattern, over max length of 4 bytes
2246 "table T { F:string; }"
2248 "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}",
2249 "illegal UTF-8 sequence");
2250 // "6 byte" pattern, over max length of 4 bytes
2252 "table T { F:string; }"
2254 "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}",
2255 "illegal UTF-8 sequence");
2256 // "7 byte" pattern, over max length of 4 bytes
2258 "table T { F:string; }"
2260 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}",
2261 "illegal UTF-8 sequence");
2263 // Three invalid encodings for U+000A (\n, aka NEWLINE)
2265 "table T { F:string; }"
2267 "{ F:\"\xC0\x8A\"}",
2268 "illegal UTF-8 sequence");
2270 "table T { F:string; }"
2272 "{ F:\"\xE0\x80\x8A\"}",
2273 "illegal UTF-8 sequence");
2275 "table T { F:string; }"
2277 "{ F:\"\xF0\x80\x80\x8A\"}",
2278 "illegal UTF-8 sequence");
2280 // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
2282 "table T { F:string; }"
2284 "{ F:\"\xE0\x81\xA9\"}",
2285 "illegal UTF-8 sequence");
2287 "table T { F:string; }"
2289 "{ F:\"\xF0\x80\x81\xA9\"}",
2290 "illegal UTF-8 sequence");
2292 // Invalid encoding for U+20AC (EURO SYMBOL)
2294 "table T { F:string; }"
2296 "{ F:\"\xF0\x82\x82\xAC\"}",
2297 "illegal UTF-8 sequence");
2299 // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in
2302 "table T { F:string; }"
2304 // U+10400 "encoded" as U+D801 U+DC00
2305 "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}",
2306 "illegal UTF-8 sequence");
2308 // Check independence of identifier from locale.
2309 std::string locale_ident;
2310 locale_ident += "table T { F";
2311 locale_ident += static_cast<char>(-32); // unsigned 0xE0
2312 locale_ident += " :string; }";
2313 locale_ident += "root_type T;";
2314 locale_ident += "{}";
2315 TestError(locale_ident.c_str(), "");
2318 void UnknownFieldsTest() {
2319 flatbuffers::IDLOptions opts;
2320 opts.skip_unexpected_fields_in_json = true;
2321 flatbuffers::Parser parser(opts);
2323 TEST_EQ(parser.Parse("table T { str:string; i:int;}"
2326 "unknown_string:\"test\","
2327 "\"unknown_string\":\"test\","
2329 "unknown_float:1.0,"
2330 "unknown_array: [ 1, 2, 3, 4],"
2331 "unknown_object: { i: 10 },"
2332 "\"unknown_object\": { \"i\": 10 },"
2336 std::string jsongen;
2337 parser.opts.indent_step = -1;
2339 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2340 TEST_EQ(result, true);
2341 TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
2344 void ParseUnionTest() {
2345 // Unions must be parseable with the type field following the object.
2346 flatbuffers::Parser parser;
2347 TEST_EQ(parser.Parse("table T { A:int; }"
2351 "{ X:{ A:1 }, X_type: T }"),
2353 // Unions must be parsable with prefixed namespace.
2354 flatbuffers::Parser parser2;
2355 TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
2356 "table B { e:U; } root_type B;"
2357 "{ e_type: N_A, e: {} }"),
2361 void InvalidNestedFlatbufferTest() {
2362 // First, load and parse FlatBuffer schema (.fbs)
2363 std::string schemafile;
2364 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2365 false, &schemafile),
2367 auto include_test_path =
2368 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2369 const char *include_directories[] = { test_data_path.c_str(),
2370 include_test_path.c_str(), nullptr };
2371 flatbuffers::Parser parser1;
2372 TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
2374 // "color" inside nested flatbuffer contains invalid enum value
2375 TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
2376 "\"Leela\", color: \"nonexistent\"}}"),
2380 void EvolutionTest() {
2381 // VS10 does not support typed enums, exclude from tests
2382 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2383 const int NUM_VERSIONS = 2;
2384 std::string schemas[NUM_VERSIONS];
2385 std::string jsonfiles[NUM_VERSIONS];
2386 std::vector<uint8_t> binaries[NUM_VERSIONS];
2388 flatbuffers::IDLOptions idl_opts;
2389 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2390 flatbuffers::Parser parser(idl_opts);
2392 // Load all the schema versions and their associated data.
2393 for (int i = 0; i < NUM_VERSIONS; ++i) {
2394 std::string schema = test_data_path + "evolution_test/evolution_v" +
2395 flatbuffers::NumToString(i + 1) + ".fbs";
2396 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2397 std::string json = test_data_path + "evolution_test/evolution_v" +
2398 flatbuffers::NumToString(i + 1) + ".json";
2399 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2401 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2402 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2404 auto bufLen = parser.builder_.GetSize();
2405 auto buf = parser.builder_.GetBufferPointer();
2406 binaries[i].reserve(bufLen);
2407 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2410 // Assert that all the verifiers for the different schema versions properly verify any version data.
2411 for (int i = 0; i < NUM_VERSIONS; ++i) {
2412 flatbuffers::Verifier verifier(&binaries[i].front(), binaries[i].size());
2413 TEST_ASSERT(Evolution::V1::VerifyRootBuffer(verifier));
2414 TEST_ASSERT(Evolution::V2::VerifyRootBuffer(verifier));
2417 // Test backwards compatibility by reading old data with an evolved schema.
2418 auto root_v1_viewed_from_v2 = Evolution::V2::GetRoot(&binaries[0].front());
2419 // field 'j' is new in version 2, so it should be null.
2420 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->j());
2421 // field 'k' is new in version 2 with a default of 56.
2422 TEST_EQ(root_v1_viewed_from_v2->k(), 56);
2423 // field 'c' of 'TableA' is new in version 2, so it should be null.
2424 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->e()->c());
2425 // 'TableC' was added to field 'c' union in version 2, so it should be null.
2426 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->c_as_TableC());
2427 // The field 'c' union should be of type 'TableB' regardless of schema version
2428 TEST_ASSERT(root_v1_viewed_from_v2->c_type() == Evolution::V2::Union::TableB);
2429 // The field 'f' was renamed to 'ff' in version 2, it should still be readable.
2430 TEST_EQ(root_v1_viewed_from_v2->ff()->a(), 16);
2432 // Test forwards compatibility by reading new data with an old schema.
2433 auto root_v2_viewed_from_v1 = Evolution::V1::GetRoot(&binaries[1].front());
2434 // The field 'c' union in version 2 is a new table (index = 3) and should still be accessible,
2435 // but not interpretable.
2436 TEST_EQ(static_cast<uint8_t>(root_v2_viewed_from_v1->c_type()), 3);
2437 TEST_NOTNULL(root_v2_viewed_from_v1->c());
2438 // The field 'd' enum in verison 2 has new members and should still be accessible, but not interpretable.
2439 TEST_EQ(static_cast<int8_t>(root_v2_viewed_from_v1->d()), 3);
2440 // The field 'a' in version 2 is deprecated and should return the default value (0) instead of the value stored in
2441 // the in the buffer (42).
2442 TEST_EQ(root_v2_viewed_from_v1->a(), 0);
2443 // The field 'ff' was originally named 'f' in version 1, it should still be readable.
2444 TEST_EQ(root_v2_viewed_from_v1->f()->a(), 35);
2448 void UnionVectorTest() {
2449 // load FlatBuffer fbs schema and json.
2450 std::string schemafile, jsonfile;
2451 TEST_EQ(flatbuffers::LoadFile(
2452 (test_data_path + "union_vector/union_vector.fbs").c_str(), false,
2455 TEST_EQ(flatbuffers::LoadFile(
2456 (test_data_path + "union_vector/union_vector.json").c_str(),
2461 flatbuffers::IDLOptions idl_opts;
2462 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2463 flatbuffers::Parser parser(idl_opts);
2464 TEST_EQ(parser.Parse(schemafile.c_str()), true);
2466 flatbuffers::FlatBufferBuilder fbb;
2469 std::vector<uint8_t> types;
2470 types.push_back(static_cast<uint8_t>(Character_Belle));
2471 types.push_back(static_cast<uint8_t>(Character_MuLan));
2472 types.push_back(static_cast<uint8_t>(Character_BookFan));
2473 types.push_back(static_cast<uint8_t>(Character_Other));
2474 types.push_back(static_cast<uint8_t>(Character_Unused));
2477 std::vector<flatbuffers::Offset<void>> characters;
2478 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
2479 characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
2480 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
2481 characters.push_back(fbb.CreateString("Other").Union());
2482 characters.push_back(fbb.CreateString("Unused").Union());
2485 const auto movie_offset =
2486 CreateMovie(fbb, Character_Rapunzel,
2487 fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
2488 fbb.CreateVector(types), fbb.CreateVector(characters));
2489 FinishMovieBuffer(fbb, movie_offset);
2491 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
2492 TEST_EQ(VerifyMovieBuffer(verifier), true);
2494 auto flat_movie = GetMovie(fbb.GetBufferPointer());
2496 auto TestMovie = [](const Movie *movie) {
2497 TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
2499 auto cts = movie->characters_type();
2500 TEST_EQ(movie->characters_type()->size(), 5);
2501 TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
2502 TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
2503 TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
2504 TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
2505 TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
2507 auto rapunzel = movie->main_character_as_Rapunzel();
2508 TEST_NOTNULL(rapunzel);
2509 TEST_EQ(rapunzel->hair_length(), 6);
2511 auto cs = movie->characters();
2512 TEST_EQ(cs->size(), 5);
2513 auto belle = cs->GetAs<BookReader>(0);
2514 TEST_EQ(belle->books_read(), 7);
2515 auto mu_lan = cs->GetAs<Attacker>(1);
2516 TEST_EQ(mu_lan->sword_attack_damage(), 5);
2517 auto book_fan = cs->GetAs<BookReader>(2);
2518 TEST_EQ(book_fan->books_read(), 2);
2519 auto other = cs->GetAsString(3);
2520 TEST_EQ_STR(other->c_str(), "Other");
2521 auto unused = cs->GetAsString(4);
2522 TEST_EQ_STR(unused->c_str(), "Unused");
2525 TestMovie(flat_movie);
2527 // Also test the JSON we loaded above.
2528 TEST_EQ(parser.Parse(jsonfile.c_str()), true);
2529 auto jbuf = parser.builder_.GetBufferPointer();
2530 flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
2531 TEST_EQ(VerifyMovieBuffer(jverifier), true);
2532 TestMovie(GetMovie(jbuf));
2534 auto movie_object = flat_movie->UnPack();
2535 TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
2536 TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
2537 TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
2538 TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
2539 TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
2540 TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
2543 fbb.Finish(Movie::Pack(fbb, movie_object));
2545 delete movie_object;
2547 auto repacked_movie = GetMovie(fbb.GetBufferPointer());
2549 TestMovie(repacked_movie);
2551 // Generate text using mini-reflection.
2553 flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
2556 "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
2557 "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
2558 "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
2559 "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
2561 flatbuffers::ToStringVisitor visitor("\n", true, " ");
2562 IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
2563 TEST_EQ_STR(visitor.s.c_str(),
2565 " \"main_character_type\": \"Rapunzel\",\n"
2566 " \"main_character\": {\n"
2567 " \"hair_length\": 6\n"
2569 " \"characters_type\": [\n"
2576 " \"characters\": [\n"
2578 " \"books_read\": 7\n"
2581 " \"sword_attack_damage\": 5\n"
2584 " \"books_read\": 2\n"
2591 // Generate text using parsed schema.
2592 std::string jsongen;
2593 auto result = GenerateText(parser, fbb.GetBufferPointer(), &jsongen);
2594 TEST_EQ(result, true);
2595 TEST_EQ_STR(jsongen.c_str(),
2597 " main_character_type: \"Rapunzel\",\n"
2598 " main_character: {\n"
2601 " characters_type: [\n"
2613 " sword_attack_damage: 5\n"
2623 // Simple test with reflection.
2625 auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
2626 auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
2627 fbb.GetBufferPointer(), fbb.GetSize());
2630 flatbuffers::Parser parser2(idl_opts);
2631 TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
2632 "union Any { Bool }"
2633 "table Root { a:Any; }"
2636 TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
2639 void ConformTest() {
2640 flatbuffers::Parser parser;
2641 TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
2643 auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
2644 const char *expected_err) {
2645 flatbuffers::Parser parser2;
2646 TEST_EQ(parser2.Parse(test), true);
2647 auto err = parser2.ConformTo(parser1);
2648 TEST_NOTNULL(strstr(err.c_str(), expected_err));
2651 test_conform(parser, "table T { A:byte; }", "types differ for field");
2652 test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
2653 test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
2654 test_conform(parser, "table T { B:float; }",
2655 "field renamed to different type");
2656 test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
2659 void ParseProtoBufAsciiTest() {
2660 // We can put the parser in a mode where it will accept JSON that looks more
2661 // like Protobuf ASCII, for users that have data in that format.
2662 // This uses no "" for field names (which we already support by default,
2663 // omits `,`, `:` before `{` and a couple of other features.
2664 flatbuffers::Parser parser;
2665 parser.opts.protobuf_ascii_alike = true;
2667 parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
2669 TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
2670 // Similarly, in text output, it should omit these.
2672 auto ok = flatbuffers::GenerateText(
2673 parser, parser.builder_.GetBufferPointer(), &text);
2675 TEST_EQ_STR(text.c_str(),
2676 "{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n");
2679 void FlexBuffersTest() {
2680 flexbuffers::Builder slb(512,
2681 flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
2683 // Write the equivalent of:
2684 // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ],
2685 // foo: 100, bool: true, mymap: { foo: "Fred" } }
2687 #ifndef FLATBUFFERS_CPP98_STL
2688 // It's possible to do this without std::function support as well.
2690 slb.Vector("vec", [&]() {
2691 slb += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2693 slb.IndirectFloat(4.0f);
2694 auto i_f = slb.LastValue();
2695 uint8_t blob[] = { 77 };
2698 slb.ReuseValue(i_f);
2700 int ints[] = { 1, 2, 3 };
2701 slb.Vector("bar", ints, 3);
2702 slb.FixedTypedVector("bar3", ints, 3);
2703 bool bools[] = {true, false, true, false};
2704 slb.Vector("bools", bools, 4);
2705 slb.Bool("bool", true);
2706 slb.Double("foo", 100);
2707 slb.Map("mymap", [&]() {
2708 slb.String("foo", "Fred"); // Testing key and string reuse.
2713 // It's possible to do this without std::function support as well.
2714 slb.Map([](flexbuffers::Builder& slb2) {
2715 slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
2716 slb3 += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2718 slb3.IndirectFloat(4.0f);
2719 auto i_f = slb3.LastValue();
2720 uint8_t blob[] = { 77 };
2723 slb3.ReuseValue(i_f);
2725 int ints[] = { 1, 2, 3 };
2726 slb2.Vector("bar", ints, 3);
2727 slb2.FixedTypedVector("bar3", ints, 3);
2728 slb2.Bool("bool", true);
2729 slb2.Double("foo", 100);
2730 slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
2731 slb3.String("foo", "Fred"); // Testing key and string reuse.
2735 #endif // FLATBUFFERS_CPP98_STL
2737 #ifdef FLATBUFFERS_TEST_VERBOSE
2738 for (size_t i = 0; i < slb.GetBuffer().size(); i++)
2739 printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
2744 auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
2745 TEST_EQ(map.size(), 7);
2746 auto vec = map["vec"].AsVector();
2747 TEST_EQ(vec.size(), 6);
2748 TEST_EQ(vec[0].AsInt64(), -100);
2749 TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
2750 TEST_EQ(vec[1].AsInt64(), 0); // Number parsing failed.
2751 TEST_EQ(vec[2].AsDouble(), 4.0);
2752 TEST_EQ(vec[2].AsString().IsTheEmptyString(), true); // Wrong Type.
2753 TEST_EQ_STR(vec[2].AsString().c_str(), ""); // This still works though.
2754 TEST_EQ_STR(vec[2].ToString().c_str(), "4.0"); // Or have it converted.
2755 // Few tests for templated version of As.
2756 TEST_EQ(vec[0].As<int64_t>(), -100);
2757 TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
2758 TEST_EQ(vec[1].As<int64_t>(), 0); // Number parsing failed.
2759 TEST_EQ(vec[2].As<double>(), 4.0);
2760 // Test that the blob can be accessed.
2761 TEST_EQ(vec[3].IsBlob(), true);
2762 auto blob = vec[3].AsBlob();
2763 TEST_EQ(blob.size(), 1);
2764 TEST_EQ(blob.data()[0], 77);
2765 TEST_EQ(vec[4].IsBool(), true); // Check if type is a bool
2766 TEST_EQ(vec[4].AsBool(), false); // Check if value is false
2767 TEST_EQ(vec[5].AsDouble(), 4.0); // This is shared with vec[2] !
2768 auto tvec = map["bar"].AsTypedVector();
2769 TEST_EQ(tvec.size(), 3);
2770 TEST_EQ(tvec[2].AsInt8(), 3);
2771 auto tvec3 = map["bar3"].AsFixedTypedVector();
2772 TEST_EQ(tvec3.size(), 3);
2773 TEST_EQ(tvec3[2].AsInt8(), 3);
2774 TEST_EQ(map["bool"].AsBool(), true);
2775 auto tvecb = map["bools"].AsTypedVector();
2776 TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
2777 TEST_EQ(map["foo"].AsUInt8(), 100);
2778 TEST_EQ(map["unknown"].IsNull(), true);
2779 auto mymap = map["mymap"].AsMap();
2780 // These should be equal by pointer equality, since key and value are shared.
2781 TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
2782 TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
2783 // We can mutate values in the buffer.
2784 TEST_EQ(vec[0].MutateInt(-99), true);
2785 TEST_EQ(vec[0].AsInt64(), -99);
2786 TEST_EQ(vec[1].MutateString("John"), true); // Size must match.
2787 TEST_EQ_STR(vec[1].AsString().c_str(), "John");
2788 TEST_EQ(vec[1].MutateString("Alfred"), false); // Too long.
2789 TEST_EQ(vec[2].MutateFloat(2.0f), true);
2790 TEST_EQ(vec[2].AsFloat(), 2.0f);
2791 TEST_EQ(vec[2].MutateFloat(3.14159), false); // Double does not fit in float.
2792 TEST_EQ(vec[4].AsBool(), false); // Is false before change
2793 TEST_EQ(vec[4].MutateBool(true), true); // Can change a bool
2794 TEST_EQ(vec[4].AsBool(), true); // Changed bool is now true
2797 flatbuffers::Parser parser;
2799 auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
2800 TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
2801 auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
2802 auto jmap = jroot.AsMap();
2803 auto jvec = jmap["a"].AsVector();
2804 TEST_EQ(jvec[0].AsInt64(), 123);
2805 TEST_EQ(jvec[1].AsDouble(), 456.0);
2806 TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
2807 TEST_EQ(jmap["c"].IsBool(), true); // Parsed correctly to a bool
2808 TEST_EQ(jmap["c"].AsBool(), true); // Parsed correctly to true
2809 TEST_EQ(jmap["d"].IsBool(), true); // Parsed correctly to a bool
2810 TEST_EQ(jmap["d"].AsBool(), false); // Parsed correctly to false
2811 // And from FlexBuffer back to JSON:
2812 auto jsonback = jroot.ToString();
2813 TEST_EQ_STR(jsontest, jsonback.c_str());
2816 void TypeAliasesTest() {
2817 flatbuffers::FlatBufferBuilder builder;
2819 builder.Finish(CreateTypeAliases(
2820 builder, flatbuffers::numeric_limits<int8_t>::min(),
2821 flatbuffers::numeric_limits<uint8_t>::max(),
2822 flatbuffers::numeric_limits<int16_t>::min(),
2823 flatbuffers::numeric_limits<uint16_t>::max(),
2824 flatbuffers::numeric_limits<int32_t>::min(),
2825 flatbuffers::numeric_limits<uint32_t>::max(),
2826 flatbuffers::numeric_limits<int64_t>::min(),
2827 flatbuffers::numeric_limits<uint64_t>::max(), 2.3f, 2.3));
2829 auto p = builder.GetBufferPointer();
2830 auto ta = flatbuffers::GetRoot<TypeAliases>(p);
2832 TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
2833 TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
2834 TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
2835 TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
2836 TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
2837 TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
2838 TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
2839 TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
2840 TEST_EQ(ta->f32(), 2.3f);
2841 TEST_EQ(ta->f64(), 2.3);
2842 using namespace flatbuffers; // is_same
2843 static_assert(is_same<decltype(ta->i8()), int8_t>::value, "invalid type");
2844 static_assert(is_same<decltype(ta->i16()), int16_t>::value, "invalid type");
2845 static_assert(is_same<decltype(ta->i32()), int32_t>::value, "invalid type");
2846 static_assert(is_same<decltype(ta->i64()), int64_t>::value, "invalid type");
2847 static_assert(is_same<decltype(ta->u8()), uint8_t>::value, "invalid type");
2848 static_assert(is_same<decltype(ta->u16()), uint16_t>::value, "invalid type");
2849 static_assert(is_same<decltype(ta->u32()), uint32_t>::value, "invalid type");
2850 static_assert(is_same<decltype(ta->u64()), uint64_t>::value, "invalid type");
2851 static_assert(is_same<decltype(ta->f32()), float>::value, "invalid type");
2852 static_assert(is_same<decltype(ta->f64()), double>::value, "invalid type");
2855 void EndianSwapTest() {
2856 TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
2857 TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
2859 TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
2860 0xEFCDAB9078563412);
2861 TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
2864 void UninitializedVectorTest() {
2865 flatbuffers::FlatBufferBuilder builder;
2867 Test *buf = nullptr;
2868 auto vector_offset =
2869 builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
2871 buf[0] = Test(10, 20);
2872 buf[1] = Test(30, 40);
2874 auto required_name = builder.CreateString("myMonster");
2875 auto monster_builder = MonsterBuilder(builder);
2876 monster_builder.add_name(
2877 required_name); // required field mandated for monster.
2878 monster_builder.add_test4(vector_offset);
2879 builder.Finish(monster_builder.Finish());
2881 auto p = builder.GetBufferPointer();
2882 auto uvt = flatbuffers::GetRoot<Monster>(p);
2884 auto vec = uvt->test4();
2886 auto test_0 = vec->Get(0);
2887 auto test_1 = vec->Get(1);
2888 TEST_EQ(test_0->a(), 10);
2889 TEST_EQ(test_0->b(), 20);
2890 TEST_EQ(test_1->a(), 30);
2891 TEST_EQ(test_1->b(), 40);
2894 void EqualOperatorTest() {
2897 TEST_EQ(b == a, true);
2898 TEST_EQ(b != a, false);
2901 TEST_EQ(b == a, false);
2902 TEST_EQ(b != a, true);
2904 TEST_EQ(b == a, true);
2905 TEST_EQ(b != a, false);
2907 b.inventory.push_back(3);
2908 TEST_EQ(b == a, false);
2909 TEST_EQ(b != a, true);
2910 b.inventory.clear();
2911 TEST_EQ(b == a, true);
2912 TEST_EQ(b != a, false);
2914 b.test.type = Any_Monster;
2915 TEST_EQ(b == a, false);
2916 TEST_EQ(b != a, true);
2919 // For testing any binaries, e.g. from fuzzing.
2920 void LoadVerifyBinaryTest() {
2922 if (flatbuffers::LoadFile(
2923 (test_data_path + "fuzzer/your-filename-here").c_str(), true,
2925 flatbuffers::Verifier verifier(
2926 reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
2927 TEST_EQ(VerifyMonsterBuffer(verifier), true);
2931 void CreateSharedStringTest() {
2932 flatbuffers::FlatBufferBuilder builder;
2933 const auto one1 = builder.CreateSharedString("one");
2934 const auto two = builder.CreateSharedString("two");
2935 const auto one2 = builder.CreateSharedString("one");
2936 TEST_EQ(one1.o, one2.o);
2937 const auto onetwo = builder.CreateSharedString("onetwo");
2938 TEST_EQ(onetwo.o != one1.o, true);
2939 TEST_EQ(onetwo.o != two.o, true);
2941 // Support for embedded nulls
2942 const char chars_b[] = { 'a', '\0', 'b' };
2943 const char chars_c[] = { 'a', '\0', 'c' };
2944 const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
2945 const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
2946 const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
2947 TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
2948 TEST_EQ(null_b1.o, null_b2.o);
2950 // Put the strings into an array for round trip verification.
2951 const flatbuffers::Offset<flatbuffers::String> array[7] = {
2952 one1, two, one2, onetwo, null_b1, null_c, null_b2
2954 const auto vector_offset =
2955 builder.CreateVector(array, flatbuffers::uoffset_t(7));
2956 MonsterBuilder monster_builder(builder);
2957 monster_builder.add_name(two);
2958 monster_builder.add_testarrayofstring(vector_offset);
2959 builder.Finish(monster_builder.Finish());
2961 // Read the Monster back.
2962 const auto *monster =
2963 flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
2964 TEST_EQ_STR(monster->name()->c_str(), "two");
2965 const auto *testarrayofstring = monster->testarrayofstring();
2966 TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
2967 const auto &a = *testarrayofstring;
2968 TEST_EQ_STR(a[0]->c_str(), "one");
2969 TEST_EQ_STR(a[1]->c_str(), "two");
2970 TEST_EQ_STR(a[2]->c_str(), "one");
2971 TEST_EQ_STR(a[3]->c_str(), "onetwo");
2972 TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
2973 TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
2974 TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
2976 // Make sure String::operator< works, too, since it is related to
2977 // StringOffsetCompare.
2978 TEST_EQ((*a[0]) < (*a[1]), true);
2979 TEST_EQ((*a[1]) < (*a[0]), false);
2980 TEST_EQ((*a[1]) < (*a[2]), false);
2981 TEST_EQ((*a[2]) < (*a[1]), true);
2982 TEST_EQ((*a[4]) < (*a[3]), true);
2983 TEST_EQ((*a[5]) < (*a[4]), false);
2984 TEST_EQ((*a[5]) < (*a[4]), false);
2985 TEST_EQ((*a[6]) < (*a[5]), true);
2988 void FixedLengthArrayTest() {
2989 // VS10 does not support typed enums, exclude from tests
2990 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2991 // Generate an ArrayTable containing one ArrayStruct.
2992 flatbuffers::FlatBufferBuilder fbb;
2993 MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
2994 TEST_NOTNULL(nStruct0.mutable_a());
2995 nStruct0.mutable_a()->Mutate(0, 1);
2996 nStruct0.mutable_a()->Mutate(1, 2);
2997 TEST_NOTNULL(nStruct0.mutable_c());
2998 nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
2999 nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3000 TEST_NOTNULL(nStruct0.mutable_d());
3001 nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
3002 nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
3003 MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
3004 TEST_NOTNULL(nStruct1.mutable_a());
3005 nStruct1.mutable_a()->Mutate(0, 3);
3006 nStruct1.mutable_a()->Mutate(1, 4);
3007 TEST_NOTNULL(nStruct1.mutable_c());
3008 nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3009 nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3010 TEST_NOTNULL(nStruct1.mutable_d());
3011 nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
3012 nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
3013 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
3014 TEST_NOTNULL(aStruct.b());
3015 TEST_NOTNULL(aStruct.mutable_b());
3016 TEST_NOTNULL(aStruct.mutable_d());
3017 TEST_NOTNULL(aStruct.mutable_f());
3018 for (int i = 0; i < aStruct.b()->size(); i++)
3019 aStruct.mutable_b()->Mutate(i, i + 1);
3020 aStruct.mutable_d()->Mutate(0, nStruct0);
3021 aStruct.mutable_d()->Mutate(1, nStruct1);
3022 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
3025 // Verify correctness of the ArrayTable.
3026 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
3027 MyGame::Example::VerifyArrayTableBuffer(verifier);
3028 auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
3029 auto mArStruct = p->mutable_a();
3030 TEST_NOTNULL(mArStruct);
3031 TEST_NOTNULL(mArStruct->b());
3032 TEST_NOTNULL(mArStruct->d());
3033 TEST_NOTNULL(mArStruct->f());
3034 TEST_NOTNULL(mArStruct->mutable_b());
3035 TEST_NOTNULL(mArStruct->mutable_d());
3036 TEST_NOTNULL(mArStruct->mutable_f());
3037 mArStruct->mutable_b()->Mutate(14, -14);
3038 TEST_EQ(mArStruct->a(), 2);
3039 TEST_EQ(mArStruct->b()->size(), 15);
3040 TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14);
3041 TEST_EQ(mArStruct->c(), 12);
3042 TEST_NOTNULL(mArStruct->d()->Get(0));
3043 TEST_NOTNULL(mArStruct->d()->Get(0)->a());
3044 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
3045 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
3046 TEST_NOTNULL(mArStruct->d()->Get(1));
3047 TEST_NOTNULL(mArStruct->d()->Get(1)->a());
3048 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
3049 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
3050 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
3051 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
3052 mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
3053 TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
3054 TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
3055 TEST_NOTNULL(mArStruct->d()->Get(0)->c());
3056 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
3057 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
3058 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3059 mArStruct->d()->Get(0)->d()->Get(0));
3060 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3061 mArStruct->d()->Get(0)->d()->Get(1));
3062 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
3063 TEST_NOTNULL(mArStruct->d()->Get(1)->c());
3064 TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
3065 TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
3066 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3067 mArStruct->d()->Get(1)->d()->Get(0));
3068 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3069 mArStruct->d()->Get(1)->d()->Get(1));
3070 for (int i = 0; i < mArStruct->b()->size() - 1; i++)
3071 TEST_EQ(mArStruct->b()->Get(i), i + 1);
3073 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
3074 TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
3078 void NativeTypeTest() {
3081 Geometry::ApplicationDataT src_data;
3082 src_data.vectors.reserve(N);
3084 for (int i = 0; i < N; ++i) {
3085 src_data.vectors.push_back(
3086 Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
3089 flatbuffers::FlatBufferBuilder fbb;
3090 fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
3092 auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
3094 for (int i = 0; i < N; ++i) {
3095 Native::Vector3D &v = dstDataT->vectors[i];
3096 TEST_EQ(v.x, 10 * i + 0.1f);
3097 TEST_EQ(v.y, 10 * i + 0.2f);
3098 TEST_EQ(v.z, 10 * i + 0.3f);
3102 void FixedLengthArrayJsonTest(bool binary) {
3103 // VS10 does not support typed enums, exclude from tests
3104 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3105 // load FlatBuffer schema (.fbs) and JSON from disk
3106 std::string schemafile;
3107 std::string jsonfile;
3109 flatbuffers::LoadFile(
3110 (test_data_path + "arrays_test." + (binary ? "bfbs" : "fbs")).c_str(),
3111 binary, &schemafile),
3113 TEST_EQ(flatbuffers::LoadFile((test_data_path + "arrays_test.golden").c_str(),
3117 // parse schema first, so we can use it to parse the data after
3118 flatbuffers::Parser parserOrg, parserGen;
3120 flatbuffers::Verifier verifier(
3121 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
3123 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3124 TEST_EQ(parserOrg.Deserialize((const uint8_t *)schemafile.c_str(),
3127 TEST_EQ(parserGen.Deserialize((const uint8_t *)schemafile.c_str(),
3131 TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
3132 TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
3134 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3136 // First, verify it, just in case:
3137 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3138 parserOrg.builder_.GetSize());
3139 TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
3142 std::string jsonGen;
3144 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3148 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3150 // Verify buffer from generated JSON
3151 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3152 parserGen.builder_.GetSize());
3153 TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
3155 // Compare generated buffer to original
3156 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3157 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3158 parserGen.builder_.GetBufferPointer(),
3159 parserOrg.builder_.GetSize()),
3166 int FlatBufferTests() {
3169 // Run our various test suites:
3172 auto flatbuf1 = CreateFlatBufferTest(rawbuf);
3173 #if !defined(FLATBUFFERS_CPP98_STL)
3174 auto flatbuf = std::move(flatbuf1); // Test move assignment.
3176 auto &flatbuf = flatbuf1;
3177 #endif // !defined(FLATBUFFERS_CPP98_STL)
3179 TriviallyCopyableTest();
3181 AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
3183 AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
3185 MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
3187 ObjectFlatBuffersTest(flatbuf.data());
3189 MiniReflectFlatBuffersTest(flatbuf.data());
3193 #ifndef FLATBUFFERS_NO_FILE_TESTS
3194 #ifdef FLATBUFFERS_TEST_PATH_PREFIX
3195 test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
3198 ParseAndGenerateTextTest(false);
3199 ParseAndGenerateTextTest(true);
3200 FixedLengthArrayJsonTest(false);
3201 FixedLengthArrayJsonTest(true);
3202 ReflectionTest(flatbuf.data(), flatbuf.size());
3204 ParseProtoTestWithIncludes();
3207 LoadVerifyBinaryTest();
3208 GenerateTableTextTest();
3220 EnumOutOfRangeTest();
3221 IntegerOutOfRangeTest();
3222 IntegerBoundaryTest();
3224 UnicodeTestAllowNonUTF8();
3225 UnicodeTestGenerateTextFailsOnNonUTF8();
3226 UnicodeSurrogatesTest();
3227 UnicodeInvalidSurrogatesTest();
3229 UnknownFieldsTest();
3231 InvalidNestedFlatbufferTest();
3233 ParseProtoBufAsciiTest();
3236 CreateSharedStringTest();
3240 UninitializedVectorTest();
3241 EqualOperatorTest();
3246 TestMonsterExtraFloats();
3247 FixedLengthArrayTest();
3252 int main(int /*argc*/, const char * /*argv*/[]) {
3255 std::string req_locale;
3256 if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
3258 TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
3259 req_locale.c_str());
3260 req_locale = flatbuffers::RemoveStringQuotes(req_locale);
3261 std::string the_locale;
3263 flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
3264 TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
3268 FlatBufferBuilderTest();
3270 if (!testing_fails) {
3271 TEST_OUTPUT_LINE("ALL TESTS PASSED");
3273 TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
3275 return CloseTestEngine();