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"
42 #include "native_type_test_generated.h"
43 #include "test_assert.h"
45 #include "flatbuffers/flexbuffers.h"
48 // Check that char* and uint8_t* are interoperable types.
49 // The reinterpret_cast<> between the pointers are used to simplify data loading.
50 static_assert(flatbuffers::is_same<uint8_t, char>::value ||
51 flatbuffers::is_same<uint8_t, unsigned char>::value,
52 "unexpected uint8_t type");
54 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
55 // Ensure IEEE-754 support if tests of floats with NaN/Inf will run.
56 static_assert(std::numeric_limits<float>::is_iec559 &&
57 std::numeric_limits<double>::is_iec559,
58 "IEC-559 (IEEE-754) standard required");
62 // Shortcuts for the infinity.
63 static const auto infinityf = std::numeric_limits<float>::infinity();
64 static const auto infinityd = std::numeric_limits<double>::infinity();
66 using namespace MyGame::Example;
68 void FlatBufferBuilderTest();
70 // Include simple random number generator to ensure results will be the
71 // same cross platform.
72 // http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
73 uint32_t lcg_seed = 48271;
76 (static_cast<uint64_t>(lcg_seed) * 279470273UL) % 4294967291UL;
78 void lcg_reset() { lcg_seed = 48271; }
80 std::string test_data_path =
81 #ifdef BAZEL_TEST_DATA_PATH
82 "../com_github_google_flatbuffers/tests/";
87 // example of how to build up a serialized buffer algorithmically:
88 flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) {
89 flatbuffers::FlatBufferBuilder builder;
91 auto vec = Vec3(1, 2, 3, 0, Color_Red, Test(10, 20));
93 auto name = builder.CreateString("MyMonster");
95 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
96 auto inventory = builder.CreateVector(inv_data, 10);
98 // Alternatively, create the vector first, and fill in data later:
99 // unsigned char *inv_buf = nullptr;
100 // auto inventory = builder.CreateUninitializedVector<unsigned char>(
102 // memcpy(inv_buf, inv_data, 10);
104 Test tests[] = { Test(10, 20), Test(30, 40) };
105 auto testv = builder.CreateVectorOfStructs(tests, 2);
108 #ifndef FLATBUFFERS_CPP98_STL
109 // Create a vector of structures from a lambda.
110 auto testv2 = builder.CreateVectorOfStructs<Test>(
111 2, [&](size_t i, Test* s) -> void {
115 // Create a vector of structures using a plain old C++ function.
116 auto testv2 = builder.CreateVectorOfStructs<Test>(
117 2, [](size_t i, Test* s, void *state) -> void {
118 *s = (reinterpret_cast<Test*>(state))[i];
120 #endif // FLATBUFFERS_CPP98_STL
123 // create monster with very few fields set:
124 // (same functionality as CreateMonster below, but sets fields manually)
125 flatbuffers::Offset<Monster> mlocs[3];
126 auto fred = builder.CreateString("Fred");
127 auto barney = builder.CreateString("Barney");
128 auto wilma = builder.CreateString("Wilma");
129 MonsterBuilder mb1(builder);
131 mlocs[0] = mb1.Finish();
132 MonsterBuilder mb2(builder);
133 mb2.add_name(barney);
135 mlocs[1] = mb2.Finish();
136 MonsterBuilder mb3(builder);
138 mlocs[2] = mb3.Finish();
140 // Create an array of strings. Also test string pooling, and lambdas.
142 builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(
144 [](size_t i, flatbuffers::FlatBufferBuilder *b)
145 -> flatbuffers::Offset<flatbuffers::String> {
146 static const char *names[] = { "bob", "fred", "bob", "fred" };
147 return b->CreateSharedString(names[i]);
151 // Creating vectors of strings in one convenient call.
152 std::vector<std::string> names2;
153 names2.push_back("jane");
154 names2.push_back("mary");
155 auto vecofstrings2 = builder.CreateVectorOfStrings(names2);
157 // Create an array of sorted tables, can be used with binary search when read:
158 auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3);
160 // Create an array of sorted structs,
161 // can be used with binary search when read:
162 std::vector<Ability> abilities;
163 abilities.push_back(Ability(4, 40));
164 abilities.push_back(Ability(3, 30));
165 abilities.push_back(Ability(2, 20));
166 abilities.push_back(Ability(1, 10));
167 auto vecofstructs = builder.CreateVectorOfSortedStructs(&abilities);
169 // Create a nested FlatBuffer.
170 // Nested FlatBuffers are stored in a ubyte vector, which can be convenient
171 // since they can be memcpy'd around much easier than other FlatBuffer
172 // values. They have little overhead compared to storing the table directly.
173 // As a test, create a mostly empty Monster buffer:
174 flatbuffers::FlatBufferBuilder nested_builder;
175 auto nmloc = CreateMonster(nested_builder, nullptr, 0, 0,
176 nested_builder.CreateString("NestedMonster"));
177 FinishMonsterBuffer(nested_builder, nmloc);
178 // Now we can store the buffer in the parent. Note that by default, vectors
179 // are only aligned to their elements or size field, so in this case if the
180 // buffer contains 64-bit elements, they may not be correctly aligned. We fix
182 builder.ForceVectorAlignment(nested_builder.GetSize(), sizeof(uint8_t),
183 nested_builder.GetBufferMinAlignment());
184 // If for whatever reason you don't have the nested_builder available, you
185 // can substitute flatbuffers::largest_scalar_t (64-bit) for the alignment, or
186 // the largest force_align value in your schema if you're using it.
187 auto nested_flatbuffer_vector = builder.CreateVector(
188 nested_builder.GetBufferPointer(), nested_builder.GetSize());
190 // Test a nested FlexBuffer:
191 flexbuffers::Builder flexbuild;
194 auto flex = builder.CreateVector(flexbuild.GetBuffer());
196 // Test vector of enums.
197 Color colors[] = { Color_Blue, Color_Green };
198 // We use this special creation function because we have an array of
199 // pre-C++11 (enum class) enums whose size likely is int, yet its declared
200 // type in the schema is byte.
201 auto vecofcolors = builder.CreateVectorScalarCast<uint8_t, Color>(colors, 2);
203 // shortcut for creating monster with all fields set:
204 auto mloc = CreateMonster(
205 builder, &vec, 150, 80, name, inventory, Color_Blue, Any_Monster,
206 mlocs[1].Union(), // Store a union.
207 testv, vecofstrings, vecoftables, 0, nested_flatbuffer_vector, 0, false,
208 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f, vecofstrings2,
209 vecofstructs, flex, testv2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210 AnyUniqueAliases_NONE, 0, AnyAmbiguousAliases_NONE, 0, vecofcolors);
212 FinishMonsterBuffer(builder, mloc);
215 #ifdef FLATBUFFERS_TEST_VERBOSE
216 // print byte data for debugging:
217 auto p = builder.GetBufferPointer();
218 for (flatbuffers::uoffset_t i = 0; i < builder.GetSize(); i++)
223 // return the buffer for the caller to use.
225 reinterpret_cast<const char *>(builder.GetBufferPointer());
226 buffer.assign(bufferpointer, bufferpointer + builder.GetSize());
228 return builder.Release();
231 // example of accessing a buffer loaded in memory:
232 void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
233 bool pooled = true) {
234 // First, verify the buffers integrity (optional)
235 flatbuffers::Verifier verifier(flatbuf, length);
236 TEST_EQ(VerifyMonsterBuffer(verifier), true);
239 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
240 std::vector<uint8_t> test_buff;
241 test_buff.resize(length * 2);
242 std::memcpy(&test_buff[0], flatbuf, length);
243 std::memcpy(&test_buff[length], flatbuf, length);
245 flatbuffers::Verifier verifier1(&test_buff[0], length);
246 TEST_EQ(VerifyMonsterBuffer(verifier1), true);
247 TEST_EQ(verifier1.GetComputedSize(), length);
249 flatbuffers::Verifier verifier2(&test_buff[length], length);
250 TEST_EQ(VerifyMonsterBuffer(verifier2), true);
251 TEST_EQ(verifier2.GetComputedSize(), length);
255 TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0);
256 TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true);
257 TEST_EQ(strcmp(MonsterExtension(), "mon"), 0);
259 // Access the buffer from the root.
260 auto monster = GetMonster(flatbuf);
262 TEST_EQ(monster->hp(), 80);
263 TEST_EQ(monster->mana(), 150); // default
264 TEST_EQ_STR(monster->name()->c_str(), "MyMonster");
265 // Can't access the following field, it is deprecated in the schema,
266 // which means accessors are not generated:
267 // monster.friendly()
269 auto pos = monster->pos();
271 TEST_EQ(pos->z(), 3);
272 TEST_EQ(pos->test3().a(), 10);
273 TEST_EQ(pos->test3().b(), 20);
275 auto inventory = monster->inventory();
276 TEST_EQ(VectorLength(inventory), 10UL); // Works even if inventory is null.
277 TEST_NOTNULL(inventory);
278 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
279 // Check compatibilty of iterators with STL.
280 std::vector<unsigned char> inv_vec(inventory->begin(), inventory->end());
282 for (auto it = inventory->begin(); it != inventory->end(); ++it, ++n) {
283 auto indx = it - inventory->begin();
284 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
285 TEST_EQ(*it, inv_data[indx]);
287 TEST_EQ(n, inv_vec.size());
290 for (auto it = inventory->cbegin(); it != inventory->cend(); ++it, ++n) {
291 auto indx = it - inventory->cbegin();
292 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
293 TEST_EQ(*it, inv_data[indx]);
295 TEST_EQ(n, inv_vec.size());
298 for (auto it = inventory->rbegin(); it != inventory->rend(); ++it, ++n) {
299 auto indx = inventory->rend() - it - 1;
300 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
301 TEST_EQ(*it, inv_data[indx]);
303 TEST_EQ(n, inv_vec.size());
306 for (auto it = inventory->crbegin(); it != inventory->crend(); ++it, ++n) {
307 auto indx = inventory->crend() - it - 1;
308 TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
309 TEST_EQ(*it, inv_data[indx]);
311 TEST_EQ(n, inv_vec.size());
313 TEST_EQ(monster->color(), Color_Blue);
315 // Example of accessing a union:
316 TEST_EQ(monster->test_type(), Any_Monster); // First make sure which it is.
317 auto monster2 = reinterpret_cast<const Monster *>(monster->test());
318 TEST_NOTNULL(monster2);
319 TEST_EQ_STR(monster2->name()->c_str(), "Fred");
321 // Example of accessing a vector of strings:
322 auto vecofstrings = monster->testarrayofstring();
323 TEST_EQ(vecofstrings->size(), 4U);
324 TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
325 TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
327 // These should have pointer equality because of string pooling.
328 TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
329 TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
332 auto vecofstrings2 = monster->testarrayofstring2();
334 TEST_EQ(vecofstrings2->size(), 2U);
335 TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
336 TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
339 // Example of accessing a vector of tables:
340 auto vecoftables = monster->testarrayoftables();
341 TEST_EQ(vecoftables->size(), 3U);
342 for (auto it = vecoftables->begin(); it != vecoftables->end(); ++it) {
343 TEST_EQ(strlen(it->name()->c_str()) >= 4, true);
345 TEST_EQ_STR(vecoftables->Get(0)->name()->c_str(), "Barney");
346 TEST_EQ(vecoftables->Get(0)->hp(), 1000);
347 TEST_EQ_STR(vecoftables->Get(1)->name()->c_str(), "Fred");
348 TEST_EQ_STR(vecoftables->Get(2)->name()->c_str(), "Wilma");
349 TEST_NOTNULL(vecoftables->LookupByKey("Barney"));
350 TEST_NOTNULL(vecoftables->LookupByKey("Fred"));
351 TEST_NOTNULL(vecoftables->LookupByKey("Wilma"));
353 // Test accessing a vector of sorted structs
354 auto vecofstructs = monster->testarrayofsortedstruct();
355 if (vecofstructs) { // not filled in monster_test.bfbs
356 for (flatbuffers::uoffset_t i = 0; i < vecofstructs->size() - 1; i++) {
357 auto left = vecofstructs->Get(i);
358 auto right = vecofstructs->Get(i + 1);
359 TEST_EQ(true, (left->KeyCompareLessThan(right)));
361 TEST_NOTNULL(vecofstructs->LookupByKey(3));
362 TEST_EQ(static_cast<const Ability *>(nullptr),
363 vecofstructs->LookupByKey(5));
366 // Test nested FlatBuffers if available:
367 auto nested_buffer = monster->testnestedflatbuffer();
369 // nested_buffer is a vector of bytes you can memcpy. However, if you
370 // actually want to access the nested data, this is a convenient
371 // accessor that directly gives you the root table:
372 auto nested_monster = monster->testnestedflatbuffer_nested_root();
373 TEST_EQ_STR(nested_monster->name()->c_str(), "NestedMonster");
376 // Test flexbuffer if available:
377 auto flex = monster->flex();
378 // flex is a vector of bytes you can memcpy etc.
379 TEST_EQ(flex->size(), 4); // Encoded FlexBuffer bytes.
380 // However, if you actually want to access the nested data, this is a
381 // convenient accessor that directly gives you the root value:
382 TEST_EQ(monster->flex_flexbuffer_root().AsInt16(), 1234);
384 // Test vector of enums:
385 auto colors = monster->vector_of_enums();
387 TEST_EQ(colors->size(), 2);
388 TEST_EQ(colors->Get(0), Color_Blue);
389 TEST_EQ(colors->Get(1), Color_Green);
392 // Since Flatbuffers uses explicit mechanisms to override the default
393 // compiler alignment, double check that the compiler indeed obeys them:
394 // (Test consists of a short and byte):
395 TEST_EQ(flatbuffers::AlignOf<Test>(), 2UL);
396 TEST_EQ(sizeof(Test), 4UL);
398 const flatbuffers::Vector<const Test *> *tests_array[] = {
402 for (size_t i = 0; i < sizeof(tests_array) / sizeof(tests_array[0]); ++i) {
403 auto tests = tests_array[i];
405 auto test_0 = tests->Get(0);
406 auto test_1 = tests->Get(1);
407 TEST_EQ(test_0->a(), 10);
408 TEST_EQ(test_0->b(), 20);
409 TEST_EQ(test_1->a(), 30);
410 TEST_EQ(test_1->b(), 40);
411 for (auto it = tests->begin(); it != tests->end(); ++it) {
412 TEST_EQ(it->a() == 10 || it->a() == 30, true); // Just testing iterators.
416 // Checking for presence of fields:
417 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
418 TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
420 // Obtaining a buffer from a root:
421 TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
424 // Change a FlatBuffer in-place, after it has been constructed.
425 void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
426 // Get non-const pointer to root.
427 auto monster = GetMutableMonster(flatbuf);
429 // Each of these tests mutates, then tests, then set back to the original,
430 // so we can test that the buffer in the end still passes our original test.
431 auto hp_ok = monster->mutate_hp(10);
432 TEST_EQ(hp_ok, true); // Field was present.
433 TEST_EQ(monster->hp(), 10);
434 // Mutate to default value
435 auto hp_ok_default = monster->mutate_hp(100);
436 TEST_EQ(hp_ok_default, true); // Field was present.
437 TEST_EQ(monster->hp(), 100);
438 // Test that mutate to default above keeps field valid for further mutations
439 auto hp_ok_2 = monster->mutate_hp(20);
440 TEST_EQ(hp_ok_2, true);
441 TEST_EQ(monster->hp(), 20);
442 monster->mutate_hp(80);
444 // Monster originally at 150 mana (default value)
445 auto mana_default_ok = monster->mutate_mana(150); // Mutate to default value.
446 TEST_EQ(mana_default_ok,
447 true); // Mutation should succeed, because default value.
448 TEST_EQ(monster->mana(), 150);
449 auto mana_ok = monster->mutate_mana(10);
450 TEST_EQ(mana_ok, false); // Field was NOT present, because default value.
451 TEST_EQ(monster->mana(), 150);
454 auto pos = monster->mutable_pos();
455 auto test3 = pos->mutable_test3(); // Struct inside a struct.
456 test3.mutate_a(50); // Struct fields never fail.
457 TEST_EQ(test3.a(), 50);
461 auto inventory = monster->mutable_inventory();
462 inventory->Mutate(9, 100);
463 TEST_EQ(inventory->Get(9), 100);
464 inventory->Mutate(9, 9);
466 auto tables = monster->mutable_testarrayoftables();
467 auto first = tables->GetMutableObject(0);
468 TEST_EQ(first->hp(), 1000);
470 TEST_EQ(first->hp(), 0);
471 first->mutate_hp(1000);
473 // Run the verifier and the regular test to make sure we didn't trample on
475 AccessFlatBufferTest(flatbuf, length);
478 // Unpack a FlatBuffer into objects.
479 void ObjectFlatBuffersTest(uint8_t *flatbuf) {
480 // Optional: we can specify resolver and rehasher functions to turn hashed
481 // strings into object pointers and back, to implement remote references
483 auto resolver = flatbuffers::resolver_function_t(
484 [](void **pointer_adr, flatbuffers::hash_value_t hash) {
487 // Don't actually do anything, leave variable null.
489 auto rehasher = flatbuffers::rehasher_function_t(
490 [](void *pointer) -> flatbuffers::hash_value_t {
495 // Turn a buffer into C++ objects.
496 auto monster1 = UnPackMonster(flatbuf, &resolver);
498 // Re-serialize the data.
499 flatbuffers::FlatBufferBuilder fbb1;
500 fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
501 MonsterIdentifier());
503 // Unpack again, and re-serialize again.
504 auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
505 flatbuffers::FlatBufferBuilder fbb2;
506 fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
507 MonsterIdentifier());
509 // Now we've gone full round-trip, the two buffers should match.
510 auto len1 = fbb1.GetSize();
511 auto len2 = fbb2.GetSize();
513 TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), len1), 0);
515 // Test it with the original buffer test to make sure all data survived.
516 AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
518 // Test accessing fields, similar to AccessFlatBufferTest above.
519 TEST_EQ(monster2->hp, 80);
520 TEST_EQ(monster2->mana, 150); // default
521 TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
523 auto &pos = monster2->pos;
525 TEST_EQ(pos->z(), 3);
526 TEST_EQ(pos->test3().a(), 10);
527 TEST_EQ(pos->test3().b(), 20);
529 auto &inventory = monster2->inventory;
530 TEST_EQ(inventory.size(), 10UL);
531 unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
532 for (auto it = inventory.begin(); it != inventory.end(); ++it)
533 TEST_EQ(*it, inv_data[it - inventory.begin()]);
535 TEST_EQ(monster2->color, Color_Blue);
537 auto monster3 = monster2->test.AsMonster();
538 TEST_NOTNULL(monster3);
539 TEST_EQ_STR(monster3->name.c_str(), "Fred");
541 auto &vecofstrings = monster2->testarrayofstring;
542 TEST_EQ(vecofstrings.size(), 4U);
543 TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
544 TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
546 auto &vecofstrings2 = monster2->testarrayofstring2;
547 TEST_EQ(vecofstrings2.size(), 2U);
548 TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
549 TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
551 auto &vecoftables = monster2->testarrayoftables;
552 TEST_EQ(vecoftables.size(), 3U);
553 TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
554 TEST_EQ(vecoftables[0]->hp, 1000);
555 TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
556 TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
558 auto &tests = monster2->test4;
559 TEST_EQ(tests[0].a(), 10);
560 TEST_EQ(tests[0].b(), 20);
561 TEST_EQ(tests[1].a(), 30);
562 TEST_EQ(tests[1].b(), 40);
565 // Prefix a FlatBuffer with a size field.
566 void SizePrefixedTest() {
567 // Create size prefixed buffer.
568 flatbuffers::FlatBufferBuilder fbb;
569 FinishSizePrefixedMonsterBuffer(
570 fbb, CreateMonster(fbb, 0, 200, 300, fbb.CreateString("bob")));
573 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
574 TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier), true);
577 auto m = GetSizePrefixedMonster(fbb.GetBufferPointer());
578 TEST_EQ(m->mana(), 200);
579 TEST_EQ(m->hp(), 300);
580 TEST_EQ_STR(m->name()->c_str(), "bob");
583 void TriviallyCopyableTest() {
585 #if __GNUG__ && __GNUC__ < 5
586 TEST_EQ(__has_trivial_copy(Vec3), true);
588 #if __cplusplus >= 201103L
589 TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
595 // Check stringify of an default enum value to json
596 void JsonDefaultTest() {
597 // load FlatBuffer schema (.fbs) from disk
598 std::string schemafile;
599 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
602 // parse schema first, so we can use it to parse the data after
603 flatbuffers::Parser parser;
604 auto include_test_path =
605 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
606 const char *include_directories[] = { test_data_path.c_str(),
607 include_test_path.c_str(), nullptr };
609 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
610 // create incomplete monster and store to json
611 parser.opts.output_default_scalars_in_json = true;
612 parser.opts.output_enum_identifiers = true;
613 flatbuffers::FlatBufferBuilder builder;
614 auto name = builder.CreateString("default_enum");
615 MonsterBuilder color_monster(builder);
616 color_monster.add_name(name);
617 FinishMonsterBuffer(builder, color_monster.Finish());
619 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
620 TEST_EQ(result, true);
621 // default value of the "color" field is Blue
622 TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true);
623 // default value of the "testf" field is 3.14159
624 TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true);
627 void JsonEnumsTest() {
628 // load FlatBuffer schema (.fbs) from disk
629 std::string schemafile;
630 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
633 // parse schema first, so we can use it to parse the data after
634 flatbuffers::Parser parser;
635 auto include_test_path =
636 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
637 const char *include_directories[] = { test_data_path.c_str(),
638 include_test_path.c_str(), nullptr };
639 parser.opts.output_enum_identifiers = true;
640 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
641 flatbuffers::FlatBufferBuilder builder;
642 auto name = builder.CreateString("bitflag_enum");
643 MonsterBuilder color_monster(builder);
644 color_monster.add_name(name);
645 color_monster.add_color(Color(Color_Blue | Color_Red));
646 FinishMonsterBuffer(builder, color_monster.Finish());
648 auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
649 TEST_EQ(result, true);
650 TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true);
653 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
654 // The IEEE-754 quiet_NaN is not simple binary constant.
655 // All binary NaN bit strings have all the bits of the biased exponent field E
656 // set to 1. A quiet NaN bit string should be encoded with the first bit d[1]
657 // of the trailing significand field T being 1 (d[0] is implicit bit).
658 // It is assumed that endianness of floating-point is same as integer.
659 template<typename T, typename U, U qnan_base> bool is_quiet_nan_impl(T v) {
660 static_assert(sizeof(T) == sizeof(U), "unexpected");
662 std::memcpy(&b, &v, sizeof(T));
663 return ((b & qnan_base) == qnan_base);
665 static bool is_quiet_nan(float v) {
666 return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v);
668 static bool is_quiet_nan(double v) {
669 return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v);
672 void TestMonsterExtraFloats() {
673 TEST_EQ(is_quiet_nan(1.0), false);
674 TEST_EQ(is_quiet_nan(infinityd), false);
675 TEST_EQ(is_quiet_nan(-infinityf), false);
676 TEST_EQ(is_quiet_nan(std::numeric_limits<float>::quiet_NaN()), true);
677 TEST_EQ(is_quiet_nan(std::numeric_limits<double>::quiet_NaN()), true);
679 using namespace flatbuffers;
680 using namespace MyGame;
681 // Load FlatBuffer schema (.fbs) from disk.
682 std::string schemafile;
683 TEST_EQ(LoadFile((test_data_path + "monster_extra.fbs").c_str(), false,
686 // Parse schema first, so we can use it to parse the data after.
688 auto include_test_path = ConCatPathFileName(test_data_path, "include_test");
689 const char *include_directories[] = { test_data_path.c_str(),
690 include_test_path.c_str(), nullptr };
691 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
692 // Create empty extra and store to json.
693 parser.opts.output_default_scalars_in_json = true;
694 parser.opts.output_enum_identifiers = true;
695 FlatBufferBuilder builder;
696 const auto def_root = MonsterExtraBuilder(builder).Finish();
697 FinishMonsterExtraBuffer(builder, def_root);
698 const auto def_obj = builder.GetBufferPointer();
699 const auto def_extra = GetMonsterExtra(def_obj);
700 TEST_NOTNULL(def_extra);
701 TEST_EQ(is_quiet_nan(def_extra->f0()), true);
702 TEST_EQ(is_quiet_nan(def_extra->f1()), true);
703 TEST_EQ(def_extra->f2(), +infinityf);
704 TEST_EQ(def_extra->f3(), -infinityf);
705 TEST_EQ(is_quiet_nan(def_extra->d0()), true);
706 TEST_EQ(is_quiet_nan(def_extra->d1()), true);
707 TEST_EQ(def_extra->d2(), +infinityd);
708 TEST_EQ(def_extra->d3(), -infinityd);
710 auto result = GenerateText(parser, def_obj, &jsongen);
711 TEST_EQ(result, true);
712 // Check expected default values.
713 TEST_EQ(std::string::npos != jsongen.find("f0: nan"), true);
714 TEST_EQ(std::string::npos != jsongen.find("f1: nan"), true);
715 TEST_EQ(std::string::npos != jsongen.find("f2: inf"), true);
716 TEST_EQ(std::string::npos != jsongen.find("f3: -inf"), true);
717 TEST_EQ(std::string::npos != jsongen.find("d0: nan"), true);
718 TEST_EQ(std::string::npos != jsongen.find("d1: nan"), true);
719 TEST_EQ(std::string::npos != jsongen.find("d2: inf"), true);
720 TEST_EQ(std::string::npos != jsongen.find("d3: -inf"), true);
721 // Parse 'mosterdata_extra.json'.
722 const auto extra_base = test_data_path + "monsterdata_extra";
724 TEST_EQ(LoadFile((extra_base + ".json").c_str(), false, &jsongen), true);
725 TEST_EQ(parser.Parse(jsongen.c_str()), true);
726 const auto test_file = parser.builder_.GetBufferPointer();
727 const auto test_size = parser.builder_.GetSize();
728 Verifier verifier(test_file, test_size);
729 TEST_ASSERT(VerifyMonsterExtraBuffer(verifier));
730 const auto extra = GetMonsterExtra(test_file);
732 TEST_EQ(is_quiet_nan(extra->f0()), true);
733 TEST_EQ(is_quiet_nan(extra->f1()), true);
734 TEST_EQ(extra->f2(), +infinityf);
735 TEST_EQ(extra->f3(), -infinityf);
736 TEST_EQ(is_quiet_nan(extra->d0()), true);
737 TEST_EQ(extra->d1(), +infinityd);
738 TEST_EQ(extra->d2(), -infinityd);
739 TEST_EQ(is_quiet_nan(extra->d3()), true);
740 TEST_NOTNULL(extra->fvec());
741 TEST_EQ(extra->fvec()->size(), 4);
742 TEST_EQ(extra->fvec()->Get(0), 1.0f);
743 TEST_EQ(extra->fvec()->Get(1), -infinityf);
744 TEST_EQ(extra->fvec()->Get(2), +infinityf);
745 TEST_EQ(is_quiet_nan(extra->fvec()->Get(3)), true);
746 TEST_NOTNULL(extra->dvec());
747 TEST_EQ(extra->dvec()->size(), 4);
748 TEST_EQ(extra->dvec()->Get(0), 2.0);
749 TEST_EQ(extra->dvec()->Get(1), +infinityd);
750 TEST_EQ(extra->dvec()->Get(2), -infinityd);
751 TEST_EQ(is_quiet_nan(extra->dvec()->Get(3)), true);
754 void TestMonsterExtraFloats() {}
757 // example of parsing text straight into a buffer, and generating
758 // text back from it:
759 void ParseAndGenerateTextTest(bool binary) {
760 // load FlatBuffer schema (.fbs) and JSON from disk
761 std::string schemafile;
762 std::string jsonfile;
763 TEST_EQ(flatbuffers::LoadFile(
764 (test_data_path + "monster_test." + (binary ? "bfbs" : "fbs"))
766 binary, &schemafile),
768 TEST_EQ(flatbuffers::LoadFile(
769 (test_data_path + "monsterdata_test.golden").c_str(), false,
773 auto include_test_path =
774 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
775 const char *include_directories[] = { test_data_path.c_str(),
776 include_test_path.c_str(), nullptr };
778 // parse schema first, so we can use it to parse the data after
779 flatbuffers::Parser parser;
781 flatbuffers::Verifier verifier(
782 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
784 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
785 // auto schema = reflection::GetSchema(schemafile.c_str());
786 TEST_EQ(parser.Deserialize((const uint8_t *)schemafile.c_str(),
790 TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
792 TEST_EQ(parser.Parse(jsonfile.c_str(), include_directories), true);
794 // here, parser.builder_ contains a binary buffer that is the parsed data.
796 // First, verify it, just in case:
797 flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
798 parser.builder_.GetSize());
799 TEST_EQ(VerifyMonsterBuffer(verifier), true);
801 AccessFlatBufferTest(parser.builder_.GetBufferPointer(),
802 parser.builder_.GetSize(), false);
804 // to ensure it is correct, we now generate text back from the binary,
805 // and compare the two:
808 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
809 TEST_EQ(result, true);
810 TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
812 // We can also do the above using the convenient Registry that knows about
813 // a set of file_identifiers mapped to schemas.
814 flatbuffers::Registry registry;
815 // Make sure schemas can find their includes.
816 registry.AddIncludeDirectory(test_data_path.c_str());
817 registry.AddIncludeDirectory(include_test_path.c_str());
818 // Call this with many schemas if possible.
819 registry.Register(MonsterIdentifier(),
820 (test_data_path + "monster_test.fbs").c_str());
821 // Now we got this set up, we can parse by just specifying the identifier,
822 // the correct schema will be loaded on the fly:
823 auto buf = registry.TextToFlatBuffer(jsonfile.c_str(), MonsterIdentifier());
824 // If this fails, check registry.lasterror_.
825 TEST_NOTNULL(buf.data());
826 // Test the buffer, to be sure:
827 AccessFlatBufferTest(buf.data(), buf.size(), false);
828 // We can use the registry to turn this back into text, in this case it
829 // will get the file_identifier from the binary:
831 auto ok = registry.FlatBufferToText(buf.data(), buf.size(), &text);
832 // If this fails, check registry.lasterror_.
834 TEST_EQ_STR(text.c_str(), jsonfile.c_str());
836 // Generate text for UTF-8 strings without escapes.
837 std::string jsonfile_utf8;
838 TEST_EQ(flatbuffers::LoadFile((test_data_path + "unicode_test.json").c_str(),
839 false, &jsonfile_utf8),
841 TEST_EQ(parser.Parse(jsonfile_utf8.c_str(), include_directories), true);
842 // To ensure it is correct, generate utf-8 text back from the binary.
843 std::string jsongen_utf8;
844 // request natural printing for utf-8 strings
845 parser.opts.natural_utf8 = true;
846 parser.opts.strict_json = true;
848 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen_utf8),
850 TEST_EQ_STR(jsongen_utf8.c_str(), jsonfile_utf8.c_str());
853 void ReflectionTest(uint8_t *flatbuf, size_t length) {
854 // Load a binary schema.
855 std::string bfbsfile;
856 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.bfbs").c_str(),
860 // Verify it, just in case:
861 flatbuffers::Verifier verifier(
862 reinterpret_cast<const uint8_t *>(bfbsfile.c_str()), bfbsfile.length());
863 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
865 // Make sure the schema is what we expect it to be.
866 auto &schema = *reflection::GetSchema(bfbsfile.c_str());
867 auto root_table = schema.root_table();
868 TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
869 auto fields = root_table->fields();
870 auto hp_field_ptr = fields->LookupByKey("hp");
871 TEST_NOTNULL(hp_field_ptr);
872 auto &hp_field = *hp_field_ptr;
873 TEST_EQ_STR(hp_field.name()->c_str(), "hp");
874 TEST_EQ(hp_field.id(), 2);
875 TEST_EQ(hp_field.type()->base_type(), reflection::Short);
876 auto friendly_field_ptr = fields->LookupByKey("friendly");
877 TEST_NOTNULL(friendly_field_ptr);
878 TEST_NOTNULL(friendly_field_ptr->attributes());
879 TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
881 // Make sure the table index is what we expect it to be.
882 auto pos_field_ptr = fields->LookupByKey("pos");
883 TEST_NOTNULL(pos_field_ptr);
884 TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
885 auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
886 TEST_NOTNULL(pos_table_ptr);
887 TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
889 // Now use it to dynamically access a buffer.
890 auto &root = *flatbuffers::GetAnyRoot(flatbuf);
892 // Verify the buffer first using reflection based verification
893 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
896 auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
899 // Rather than needing to know the type, we can also get the value of
900 // any field as an int64_t/double/string, regardless of what it actually is.
901 auto hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
902 TEST_EQ(hp_int64, 80);
903 auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
904 TEST_EQ(hp_double, 80.0);
905 auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
906 TEST_EQ_STR(hp_string.c_str(), "80");
908 // Get struct field through reflection
909 auto pos_struct = flatbuffers::GetFieldStruct(root, *pos_field_ptr);
910 TEST_NOTNULL(pos_struct);
911 TEST_EQ(flatbuffers::GetAnyFieldF(*pos_struct,
912 *pos_table_ptr->fields()->LookupByKey("z")),
915 auto test3_field = pos_table_ptr->fields()->LookupByKey("test3");
916 auto test3_struct = flatbuffers::GetFieldStruct(*pos_struct, *test3_field);
917 TEST_NOTNULL(test3_struct);
918 auto test3_object = schema.objects()->Get(test3_field->type()->index());
920 TEST_EQ(flatbuffers::GetAnyFieldF(*test3_struct,
921 *test3_object->fields()->LookupByKey("a")),
924 // We can also modify it.
925 flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
926 hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
929 // We can also set fields generically:
930 flatbuffers::SetAnyFieldI(&root, hp_field, 300);
931 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
932 TEST_EQ(hp_int64, 300);
933 flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
934 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
935 TEST_EQ(hp_int64, 300);
936 flatbuffers::SetAnyFieldS(&root, hp_field, "300");
937 hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
938 TEST_EQ(hp_int64, 300);
940 // Test buffer is valid after the modifications
941 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
944 // Reset it, for further tests.
945 flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
947 // More advanced functionality: changing the size of items in-line!
948 // First we put the FlatBuffer inside an std::vector.
949 std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
950 // Find the field we want to modify.
951 auto &name_field = *fields->LookupByKey("name");
953 // This time we wrap the result from GetAnyRoot in a smartpointer that
954 // will keep rroot valid as resizingbuf resizes.
955 auto rroot = flatbuffers::piv(
956 flatbuffers::GetAnyRoot(flatbuffers::vector_data(resizingbuf)),
958 SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
960 // Here resizingbuf has changed, but rroot is still valid.
961 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
962 // Now lets extend a vector by 100 elements (10 -> 110).
963 auto &inventory_field = *fields->LookupByKey("inventory");
964 auto rinventory = flatbuffers::piv(
965 flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field), resizingbuf);
966 flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
968 // rinventory still valid, so lets read from it.
969 TEST_EQ(rinventory->Get(10), 50);
971 // For reflection uses not covered already, there is a more powerful way:
972 // we can simply generate whatever object we want to add/modify in a
973 // FlatBuffer of its own, then add that to an existing FlatBuffer:
974 // As an example, let's add a string to an array of strings.
975 // First, find our field:
976 auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
977 // Find the vector value:
978 auto rtestarrayofstring = flatbuffers::piv(
979 flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
980 **rroot, testarrayofstring_field),
982 // It's a vector of 2 strings, to which we add one more, initialized to
984 flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
985 schema, 3, 0, *rtestarrayofstring, &resizingbuf);
986 // Here we just create a buffer that contans a single string, but this
987 // could also be any complex set of tables and other values.
988 flatbuffers::FlatBufferBuilder stringfbb;
989 stringfbb.Finish(stringfbb.CreateString("hank"));
990 // Add the contents of it to our existing FlatBuffer.
991 // We do this last, so the pointer doesn't get invalidated (since it is
992 // at the end of the buffer):
993 auto string_ptr = flatbuffers::AddFlatBuffer(
994 resizingbuf, stringfbb.GetBufferPointer(), stringfbb.GetSize());
995 // Finally, set the new value in the vector.
996 rtestarrayofstring->MutateOffset(2, string_ptr);
997 TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
998 TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
999 // Test integrity of all resize operations above.
1000 flatbuffers::Verifier resize_verifier(
1001 reinterpret_cast<const uint8_t *>(flatbuffers::vector_data(resizingbuf)),
1002 resizingbuf.size());
1003 TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
1005 // Test buffer is valid using reflection as well
1006 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1007 flatbuffers::vector_data(resizingbuf),
1008 resizingbuf.size()),
1011 // As an additional test, also set it on the name field.
1012 // Note: unlike the name change above, this just overwrites the offset,
1013 // rather than changing the string in-place.
1014 SetFieldT(*rroot, name_field, string_ptr);
1015 TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
1017 // Using reflection, rather than mutating binary FlatBuffers, we can also copy
1018 // tables and other things out of other FlatBuffers into a FlatBufferBuilder,
1019 // either part or whole.
1020 flatbuffers::FlatBufferBuilder fbb;
1021 auto root_offset = flatbuffers::CopyTable(
1022 fbb, schema, *root_table, *flatbuffers::GetAnyRoot(flatbuf), true);
1023 fbb.Finish(root_offset, MonsterIdentifier());
1024 // Test that it was copied correctly:
1025 AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
1027 // Test buffer is valid using reflection as well
1028 TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1029 fbb.GetBufferPointer(), fbb.GetSize()),
1033 void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
1035 flatbuffers::FlatBufferToString(flatbuf, Monster::MiniReflectTypeTable());
1039 "pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
1040 "{ a: 10, b: 20 } }, "
1042 "name: \"MyMonster\", "
1043 "inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
1044 "test_type: Monster, "
1045 "test: { name: \"Fred\" }, "
1046 "test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1047 "testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
1048 "testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" "
1050 "{ name: \"Wilma\" } ], "
1051 // TODO(wvo): should really print this nested buffer correctly.
1052 "testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, "
1054 "4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
1055 "101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
1056 "testarrayofstring2: [ \"jane\", \"mary\" ], "
1057 "testarrayofsortedstruct: [ { id: 1, distance: 10 }, "
1058 "{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
1059 "{ id: 4, distance: 40 } ], "
1060 "flex: [ 210, 4, 5, 2 ], "
1061 "test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1062 "vector_of_enums: [ Blue, Green ] "
1066 Vec3 vec(1, 2, 3, 1.5, Color_Red, test);
1067 flatbuffers::FlatBufferBuilder vec_builder;
1068 vec_builder.Finish(vec_builder.CreateStruct(vec));
1069 auto vec_buffer = vec_builder.Release();
1070 auto vec_str = flatbuffers::FlatBufferToString(vec_buffer.data(),
1071 Vec3::MiniReflectTypeTable());
1072 TEST_EQ_STR(vec_str.c_str(),
1073 "{ x: 1.0, y: 2.0, z: 3.0, test1: 1.5, test2: Red, test3: { a: "
1077 // Parse a .proto schema, output as .fbs
1078 void ParseProtoTest() {
1079 // load the .proto and the golden file from disk
1080 std::string protofile;
1081 std::string goldenfile;
1082 std::string goldenunionfile;
1084 flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1088 flatbuffers::LoadFile((test_data_path + "prototest/test.golden").c_str(),
1089 false, &goldenfile),
1091 TEST_EQ(flatbuffers::LoadFile(
1092 (test_data_path + "prototest/test_union.golden").c_str(), false,
1096 flatbuffers::IDLOptions opts;
1097 opts.include_dependence_headers = false;
1098 opts.proto_mode = true;
1101 flatbuffers::Parser parser(opts);
1102 auto protopath = test_data_path + "prototest/";
1103 const char *include_directories[] = { protopath.c_str(), nullptr };
1104 TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1107 auto fbs = flatbuffers::GenerateFBS(parser, "test");
1109 // Ensure generated file is parsable.
1110 flatbuffers::Parser parser2;
1111 TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1112 TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1114 // Parse proto with --oneof-union option.
1115 opts.proto_oneof_union = true;
1116 flatbuffers::Parser parser3(opts);
1117 TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1120 auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1122 // Ensure generated file is parsable.
1123 flatbuffers::Parser parser4;
1124 TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1125 TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1128 template<typename T>
1129 void CompareTableFieldValue(flatbuffers::Table *table,
1130 flatbuffers::voffset_t voffset, T val) {
1131 T read = table->GetField(voffset, static_cast<T>(0));
1135 // Low level stress/fuzz test: serialize/deserialize a variety of
1136 // different kinds of data in different combinations
1138 // Values we're testing against: chosen to ensure no bits get chopped
1139 // off anywhere, and also be different from eachother.
1140 const uint8_t bool_val = true;
1141 const int8_t char_val = -127; // 0x81
1142 const uint8_t uchar_val = 0xFF;
1143 const int16_t short_val = -32222; // 0x8222;
1144 const uint16_t ushort_val = 0xFEEE;
1145 const int32_t int_val = 0x83333333;
1146 const uint32_t uint_val = 0xFDDDDDDD;
1147 const int64_t long_val = 0x8444444444444444LL;
1148 const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
1149 const float float_val = 3.14159f;
1150 const double double_val = 3.14159265359;
1152 const int test_values_max = 11;
1153 const flatbuffers::voffset_t fields_per_object = 4;
1154 const int num_fuzz_objects = 10000; // The higher, the more thorough :)
1156 flatbuffers::FlatBufferBuilder builder;
1158 lcg_reset(); // Keep it deterministic.
1160 flatbuffers::uoffset_t objects[num_fuzz_objects];
1162 // Generate num_fuzz_objects random objects each consisting of
1163 // fields_per_object fields, each of a random type.
1164 for (int i = 0; i < num_fuzz_objects; i++) {
1165 auto start = builder.StartTable();
1166 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1167 int choice = lcg_rand() % test_values_max;
1168 auto off = flatbuffers::FieldIndexToOffset(f);
1170 case 0: builder.AddElement<uint8_t>(off, bool_val, 0); break;
1171 case 1: builder.AddElement<int8_t>(off, char_val, 0); break;
1172 case 2: builder.AddElement<uint8_t>(off, uchar_val, 0); break;
1173 case 3: builder.AddElement<int16_t>(off, short_val, 0); break;
1174 case 4: builder.AddElement<uint16_t>(off, ushort_val, 0); break;
1175 case 5: builder.AddElement<int32_t>(off, int_val, 0); break;
1176 case 6: builder.AddElement<uint32_t>(off, uint_val, 0); break;
1177 case 7: builder.AddElement<int64_t>(off, long_val, 0); break;
1178 case 8: builder.AddElement<uint64_t>(off, ulong_val, 0); break;
1179 case 9: builder.AddElement<float>(off, float_val, 0); break;
1180 case 10: builder.AddElement<double>(off, double_val, 0); break;
1183 objects[i] = builder.EndTable(start);
1185 builder.PreAlign<flatbuffers::largest_scalar_t>(0); // Align whole buffer.
1187 lcg_reset(); // Reset.
1189 uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
1191 // Test that all objects we generated are readable and return the
1192 // expected values. We generate random objects in the same order
1193 // so this is deterministic.
1194 for (int i = 0; i < num_fuzz_objects; i++) {
1195 auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
1196 for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1197 int choice = lcg_rand() % test_values_max;
1198 flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
1200 case 0: CompareTableFieldValue(table, off, bool_val); break;
1201 case 1: CompareTableFieldValue(table, off, char_val); break;
1202 case 2: CompareTableFieldValue(table, off, uchar_val); break;
1203 case 3: CompareTableFieldValue(table, off, short_val); break;
1204 case 4: CompareTableFieldValue(table, off, ushort_val); break;
1205 case 5: CompareTableFieldValue(table, off, int_val); break;
1206 case 6: CompareTableFieldValue(table, off, uint_val); break;
1207 case 7: CompareTableFieldValue(table, off, long_val); break;
1208 case 8: CompareTableFieldValue(table, off, ulong_val); break;
1209 case 9: CompareTableFieldValue(table, off, float_val); break;
1210 case 10: CompareTableFieldValue(table, off, double_val); break;
1216 // High level stress/fuzz test: generate a big schema and
1217 // matching json data in random combinations, then parse both,
1218 // generate json back from the binary, and compare with the original.
1220 lcg_reset(); // Keep it deterministic.
1222 const int num_definitions = 30;
1223 const int num_struct_definitions = 5; // Subset of num_definitions.
1224 const int fields_per_definition = 15;
1225 const int instances_per_definition = 5;
1226 const int deprecation_rate = 10; // 1 in deprecation_rate fields will
1229 std::string schema = "namespace test;\n\n";
1232 std::string instances[instances_per_definition];
1234 // Since we're generating schema and corresponding data in tandem,
1235 // this convenience function adds strings to both at once.
1236 static void Add(RndDef (&definitions_l)[num_definitions],
1237 std::string &schema_l, const int instances_per_definition_l,
1238 const char *schema_add, const char *instance_add,
1240 schema_l += schema_add;
1241 for (int i = 0; i < instances_per_definition_l; i++)
1242 definitions_l[definition].instances[i] += instance_add;
1247 #define AddToSchemaAndInstances(schema_add, instance_add) \
1248 RndDef::Add(definitions, schema, instances_per_definition, \
1249 schema_add, instance_add, definition)
1252 RndDef::Add(definitions, schema, instances_per_definition, \
1253 "byte", "1", definition)
1256 RndDef definitions[num_definitions];
1258 // We are going to generate num_definitions, the first
1259 // num_struct_definitions will be structs, the rest tables. For each
1260 // generate random fields, some of which may be struct/table types
1261 // referring to previously generated structs/tables.
1262 // Simultanenously, we generate instances_per_definition JSON data
1263 // definitions, which will have identical structure to the schema
1264 // being generated. We generate multiple instances such that when creating
1265 // hierarchy, we get some variety by picking one randomly.
1266 for (int definition = 0; definition < num_definitions; definition++) {
1267 std::string definition_name = "D" + flatbuffers::NumToString(definition);
1269 bool is_struct = definition < num_struct_definitions;
1271 AddToSchemaAndInstances(
1272 ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
1275 for (int field = 0; field < fields_per_definition; field++) {
1276 const bool is_last_field = field == fields_per_definition - 1;
1278 // Deprecate 1 in deprecation_rate fields. Only table fields can be
1280 // Don't deprecate the last field to avoid dangling commas in JSON.
1281 const bool deprecated =
1282 !is_struct && !is_last_field && (lcg_rand() % deprecation_rate == 0);
1284 std::string field_name = "f" + flatbuffers::NumToString(field);
1285 AddToSchemaAndInstances((" " + field_name + ":").c_str(),
1286 deprecated ? "" : (field_name + ": ").c_str());
1287 // Pick random type:
1288 auto base_type = static_cast<flatbuffers::BaseType>(
1289 lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
1290 switch (base_type) {
1291 case flatbuffers::BASE_TYPE_STRING:
1293 Dummy(); // No strings in structs.
1295 AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
1298 case flatbuffers::BASE_TYPE_VECTOR:
1300 Dummy(); // No vectors in structs.
1302 AddToSchemaAndInstances("[ubyte]",
1303 deprecated ? "" : "[\n0,\n1,\n255\n]");
1306 case flatbuffers::BASE_TYPE_NONE:
1307 case flatbuffers::BASE_TYPE_UTYPE:
1308 case flatbuffers::BASE_TYPE_STRUCT:
1309 case flatbuffers::BASE_TYPE_UNION:
1311 // Pick a random previous definition and random data instance of
1313 int defref = lcg_rand() % definition;
1314 int instance = lcg_rand() % instances_per_definition;
1315 AddToSchemaAndInstances(
1316 ("D" + flatbuffers::NumToString(defref)).c_str(),
1318 : definitions[defref].instances[instance].c_str());
1320 // If this is the first definition, we have no definition we can
1325 case flatbuffers::BASE_TYPE_BOOL:
1326 AddToSchemaAndInstances(
1327 "bool", deprecated ? "" : (lcg_rand() % 2 ? "true" : "false"));
1329 case flatbuffers::BASE_TYPE_ARRAY:
1331 AddToSchemaAndInstances(
1333 deprecated ? "" : "255"); // No fixed-length arrays in tables.
1335 AddToSchemaAndInstances("[int:3]", deprecated ? "" : "[\n,\n,\n]");
1339 // All the scalar types.
1340 schema += flatbuffers::kTypeNames[base_type];
1343 // We want each instance to use its own random value.
1344 for (int inst = 0; inst < instances_per_definition; inst++)
1345 definitions[definition].instances[inst] +=
1346 flatbuffers::IsFloat(base_type)
1347 ? flatbuffers::NumToString<double>(lcg_rand() % 128)
1349 : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
1352 AddToSchemaAndInstances(deprecated ? "(deprecated);\n" : ";\n",
1353 deprecated ? "" : is_last_field ? "\n" : ",\n");
1355 AddToSchemaAndInstances("}\n\n", "}");
1358 schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
1361 flatbuffers::Parser parser;
1363 // Will not compare against the original if we don't write defaults
1364 parser.builder_.ForceDefaults(true);
1366 // Parse the schema, parse the generated data, then generate text back
1367 // from the binary and compare against the original.
1368 TEST_EQ(parser.Parse(schema.c_str()), true);
1370 const std::string &json =
1371 definitions[num_definitions - 1].instances[0] + "\n";
1373 TEST_EQ(parser.Parse(json.c_str()), true);
1375 std::string jsongen;
1376 parser.opts.indent_step = 0;
1378 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
1379 TEST_EQ(result, true);
1381 if (jsongen != json) {
1382 // These strings are larger than a megabyte, so we show the bytes around
1383 // the first bytes that are different rather than the whole string.
1384 size_t len = std::min(json.length(), jsongen.length());
1385 for (size_t i = 0; i < len; i++) {
1386 if (json[i] != jsongen[i]) {
1387 i -= std::min(static_cast<size_t>(10), i); // show some context;
1388 size_t end = std::min(len, i + 20);
1389 for (; i < end; i++)
1390 TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
1391 static_cast<int>(i), jsongen[i], json[i]);
1399 #ifdef FLATBUFFERS_TEST_VERBOSE
1400 TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
1401 static_cast<int>(schema.length() / 1024),
1402 static_cast<int>(json.length() / 1024));
1407 // Test that parser errors are actually generated.
1408 void TestError_(const char *src, const char *error_substr, bool strict_json,
1409 const char *file, int line, const char *func) {
1410 flatbuffers::IDLOptions opts;
1411 opts.strict_json = strict_json;
1412 flatbuffers::Parser parser(opts);
1413 if (parser.Parse(src)) {
1414 TestFail("true", "false",
1415 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1417 } else if (!strstr(parser.error_.c_str(), error_substr)) {
1418 TestFail(parser.error_.c_str(), error_substr,
1419 ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1424 void TestError_(const char *src, const char *error_substr, const char *file,
1425 int line, const char *func) {
1426 TestError_(src, error_substr, false, file, line, func);
1430 # define TestError(src, ...) \
1431 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
1433 # define TestError(src, ...) \
1434 TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1437 // Test that parsing errors occur as we'd expect.
1438 // Also useful for coverage, making sure these paths are run.
1440 // In order they appear in idl_parser.cpp
1441 TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
1442 TestError("\"\0", "illegal");
1443 TestError("\"\\q", "escape code");
1444 TestError("table ///", "documentation");
1445 TestError("@", "illegal");
1446 TestError("table 1", "expecting");
1447 TestError("table X { Y:[[int]]; }", "nested vector");
1448 TestError("table X { Y:1; }", "illegal type");
1449 TestError("table X { Y:int; Y:int; }", "field already");
1450 TestError("table Y {} table X { Y:int; }", "same as table");
1451 TestError("struct X { Y:string; }", "only scalar");
1452 TestError("table X { Y:string = \"\"; }", "default values");
1453 TestError("struct X { a:uint = 42; }", "default values");
1454 TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
1455 TestError("struct X { Y:int (deprecated); }", "deprecate");
1456 TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
1457 "missing type field");
1458 TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
1460 TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
1461 TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
1462 TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
1465 "struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
1468 TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
1469 "unknown enum value");
1470 TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
1471 TestError("enum X:byte { Y } enum X {", "enum already");
1472 TestError("enum X:float {}", "underlying");
1473 TestError("enum X:byte { Y, Y }", "value already");
1474 TestError("enum X:byte { Y=2, Z=1 }", "ascending");
1475 TestError("table X { Y:int; } table X {", "datatype already");
1476 TestError("struct X (force_align: 7) { Y:int; }", "force_align");
1477 TestError("struct X {}", "size 0");
1478 TestError("{}", "no root");
1479 TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
1480 TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
1482 TestError("root_type X;", "unknown root");
1483 TestError("struct X { Y:int; } root_type X;", "a table");
1484 TestError("union X { Y }", "referenced");
1485 TestError("union Z { X } struct X { Y:int; }", "only tables");
1486 TestError("table X { Y:[int]; YLength:int; }", "clash");
1487 TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
1488 // float to integer conversion is forbidden
1489 TestError("table X { Y:int; } root_type X; { Y:1.0 }", "float");
1490 TestError("table X { Y:bool; } root_type X; { Y:1.0 }", "float");
1491 TestError("enum X:bool { Y = true }", "must be integral");
1494 template<typename T>
1495 T TestValue(const char *json, const char *type_name,
1496 const char *decls = nullptr) {
1497 flatbuffers::Parser parser;
1498 parser.builder_.ForceDefaults(true); // return defaults
1499 auto check_default = json ? false : true;
1500 if (check_default) { parser.opts.output_default_scalars_in_json = true; }
1502 std::string schema = std::string(decls ? decls : "") + "\n" +
1503 "table X { Y:" + std::string(type_name) +
1505 auto schema_done = parser.Parse(schema.c_str());
1506 TEST_EQ_STR(parser.error_.c_str(), "");
1507 TEST_EQ(schema_done, true);
1509 auto done = parser.Parse(check_default ? "{}" : json);
1510 TEST_EQ_STR(parser.error_.c_str(), "");
1511 TEST_EQ(done, true);
1513 // Check with print.
1514 std::string print_back;
1515 parser.opts.indent_step = -1;
1516 TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back),
1518 // restore value from its default
1519 if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); }
1521 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
1522 parser.builder_.GetBufferPointer());
1523 return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
1526 bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
1528 // Additional parser testing not covered elsewhere.
1530 // Test scientific notation numbers.
1532 FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"), 3.14159f),
1535 TEST_EQ(FloatCompare(TestValue<float>("{ Y:\"0.0314159e+2\" }", "float"),
1539 // Test conversion functions.
1540 TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }", "float"), -1),
1543 // int embedded to string
1544 TEST_EQ(TestValue<int>("{ Y:\"-876\" }", "int=-123"), -876);
1545 TEST_EQ(TestValue<int>("{ Y:\"876\" }", "int=-123"), 876);
1547 // Test negative hex constant.
1548 TEST_EQ(TestValue<int>("{ Y:-0x8ea0 }", "int=-0x8ea0"), -36512);
1549 TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
1551 // positive hex constant
1552 TEST_EQ(TestValue<int>("{ Y:0x1abcdef }", "int=0x1"), 0x1abcdef);
1553 // with optional '+' sign
1554 TEST_EQ(TestValue<int>("{ Y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
1556 TEST_EQ(TestValue<int>("{ Y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
1558 // Make sure we do unsigned 64bit correctly.
1559 TEST_EQ(TestValue<uint64_t>("{ Y:12335089644688340133 }", "ulong"),
1560 12335089644688340133ULL);
1563 TEST_EQ(TestValue<bool>("{ Y:\"false\" }", "bool=true"), false);
1564 TEST_EQ(TestValue<bool>("{ Y:\"true\" }", "bool=\"true\""), true);
1565 TEST_EQ(TestValue<bool>("{ Y:'false' }", "bool=true"), false);
1566 TEST_EQ(TestValue<bool>("{ Y:'true' }", "bool=\"true\""), true);
1568 // check comments before and after json object
1569 TEST_EQ(TestValue<int>("/*before*/ { Y:1 } /*after*/", "int"), 1);
1570 TEST_EQ(TestValue<int>("//before \n { Y:1 } //after", "int"), 1);
1573 void NestedListTest() {
1574 flatbuffers::Parser parser1;
1575 TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
1577 "{ F:[ [10,20], [30,40]] }"),
1581 void EnumStringsTest() {
1582 flatbuffers::Parser parser1;
1583 TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
1585 "{ F:[ A, B, \"C\", \"A B C\" ] }"),
1587 flatbuffers::Parser parser2;
1588 TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
1590 "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"),
1592 // unsigned bit_flags
1593 flatbuffers::Parser parser3;
1595 parser3.Parse("enum E:uint16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }"
1596 " table T { F: E = \"F15 F08\"; }"
1601 void EnumNamesTest() {
1602 TEST_EQ_STR("Red", EnumNameColor(Color_Red));
1603 TEST_EQ_STR("Green", EnumNameColor(Color_Green));
1604 TEST_EQ_STR("Blue", EnumNameColor(Color_Blue));
1605 // Check that Color to string don't crash while decode a mixture of Colors.
1606 // 1) Example::Color enum is enum with unfixed underlying type.
1607 // 2) Valid enum range: [0; 2^(ceil(log2(Color_ANY))) - 1].
1608 // Consequence: A value is out of this range will lead to UB (since C++17).
1609 // For details see C++17 standard or explanation on the SO:
1610 // stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class
1611 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(0)));
1612 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY - 1)));
1613 TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY + 1)));
1616 void EnumOutOfRangeTest() {
1617 TestError("enum X:byte { Y = 128 }", "enum value does not fit");
1618 TestError("enum X:byte { Y = -129 }", "enum value does not fit");
1619 TestError("enum X:byte { Y = 126, Z0, Z1 }", "enum value does not fit");
1620 TestError("enum X:ubyte { Y = -1 }", "enum value does not fit");
1621 TestError("enum X:ubyte { Y = 256 }", "enum value does not fit");
1622 TestError("enum X:ubyte { Y = 255, Z }", "enum value does not fit");
1623 // Unions begin with an implicit "NONE = 0".
1624 TestError("table Y{} union X { Y = -1 }",
1625 "enum values must be specified in ascending order");
1626 TestError("table Y{} union X { Y = 256 }", "enum value does not fit");
1627 TestError("table Y{} union X { Y = 255, Z:Y }", "enum value does not fit");
1628 TestError("enum X:int { Y = -2147483649 }", "enum value does not fit");
1629 TestError("enum X:int { Y = 2147483648 }", "enum value does not fit");
1630 TestError("enum X:uint { Y = -1 }", "enum value does not fit");
1631 TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit");
1632 TestError("enum X:long { Y = 9223372036854775808 }", "does not fit");
1633 TestError("enum X:long { Y = 9223372036854775807, Z }",
1634 "enum value does not fit");
1635 TestError("enum X:ulong { Y = -1 }", "does not fit");
1636 TestError("enum X:ubyte (bit_flags) { Y=8 }", "bit flag out");
1637 TestError("enum X:byte (bit_flags) { Y=7 }", "must be unsigned"); // -128
1638 // bit_flgs out of range
1639 TestError("enum X:ubyte (bit_flags) { Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8 }",
1643 void EnumValueTest() {
1644 // json: "{ Y:0 }", schema: table X { Y : "E"}
1645 // 0 in enum (V=0) E then Y=0 is valid.
1646 TEST_EQ(TestValue<int>("{ Y:0 }", "E", "enum E:int { V }"), 0);
1647 TEST_EQ(TestValue<int>("{ Y:V }", "E", "enum E:int { V }"), 0);
1648 // A default value of Y is 0.
1649 TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
1650 TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { V=5 }"), 5);
1651 // Generate json with defaults and check.
1652 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
1654 TEST_EQ(TestValue<int>("{ Y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
1655 TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
1656 // Generate json with defaults and check.
1657 TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
1658 TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
1660 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1661 "enum E:ulong { V = 13835058055282163712 }"),
1662 13835058055282163712ULL);
1663 TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1664 "enum E:ulong { V = 18446744073709551615 }"),
1665 18446744073709551615ULL);
1666 // Assign non-enum value to enum field. Is it right?
1667 TEST_EQ(TestValue<int>("{ Y:7 }", "E", "enum E:int { V = 0 }"), 7);
1670 void IntegerOutOfRangeTest() {
1671 TestError("table T { F:byte; } root_type T; { F:128 }",
1672 "constant does not fit");
1673 TestError("table T { F:byte; } root_type T; { F:-129 }",
1674 "constant does not fit");
1675 TestError("table T { F:ubyte; } root_type T; { F:256 }",
1676 "constant does not fit");
1677 TestError("table T { F:ubyte; } root_type T; { F:-1 }",
1678 "constant does not fit");
1679 TestError("table T { F:short; } root_type T; { F:32768 }",
1680 "constant does not fit");
1681 TestError("table T { F:short; } root_type T; { F:-32769 }",
1682 "constant does not fit");
1683 TestError("table T { F:ushort; } root_type T; { F:65536 }",
1684 "constant does not fit");
1685 TestError("table T { F:ushort; } root_type T; { F:-1 }",
1686 "constant does not fit");
1687 TestError("table T { F:int; } root_type T; { F:2147483648 }",
1688 "constant does not fit");
1689 TestError("table T { F:int; } root_type T; { F:-2147483649 }",
1690 "constant does not fit");
1691 TestError("table T { F:uint; } root_type T; { F:4294967296 }",
1692 "constant does not fit");
1693 TestError("table T { F:uint; } root_type T; { F:-1 }",
1694 "constant does not fit");
1695 // Check fixed width aliases
1696 TestError("table X { Y:uint8; } root_type X; { Y: -1 }", "does not fit");
1697 TestError("table X { Y:uint8; } root_type X; { Y: 256 }", "does not fit");
1698 TestError("table X { Y:uint16; } root_type X; { Y: -1 }", "does not fit");
1699 TestError("table X { Y:uint16; } root_type X; { Y: 65536 }", "does not fit");
1700 TestError("table X { Y:uint32; } root_type X; { Y: -1 }", "");
1701 TestError("table X { Y:uint32; } root_type X; { Y: 4294967296 }",
1703 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1704 TestError("table X { Y:uint64; } root_type X; { Y: -9223372036854775809 }",
1706 TestError("table X { Y:uint64; } root_type X; { Y: 18446744073709551616 }",
1709 TestError("table X { Y:int8; } root_type X; { Y: -129 }", "does not fit");
1710 TestError("table X { Y:int8; } root_type X; { Y: 128 }", "does not fit");
1711 TestError("table X { Y:int16; } root_type X; { Y: -32769 }", "does not fit");
1712 TestError("table X { Y:int16; } root_type X; { Y: 32768 }", "does not fit");
1713 TestError("table X { Y:int32; } root_type X; { Y: -2147483649 }", "");
1714 TestError("table X { Y:int32; } root_type X; { Y: 2147483648 }",
1716 TestError("table X { Y:int64; } root_type X; { Y: -9223372036854775809 }",
1718 TestError("table X { Y:int64; } root_type X; { Y: 9223372036854775808 }",
1720 // check out-of-int64 as int8
1721 TestError("table X { Y:int8; } root_type X; { Y: -9223372036854775809 }",
1723 TestError("table X { Y:int8; } root_type X; { Y: 9223372036854775808 }",
1726 // Check default values
1727 TestError("table X { Y:int64=-9223372036854775809; } root_type X; {}",
1729 TestError("table X { Y:int64= 9223372036854775808; } root_type X; {}",
1731 TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1732 TestError("table X { Y:uint64=-9223372036854775809; } root_type X; {}",
1734 TestError("table X { Y:uint64= 18446744073709551616; } root_type X; {}",
1738 void IntegerBoundaryTest() {
1739 // Check numerical compatibility with non-C++ languages.
1740 // By the C++ standard, std::numerical_limits<int64_t>::min() ==
1741 // -9223372036854775807 (-2^63+1) or less* The Flatbuffers grammar and most of
1742 // the languages (C#, Java, Rust) expect that minimum values are: -128,
1743 // -32768,.., -9223372036854775808. Since C++20,
1744 // static_cast<int64>(0x8000000000000000ULL) is well-defined two's complement
1745 // cast. Therefore -9223372036854775808 should be valid negative value.
1746 TEST_EQ(flatbuffers::numeric_limits<int8_t>::min(), -128);
1747 TEST_EQ(flatbuffers::numeric_limits<int8_t>::max(), 127);
1748 TEST_EQ(flatbuffers::numeric_limits<int16_t>::min(), -32768);
1749 TEST_EQ(flatbuffers::numeric_limits<int16_t>::max(), 32767);
1750 TEST_EQ(flatbuffers::numeric_limits<int32_t>::min() + 1, -2147483647);
1751 TEST_EQ(flatbuffers::numeric_limits<int32_t>::max(), 2147483647ULL);
1752 TEST_EQ(flatbuffers::numeric_limits<int64_t>::min() + 1LL,
1753 -9223372036854775807LL);
1754 TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(), 9223372036854775807ULL);
1755 TEST_EQ(flatbuffers::numeric_limits<uint8_t>::max(), 255);
1756 TEST_EQ(flatbuffers::numeric_limits<uint16_t>::max(), 65535);
1757 TEST_EQ(flatbuffers::numeric_limits<uint32_t>::max(), 4294967295ULL);
1758 TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
1759 18446744073709551615ULL);
1761 TEST_EQ(TestValue<int8_t>("{ Y:127 }", "byte"), 127);
1762 TEST_EQ(TestValue<int8_t>("{ Y:-128 }", "byte"), -128);
1763 TEST_EQ(TestValue<uint8_t>("{ Y:255 }", "ubyte"), 255);
1764 TEST_EQ(TestValue<uint8_t>("{ Y:0 }", "ubyte"), 0);
1765 TEST_EQ(TestValue<int16_t>("{ Y:32767 }", "short"), 32767);
1766 TEST_EQ(TestValue<int16_t>("{ Y:-32768 }", "short"), -32768);
1767 TEST_EQ(TestValue<uint16_t>("{ Y:65535 }", "ushort"), 65535);
1768 TEST_EQ(TestValue<uint16_t>("{ Y:0 }", "ushort"), 0);
1769 TEST_EQ(TestValue<int32_t>("{ Y:2147483647 }", "int"), 2147483647);
1770 TEST_EQ(TestValue<int32_t>("{ Y:-2147483648 }", "int") + 1, -2147483647);
1771 TEST_EQ(TestValue<uint32_t>("{ Y:4294967295 }", "uint"), 4294967295);
1772 TEST_EQ(TestValue<uint32_t>("{ Y:0 }", "uint"), 0);
1773 TEST_EQ(TestValue<int64_t>("{ Y:9223372036854775807 }", "long"),
1774 9223372036854775807LL);
1775 TEST_EQ(TestValue<int64_t>("{ Y:-9223372036854775808 }", "long") + 1LL,
1776 -9223372036854775807LL);
1777 TEST_EQ(TestValue<uint64_t>("{ Y:18446744073709551615 }", "ulong"),
1778 18446744073709551615ULL);
1779 TEST_EQ(TestValue<uint64_t>("{ Y:0 }", "ulong"), 0);
1780 TEST_EQ(TestValue<uint64_t>("{ Y: 18446744073709551615 }", "uint64"),
1781 18446744073709551615ULL);
1782 // check that the default works
1783 TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
1784 18446744073709551615ULL);
1787 void ValidFloatTest() {
1788 // check rounding to infinity
1789 TEST_EQ(TestValue<float>("{ Y:+3.4029e+38 }", "float"), +infinityf);
1790 TEST_EQ(TestValue<float>("{ Y:-3.4029e+38 }", "float"), -infinityf);
1791 TEST_EQ(TestValue<double>("{ Y:+1.7977e+308 }", "double"), +infinityd);
1792 TEST_EQ(TestValue<double>("{ Y:-1.7977e+308 }", "double"), -infinityd);
1795 FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"), 3.14159f),
1798 TEST_EQ(FloatCompare(TestValue<float>("{ Y:\" 0.0314159e+2 \" }", "float"),
1802 TEST_EQ(TestValue<float>("{ Y:1 }", "float"), 1.0f);
1803 TEST_EQ(TestValue<float>("{ Y:1.0 }", "float"), 1.0f);
1804 TEST_EQ(TestValue<float>("{ Y:1. }", "float"), 1.0f);
1805 TEST_EQ(TestValue<float>("{ Y:+1. }", "float"), 1.0f);
1806 TEST_EQ(TestValue<float>("{ Y:-1. }", "float"), -1.0f);
1807 TEST_EQ(TestValue<float>("{ Y:1.e0 }", "float"), 1.0f);
1808 TEST_EQ(TestValue<float>("{ Y:1.e+0 }", "float"), 1.0f);
1809 TEST_EQ(TestValue<float>("{ Y:1.e-0 }", "float"), 1.0f);
1810 TEST_EQ(TestValue<float>("{ Y:0.125 }", "float"), 0.125f);
1811 TEST_EQ(TestValue<float>("{ Y:.125 }", "float"), 0.125f);
1812 TEST_EQ(TestValue<float>("{ Y:-.125 }", "float"), -0.125f);
1813 TEST_EQ(TestValue<float>("{ Y:+.125 }", "float"), +0.125f);
1814 TEST_EQ(TestValue<float>("{ Y:5 }", "float"), 5.0f);
1815 TEST_EQ(TestValue<float>("{ Y:\"5\" }", "float"), 5.0f);
1817 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
1818 // Old MSVC versions may have problem with this check.
1819 // https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
1820 TEST_EQ(TestValue<double>("{ Y:6.9294956446009195e15 }", "double"),
1821 6929495644600920.0);
1823 TEST_EQ(std::isnan(TestValue<double>("{ Y:nan }", "double")), true);
1824 TEST_EQ(std::isnan(TestValue<float>("{ Y:nan }", "float")), true);
1825 TEST_EQ(std::isnan(TestValue<float>("{ Y:\"nan\" }", "float")), true);
1826 TEST_EQ(std::isnan(TestValue<float>("{ Y:+nan }", "float")), true);
1827 TEST_EQ(std::isnan(TestValue<float>("{ Y:-nan }", "float")), true);
1828 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
1829 TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
1831 TEST_EQ(TestValue<float>("{ Y:inf }", "float"), infinityf);
1832 TEST_EQ(TestValue<float>("{ Y:\"inf\" }", "float"), infinityf);
1833 TEST_EQ(TestValue<float>("{ Y:+inf }", "float"), infinityf);
1834 TEST_EQ(TestValue<float>("{ Y:-inf }", "float"), -infinityf);
1835 TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinityf);
1836 TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinityf);
1838 "{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
1842 "{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
1846 // Test binary format of float point.
1847 // https://en.cppreference.com/w/cpp/language/floating_literal
1848 // 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
1849 TEST_EQ(TestValue<double>("{ Y:0x12.34p-1 }", "double"), 9.1015625);
1850 // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
1851 TEST_EQ(TestValue<float>("{ Y:-0x0.2p0 }", "float"), -0.125f);
1852 TEST_EQ(TestValue<float>("{ Y:-0x.2p1 }", "float"), -0.25f);
1853 TEST_EQ(TestValue<float>("{ Y:0x1.2p3 }", "float"), 9.0f);
1854 TEST_EQ(TestValue<float>("{ Y:0x10.1p0 }", "float"), 16.0625f);
1855 TEST_EQ(TestValue<double>("{ Y:0x1.2p3 }", "double"), 9.0);
1856 TEST_EQ(TestValue<double>("{ Y:0x10.1p0 }", "double"), 16.0625);
1857 TEST_EQ(TestValue<double>("{ Y:0xC.68p+2 }", "double"), 49.625);
1858 TestValue<double>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
1859 TestValue<float>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
1861 #else // FLATBUFFERS_HAS_NEW_STRTOD
1862 TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");
1863 #endif // !FLATBUFFERS_HAS_NEW_STRTOD
1866 void InvalidFloatTest() {
1867 auto invalid_msg = "invalid number";
1868 auto comma_msg = "expecting: ,";
1869 TestError("table T { F:float; } root_type T; { F:1,0 }", "");
1870 TestError("table T { F:float; } root_type T; { F:. }", "");
1871 TestError("table T { F:float; } root_type T; { F:- }", invalid_msg);
1872 TestError("table T { F:float; } root_type T; { F:+ }", invalid_msg);
1873 TestError("table T { F:float; } root_type T; { F:-. }", invalid_msg);
1874 TestError("table T { F:float; } root_type T; { F:+. }", invalid_msg);
1875 TestError("table T { F:float; } root_type T; { F:.e }", "");
1876 TestError("table T { F:float; } root_type T; { F:-e }", invalid_msg);
1877 TestError("table T { F:float; } root_type T; { F:+e }", invalid_msg);
1878 TestError("table T { F:float; } root_type T; { F:-.e }", invalid_msg);
1879 TestError("table T { F:float; } root_type T; { F:+.e }", invalid_msg);
1880 TestError("table T { F:float; } root_type T; { F:-e1 }", invalid_msg);
1881 TestError("table T { F:float; } root_type T; { F:+e1 }", invalid_msg);
1882 TestError("table T { F:float; } root_type T; { F:1.0e+ }", invalid_msg);
1883 TestError("table T { F:float; } root_type T; { F:1.0e- }", invalid_msg);
1884 // exponent pP is mandatory for hex-float
1885 TestError("table T { F:float; } root_type T; { F:0x0 }", invalid_msg);
1886 TestError("table T { F:float; } root_type T; { F:-0x. }", invalid_msg);
1887 TestError("table T { F:float; } root_type T; { F:0x. }", invalid_msg);
1888 // eE not exponent in hex-float!
1889 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
1890 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
1891 TestError("table T { F:float; } root_type T; { F:0x0.0p }", invalid_msg);
1892 TestError("table T { F:float; } root_type T; { F:0x0.0p+ }", invalid_msg);
1893 TestError("table T { F:float; } root_type T; { F:0x0.0p- }", invalid_msg);
1894 TestError("table T { F:float; } root_type T; { F:0x0.0pa1 }", invalid_msg);
1895 TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
1896 TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
1897 TestError("table T { F:float; } root_type T; { F:0x0.0e+0 }", invalid_msg);
1898 TestError("table T { F:float; } root_type T; { F:0x0.0e-0 }", invalid_msg);
1899 TestError("table T { F:float; } root_type T; { F:0x0.0ep+ }", invalid_msg);
1900 TestError("table T { F:float; } root_type T; { F:0x0.0ep- }", invalid_msg);
1901 TestError("table T { F:float; } root_type T; { F:1.2.3 }", invalid_msg);
1902 TestError("table T { F:float; } root_type T; { F:1.2.e3 }", invalid_msg);
1903 TestError("table T { F:float; } root_type T; { F:1.2e.3 }", invalid_msg);
1904 TestError("table T { F:float; } root_type T; { F:1.2e0.3 }", invalid_msg);
1905 TestError("table T { F:float; } root_type T; { F:1.2e3. }", invalid_msg);
1906 TestError("table T { F:float; } root_type T; { F:1.2e3.0 }", invalid_msg);
1907 TestError("table T { F:float; } root_type T; { F:+-1.0 }", invalid_msg);
1908 TestError("table T { F:float; } root_type T; { F:1.0e+-1 }", invalid_msg);
1909 TestError("table T { F:float; } root_type T; { F:\"1.0e+-1\" }", invalid_msg);
1910 TestError("table T { F:float; } root_type T; { F:1.e0e }", comma_msg);
1911 TestError("table T { F:float; } root_type T; { F:0x1.p0e }", comma_msg);
1912 TestError("table T { F:float; } root_type T; { F:\" 0x10 \" }", invalid_msg);
1914 TestError("table T { F:float; } root_type T; { F:\"1,2.\" }", invalid_msg);
1915 TestError("table T { F:float; } root_type T; { F:\"1.2e3.\" }", invalid_msg);
1916 TestError("table T { F:float; } root_type T; { F:\"0x1.p0e\" }", invalid_msg);
1917 TestError("table T { F:float; } root_type T; { F:\"0x1.0\" }", invalid_msg);
1918 TestError("table T { F:float; } root_type T; { F:\" 0x1.0\" }", invalid_msg);
1919 TestError("table T { F:float; } root_type T; { F:\"+ 0\" }", invalid_msg);
1920 // disable escapes for "number-in-string"
1921 TestError("table T { F:float; } root_type T; { F:\"\\f1.2e3.\" }", "invalid");
1922 TestError("table T { F:float; } root_type T; { F:\"\\t1.2e3.\" }", "invalid");
1923 TestError("table T { F:float; } root_type T; { F:\"\\n1.2e3.\" }", "invalid");
1924 TestError("table T { F:float; } root_type T; { F:\"\\r1.2e3.\" }", "invalid");
1925 TestError("table T { F:float; } root_type T; { F:\"4\\x005\" }", "invalid");
1926 TestError("table T { F:float; } root_type T; { F:\"\'12\'\" }", invalid_msg);
1927 // null is not a number constant!
1928 TestError("table T { F:float; } root_type T; { F:\"null\" }", invalid_msg);
1929 TestError("table T { F:float; } root_type T; { F:null }", invalid_msg);
1932 void GenerateTableTextTest() {
1933 std::string schemafile;
1934 std::string jsonfile;
1936 flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
1937 false, &schemafile) &&
1938 flatbuffers::LoadFile((test_data_path + "monsterdata_test.json").c_str(),
1941 auto include_test_path =
1942 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
1943 const char *include_directories[] = { test_data_path.c_str(),
1944 include_test_path.c_str(), nullptr };
1945 flatbuffers::IDLOptions opt;
1946 opt.indent_step = -1;
1947 flatbuffers::Parser parser(opt);
1948 ok = parser.Parse(schemafile.c_str(), include_directories) &&
1949 parser.Parse(jsonfile.c_str(), include_directories);
1952 const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
1953 std::string jsongen;
1954 auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster",
1956 TEST_EQ(result, true);
1958 const Vec3 *pos = monster->pos();
1960 result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
1961 TEST_EQ(result, true);
1964 "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
1965 const Test &test3 = pos->test3();
1968 GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
1969 TEST_EQ(result, true);
1970 TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
1971 const Test *test4 = monster->test4()->Get(0);
1974 GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
1975 TEST_EQ(result, true);
1976 TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
1979 template<typename T>
1980 void NumericUtilsTestInteger(const char *lower, const char *upper) {
1982 TEST_EQ(flatbuffers::StringToNumber("1q", &x), false);
1984 TEST_EQ(flatbuffers::StringToNumber(upper, &x), false);
1985 TEST_EQ(x, flatbuffers::numeric_limits<T>::max());
1986 TEST_EQ(flatbuffers::StringToNumber(lower, &x), false);
1987 auto expval = flatbuffers::is_unsigned<T>::value
1988 ? flatbuffers::numeric_limits<T>::max()
1989 : flatbuffers::numeric_limits<T>::lowest();
1993 template<typename T>
1994 void NumericUtilsTestFloat(const char *lower, const char *upper) {
1996 TEST_EQ(flatbuffers::StringToNumber("", &f), false);
1997 TEST_EQ(flatbuffers::StringToNumber("1q", &f), false);
1999 TEST_EQ(flatbuffers::StringToNumber(upper, &f), true);
2000 TEST_EQ(f, +flatbuffers::numeric_limits<T>::infinity());
2001 TEST_EQ(flatbuffers::StringToNumber(lower, &f), true);
2002 TEST_EQ(f, -flatbuffers::numeric_limits<T>::infinity());
2005 void NumericUtilsTest() {
2006 NumericUtilsTestInteger<uint64_t>("-1", "18446744073709551616");
2007 NumericUtilsTestInteger<uint8_t>("-1", "256");
2008 NumericUtilsTestInteger<int64_t>("-9223372036854775809",
2009 "9223372036854775808");
2010 NumericUtilsTestInteger<int8_t>("-129", "128");
2011 NumericUtilsTestFloat<float>("-3.4029e+38", "+3.4029e+38");
2012 NumericUtilsTestFloat<float>("-1.7977e+308", "+1.7977e+308");
2015 void IsAsciiUtilsTest() {
2017 for (int cnt = 0; cnt < 256; cnt++) {
2018 auto alpha = (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
2019 auto dec = (('0' <= c) && (c <= '9'));
2020 auto hex = (('a' <= c) && (c <= 'f')) || (('A' <= c) && (c <= 'F'));
2021 TEST_EQ(flatbuffers::is_alpha(c), alpha);
2022 TEST_EQ(flatbuffers::is_alnum(c), alpha || dec);
2023 TEST_EQ(flatbuffers::is_digit(c), dec);
2024 TEST_EQ(flatbuffers::is_xdigit(c), dec || hex);
2029 void UnicodeTest() {
2030 flatbuffers::Parser parser;
2031 // Without setting allow_non_utf8 = true, we treat \x sequences as byte
2032 // sequences which are then validated as UTF-8.
2033 TEST_EQ(parser.Parse("table T { F:string; }"
2035 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2036 "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD8"
2039 std::string jsongen;
2040 parser.opts.indent_step = -1;
2042 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2043 TEST_EQ(result, true);
2044 TEST_EQ_STR(jsongen.c_str(),
2045 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2046 "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
2049 void UnicodeTestAllowNonUTF8() {
2050 flatbuffers::Parser parser;
2051 parser.opts.allow_non_utf8 = true;
2054 "table T { F:string; }"
2056 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2057 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2059 std::string jsongen;
2060 parser.opts.indent_step = -1;
2062 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2063 TEST_EQ(result, true);
2066 "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2067 "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
2070 void UnicodeTestGenerateTextFailsOnNonUTF8() {
2071 flatbuffers::Parser parser;
2072 // Allow non-UTF-8 initially to model what happens when we load a binary
2073 // flatbuffer from disk which contains non-UTF-8 strings.
2074 parser.opts.allow_non_utf8 = true;
2077 "table T { F:string; }"
2079 "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2080 "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2082 std::string jsongen;
2083 parser.opts.indent_step = -1;
2084 // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates
2086 parser.opts.allow_non_utf8 = false;
2088 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2089 TEST_EQ(result, false);
2092 void UnicodeSurrogatesTest() {
2093 flatbuffers::Parser parser;
2095 TEST_EQ(parser.Parse("table T { F:string (id: 0); }"
2097 "{ F:\"\\uD83D\\uDCA9\"}"),
2099 auto root = flatbuffers::GetRoot<flatbuffers::Table>(
2100 parser.builder_.GetBufferPointer());
2101 auto string = root->GetPointer<flatbuffers::String *>(
2102 flatbuffers::FieldIndexToOffset(0));
2103 TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
2106 void UnicodeInvalidSurrogatesTest() {
2108 "table T { F:string; }"
2111 "unpaired high surrogate");
2113 "table T { F:string; }"
2115 "{ F:\"\\uD800abcd\"}",
2116 "unpaired high surrogate");
2118 "table T { F:string; }"
2120 "{ F:\"\\uD800\\n\"}",
2121 "unpaired high surrogate");
2123 "table T { F:string; }"
2125 "{ F:\"\\uD800\\uD800\"}",
2126 "multiple high surrogates");
2128 "table T { F:string; }"
2131 "unpaired low surrogate");
2134 void InvalidUTF8Test() {
2135 // "1 byte" pattern, under min length of 2 bytes
2137 "table T { F:string; }"
2140 "illegal UTF-8 sequence");
2141 // 2 byte pattern, string too short
2143 "table T { F:string; }"
2146 "illegal UTF-8 sequence");
2147 // 3 byte pattern, string too short
2149 "table T { F:string; }"
2151 "{ F:\"\xEF\xBF\"}",
2152 "illegal UTF-8 sequence");
2153 // 4 byte pattern, string too short
2155 "table T { F:string; }"
2157 "{ F:\"\xF7\xBF\xBF\"}",
2158 "illegal UTF-8 sequence");
2159 // "5 byte" pattern, string too short
2161 "table T { F:string; }"
2163 "{ F:\"\xFB\xBF\xBF\xBF\"}",
2164 "illegal UTF-8 sequence");
2165 // "6 byte" pattern, string too short
2167 "table T { F:string; }"
2169 "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}",
2170 "illegal UTF-8 sequence");
2171 // "7 byte" pattern, string too short
2173 "table T { F:string; }"
2175 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}",
2176 "illegal UTF-8 sequence");
2177 // "5 byte" pattern, over max length of 4 bytes
2179 "table T { F:string; }"
2181 "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}",
2182 "illegal UTF-8 sequence");
2183 // "6 byte" pattern, over max length of 4 bytes
2185 "table T { F:string; }"
2187 "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}",
2188 "illegal UTF-8 sequence");
2189 // "7 byte" pattern, over max length of 4 bytes
2191 "table T { F:string; }"
2193 "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}",
2194 "illegal UTF-8 sequence");
2196 // Three invalid encodings for U+000A (\n, aka NEWLINE)
2198 "table T { F:string; }"
2200 "{ F:\"\xC0\x8A\"}",
2201 "illegal UTF-8 sequence");
2203 "table T { F:string; }"
2205 "{ F:\"\xE0\x80\x8A\"}",
2206 "illegal UTF-8 sequence");
2208 "table T { F:string; }"
2210 "{ F:\"\xF0\x80\x80\x8A\"}",
2211 "illegal UTF-8 sequence");
2213 // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
2215 "table T { F:string; }"
2217 "{ F:\"\xE0\x81\xA9\"}",
2218 "illegal UTF-8 sequence");
2220 "table T { F:string; }"
2222 "{ F:\"\xF0\x80\x81\xA9\"}",
2223 "illegal UTF-8 sequence");
2225 // Invalid encoding for U+20AC (EURO SYMBOL)
2227 "table T { F:string; }"
2229 "{ F:\"\xF0\x82\x82\xAC\"}",
2230 "illegal UTF-8 sequence");
2232 // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in
2235 "table T { F:string; }"
2237 // U+10400 "encoded" as U+D801 U+DC00
2238 "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}",
2239 "illegal UTF-8 sequence");
2241 // Check independence of identifier from locale.
2242 std::string locale_ident;
2243 locale_ident += "table T { F";
2244 locale_ident += static_cast<char>(-32); // unsigned 0xE0
2245 locale_ident += " :string; }";
2246 locale_ident += "root_type T;";
2247 locale_ident += "{}";
2248 TestError(locale_ident.c_str(), "");
2251 void UnknownFieldsTest() {
2252 flatbuffers::IDLOptions opts;
2253 opts.skip_unexpected_fields_in_json = true;
2254 flatbuffers::Parser parser(opts);
2256 TEST_EQ(parser.Parse("table T { str:string; i:int;}"
2259 "unknown_string:\"test\","
2260 "\"unknown_string\":\"test\","
2262 "unknown_float:1.0,"
2263 "unknown_array: [ 1, 2, 3, 4],"
2264 "unknown_object: { i: 10 },"
2265 "\"unknown_object\": { \"i\": 10 },"
2269 std::string jsongen;
2270 parser.opts.indent_step = -1;
2272 GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2273 TEST_EQ(result, true);
2274 TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
2277 void ParseUnionTest() {
2278 // Unions must be parseable with the type field following the object.
2279 flatbuffers::Parser parser;
2280 TEST_EQ(parser.Parse("table T { A:int; }"
2284 "{ X:{ A:1 }, X_type: T }"),
2286 // Unions must be parsable with prefixed namespace.
2287 flatbuffers::Parser parser2;
2288 TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
2289 "table B { e:U; } root_type B;"
2290 "{ e_type: N_A, e: {} }"),
2294 void InvalidNestedFlatbufferTest() {
2295 // First, load and parse FlatBuffer schema (.fbs)
2296 std::string schemafile;
2297 TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2298 false, &schemafile),
2300 auto include_test_path =
2301 flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2302 const char *include_directories[] = { test_data_path.c_str(),
2303 include_test_path.c_str(), nullptr };
2304 flatbuffers::Parser parser1;
2305 TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
2307 // "color" inside nested flatbuffer contains invalid enum value
2308 TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
2309 "\"Leela\", color: \"nonexistent\"}}"),
2311 // Check that Parser is destroyed correctly after parsing invalid json
2314 void UnionVectorTest() {
2315 // load FlatBuffer fbs schema and json.
2316 std::string schemafile, jsonfile;
2317 TEST_EQ(flatbuffers::LoadFile(
2318 (test_data_path + "union_vector/union_vector.fbs").c_str(), false,
2321 TEST_EQ(flatbuffers::LoadFile(
2322 (test_data_path + "union_vector/union_vector.json").c_str(),
2327 flatbuffers::IDLOptions idl_opts;
2328 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2329 flatbuffers::Parser parser(idl_opts);
2330 TEST_EQ(parser.Parse(schemafile.c_str()), true);
2332 flatbuffers::FlatBufferBuilder fbb;
2335 std::vector<uint8_t> types;
2336 types.push_back(static_cast<uint8_t>(Character_Belle));
2337 types.push_back(static_cast<uint8_t>(Character_MuLan));
2338 types.push_back(static_cast<uint8_t>(Character_BookFan));
2339 types.push_back(static_cast<uint8_t>(Character_Other));
2340 types.push_back(static_cast<uint8_t>(Character_Unused));
2343 std::vector<flatbuffers::Offset<void>> characters;
2344 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
2345 characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
2346 characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
2347 characters.push_back(fbb.CreateString("Other").Union());
2348 characters.push_back(fbb.CreateString("Unused").Union());
2351 const auto movie_offset =
2352 CreateMovie(fbb, Character_Rapunzel,
2353 fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
2354 fbb.CreateVector(types), fbb.CreateVector(characters));
2355 FinishMovieBuffer(fbb, movie_offset);
2357 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
2358 TEST_EQ(VerifyMovieBuffer(verifier), true);
2360 auto flat_movie = GetMovie(fbb.GetBufferPointer());
2362 auto TestMovie = [](const Movie *movie) {
2363 TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
2365 auto cts = movie->characters_type();
2366 TEST_EQ(movie->characters_type()->size(), 5);
2367 TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
2368 TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
2369 TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
2370 TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
2371 TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
2373 auto rapunzel = movie->main_character_as_Rapunzel();
2374 TEST_NOTNULL(rapunzel);
2375 TEST_EQ(rapunzel->hair_length(), 6);
2377 auto cs = movie->characters();
2378 TEST_EQ(cs->size(), 5);
2379 auto belle = cs->GetAs<BookReader>(0);
2380 TEST_EQ(belle->books_read(), 7);
2381 auto mu_lan = cs->GetAs<Attacker>(1);
2382 TEST_EQ(mu_lan->sword_attack_damage(), 5);
2383 auto book_fan = cs->GetAs<BookReader>(2);
2384 TEST_EQ(book_fan->books_read(), 2);
2385 auto other = cs->GetAsString(3);
2386 TEST_EQ_STR(other->c_str(), "Other");
2387 auto unused = cs->GetAsString(4);
2388 TEST_EQ_STR(unused->c_str(), "Unused");
2391 TestMovie(flat_movie);
2393 // Also test the JSON we loaded above.
2394 TEST_EQ(parser.Parse(jsonfile.c_str()), true);
2395 auto jbuf = parser.builder_.GetBufferPointer();
2396 flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
2397 TEST_EQ(VerifyMovieBuffer(jverifier), true);
2398 TestMovie(GetMovie(jbuf));
2400 auto movie_object = flat_movie->UnPack();
2401 TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
2402 TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
2403 TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
2404 TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
2405 TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
2406 TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
2409 fbb.Finish(Movie::Pack(fbb, movie_object));
2411 delete movie_object;
2413 auto repacked_movie = GetMovie(fbb.GetBufferPointer());
2415 TestMovie(repacked_movie);
2417 // Generate text using mini-reflection.
2419 flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
2422 "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
2423 "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
2424 "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
2425 "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
2427 flatbuffers::ToStringVisitor visitor("\n", true, " ");
2428 IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
2429 TEST_EQ_STR(visitor.s.c_str(),
2431 " \"main_character_type\": \"Rapunzel\",\n"
2432 " \"main_character\": {\n"
2433 " \"hair_length\": 6\n"
2435 " \"characters_type\": [\n"
2442 " \"characters\": [\n"
2444 " \"books_read\": 7\n"
2447 " \"sword_attack_damage\": 5\n"
2450 " \"books_read\": 2\n"
2457 // Generate text using parsed schema.
2458 std::string jsongen;
2459 auto result = GenerateText(parser, fbb.GetBufferPointer(), &jsongen);
2460 TEST_EQ(result, true);
2461 TEST_EQ_STR(jsongen.c_str(),
2463 " main_character_type: \"Rapunzel\",\n"
2464 " main_character: {\n"
2467 " characters_type: [\n"
2479 " sword_attack_damage: 5\n"
2489 // Simple test with reflection.
2491 auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
2492 auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
2493 fbb.GetBufferPointer(), fbb.GetSize());
2496 flatbuffers::Parser parser2(idl_opts);
2497 TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
2498 "union Any { Bool }"
2499 "table Root { a:Any; }"
2502 TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
2505 void ConformTest() {
2506 flatbuffers::Parser parser;
2507 TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
2509 auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
2510 const char *expected_err) {
2511 flatbuffers::Parser parser2;
2512 TEST_EQ(parser2.Parse(test), true);
2513 auto err = parser2.ConformTo(parser1);
2514 TEST_NOTNULL(strstr(err.c_str(), expected_err));
2517 test_conform(parser, "table T { A:byte; }", "types differ for field");
2518 test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
2519 test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
2520 test_conform(parser, "table T { B:float; }",
2521 "field renamed to different type");
2522 test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
2525 void ParseProtoBufAsciiTest() {
2526 // We can put the parser in a mode where it will accept JSON that looks more
2527 // like Protobuf ASCII, for users that have data in that format.
2528 // This uses no "" for field names (which we already support by default,
2529 // omits `,`, `:` before `{` and a couple of other features.
2530 flatbuffers::Parser parser;
2531 parser.opts.protobuf_ascii_alike = true;
2533 parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
2535 TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
2536 // Similarly, in text output, it should omit these.
2538 auto ok = flatbuffers::GenerateText(
2539 parser, parser.builder_.GetBufferPointer(), &text);
2541 TEST_EQ_STR(text.c_str(),
2542 "{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n");
2545 void FlexBuffersTest() {
2546 flexbuffers::Builder slb(512,
2547 flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
2549 // Write the equivalent of:
2550 // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ],
2551 // foo: 100, bool: true, mymap: { foo: "Fred" } }
2553 #ifndef FLATBUFFERS_CPP98_STL
2554 // It's possible to do this without std::function support as well.
2556 slb.Vector("vec", [&]() {
2557 slb += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2559 slb.IndirectFloat(4.0f);
2560 auto i_f = slb.LastValue();
2561 uint8_t blob[] = { 77 };
2564 slb.ReuseValue(i_f);
2566 int ints[] = { 1, 2, 3 };
2567 slb.Vector("bar", ints, 3);
2568 slb.FixedTypedVector("bar3", ints, 3);
2569 bool bools[] = {true, false, true, false};
2570 slb.Vector("bools", bools, 4);
2571 slb.Bool("bool", true);
2572 slb.Double("foo", 100);
2573 slb.Map("mymap", [&]() {
2574 slb.String("foo", "Fred"); // Testing key and string reuse.
2579 // It's possible to do this without std::function support as well.
2580 slb.Map([](flexbuffers::Builder& slb2) {
2581 slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
2582 slb3 += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
2584 slb3.IndirectFloat(4.0f);
2585 auto i_f = slb3.LastValue();
2586 uint8_t blob[] = { 77 };
2589 slb3.ReuseValue(i_f);
2591 int ints[] = { 1, 2, 3 };
2592 slb2.Vector("bar", ints, 3);
2593 slb2.FixedTypedVector("bar3", ints, 3);
2594 slb2.Bool("bool", true);
2595 slb2.Double("foo", 100);
2596 slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
2597 slb3.String("foo", "Fred"); // Testing key and string reuse.
2601 #endif // FLATBUFFERS_CPP98_STL
2603 #ifdef FLATBUFFERS_TEST_VERBOSE
2604 for (size_t i = 0; i < slb.GetBuffer().size(); i++)
2605 printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
2610 auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
2611 TEST_EQ(map.size(), 7);
2612 auto vec = map["vec"].AsVector();
2613 TEST_EQ(vec.size(), 6);
2614 TEST_EQ(vec[0].AsInt64(), -100);
2615 TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
2616 TEST_EQ(vec[1].AsInt64(), 0); // Number parsing failed.
2617 TEST_EQ(vec[2].AsDouble(), 4.0);
2618 TEST_EQ(vec[2].AsString().IsTheEmptyString(), true); // Wrong Type.
2619 TEST_EQ_STR(vec[2].AsString().c_str(), ""); // This still works though.
2620 TEST_EQ_STR(vec[2].ToString().c_str(), "4.0"); // Or have it converted.
2621 // Few tests for templated version of As.
2622 TEST_EQ(vec[0].As<int64_t>(), -100);
2623 TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
2624 TEST_EQ(vec[1].As<int64_t>(), 0); // Number parsing failed.
2625 TEST_EQ(vec[2].As<double>(), 4.0);
2626 // Test that the blob can be accessed.
2627 TEST_EQ(vec[3].IsBlob(), true);
2628 auto blob = vec[3].AsBlob();
2629 TEST_EQ(blob.size(), 1);
2630 TEST_EQ(blob.data()[0], 77);
2631 TEST_EQ(vec[4].IsBool(), true); // Check if type is a bool
2632 TEST_EQ(vec[4].AsBool(), false); // Check if value is false
2633 TEST_EQ(vec[5].AsDouble(), 4.0); // This is shared with vec[2] !
2634 auto tvec = map["bar"].AsTypedVector();
2635 TEST_EQ(tvec.size(), 3);
2636 TEST_EQ(tvec[2].AsInt8(), 3);
2637 auto tvec3 = map["bar3"].AsFixedTypedVector();
2638 TEST_EQ(tvec3.size(), 3);
2639 TEST_EQ(tvec3[2].AsInt8(), 3);
2640 TEST_EQ(map["bool"].AsBool(), true);
2641 auto tvecb = map["bools"].AsTypedVector();
2642 TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
2643 TEST_EQ(map["foo"].AsUInt8(), 100);
2644 TEST_EQ(map["unknown"].IsNull(), true);
2645 auto mymap = map["mymap"].AsMap();
2646 // These should be equal by pointer equality, since key and value are shared.
2647 TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
2648 TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
2649 // We can mutate values in the buffer.
2650 TEST_EQ(vec[0].MutateInt(-99), true);
2651 TEST_EQ(vec[0].AsInt64(), -99);
2652 TEST_EQ(vec[1].MutateString("John"), true); // Size must match.
2653 TEST_EQ_STR(vec[1].AsString().c_str(), "John");
2654 TEST_EQ(vec[1].MutateString("Alfred"), false); // Too long.
2655 TEST_EQ(vec[2].MutateFloat(2.0f), true);
2656 TEST_EQ(vec[2].AsFloat(), 2.0f);
2657 TEST_EQ(vec[2].MutateFloat(3.14159), false); // Double does not fit in float.
2658 TEST_EQ(vec[4].AsBool(), false); // Is false before change
2659 TEST_EQ(vec[4].MutateBool(true), true); // Can change a bool
2660 TEST_EQ(vec[4].AsBool(), true); // Changed bool is now true
2663 flatbuffers::Parser parser;
2665 auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
2666 TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
2667 auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
2668 auto jmap = jroot.AsMap();
2669 auto jvec = jmap["a"].AsVector();
2670 TEST_EQ(jvec[0].AsInt64(), 123);
2671 TEST_EQ(jvec[1].AsDouble(), 456.0);
2672 TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
2673 TEST_EQ(jmap["c"].IsBool(), true); // Parsed correctly to a bool
2674 TEST_EQ(jmap["c"].AsBool(), true); // Parsed correctly to true
2675 TEST_EQ(jmap["d"].IsBool(), true); // Parsed correctly to a bool
2676 TEST_EQ(jmap["d"].AsBool(), false); // Parsed correctly to false
2677 // And from FlexBuffer back to JSON:
2678 auto jsonback = jroot.ToString();
2679 TEST_EQ_STR(jsontest, jsonback.c_str());
2682 void TypeAliasesTest() {
2683 flatbuffers::FlatBufferBuilder builder;
2685 builder.Finish(CreateTypeAliases(
2686 builder, flatbuffers::numeric_limits<int8_t>::min(),
2687 flatbuffers::numeric_limits<uint8_t>::max(),
2688 flatbuffers::numeric_limits<int16_t>::min(),
2689 flatbuffers::numeric_limits<uint16_t>::max(),
2690 flatbuffers::numeric_limits<int32_t>::min(),
2691 flatbuffers::numeric_limits<uint32_t>::max(),
2692 flatbuffers::numeric_limits<int64_t>::min(),
2693 flatbuffers::numeric_limits<uint64_t>::max(), 2.3f, 2.3));
2695 auto p = builder.GetBufferPointer();
2696 auto ta = flatbuffers::GetRoot<TypeAliases>(p);
2698 TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
2699 TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
2700 TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
2701 TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
2702 TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
2703 TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
2704 TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
2705 TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
2706 TEST_EQ(ta->f32(), 2.3f);
2707 TEST_EQ(ta->f64(), 2.3);
2708 using namespace flatbuffers; // is_same
2709 static_assert(is_same<decltype(ta->i8()), int8_t>::value, "invalid type");
2710 static_assert(is_same<decltype(ta->i16()), int16_t>::value, "invalid type");
2711 static_assert(is_same<decltype(ta->i32()), int32_t>::value, "invalid type");
2712 static_assert(is_same<decltype(ta->i64()), int64_t>::value, "invalid type");
2713 static_assert(is_same<decltype(ta->u8()), uint8_t>::value, "invalid type");
2714 static_assert(is_same<decltype(ta->u16()), uint16_t>::value, "invalid type");
2715 static_assert(is_same<decltype(ta->u32()), uint32_t>::value, "invalid type");
2716 static_assert(is_same<decltype(ta->u64()), uint64_t>::value, "invalid type");
2717 static_assert(is_same<decltype(ta->f32()), float>::value, "invalid type");
2718 static_assert(is_same<decltype(ta->f64()), double>::value, "invalid type");
2721 void EndianSwapTest() {
2722 TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
2723 TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
2725 TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
2726 0xEFCDAB9078563412);
2727 TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
2730 void UninitializedVectorTest() {
2731 flatbuffers::FlatBufferBuilder builder;
2733 Test *buf = nullptr;
2734 auto vector_offset =
2735 builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
2737 buf[0] = Test(10, 20);
2738 buf[1] = Test(30, 40);
2740 auto required_name = builder.CreateString("myMonster");
2741 auto monster_builder = MonsterBuilder(builder);
2742 monster_builder.add_name(
2743 required_name); // required field mandated for monster.
2744 monster_builder.add_test4(vector_offset);
2745 builder.Finish(monster_builder.Finish());
2747 auto p = builder.GetBufferPointer();
2748 auto uvt = flatbuffers::GetRoot<Monster>(p);
2750 auto vec = uvt->test4();
2752 auto test_0 = vec->Get(0);
2753 auto test_1 = vec->Get(1);
2754 TEST_EQ(test_0->a(), 10);
2755 TEST_EQ(test_0->b(), 20);
2756 TEST_EQ(test_1->a(), 30);
2757 TEST_EQ(test_1->b(), 40);
2760 void EqualOperatorTest() {
2763 TEST_EQ(b == a, true);
2764 TEST_EQ(b != a, false);
2767 TEST_EQ(b == a, false);
2768 TEST_EQ(b != a, true);
2770 TEST_EQ(b == a, true);
2771 TEST_EQ(b != a, false);
2773 b.inventory.push_back(3);
2774 TEST_EQ(b == a, false);
2775 TEST_EQ(b != a, true);
2776 b.inventory.clear();
2777 TEST_EQ(b == a, true);
2778 TEST_EQ(b != a, false);
2780 b.test.type = Any_Monster;
2781 TEST_EQ(b == a, false);
2782 TEST_EQ(b != a, true);
2785 // For testing any binaries, e.g. from fuzzing.
2786 void LoadVerifyBinaryTest() {
2788 if (flatbuffers::LoadFile(
2789 (test_data_path + "fuzzer/your-filename-here").c_str(), true,
2791 flatbuffers::Verifier verifier(
2792 reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
2793 TEST_EQ(VerifyMonsterBuffer(verifier), true);
2797 void CreateSharedStringTest() {
2798 flatbuffers::FlatBufferBuilder builder;
2799 const auto one1 = builder.CreateSharedString("one");
2800 const auto two = builder.CreateSharedString("two");
2801 const auto one2 = builder.CreateSharedString("one");
2802 TEST_EQ(one1.o, one2.o);
2803 const auto onetwo = builder.CreateSharedString("onetwo");
2804 TEST_EQ(onetwo.o != one1.o, true);
2805 TEST_EQ(onetwo.o != two.o, true);
2807 // Support for embedded nulls
2808 const char chars_b[] = { 'a', '\0', 'b' };
2809 const char chars_c[] = { 'a', '\0', 'c' };
2810 const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
2811 const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
2812 const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
2813 TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
2814 TEST_EQ(null_b1.o, null_b2.o);
2816 // Put the strings into an array for round trip verification.
2817 const flatbuffers::Offset<flatbuffers::String> array[7] = {
2818 one1, two, one2, onetwo, null_b1, null_c, null_b2
2820 const auto vector_offset =
2821 builder.CreateVector(array, flatbuffers::uoffset_t(7));
2822 MonsterBuilder monster_builder(builder);
2823 monster_builder.add_name(two);
2824 monster_builder.add_testarrayofstring(vector_offset);
2825 builder.Finish(monster_builder.Finish());
2827 // Read the Monster back.
2828 const auto *monster =
2829 flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
2830 TEST_EQ_STR(monster->name()->c_str(), "two");
2831 const auto *testarrayofstring = monster->testarrayofstring();
2832 TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
2833 const auto &a = *testarrayofstring;
2834 TEST_EQ_STR(a[0]->c_str(), "one");
2835 TEST_EQ_STR(a[1]->c_str(), "two");
2836 TEST_EQ_STR(a[2]->c_str(), "one");
2837 TEST_EQ_STR(a[3]->c_str(), "onetwo");
2838 TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
2839 TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
2840 TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
2842 // Make sure String::operator< works, too, since it is related to
2843 // StringOffsetCompare.
2844 TEST_EQ((*a[0]) < (*a[1]), true);
2845 TEST_EQ((*a[1]) < (*a[0]), false);
2846 TEST_EQ((*a[1]) < (*a[2]), false);
2847 TEST_EQ((*a[2]) < (*a[1]), true);
2848 TEST_EQ((*a[4]) < (*a[3]), true);
2849 TEST_EQ((*a[5]) < (*a[4]), false);
2850 TEST_EQ((*a[5]) < (*a[4]), false);
2851 TEST_EQ((*a[6]) < (*a[5]), true);
2854 void FixedLengthArrayTest() {
2855 // VS10 does not support typed enums, exclude from tests
2856 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2857 // Generate an ArrayTable containing one ArrayStruct.
2858 flatbuffers::FlatBufferBuilder fbb;
2859 MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
2860 TEST_NOTNULL(nStruct0.mutable_a());
2861 nStruct0.mutable_a()->Mutate(0, 1);
2862 nStruct0.mutable_a()->Mutate(1, 2);
2863 TEST_NOTNULL(nStruct0.mutable_c());
2864 nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
2865 nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
2866 TEST_NOTNULL(nStruct0.mutable_d());
2867 nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
2868 nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
2869 MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
2870 TEST_NOTNULL(nStruct1.mutable_a());
2871 nStruct1.mutable_a()->Mutate(0, 3);
2872 nStruct1.mutable_a()->Mutate(1, 4);
2873 TEST_NOTNULL(nStruct1.mutable_c());
2874 nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
2875 nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
2876 TEST_NOTNULL(nStruct1.mutable_d());
2877 nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
2878 nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
2879 MyGame::Example::ArrayStruct aStruct(2, 12, 1);
2880 TEST_NOTNULL(aStruct.b());
2881 TEST_NOTNULL(aStruct.mutable_b());
2882 TEST_NOTNULL(aStruct.mutable_d());
2883 TEST_NOTNULL(aStruct.mutable_f());
2884 for (int i = 0; i < aStruct.b()->size(); i++)
2885 aStruct.mutable_b()->Mutate(i, i + 1);
2886 aStruct.mutable_d()->Mutate(0, nStruct0);
2887 aStruct.mutable_d()->Mutate(1, nStruct1);
2888 auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
2891 // Verify correctness of the ArrayTable.
2892 flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
2893 MyGame::Example::VerifyArrayTableBuffer(verifier);
2894 auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
2895 auto mArStruct = p->mutable_a();
2896 TEST_NOTNULL(mArStruct);
2897 TEST_NOTNULL(mArStruct->b());
2898 TEST_NOTNULL(mArStruct->d());
2899 TEST_NOTNULL(mArStruct->f());
2900 TEST_NOTNULL(mArStruct->mutable_b());
2901 TEST_NOTNULL(mArStruct->mutable_d());
2902 TEST_NOTNULL(mArStruct->mutable_f());
2903 mArStruct->mutable_b()->Mutate(14, -14);
2904 TEST_EQ(mArStruct->a(), 2);
2905 TEST_EQ(mArStruct->b()->size(), 15);
2906 TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14);
2907 TEST_EQ(mArStruct->c(), 12);
2908 TEST_NOTNULL(mArStruct->d()->Get(0));
2909 TEST_NOTNULL(mArStruct->d()->Get(0)->a());
2910 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
2911 TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
2912 TEST_NOTNULL(mArStruct->d()->Get(1));
2913 TEST_NOTNULL(mArStruct->d()->Get(1)->a());
2914 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
2915 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
2916 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
2917 TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
2918 mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
2919 TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 5);
2920 TEST_EQ(mArStruct->d()->Get(0)->b() == MyGame::Example::TestEnum::B, true);
2921 TEST_NOTNULL(mArStruct->d()->Get(0)->c());
2922 TEST_EQ(mArStruct->d()->Get(0)->c()->Get(0) == MyGame::Example::TestEnum::C,
2924 TEST_EQ(mArStruct->d()->Get(0)->c()->Get(1) == MyGame::Example::TestEnum::A,
2926 TEST_EQ(mArStruct->d()->Get(0)->d()->Get(0),
2927 flatbuffers::numeric_limits<int64_t>::max());
2928 TEST_EQ(mArStruct->d()->Get(0)->d()->Get(1),
2929 flatbuffers::numeric_limits<int64_t>::min());
2930 TEST_EQ(mArStruct->d()->Get(1)->b() == MyGame::Example::TestEnum::C, true);
2931 TEST_NOTNULL(mArStruct->d()->Get(1)->c());
2932 TEST_EQ(mArStruct->d()->Get(1)->c()->Get(0) == MyGame::Example::TestEnum::C,
2934 TEST_EQ(mArStruct->d()->Get(1)->c()->Get(1) == MyGame::Example::TestEnum::A,
2936 TEST_EQ(mArStruct->d()->Get(1)->d()->Get(0),
2937 flatbuffers::numeric_limits<int64_t>::min());
2938 TEST_EQ(mArStruct->d()->Get(1)->d()->Get(1),
2939 flatbuffers::numeric_limits<int64_t>::max());
2940 for (int i = 0; i < mArStruct->b()->size() - 1; i++)
2941 TEST_EQ(mArStruct->b()->Get(i), i + 1);
2943 TEST_EQ(reinterpret_cast<uintptr_t>(mArStruct->d()) % 8, 0);
2944 TEST_EQ(reinterpret_cast<uintptr_t>(mArStruct->f()) % 8, 0);
2948 void NativeTypeTest() {
2951 Geometry::ApplicationDataT src_data;
2952 src_data.vectors.reserve(N);
2954 for (int i = 0; i < N; ++i) {
2955 src_data.vectors.push_back(
2956 Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
2959 flatbuffers::FlatBufferBuilder fbb;
2960 fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
2962 auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
2964 for (int i = 0; i < N; ++i) {
2965 Native::Vector3D &v = dstDataT->vectors[i];
2966 TEST_EQ(v.x, 10 * i + 0.1f);
2967 TEST_EQ(v.y, 10 * i + 0.2f);
2968 TEST_EQ(v.z, 10 * i + 0.3f);
2972 void FixedLengthArrayJsonTest(bool binary) {
2973 // VS10 does not support typed enums, exclude from tests
2974 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2975 // load FlatBuffer schema (.fbs) and JSON from disk
2976 std::string schemafile;
2977 std::string jsonfile;
2979 flatbuffers::LoadFile(
2980 (test_data_path + "arrays_test." + (binary ? "bfbs" : "fbs")).c_str(),
2981 binary, &schemafile),
2983 TEST_EQ(flatbuffers::LoadFile((test_data_path + "arrays_test.golden").c_str(),
2987 // parse schema first, so we can use it to parse the data after
2988 flatbuffers::Parser parserOrg, parserGen;
2990 flatbuffers::Verifier verifier(
2991 reinterpret_cast<const uint8_t *>(schemafile.c_str()),
2993 TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
2994 TEST_EQ(parserOrg.Deserialize((const uint8_t *)schemafile.c_str(),
2997 TEST_EQ(parserGen.Deserialize((const uint8_t *)schemafile.c_str(),
3001 TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
3002 TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
3004 TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3006 // First, verify it, just in case:
3007 flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3008 parserOrg.builder_.GetSize());
3009 TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
3012 std::string jsonGen;
3014 GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3018 TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3020 // Verify buffer from generated JSON
3021 flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3022 parserGen.builder_.GetSize());
3023 TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
3025 // Compare generated buffer to original
3026 TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3027 TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3028 parserGen.builder_.GetBufferPointer(),
3029 parserOrg.builder_.GetSize()),
3036 int FlatBufferTests() {
3039 // Run our various test suites:
3042 auto flatbuf1 = CreateFlatBufferTest(rawbuf);
3043 #if !defined(FLATBUFFERS_CPP98_STL)
3044 auto flatbuf = std::move(flatbuf1); // Test move assignment.
3046 auto &flatbuf = flatbuf1;
3047 #endif // !defined(FLATBUFFERS_CPP98_STL)
3049 TriviallyCopyableTest();
3051 AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
3053 AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
3055 MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
3057 ObjectFlatBuffersTest(flatbuf.data());
3059 MiniReflectFlatBuffersTest(flatbuf.data());
3063 #ifndef FLATBUFFERS_NO_FILE_TESTS
3064 #ifdef FLATBUFFERS_TEST_PATH_PREFIX
3065 test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
3068 ParseAndGenerateTextTest(false);
3069 ParseAndGenerateTextTest(true);
3070 FixedLengthArrayJsonTest(false);
3071 FixedLengthArrayJsonTest(true);
3072 ReflectionTest(flatbuf.data(), flatbuf.size());
3075 LoadVerifyBinaryTest();
3076 GenerateTableTextTest();
3088 EnumOutOfRangeTest();
3089 IntegerOutOfRangeTest();
3090 IntegerBoundaryTest();
3092 UnicodeTestAllowNonUTF8();
3093 UnicodeTestGenerateTextFailsOnNonUTF8();
3094 UnicodeSurrogatesTest();
3095 UnicodeInvalidSurrogatesTest();
3097 UnknownFieldsTest();
3099 InvalidNestedFlatbufferTest();
3101 ParseProtoBufAsciiTest();
3104 CreateSharedStringTest();
3108 UninitializedVectorTest();
3109 EqualOperatorTest();
3114 TestMonsterExtraFloats();
3115 FixedLengthArrayTest();
3120 int main(int /*argc*/, const char * /*argv*/[]) {
3123 std::string req_locale;
3124 if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
3126 TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
3127 req_locale.c_str());
3128 req_locale = flatbuffers::RemoveStringQuotes(req_locale);
3129 std::string the_locale;
3131 flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
3132 TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
3136 FlatBufferBuilderTest();
3138 if (!testing_fails) {
3139 TEST_OUTPUT_LINE("ALL TESTS PASSED");
3141 TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
3143 return CloseTestEngine();