Formats cpp code (#6349)
[platform/upstream/flatbuffers.git] / tests / test.cpp
1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 #include <cmath>
17
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"
23
24 // clang-format off
25 #ifdef FLATBUFFERS_CPP98_STL
26   namespace std {
27     using flatbuffers::unique_ptr;
28   }
29 #endif
30 // clang-format on
31
32 #include "monster_test_generated.h"
33 #include "namespace_test/namespace_test1_generated.h"
34 #include "namespace_test/namespace_test2_generated.h"
35 #include "union_vector/union_vector_generated.h"
36 #include "optional_scalars_generated.h"
37 #if !defined(_MSC_VER) || _MSC_VER >= 1700
38 #  include "monster_extra_generated.h"
39 #  include "arrays_test_generated.h"
40 #  include "evolution_test/evolution_v1_generated.h"
41 #  include "evolution_test/evolution_v2_generated.h"
42 #endif
43
44 #include "native_type_test_generated.h"
45 #include "test_assert.h"
46
47 #include "flatbuffers/flexbuffers.h"
48 #include "monster_test_bfbs_generated.h"  // Generated using --bfbs-comments --bfbs-builtins --cpp --bfbs-gen-embed
49
50 // clang-format off
51 // Check that char* and uint8_t* are interoperable types.
52 // The reinterpret_cast<> between the pointers are used to simplify data loading.
53 static_assert(flatbuffers::is_same<uint8_t, char>::value ||
54               flatbuffers::is_same<uint8_t, unsigned char>::value,
55               "unexpected uint8_t type");
56
57 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
58   // Ensure IEEE-754 support if tests of floats with NaN/Inf will run.
59   static_assert(std::numeric_limits<float>::is_iec559 &&
60                 std::numeric_limits<double>::is_iec559,
61                 "IEC-559 (IEEE-754) standard required");
62 #endif
63 // clang-format on
64
65 // Shortcuts for the infinity.
66 static const auto infinity_f = std::numeric_limits<float>::infinity();
67 static const auto infinity_d = std::numeric_limits<double>::infinity();
68
69 using namespace MyGame::Example;
70
71 void FlatBufferBuilderTest();
72
73 // Include simple random number generator to ensure results will be the
74 // same cross platform.
75 // http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
76 uint32_t lcg_seed = 48271;
77 uint32_t lcg_rand() {
78   return lcg_seed =
79              (static_cast<uint64_t>(lcg_seed) * 279470273UL) % 4294967291UL;
80 }
81 void lcg_reset() { lcg_seed = 48271; }
82
83 std::string test_data_path =
84 #ifdef BAZEL_TEST_DATA_PATH
85     "../com_github_google_flatbuffers/tests/";
86 #else
87     "tests/";
88 #endif
89
90 // example of how to build up a serialized buffer algorithmically:
91 flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) {
92   flatbuffers::FlatBufferBuilder builder;
93
94   auto vec = Vec3(1, 2, 3, 0, Color_Red, Test(10, 20));
95
96   auto name = builder.CreateString("MyMonster");
97
98   unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
99   auto inventory = builder.CreateVector(inv_data, 10);
100
101   // Alternatively, create the vector first, and fill in data later:
102   // unsigned char *inv_buf = nullptr;
103   // auto inventory = builder.CreateUninitializedVector<unsigned char>(
104   //                                                              10, &inv_buf);
105   // memcpy(inv_buf, inv_data, 10);
106
107   Test tests[] = { Test(10, 20), Test(30, 40) };
108   auto testv = builder.CreateVectorOfStructs(tests, 2);
109
110   // clang-format off
111   #ifndef FLATBUFFERS_CPP98_STL
112     // Create a vector of structures from a lambda.
113     auto testv2 = builder.CreateVectorOfStructs<Test>(
114           2, [&](size_t i, Test* s) -> void {
115             *s = tests[i];
116           });
117   #else
118     // Create a vector of structures using a plain old C++ function.
119     auto testv2 = builder.CreateVectorOfStructs<Test>(
120           2, [](size_t i, Test* s, void *state) -> void {
121             *s = (reinterpret_cast<Test*>(state))[i];
122           }, tests);
123   #endif  // FLATBUFFERS_CPP98_STL
124   // clang-format on
125
126   // create monster with very few fields set:
127   // (same functionality as CreateMonster below, but sets fields manually)
128   flatbuffers::Offset<Monster> mlocs[3];
129   auto fred = builder.CreateString("Fred");
130   auto barney = builder.CreateString("Barney");
131   auto wilma = builder.CreateString("Wilma");
132   MonsterBuilder mb1(builder);
133   mb1.add_name(fred);
134   mlocs[0] = mb1.Finish();
135   MonsterBuilder mb2(builder);
136   mb2.add_name(barney);
137   mb2.add_hp(1000);
138   mlocs[1] = mb2.Finish();
139   MonsterBuilder mb3(builder);
140   mb3.add_name(wilma);
141   mlocs[2] = mb3.Finish();
142
143   // Create an array of strings. Also test string pooling, and lambdas.
144   auto vecofstrings =
145       builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(
146           4,
147           [](size_t i, flatbuffers::FlatBufferBuilder *b)
148               -> flatbuffers::Offset<flatbuffers::String> {
149             static const char *names[] = { "bob", "fred", "bob", "fred" };
150             return b->CreateSharedString(names[i]);
151           },
152           &builder);
153
154   // Creating vectors of strings in one convenient call.
155   std::vector<std::string> names2;
156   names2.push_back("jane");
157   names2.push_back("mary");
158   auto vecofstrings2 = builder.CreateVectorOfStrings(names2);
159
160   // Create an array of sorted tables, can be used with binary search when read:
161   auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3);
162
163   // Create an array of sorted structs,
164   // can be used with binary search when read:
165   std::vector<Ability> abilities;
166   abilities.push_back(Ability(4, 40));
167   abilities.push_back(Ability(3, 30));
168   abilities.push_back(Ability(2, 20));
169   abilities.push_back(Ability(0, 0));
170   auto vecofstructs = builder.CreateVectorOfSortedStructs(&abilities);
171
172   flatbuffers::Offset<Stat> mlocs_stats[1];
173   auto miss = builder.CreateString("miss");
174   StatBuilder mb_miss(builder);
175   mb_miss.add_id(miss);
176   mb_miss.add_val(0);
177   mb_miss.add_count(0);  // key
178   mlocs_stats[0] = mb_miss.Finish();
179   auto vec_of_stats = builder.CreateVectorOfSortedTables(mlocs_stats, 1);
180
181   // Create a nested FlatBuffer.
182   // Nested FlatBuffers are stored in a ubyte vector, which can be convenient
183   // since they can be memcpy'd around much easier than other FlatBuffer
184   // values. They have little overhead compared to storing the table directly.
185   // As a test, create a mostly empty Monster buffer:
186   flatbuffers::FlatBufferBuilder nested_builder;
187   auto nmloc = CreateMonster(nested_builder, nullptr, 0, 0,
188                              nested_builder.CreateString("NestedMonster"));
189   FinishMonsterBuffer(nested_builder, nmloc);
190   // Now we can store the buffer in the parent. Note that by default, vectors
191   // are only aligned to their elements or size field, so in this case if the
192   // buffer contains 64-bit elements, they may not be correctly aligned. We fix
193   // that with:
194   builder.ForceVectorAlignment(nested_builder.GetSize(), sizeof(uint8_t),
195                                nested_builder.GetBufferMinAlignment());
196   // If for whatever reason you don't have the nested_builder available, you
197   // can substitute flatbuffers::largest_scalar_t (64-bit) for the alignment, or
198   // the largest force_align value in your schema if you're using it.
199   auto nested_flatbuffer_vector = builder.CreateVector(
200       nested_builder.GetBufferPointer(), nested_builder.GetSize());
201
202   // Test a nested FlexBuffer:
203   flexbuffers::Builder flexbuild;
204   flexbuild.Int(1234);
205   flexbuild.Finish();
206   auto flex = builder.CreateVector(flexbuild.GetBuffer());
207
208   // Test vector of enums.
209   Color colors[] = { Color_Blue, Color_Green };
210   // We use this special creation function because we have an array of
211   // pre-C++11 (enum class) enums whose size likely is int, yet its declared
212   // type in the schema is byte.
213   auto vecofcolors = builder.CreateVectorScalarCast<uint8_t, Color>(colors, 2);
214
215   // shortcut for creating monster with all fields set:
216   auto mloc = CreateMonster(
217       builder, &vec, 150, 80, name, inventory, Color_Blue, Any_Monster,
218       mlocs[1].Union(),  // Store a union.
219       testv, vecofstrings, vecoftables, 0, nested_flatbuffer_vector, 0, false,
220       0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f, vecofstrings2,
221       vecofstructs, flex, testv2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
222       AnyUniqueAliases_NONE, 0, AnyAmbiguousAliases_NONE, 0, vecofcolors,
223       MyGame::Example::Race_None, 0, vec_of_stats);
224
225   FinishMonsterBuffer(builder, mloc);
226
227   // clang-format off
228   #ifdef FLATBUFFERS_TEST_VERBOSE
229   // print byte data for debugging:
230   auto p = builder.GetBufferPointer();
231   for (flatbuffers::uoffset_t i = 0; i < builder.GetSize(); i++)
232     printf("%d ", p[i]);
233   #endif
234   // clang-format on
235
236   // return the buffer for the caller to use.
237   auto bufferpointer =
238       reinterpret_cast<const char *>(builder.GetBufferPointer());
239   buffer.assign(bufferpointer, bufferpointer + builder.GetSize());
240
241   return builder.Release();
242 }
243
244 //  example of accessing a buffer loaded in memory:
245 void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
246                           bool pooled = true) {
247   // First, verify the buffers integrity (optional)
248   flatbuffers::Verifier verifier(flatbuf, length);
249   TEST_EQ(VerifyMonsterBuffer(verifier), true);
250
251   // clang-format off
252   #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
253     std::vector<uint8_t> test_buff;
254     test_buff.resize(length * 2);
255     std::memcpy(&test_buff[0], flatbuf, length);
256     std::memcpy(&test_buff[length], flatbuf, length);
257
258     flatbuffers::Verifier verifier1(&test_buff[0], length);
259     TEST_EQ(VerifyMonsterBuffer(verifier1), true);
260     TEST_EQ(verifier1.GetComputedSize(), length);
261
262     flatbuffers::Verifier verifier2(&test_buff[length], length);
263     TEST_EQ(VerifyMonsterBuffer(verifier2), true);
264     TEST_EQ(verifier2.GetComputedSize(), length);
265   #endif
266   // clang-format on
267
268   TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0);
269   TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true);
270   TEST_EQ(strcmp(MonsterExtension(), "mon"), 0);
271
272   // Access the buffer from the root.
273   auto monster = GetMonster(flatbuf);
274
275   TEST_EQ(monster->hp(), 80);
276   TEST_EQ(monster->mana(), 150);  // default
277   TEST_EQ_STR(monster->name()->c_str(), "MyMonster");
278   // Can't access the following field, it is deprecated in the schema,
279   // which means accessors are not generated:
280   // monster.friendly()
281
282   auto pos = monster->pos();
283   TEST_NOTNULL(pos);
284   TEST_EQ(pos->z(), 3);
285   TEST_EQ(pos->test3().a(), 10);
286   TEST_EQ(pos->test3().b(), 20);
287
288   auto inventory = monster->inventory();
289   TEST_EQ(VectorLength(inventory), 10UL);  // Works even if inventory is null.
290   TEST_NOTNULL(inventory);
291   unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
292   // Check compatibilty of iterators with STL.
293   std::vector<unsigned char> inv_vec(inventory->begin(), inventory->end());
294   int n = 0;
295   for (auto it = inventory->begin(); it != inventory->end(); ++it, ++n) {
296     auto indx = it - inventory->begin();
297     TEST_EQ(*it, inv_vec.at(indx));  // Use bounds-check.
298     TEST_EQ(*it, inv_data[indx]);
299   }
300   TEST_EQ(n, inv_vec.size());
301
302   n = 0;
303   for (auto it = inventory->cbegin(); it != inventory->cend(); ++it, ++n) {
304     auto indx = it - inventory->cbegin();
305     TEST_EQ(*it, inv_vec.at(indx));  // Use bounds-check.
306     TEST_EQ(*it, inv_data[indx]);
307   }
308   TEST_EQ(n, inv_vec.size());
309
310   n = 0;
311   for (auto it = inventory->rbegin(); it != inventory->rend(); ++it, ++n) {
312     auto indx = inventory->rend() - it - 1;
313     TEST_EQ(*it, inv_vec.at(indx));  // Use bounds-check.
314     TEST_EQ(*it, inv_data[indx]);
315   }
316   TEST_EQ(n, inv_vec.size());
317
318   n = 0;
319   for (auto it = inventory->crbegin(); it != inventory->crend(); ++it, ++n) {
320     auto indx = inventory->crend() - it - 1;
321     TEST_EQ(*it, inv_vec.at(indx));  // Use bounds-check.
322     TEST_EQ(*it, inv_data[indx]);
323   }
324   TEST_EQ(n, inv_vec.size());
325
326   TEST_EQ(monster->color(), Color_Blue);
327
328   // Example of accessing a union:
329   TEST_EQ(monster->test_type(), Any_Monster);  // First make sure which it is.
330   auto monster2 = reinterpret_cast<const Monster *>(monster->test());
331   TEST_NOTNULL(monster2);
332   TEST_EQ_STR(monster2->name()->c_str(), "Fred");
333
334   // Example of accessing a vector of strings:
335   auto vecofstrings = monster->testarrayofstring();
336   TEST_EQ(vecofstrings->size(), 4U);
337   TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
338   TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
339   if (pooled) {
340     // These should have pointer equality because of string pooling.
341     TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
342     TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
343   }
344
345   auto vecofstrings2 = monster->testarrayofstring2();
346   if (vecofstrings2) {
347     TEST_EQ(vecofstrings2->size(), 2U);
348     TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
349     TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
350   }
351
352   // Example of accessing a vector of tables:
353   auto vecoftables = monster->testarrayoftables();
354   TEST_EQ(vecoftables->size(), 3U);
355   for (auto it = vecoftables->begin(); it != vecoftables->end(); ++it) {
356     TEST_EQ(strlen(it->name()->c_str()) >= 4, true);
357   }
358   TEST_EQ_STR(vecoftables->Get(0)->name()->c_str(), "Barney");
359   TEST_EQ(vecoftables->Get(0)->hp(), 1000);
360   TEST_EQ_STR(vecoftables->Get(1)->name()->c_str(), "Fred");
361   TEST_EQ_STR(vecoftables->Get(2)->name()->c_str(), "Wilma");
362   TEST_NOTNULL(vecoftables->LookupByKey("Barney"));
363   TEST_NOTNULL(vecoftables->LookupByKey("Fred"));
364   TEST_NOTNULL(vecoftables->LookupByKey("Wilma"));
365
366   // Test accessing a vector of sorted structs
367   auto vecofstructs = monster->testarrayofsortedstruct();
368   if (vecofstructs) {  // not filled in monster_test.bfbs
369     for (flatbuffers::uoffset_t i = 0; i < vecofstructs->size() - 1; i++) {
370       auto left = vecofstructs->Get(i);
371       auto right = vecofstructs->Get(i + 1);
372       TEST_EQ(true, (left->KeyCompareLessThan(right)));
373     }
374     TEST_NOTNULL(vecofstructs->LookupByKey(0));  // test default value
375     TEST_NOTNULL(vecofstructs->LookupByKey(3));
376     TEST_EQ(static_cast<const Ability *>(nullptr),
377             vecofstructs->LookupByKey(5));
378   }
379
380   if (auto vec_of_stat = monster->scalar_key_sorted_tables()) {
381     auto stat_0 = vec_of_stat->LookupByKey(static_cast<uint16_t>(0u));
382     TEST_NOTNULL(stat_0);
383     TEST_NOTNULL(stat_0->id());
384     TEST_EQ(0, stat_0->count());
385     TEST_EQ_STR("miss", stat_0->id()->c_str());
386   }
387
388   // Test nested FlatBuffers if available:
389   auto nested_buffer = monster->testnestedflatbuffer();
390   if (nested_buffer) {
391     // nested_buffer is a vector of bytes you can memcpy. However, if you
392     // actually want to access the nested data, this is a convenient
393     // accessor that directly gives you the root table:
394     auto nested_monster = monster->testnestedflatbuffer_nested_root();
395     TEST_EQ_STR(nested_monster->name()->c_str(), "NestedMonster");
396   }
397
398   // Test flexbuffer if available:
399   auto flex = monster->flex();
400   // flex is a vector of bytes you can memcpy etc.
401   TEST_EQ(flex->size(), 4);  // Encoded FlexBuffer bytes.
402   // However, if you actually want to access the nested data, this is a
403   // convenient accessor that directly gives you the root value:
404   TEST_EQ(monster->flex_flexbuffer_root().AsInt16(), 1234);
405
406   // Test vector of enums:
407   auto colors = monster->vector_of_enums();
408   if (colors) {
409     TEST_EQ(colors->size(), 2);
410     TEST_EQ(colors->Get(0), Color_Blue);
411     TEST_EQ(colors->Get(1), Color_Green);
412   }
413
414   // Since Flatbuffers uses explicit mechanisms to override the default
415   // compiler alignment, double check that the compiler indeed obeys them:
416   // (Test consists of a short and byte):
417   TEST_EQ(flatbuffers::AlignOf<Test>(), 2UL);
418   TEST_EQ(sizeof(Test), 4UL);
419
420   const flatbuffers::Vector<const Test *> *tests_array[] = {
421     monster->test4(),
422     monster->test5(),
423   };
424   for (size_t i = 0; i < sizeof(tests_array) / sizeof(tests_array[0]); ++i) {
425     auto tests = tests_array[i];
426     TEST_NOTNULL(tests);
427     auto test_0 = tests->Get(0);
428     auto test_1 = tests->Get(1);
429     TEST_EQ(test_0->a(), 10);
430     TEST_EQ(test_0->b(), 20);
431     TEST_EQ(test_1->a(), 30);
432     TEST_EQ(test_1->b(), 40);
433     for (auto it = tests->begin(); it != tests->end(); ++it) {
434       TEST_EQ(it->a() == 10 || it->a() == 30, true);  // Just testing iterators.
435     }
436   }
437
438   // Checking for presence of fields:
439   TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
440   TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
441
442   // Obtaining a buffer from a root:
443   TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
444 }
445
446 // Change a FlatBuffer in-place, after it has been constructed.
447 void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
448   // Get non-const pointer to root.
449   auto monster = GetMutableMonster(flatbuf);
450
451   // Each of these tests mutates, then tests, then set back to the original,
452   // so we can test that the buffer in the end still passes our original test.
453   auto hp_ok = monster->mutate_hp(10);
454   TEST_EQ(hp_ok, true);  // Field was present.
455   TEST_EQ(monster->hp(), 10);
456   // Mutate to default value
457   auto hp_ok_default = monster->mutate_hp(100);
458   TEST_EQ(hp_ok_default, true);  // Field was present.
459   TEST_EQ(monster->hp(), 100);
460   // Test that mutate to default above keeps field valid for further mutations
461   auto hp_ok_2 = monster->mutate_hp(20);
462   TEST_EQ(hp_ok_2, true);
463   TEST_EQ(monster->hp(), 20);
464   monster->mutate_hp(80);
465
466   // Monster originally at 150 mana (default value)
467   auto mana_default_ok = monster->mutate_mana(150);  // Mutate to default value.
468   TEST_EQ(mana_default_ok,
469           true);  // Mutation should succeed, because default value.
470   TEST_EQ(monster->mana(), 150);
471   auto mana_ok = monster->mutate_mana(10);
472   TEST_EQ(mana_ok, false);  // Field was NOT present, because default value.
473   TEST_EQ(monster->mana(), 150);
474
475   // Mutate structs.
476   auto pos = monster->mutable_pos();
477   auto test3 = pos->mutable_test3();  // Struct inside a struct.
478   test3.mutate_a(50);                 // Struct fields never fail.
479   TEST_EQ(test3.a(), 50);
480   test3.mutate_a(10);
481
482   // Mutate vectors.
483   auto inventory = monster->mutable_inventory();
484   inventory->Mutate(9, 100);
485   TEST_EQ(inventory->Get(9), 100);
486   inventory->Mutate(9, 9);
487
488   auto tables = monster->mutable_testarrayoftables();
489   auto first = tables->GetMutableObject(0);
490   TEST_EQ(first->hp(), 1000);
491   first->mutate_hp(0);
492   TEST_EQ(first->hp(), 0);
493   first->mutate_hp(1000);
494
495   // Run the verifier and the regular test to make sure we didn't trample on
496   // anything.
497   AccessFlatBufferTest(flatbuf, length);
498 }
499
500 // Unpack a FlatBuffer into objects.
501 void ObjectFlatBuffersTest(uint8_t *flatbuf) {
502   // Optional: we can specify resolver and rehasher functions to turn hashed
503   // strings into object pointers and back, to implement remote references
504   // and such.
505   auto resolver = flatbuffers::resolver_function_t(
506       [](void **pointer_adr, flatbuffers::hash_value_t hash) {
507         (void)pointer_adr;
508         (void)hash;
509         // Don't actually do anything, leave variable null.
510       });
511   auto rehasher = flatbuffers::rehasher_function_t(
512       [](void *pointer) -> flatbuffers::hash_value_t {
513         (void)pointer;
514         return 0;
515       });
516
517   // Turn a buffer into C++ objects.
518   auto monster1 = UnPackMonster(flatbuf, &resolver);
519
520   // Re-serialize the data.
521   flatbuffers::FlatBufferBuilder fbb1;
522   fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
523               MonsterIdentifier());
524
525   // Unpack again, and re-serialize again.
526   auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
527   flatbuffers::FlatBufferBuilder fbb2;
528   fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
529               MonsterIdentifier());
530
531   // Now we've gone full round-trip, the two buffers should match.
532   auto len1 = fbb1.GetSize();
533   auto len2 = fbb2.GetSize();
534   TEST_EQ(len1, len2);
535   TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), len1), 0);
536
537   // Test it with the original buffer test to make sure all data survived.
538   AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
539
540   // Test accessing fields, similar to AccessFlatBufferTest above.
541   TEST_EQ(monster2->hp, 80);
542   TEST_EQ(monster2->mana, 150);  // default
543   TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
544
545   auto &pos = monster2->pos;
546   TEST_NOTNULL(pos);
547   TEST_EQ(pos->z(), 3);
548   TEST_EQ(pos->test3().a(), 10);
549   TEST_EQ(pos->test3().b(), 20);
550
551   auto &inventory = monster2->inventory;
552   TEST_EQ(inventory.size(), 10UL);
553   unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
554   for (auto it = inventory.begin(); it != inventory.end(); ++it)
555     TEST_EQ(*it, inv_data[it - inventory.begin()]);
556
557   TEST_EQ(monster2->color, Color_Blue);
558
559   auto monster3 = monster2->test.AsMonster();
560   TEST_NOTNULL(monster3);
561   TEST_EQ_STR(monster3->name.c_str(), "Fred");
562
563   auto &vecofstrings = monster2->testarrayofstring;
564   TEST_EQ(vecofstrings.size(), 4U);
565   TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
566   TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
567
568   auto &vecofstrings2 = monster2->testarrayofstring2;
569   TEST_EQ(vecofstrings2.size(), 2U);
570   TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
571   TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
572
573   auto &vecoftables = monster2->testarrayoftables;
574   TEST_EQ(vecoftables.size(), 3U);
575   TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
576   TEST_EQ(vecoftables[0]->hp, 1000);
577   TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
578   TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
579
580   auto &tests = monster2->test4;
581   TEST_EQ(tests[0].a(), 10);
582   TEST_EQ(tests[0].b(), 20);
583   TEST_EQ(tests[1].a(), 30);
584   TEST_EQ(tests[1].b(), 40);
585 }
586
587 // Prefix a FlatBuffer with a size field.
588 void SizePrefixedTest() {
589   // Create size prefixed buffer.
590   flatbuffers::FlatBufferBuilder fbb;
591   FinishSizePrefixedMonsterBuffer(
592       fbb, CreateMonster(fbb, 0, 200, 300, fbb.CreateString("bob")));
593
594   // Verify it.
595   flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
596   TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier), true);
597
598   // Access it.
599   auto m = GetSizePrefixedMonster(fbb.GetBufferPointer());
600   TEST_EQ(m->mana(), 200);
601   TEST_EQ(m->hp(), 300);
602   TEST_EQ_STR(m->name()->c_str(), "bob");
603 }
604
605 void TriviallyCopyableTest() {
606   // clang-format off
607   #if __GNUG__ && __GNUC__ < 5
608     TEST_EQ(__has_trivial_copy(Vec3), true);
609   #else
610     #if __cplusplus >= 201103L
611       TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
612     #endif
613   #endif
614   // clang-format on
615 }
616
617 // Check stringify of an default enum value to json
618 void JsonDefaultTest() {
619   // load FlatBuffer schema (.fbs) from disk
620   std::string schemafile;
621   TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
622                                 false, &schemafile),
623           true);
624   // parse schema first, so we can use it to parse the data after
625   flatbuffers::Parser parser;
626   auto include_test_path =
627       flatbuffers::ConCatPathFileName(test_data_path, "include_test");
628   const char *include_directories[] = { test_data_path.c_str(),
629                                         include_test_path.c_str(), nullptr };
630
631   TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
632   // create incomplete monster and store to json
633   parser.opts.output_default_scalars_in_json = true;
634   parser.opts.output_enum_identifiers = true;
635   flatbuffers::FlatBufferBuilder builder;
636   auto name = builder.CreateString("default_enum");
637   MonsterBuilder color_monster(builder);
638   color_monster.add_name(name);
639   FinishMonsterBuffer(builder, color_monster.Finish());
640   std::string jsongen;
641   auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
642   TEST_EQ(result, true);
643   // default value of the "color" field is Blue
644   TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true);
645   // default value of the "testf" field is 3.14159
646   TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true);
647 }
648
649 void JsonEnumsTest() {
650   // load FlatBuffer schema (.fbs) from disk
651   std::string schemafile;
652   TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
653                                 false, &schemafile),
654           true);
655   // parse schema first, so we can use it to parse the data after
656   flatbuffers::Parser parser;
657   auto include_test_path =
658       flatbuffers::ConCatPathFileName(test_data_path, "include_test");
659   const char *include_directories[] = { test_data_path.c_str(),
660                                         include_test_path.c_str(), nullptr };
661   parser.opts.output_enum_identifiers = true;
662   TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
663   flatbuffers::FlatBufferBuilder builder;
664   auto name = builder.CreateString("bitflag_enum");
665   MonsterBuilder color_monster(builder);
666   color_monster.add_name(name);
667   color_monster.add_color(Color(Color_Blue | Color_Red));
668   FinishMonsterBuffer(builder, color_monster.Finish());
669   std::string jsongen;
670   auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
671   TEST_EQ(result, true);
672   TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true);
673   // Test forward compatibility with 'output_enum_identifiers = true'.
674   // Current Color doesn't have '(1u << 2)' field, let's add it.
675   builder.Clear();
676   std::string future_json;
677   auto future_name = builder.CreateString("future bitflag_enum");
678   MonsterBuilder future_color(builder);
679   future_color.add_name(future_name);
680   future_color.add_color(
681       static_cast<Color>((1u << 2) | Color_Blue | Color_Red));
682   FinishMonsterBuffer(builder, future_color.Finish());
683   result = GenerateText(parser, builder.GetBufferPointer(), &future_json);
684   TEST_EQ(result, true);
685   TEST_EQ(std::string::npos != future_json.find("color: 13"), true);
686 }
687
688 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
689 // The IEEE-754 quiet_NaN is not simple binary constant.
690 // All binary NaN bit strings have all the bits of the biased exponent field E
691 // set to 1. A quiet NaN bit string should be encoded with the first bit d[1]
692 // of the trailing significand field T being 1 (d[0] is implicit bit).
693 // It is assumed that endianness of floating-point is same as integer.
694 template<typename T, typename U, U qnan_base> bool is_quiet_nan_impl(T v) {
695   static_assert(sizeof(T) == sizeof(U), "unexpected");
696   U b = 0;
697   std::memcpy(&b, &v, sizeof(T));
698   return ((b & qnan_base) == qnan_base);
699 }
700 #  if defined(__mips__) || defined(__hppa__)
701 static bool is_quiet_nan(float v) {
702   return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v) ||
703          is_quiet_nan_impl<float, uint32_t, 0x7FBFFFFFu>(v);
704 }
705 static bool is_quiet_nan(double v) {
706   return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v) ||
707          is_quiet_nan_impl<double, uint64_t, 0x7FF7FFFFFFFFFFFFu>(v);
708 }
709 #  else
710 static bool is_quiet_nan(float v) {
711   return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v);
712 }
713 static bool is_quiet_nan(double v) {
714   return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v);
715 }
716 #  endif
717
718 void TestMonsterExtraFloats() {
719   TEST_EQ(is_quiet_nan(1.0), false);
720   TEST_EQ(is_quiet_nan(infinity_d), false);
721   TEST_EQ(is_quiet_nan(-infinity_f), false);
722   TEST_EQ(is_quiet_nan(std::numeric_limits<float>::quiet_NaN()), true);
723   TEST_EQ(is_quiet_nan(std::numeric_limits<double>::quiet_NaN()), true);
724
725   using namespace flatbuffers;
726   using namespace MyGame;
727   // Load FlatBuffer schema (.fbs) from disk.
728   std::string schemafile;
729   TEST_EQ(LoadFile((test_data_path + "monster_extra.fbs").c_str(), false,
730                    &schemafile),
731           true);
732   // Parse schema first, so we can use it to parse the data after.
733   Parser parser;
734   auto include_test_path = ConCatPathFileName(test_data_path, "include_test");
735   const char *include_directories[] = { test_data_path.c_str(),
736                                         include_test_path.c_str(), nullptr };
737   TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
738   // Create empty extra and store to json.
739   parser.opts.output_default_scalars_in_json = true;
740   parser.opts.output_enum_identifiers = true;
741   FlatBufferBuilder builder;
742   const auto def_root = MonsterExtraBuilder(builder).Finish();
743   FinishMonsterExtraBuffer(builder, def_root);
744   const auto def_obj = builder.GetBufferPointer();
745   const auto def_extra = GetMonsterExtra(def_obj);
746   TEST_NOTNULL(def_extra);
747   TEST_EQ(is_quiet_nan(def_extra->f0()), true);
748   TEST_EQ(is_quiet_nan(def_extra->f1()), true);
749   TEST_EQ(def_extra->f2(), +infinity_f);
750   TEST_EQ(def_extra->f3(), -infinity_f);
751   TEST_EQ(is_quiet_nan(def_extra->d0()), true);
752   TEST_EQ(is_quiet_nan(def_extra->d1()), true);
753   TEST_EQ(def_extra->d2(), +infinity_d);
754   TEST_EQ(def_extra->d3(), -infinity_d);
755   std::string jsongen;
756   auto result = GenerateText(parser, def_obj, &jsongen);
757   TEST_EQ(result, true);
758   // Check expected default values.
759   TEST_EQ(std::string::npos != jsongen.find("f0: nan"), true);
760   TEST_EQ(std::string::npos != jsongen.find("f1: nan"), true);
761   TEST_EQ(std::string::npos != jsongen.find("f2: inf"), true);
762   TEST_EQ(std::string::npos != jsongen.find("f3: -inf"), true);
763   TEST_EQ(std::string::npos != jsongen.find("d0: nan"), true);
764   TEST_EQ(std::string::npos != jsongen.find("d1: nan"), true);
765   TEST_EQ(std::string::npos != jsongen.find("d2: inf"), true);
766   TEST_EQ(std::string::npos != jsongen.find("d3: -inf"), true);
767   // Parse 'mosterdata_extra.json'.
768   const auto extra_base = test_data_path + "monsterdata_extra";
769   jsongen = "";
770   TEST_EQ(LoadFile((extra_base + ".json").c_str(), false, &jsongen), true);
771   TEST_EQ(parser.Parse(jsongen.c_str()), true);
772   const auto test_file = parser.builder_.GetBufferPointer();
773   const auto test_size = parser.builder_.GetSize();
774   Verifier verifier(test_file, test_size);
775   TEST_ASSERT(VerifyMonsterExtraBuffer(verifier));
776   const auto extra = GetMonsterExtra(test_file);
777   TEST_NOTNULL(extra);
778   TEST_EQ(is_quiet_nan(extra->f0()), true);
779   TEST_EQ(is_quiet_nan(extra->f1()), true);
780   TEST_EQ(extra->f2(), +infinity_f);
781   TEST_EQ(extra->f3(), -infinity_f);
782   TEST_EQ(is_quiet_nan(extra->d0()), true);
783   TEST_EQ(extra->d1(), +infinity_d);
784   TEST_EQ(extra->d2(), -infinity_d);
785   TEST_EQ(is_quiet_nan(extra->d3()), true);
786   TEST_NOTNULL(extra->fvec());
787   TEST_EQ(extra->fvec()->size(), 4);
788   TEST_EQ(extra->fvec()->Get(0), 1.0f);
789   TEST_EQ(extra->fvec()->Get(1), -infinity_f);
790   TEST_EQ(extra->fvec()->Get(2), +infinity_f);
791   TEST_EQ(is_quiet_nan(extra->fvec()->Get(3)), true);
792   TEST_NOTNULL(extra->dvec());
793   TEST_EQ(extra->dvec()->size(), 4);
794   TEST_EQ(extra->dvec()->Get(0), 2.0);
795   TEST_EQ(extra->dvec()->Get(1), +infinity_d);
796   TEST_EQ(extra->dvec()->Get(2), -infinity_d);
797   TEST_EQ(is_quiet_nan(extra->dvec()->Get(3)), true);
798 }
799 #else
800 void TestMonsterExtraFloats() {}
801 #endif
802
803 // example of parsing text straight into a buffer, and generating
804 // text back from it:
805 void ParseAndGenerateTextTest(bool binary) {
806   // load FlatBuffer schema (.fbs) and JSON from disk
807   std::string schemafile;
808   std::string jsonfile;
809   TEST_EQ(flatbuffers::LoadFile(
810               (test_data_path + "monster_test." + (binary ? "bfbs" : "fbs"))
811                   .c_str(),
812               binary, &schemafile),
813           true);
814   TEST_EQ(flatbuffers::LoadFile(
815               (test_data_path + "monsterdata_test.golden").c_str(), false,
816               &jsonfile),
817           true);
818
819   auto include_test_path =
820       flatbuffers::ConCatPathFileName(test_data_path, "include_test");
821   const char *include_directories[] = { test_data_path.c_str(),
822                                         include_test_path.c_str(), nullptr };
823
824   // parse schema first, so we can use it to parse the data after
825   flatbuffers::Parser parser;
826   if (binary) {
827     flatbuffers::Verifier verifier(
828         reinterpret_cast<const uint8_t *>(schemafile.c_str()),
829         schemafile.size());
830     TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
831     // auto schema = reflection::GetSchema(schemafile.c_str());
832     TEST_EQ(parser.Deserialize((const uint8_t *)schemafile.c_str(),
833                                schemafile.size()),
834             true);
835   } else {
836     TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
837   }
838   TEST_EQ(parser.ParseJson(jsonfile.c_str()), true);
839
840   // here, parser.builder_ contains a binary buffer that is the parsed data.
841
842   // First, verify it, just in case:
843   flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
844                                  parser.builder_.GetSize());
845   TEST_EQ(VerifyMonsterBuffer(verifier), true);
846
847   AccessFlatBufferTest(parser.builder_.GetBufferPointer(),
848                        parser.builder_.GetSize(), false);
849
850   // to ensure it is correct, we now generate text back from the binary,
851   // and compare the two:
852   std::string jsongen;
853   auto result =
854       GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
855   TEST_EQ(result, true);
856   TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
857
858   // We can also do the above using the convenient Registry that knows about
859   // a set of file_identifiers mapped to schemas.
860   flatbuffers::Registry registry;
861   // Make sure schemas can find their includes.
862   registry.AddIncludeDirectory(test_data_path.c_str());
863   registry.AddIncludeDirectory(include_test_path.c_str());
864   // Call this with many schemas if possible.
865   registry.Register(MonsterIdentifier(),
866                     (test_data_path + "monster_test.fbs").c_str());
867   // Now we got this set up, we can parse by just specifying the identifier,
868   // the correct schema will be loaded on the fly:
869   auto buf = registry.TextToFlatBuffer(jsonfile.c_str(), MonsterIdentifier());
870   // If this fails, check registry.lasterror_.
871   TEST_NOTNULL(buf.data());
872   // Test the buffer, to be sure:
873   AccessFlatBufferTest(buf.data(), buf.size(), false);
874   // We can use the registry to turn this back into text, in this case it
875   // will get the file_identifier from the binary:
876   std::string text;
877   auto ok = registry.FlatBufferToText(buf.data(), buf.size(), &text);
878   // If this fails, check registry.lasterror_.
879   TEST_EQ(ok, true);
880   TEST_EQ_STR(text.c_str(), jsonfile.c_str());
881
882   // Generate text for UTF-8 strings without escapes.
883   std::string jsonfile_utf8;
884   TEST_EQ(flatbuffers::LoadFile((test_data_path + "unicode_test.json").c_str(),
885                                 false, &jsonfile_utf8),
886           true);
887   TEST_EQ(parser.Parse(jsonfile_utf8.c_str(), include_directories), true);
888   // To ensure it is correct, generate utf-8 text back from the binary.
889   std::string jsongen_utf8;
890   // request natural printing for utf-8 strings
891   parser.opts.natural_utf8 = true;
892   parser.opts.strict_json = true;
893   TEST_EQ(
894       GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen_utf8),
895       true);
896   TEST_EQ_STR(jsongen_utf8.c_str(), jsonfile_utf8.c_str());
897 }
898
899 void ReflectionTest(uint8_t *flatbuf, size_t length) {
900   // Load a binary schema.
901   std::string bfbsfile;
902   TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.bfbs").c_str(),
903                                 true, &bfbsfile),
904           true);
905
906   // Verify it, just in case:
907   flatbuffers::Verifier verifier(
908       reinterpret_cast<const uint8_t *>(bfbsfile.c_str()), bfbsfile.length());
909   TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
910
911   // Make sure the schema is what we expect it to be.
912   auto &schema = *reflection::GetSchema(bfbsfile.c_str());
913   auto root_table = schema.root_table();
914   TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
915   auto fields = root_table->fields();
916   auto hp_field_ptr = fields->LookupByKey("hp");
917   TEST_NOTNULL(hp_field_ptr);
918   auto &hp_field = *hp_field_ptr;
919   TEST_EQ_STR(hp_field.name()->c_str(), "hp");
920   TEST_EQ(hp_field.id(), 2);
921   TEST_EQ(hp_field.type()->base_type(), reflection::Short);
922
923   auto friendly_field_ptr = fields->LookupByKey("friendly");
924   TEST_NOTNULL(friendly_field_ptr);
925   TEST_NOTNULL(friendly_field_ptr->attributes());
926   TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
927
928   // Make sure the table index is what we expect it to be.
929   auto pos_field_ptr = fields->LookupByKey("pos");
930   TEST_NOTNULL(pos_field_ptr);
931   TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
932   auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
933   TEST_NOTNULL(pos_table_ptr);
934   TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
935
936   // Test nullability of fields: hp is a 0-default scalar, pos is a struct =>
937   // optional, and name is a required string => not optional.
938   TEST_EQ(hp_field.optional(), false);
939   TEST_EQ(pos_field_ptr->optional(), true);
940   TEST_EQ(fields->LookupByKey("name")->optional(), false);
941
942   // Now use it to dynamically access a buffer.
943   auto &root = *flatbuffers::GetAnyRoot(flatbuf);
944
945   // Verify the buffer first using reflection based verification
946   TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
947           true);
948
949   auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
950   TEST_EQ(hp, 80);
951
952   // Rather than needing to know the type, we can also get the value of
953   // any field as an int64_t/double/string, regardless of what it actually is.
954   auto hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
955   TEST_EQ(hp_int64, 80);
956   auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
957   TEST_EQ(hp_double, 80.0);
958   auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
959   TEST_EQ_STR(hp_string.c_str(), "80");
960
961   // Get struct field through reflection
962   auto pos_struct = flatbuffers::GetFieldStruct(root, *pos_field_ptr);
963   TEST_NOTNULL(pos_struct);
964   TEST_EQ(flatbuffers::GetAnyFieldF(*pos_struct,
965                                     *pos_table_ptr->fields()->LookupByKey("z")),
966           3.0f);
967
968   auto test3_field = pos_table_ptr->fields()->LookupByKey("test3");
969   auto test3_struct = flatbuffers::GetFieldStruct(*pos_struct, *test3_field);
970   TEST_NOTNULL(test3_struct);
971   auto test3_object = schema.objects()->Get(test3_field->type()->index());
972
973   TEST_EQ(flatbuffers::GetAnyFieldF(*test3_struct,
974                                     *test3_object->fields()->LookupByKey("a")),
975           10);
976
977   // We can also modify it.
978   flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
979   hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
980   TEST_EQ(hp, 200);
981
982   // We can also set fields generically:
983   flatbuffers::SetAnyFieldI(&root, hp_field, 300);
984   hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
985   TEST_EQ(hp_int64, 300);
986   flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
987   hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
988   TEST_EQ(hp_int64, 300);
989   flatbuffers::SetAnyFieldS(&root, hp_field, "300");
990   hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
991   TEST_EQ(hp_int64, 300);
992
993   // Test buffer is valid after the modifications
994   TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
995           true);
996
997   // Reset it, for further tests.
998   flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
999
1000   // More advanced functionality: changing the size of items in-line!
1001   // First we put the FlatBuffer inside an std::vector.
1002   std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
1003   // Find the field we want to modify.
1004   auto &name_field = *fields->LookupByKey("name");
1005   // Get the root.
1006   // This time we wrap the result from GetAnyRoot in a smartpointer that
1007   // will keep rroot valid as resizingbuf resizes.
1008   auto rroot = flatbuffers::piv(
1009       flatbuffers::GetAnyRoot(flatbuffers::vector_data(resizingbuf)),
1010       resizingbuf);
1011   SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
1012             &resizingbuf);
1013   // Here resizingbuf has changed, but rroot is still valid.
1014   TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
1015   // Now lets extend a vector by 100 elements (10 -> 110).
1016   auto &inventory_field = *fields->LookupByKey("inventory");
1017   auto rinventory = flatbuffers::piv(
1018       flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field), resizingbuf);
1019   flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
1020                                      &resizingbuf);
1021   // rinventory still valid, so lets read from it.
1022   TEST_EQ(rinventory->Get(10), 50);
1023
1024   // For reflection uses not covered already, there is a more powerful way:
1025   // we can simply generate whatever object we want to add/modify in a
1026   // FlatBuffer of its own, then add that to an existing FlatBuffer:
1027   // As an example, let's add a string to an array of strings.
1028   // First, find our field:
1029   auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
1030   // Find the vector value:
1031   auto rtestarrayofstring = flatbuffers::piv(
1032       flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
1033           **rroot, testarrayofstring_field),
1034       resizingbuf);
1035   // It's a vector of 2 strings, to which we add one more, initialized to
1036   // offset 0.
1037   flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
1038       schema, 3, 0, *rtestarrayofstring, &resizingbuf);
1039   // Here we just create a buffer that contans a single string, but this
1040   // could also be any complex set of tables and other values.
1041   flatbuffers::FlatBufferBuilder stringfbb;
1042   stringfbb.Finish(stringfbb.CreateString("hank"));
1043   // Add the contents of it to our existing FlatBuffer.
1044   // We do this last, so the pointer doesn't get invalidated (since it is
1045   // at the end of the buffer):
1046   auto string_ptr = flatbuffers::AddFlatBuffer(
1047       resizingbuf, stringfbb.GetBufferPointer(), stringfbb.GetSize());
1048   // Finally, set the new value in the vector.
1049   rtestarrayofstring->MutateOffset(2, string_ptr);
1050   TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
1051   TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
1052   // Test integrity of all resize operations above.
1053   flatbuffers::Verifier resize_verifier(
1054       reinterpret_cast<const uint8_t *>(flatbuffers::vector_data(resizingbuf)),
1055       resizingbuf.size());
1056   TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
1057
1058   // Test buffer is valid using reflection as well
1059   TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1060                               flatbuffers::vector_data(resizingbuf),
1061                               resizingbuf.size()),
1062           true);
1063
1064   // As an additional test, also set it on the name field.
1065   // Note: unlike the name change above, this just overwrites the offset,
1066   // rather than changing the string in-place.
1067   SetFieldT(*rroot, name_field, string_ptr);
1068   TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
1069
1070   // Using reflection, rather than mutating binary FlatBuffers, we can also copy
1071   // tables and other things out of other FlatBuffers into a FlatBufferBuilder,
1072   // either part or whole.
1073   flatbuffers::FlatBufferBuilder fbb;
1074   auto root_offset = flatbuffers::CopyTable(
1075       fbb, schema, *root_table, *flatbuffers::GetAnyRoot(flatbuf), true);
1076   fbb.Finish(root_offset, MonsterIdentifier());
1077   // Test that it was copied correctly:
1078   AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
1079
1080   // Test buffer is valid using reflection as well
1081   TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
1082                               fbb.GetBufferPointer(), fbb.GetSize()),
1083           true);
1084 }
1085
1086 void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
1087   auto s =
1088       flatbuffers::FlatBufferToString(flatbuf, Monster::MiniReflectTypeTable());
1089   TEST_EQ_STR(
1090       s.c_str(),
1091       "{ "
1092       "pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
1093       "{ a: 10, b: 20 } }, "
1094       "hp: 80, "
1095       "name: \"MyMonster\", "
1096       "inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
1097       "test_type: Monster, "
1098       "test: { name: \"Fred\" }, "
1099       "test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1100       "testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
1101       "testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" "
1102       "}, "
1103       "{ name: \"Wilma\" } ], "
1104       // TODO(wvo): should really print this nested buffer correctly.
1105       "testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, "
1106       "0, "
1107       "4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
1108       "101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
1109       "testarrayofstring2: [ \"jane\", \"mary\" ], "
1110       "testarrayofsortedstruct: [ { id: 0, distance: 0 }, "
1111       "{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
1112       "{ id: 4, distance: 40 } ], "
1113       "flex: [ 210, 4, 5, 2 ], "
1114       "test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
1115       "vector_of_enums: [ Blue, Green ], "
1116       "scalar_key_sorted_tables: [ { id: \"miss\" } ] "
1117       "}");
1118
1119   Test test(16, 32);
1120   Vec3 vec(1, 2, 3, 1.5, Color_Red, test);
1121   flatbuffers::FlatBufferBuilder vec_builder;
1122   vec_builder.Finish(vec_builder.CreateStruct(vec));
1123   auto vec_buffer = vec_builder.Release();
1124   auto vec_str = flatbuffers::FlatBufferToString(vec_buffer.data(),
1125                                                  Vec3::MiniReflectTypeTable());
1126   TEST_EQ_STR(vec_str.c_str(),
1127               "{ x: 1.0, y: 2.0, z: 3.0, test1: 1.5, test2: Red, test3: { a: "
1128               "16, b: 32 } }");
1129 }
1130
1131 void MiniReflectFixedLengthArrayTest() {
1132   // VS10 does not support typed enums, exclude from tests
1133 #if !defined(_MSC_VER) || _MSC_VER >= 1700
1134   flatbuffers::FlatBufferBuilder fbb;
1135   MyGame::Example::ArrayStruct aStruct(2, 12, 1);
1136   auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
1137   fbb.Finish(aTable);
1138
1139   auto flatbuf = fbb.Release();
1140   auto s = flatbuffers::FlatBufferToString(
1141       flatbuf.data(), MyGame::Example::ArrayTableTypeTable());
1142   TEST_EQ_STR(
1143       "{ "
1144       "a: { a: 2.0, "
1145       "b: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], "
1146       "c: 12, "
1147       "d: [ { a: [ 0, 0 ], b: A, c: [ A, A ], d: [ 0, 0 ] }, "
1148       "{ a: [ 0, 0 ], b: A, c: [ A, A ], d: [ 0, 0 ] } ], "
1149       "e: 1, f: [ 0, 0 ] } "
1150       "}",
1151       s.c_str());
1152 #endif
1153 }
1154
1155 // Parse a .proto schema, output as .fbs
1156 void ParseProtoTest() {
1157   // load the .proto and the golden file from disk
1158   std::string protofile;
1159   std::string goldenfile;
1160   std::string goldenunionfile;
1161   TEST_EQ(
1162       flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1163                             false, &protofile),
1164       true);
1165   TEST_EQ(
1166       flatbuffers::LoadFile((test_data_path + "prototest/test.golden").c_str(),
1167                             false, &goldenfile),
1168       true);
1169   TEST_EQ(flatbuffers::LoadFile(
1170               (test_data_path + "prototest/test_union.golden").c_str(), false,
1171               &goldenunionfile),
1172           true);
1173
1174   flatbuffers::IDLOptions opts;
1175   opts.include_dependence_headers = false;
1176   opts.proto_mode = true;
1177
1178   // Parse proto.
1179   flatbuffers::Parser parser(opts);
1180   auto protopath = test_data_path + "prototest/";
1181   const char *include_directories[] = { protopath.c_str(), nullptr };
1182   TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1183
1184   // Generate fbs.
1185   auto fbs = flatbuffers::GenerateFBS(parser, "test");
1186
1187   // Ensure generated file is parsable.
1188   flatbuffers::Parser parser2;
1189   TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1190   TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1191
1192   // Parse proto with --oneof-union option.
1193   opts.proto_oneof_union = true;
1194   flatbuffers::Parser parser3(opts);
1195   TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1196
1197   // Generate fbs.
1198   auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1199
1200   // Ensure generated file is parsable.
1201   flatbuffers::Parser parser4;
1202   TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1203   TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1204 }
1205
1206 // Parse a .proto schema, output as .fbs
1207 void ParseProtoTestWithSuffix() {
1208   // load the .proto and the golden file from disk
1209   std::string protofile;
1210   std::string goldenfile;
1211   std::string goldenunionfile;
1212   TEST_EQ(
1213       flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1214                             false, &protofile),
1215       true);
1216   TEST_EQ(flatbuffers::LoadFile(
1217               (test_data_path + "prototest/test_suffix.golden").c_str(), false,
1218               &goldenfile),
1219           true);
1220   TEST_EQ(flatbuffers::LoadFile(
1221               (test_data_path + "prototest/test_union_suffix.golden").c_str(),
1222               false, &goldenunionfile),
1223           true);
1224
1225   flatbuffers::IDLOptions opts;
1226   opts.include_dependence_headers = false;
1227   opts.proto_mode = true;
1228   opts.proto_namespace_suffix = "test_namespace_suffix";
1229
1230   // Parse proto.
1231   flatbuffers::Parser parser(opts);
1232   auto protopath = test_data_path + "prototest/";
1233   const char *include_directories[] = { protopath.c_str(), nullptr };
1234   TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1235
1236   // Generate fbs.
1237   auto fbs = flatbuffers::GenerateFBS(parser, "test");
1238
1239   // Ensure generated file is parsable.
1240   flatbuffers::Parser parser2;
1241   TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1242   TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1243
1244   // Parse proto with --oneof-union option.
1245   opts.proto_oneof_union = true;
1246   flatbuffers::Parser parser3(opts);
1247   TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1248
1249   // Generate fbs.
1250   auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1251
1252   // Ensure generated file is parsable.
1253   flatbuffers::Parser parser4;
1254   TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1255   TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1256 }
1257
1258 // Parse a .proto schema, output as .fbs
1259 void ParseProtoTestWithIncludes() {
1260   // load the .proto and the golden file from disk
1261   std::string protofile;
1262   std::string goldenfile;
1263   std::string goldenunionfile;
1264   std::string importprotofile;
1265   TEST_EQ(
1266       flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
1267                             false, &protofile),
1268       true);
1269   TEST_EQ(flatbuffers::LoadFile(
1270               (test_data_path + "prototest/imported.proto").c_str(), false,
1271               &importprotofile),
1272           true);
1273   TEST_EQ(flatbuffers::LoadFile(
1274               (test_data_path + "prototest/test_include.golden").c_str(), false,
1275               &goldenfile),
1276           true);
1277   TEST_EQ(flatbuffers::LoadFile(
1278               (test_data_path + "prototest/test_union_include.golden").c_str(),
1279               false, &goldenunionfile),
1280           true);
1281
1282   flatbuffers::IDLOptions opts;
1283   opts.include_dependence_headers = true;
1284   opts.proto_mode = true;
1285
1286   // Parse proto.
1287   flatbuffers::Parser parser(opts);
1288   auto protopath = test_data_path + "prototest/";
1289   const char *include_directories[] = { protopath.c_str(), nullptr };
1290   TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
1291
1292   // Generate fbs.
1293   auto fbs = flatbuffers::GenerateFBS(parser, "test");
1294
1295   // Generate fbs from import.proto
1296   flatbuffers::Parser import_parser(opts);
1297   TEST_EQ(import_parser.Parse(importprotofile.c_str(), include_directories),
1298           true);
1299   auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test");
1300
1301   // Ensure generated file is parsable.
1302   flatbuffers::Parser parser2;
1303   TEST_EQ(
1304       parser2.Parse(import_fbs.c_str(), include_directories, "imported.fbs"),
1305       true);
1306   TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
1307   TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
1308
1309   // Parse proto with --oneof-union option.
1310   opts.proto_oneof_union = true;
1311   flatbuffers::Parser parser3(opts);
1312   TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
1313
1314   // Generate fbs.
1315   auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
1316
1317   // Ensure generated file is parsable.
1318   flatbuffers::Parser parser4;
1319   TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, "imported.fbs"), true);
1320   TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
1321   TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
1322 }
1323
1324 template<typename T>
1325 void CompareTableFieldValue(flatbuffers::Table *table,
1326                             flatbuffers::voffset_t voffset, T val) {
1327   T read = table->GetField(voffset, static_cast<T>(0));
1328   TEST_EQ(read, val);
1329 }
1330
1331 // Low level stress/fuzz test: serialize/deserialize a variety of
1332 // different kinds of data in different combinations
1333 void FuzzTest1() {
1334   // Values we're testing against: chosen to ensure no bits get chopped
1335   // off anywhere, and also be different from eachother.
1336   const uint8_t bool_val = true;
1337   const int8_t char_val = -127;  // 0x81
1338   const uint8_t uchar_val = 0xFF;
1339   const int16_t short_val = -32222;  // 0x8222;
1340   const uint16_t ushort_val = 0xFEEE;
1341   const int32_t int_val = 0x83333333;
1342   const uint32_t uint_val = 0xFDDDDDDD;
1343   const int64_t long_val = 0x8444444444444444LL;
1344   const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
1345   const float float_val = 3.14159f;
1346   const double double_val = 3.14159265359;
1347
1348   const int test_values_max = 11;
1349   const flatbuffers::voffset_t fields_per_object = 4;
1350   const int num_fuzz_objects = 10000;  // The higher, the more thorough :)
1351
1352   flatbuffers::FlatBufferBuilder builder;
1353
1354   lcg_reset();  // Keep it deterministic.
1355
1356   flatbuffers::uoffset_t objects[num_fuzz_objects];
1357
1358   // Generate num_fuzz_objects random objects each consisting of
1359   // fields_per_object fields, each of a random type.
1360   for (int i = 0; i < num_fuzz_objects; i++) {
1361     auto start = builder.StartTable();
1362     for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1363       int choice = lcg_rand() % test_values_max;
1364       auto off = flatbuffers::FieldIndexToOffset(f);
1365       switch (choice) {
1366         case 0: builder.AddElement<uint8_t>(off, bool_val, 0); break;
1367         case 1: builder.AddElement<int8_t>(off, char_val, 0); break;
1368         case 2: builder.AddElement<uint8_t>(off, uchar_val, 0); break;
1369         case 3: builder.AddElement<int16_t>(off, short_val, 0); break;
1370         case 4: builder.AddElement<uint16_t>(off, ushort_val, 0); break;
1371         case 5: builder.AddElement<int32_t>(off, int_val, 0); break;
1372         case 6: builder.AddElement<uint32_t>(off, uint_val, 0); break;
1373         case 7: builder.AddElement<int64_t>(off, long_val, 0); break;
1374         case 8: builder.AddElement<uint64_t>(off, ulong_val, 0); break;
1375         case 9: builder.AddElement<float>(off, float_val, 0); break;
1376         case 10: builder.AddElement<double>(off, double_val, 0); break;
1377       }
1378     }
1379     objects[i] = builder.EndTable(start);
1380   }
1381   builder.PreAlign<flatbuffers::largest_scalar_t>(0);  // Align whole buffer.
1382
1383   lcg_reset();  // Reset.
1384
1385   uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
1386
1387   // Test that all objects we generated are readable and return the
1388   // expected values. We generate random objects in the same order
1389   // so this is deterministic.
1390   for (int i = 0; i < num_fuzz_objects; i++) {
1391     auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
1392     for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
1393       int choice = lcg_rand() % test_values_max;
1394       flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
1395       switch (choice) {
1396         case 0: CompareTableFieldValue(table, off, bool_val); break;
1397         case 1: CompareTableFieldValue(table, off, char_val); break;
1398         case 2: CompareTableFieldValue(table, off, uchar_val); break;
1399         case 3: CompareTableFieldValue(table, off, short_val); break;
1400         case 4: CompareTableFieldValue(table, off, ushort_val); break;
1401         case 5: CompareTableFieldValue(table, off, int_val); break;
1402         case 6: CompareTableFieldValue(table, off, uint_val); break;
1403         case 7: CompareTableFieldValue(table, off, long_val); break;
1404         case 8: CompareTableFieldValue(table, off, ulong_val); break;
1405         case 9: CompareTableFieldValue(table, off, float_val); break;
1406         case 10: CompareTableFieldValue(table, off, double_val); break;
1407       }
1408     }
1409   }
1410 }
1411
1412 // High level stress/fuzz test: generate a big schema and
1413 // matching json data in random combinations, then parse both,
1414 // generate json back from the binary, and compare with the original.
1415 void FuzzTest2() {
1416   lcg_reset();  // Keep it deterministic.
1417
1418   const int num_definitions = 30;
1419   const int num_struct_definitions = 5;  // Subset of num_definitions.
1420   const int fields_per_definition = 15;
1421   const int instances_per_definition = 5;
1422   const int deprecation_rate = 10;  // 1 in deprecation_rate fields will
1423                                     // be deprecated.
1424
1425   std::string schema = "namespace test;\n\n";
1426
1427   struct RndDef {
1428     std::string instances[instances_per_definition];
1429
1430     // Since we're generating schema and corresponding data in tandem,
1431     // this convenience function adds strings to both at once.
1432     static void Add(RndDef (&definitions_l)[num_definitions],
1433                     std::string &schema_l, const int instances_per_definition_l,
1434                     const char *schema_add, const char *instance_add,
1435                     int definition) {
1436       schema_l += schema_add;
1437       for (int i = 0; i < instances_per_definition_l; i++)
1438         definitions_l[definition].instances[i] += instance_add;
1439     }
1440   };
1441
1442   // clang-format off
1443   #define AddToSchemaAndInstances(schema_add, instance_add) \
1444     RndDef::Add(definitions, schema, instances_per_definition, \
1445                 schema_add, instance_add, definition)
1446
1447   #define Dummy() \
1448     RndDef::Add(definitions, schema, instances_per_definition, \
1449                 "byte", "1", definition)
1450   // clang-format on
1451
1452   RndDef definitions[num_definitions];
1453
1454   // We are going to generate num_definitions, the first
1455   // num_struct_definitions will be structs, the rest tables. For each
1456   // generate random fields, some of which may be struct/table types
1457   // referring to previously generated structs/tables.
1458   // Simultanenously, we generate instances_per_definition JSON data
1459   // definitions, which will have identical structure to the schema
1460   // being generated. We generate multiple instances such that when creating
1461   // hierarchy, we get some variety by picking one randomly.
1462   for (int definition = 0; definition < num_definitions; definition++) {
1463     std::string definition_name = "D" + flatbuffers::NumToString(definition);
1464
1465     bool is_struct = definition < num_struct_definitions;
1466
1467     AddToSchemaAndInstances(
1468         ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
1469         "{\n");
1470
1471     for (int field = 0; field < fields_per_definition; field++) {
1472       const bool is_last_field = field == fields_per_definition - 1;
1473
1474       // Deprecate 1 in deprecation_rate fields. Only table fields can be
1475       // deprecated.
1476       // Don't deprecate the last field to avoid dangling commas in JSON.
1477       const bool deprecated =
1478           !is_struct && !is_last_field && (lcg_rand() % deprecation_rate == 0);
1479
1480       std::string field_name = "f" + flatbuffers::NumToString(field);
1481       AddToSchemaAndInstances(("  " + field_name + ":").c_str(),
1482                               deprecated ? "" : (field_name + ": ").c_str());
1483       // Pick random type:
1484       auto base_type = static_cast<flatbuffers::BaseType>(
1485           lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
1486       switch (base_type) {
1487         case flatbuffers::BASE_TYPE_STRING:
1488           if (is_struct) {
1489             Dummy();  // No strings in structs.
1490           } else {
1491             AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
1492           }
1493           break;
1494         case flatbuffers::BASE_TYPE_VECTOR:
1495           if (is_struct) {
1496             Dummy();  // No vectors in structs.
1497           } else {
1498             AddToSchemaAndInstances("[ubyte]",
1499                                     deprecated ? "" : "[\n0,\n1,\n255\n]");
1500           }
1501           break;
1502         case flatbuffers::BASE_TYPE_NONE:
1503         case flatbuffers::BASE_TYPE_UTYPE:
1504         case flatbuffers::BASE_TYPE_STRUCT:
1505         case flatbuffers::BASE_TYPE_UNION:
1506           if (definition) {
1507             // Pick a random previous definition and random data instance of
1508             // that definition.
1509             int defref = lcg_rand() % definition;
1510             int instance = lcg_rand() % instances_per_definition;
1511             AddToSchemaAndInstances(
1512                 ("D" + flatbuffers::NumToString(defref)).c_str(),
1513                 deprecated ? ""
1514                            : definitions[defref].instances[instance].c_str());
1515           } else {
1516             // If this is the first definition, we have no definition we can
1517             // refer to.
1518             Dummy();
1519           }
1520           break;
1521         case flatbuffers::BASE_TYPE_BOOL:
1522           AddToSchemaAndInstances(
1523               "bool", deprecated ? "" : (lcg_rand() % 2 ? "true" : "false"));
1524           break;
1525         case flatbuffers::BASE_TYPE_ARRAY:
1526           if (!is_struct) {
1527             AddToSchemaAndInstances(
1528                 "ubyte",
1529                 deprecated ? "" : "255");  // No fixed-length arrays in tables.
1530           } else {
1531             AddToSchemaAndInstances("[int:3]", deprecated ? "" : "[\n,\n,\n]");
1532           }
1533           break;
1534         default:
1535           // All the scalar types.
1536           schema += flatbuffers::kTypeNames[base_type];
1537
1538           if (!deprecated) {
1539             // We want each instance to use its own random value.
1540             for (int inst = 0; inst < instances_per_definition; inst++)
1541               definitions[definition].instances[inst] +=
1542                   flatbuffers::IsFloat(base_type)
1543                       ? flatbuffers::NumToString<double>(lcg_rand() % 128)
1544                             .c_str()
1545                       : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
1546           }
1547       }
1548       AddToSchemaAndInstances(deprecated ? "(deprecated);\n" : ";\n",
1549                               deprecated ? "" : is_last_field ? "\n" : ",\n");
1550     }
1551     AddToSchemaAndInstances("}\n\n", "}");
1552   }
1553
1554   schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
1555   schema += ";\n";
1556
1557   flatbuffers::Parser parser;
1558
1559   // Will not compare against the original if we don't write defaults
1560   parser.builder_.ForceDefaults(true);
1561
1562   // Parse the schema, parse the generated data, then generate text back
1563   // from the binary and compare against the original.
1564   TEST_EQ(parser.Parse(schema.c_str()), true);
1565
1566   const std::string &json =
1567       definitions[num_definitions - 1].instances[0] + "\n";
1568
1569   TEST_EQ(parser.Parse(json.c_str()), true);
1570
1571   std::string jsongen;
1572   parser.opts.indent_step = 0;
1573   auto result =
1574       GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
1575   TEST_EQ(result, true);
1576
1577   if (jsongen != json) {
1578     // These strings are larger than a megabyte, so we show the bytes around
1579     // the first bytes that are different rather than the whole string.
1580     size_t len = std::min(json.length(), jsongen.length());
1581     for (size_t i = 0; i < len; i++) {
1582       if (json[i] != jsongen[i]) {
1583         i -= std::min(static_cast<size_t>(10), i);  // show some context;
1584         size_t end = std::min(len, i + 20);
1585         for (; i < end; i++)
1586           TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
1587                            static_cast<int>(i), jsongen[i], json[i]);
1588         break;
1589       }
1590     }
1591     TEST_NOTNULL(nullptr);  //-V501 (this comment supresses CWE-570 warning)
1592   }
1593
1594   // clang-format off
1595   #ifdef FLATBUFFERS_TEST_VERBOSE
1596     TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
1597                      static_cast<int>(schema.length() / 1024),
1598                      static_cast<int>(json.length() / 1024));
1599   #endif
1600   // clang-format on
1601 }
1602
1603 // Test that parser errors are actually generated.
1604 void TestError_(const char *src, const char *error_substr, bool strict_json,
1605                 const char *file, int line, const char *func) {
1606   flatbuffers::IDLOptions opts;
1607   opts.strict_json = strict_json;
1608   flatbuffers::Parser parser(opts);
1609   if (parser.Parse(src)) {
1610     TestFail("true", "false",
1611              ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1612              func);
1613   } else if (!strstr(parser.error_.c_str(), error_substr)) {
1614     TestFail(error_substr, parser.error_.c_str(),
1615              ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
1616              func);
1617   }
1618 }
1619
1620 void TestError_(const char *src, const char *error_substr, const char *file,
1621                 int line, const char *func) {
1622   TestError_(src, error_substr, false, file, line, func);
1623 }
1624
1625 #ifdef _WIN32
1626 #  define TestError(src, ...) \
1627     TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
1628 #else
1629 #  define TestError(src, ...) \
1630     TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1631 #endif
1632
1633 // Test that parsing errors occur as we'd expect.
1634 // Also useful for coverage, making sure these paths are run.
1635 void ErrorTest() {
1636   // In order they appear in idl_parser.cpp
1637   TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
1638   TestError("\"\0", "illegal");
1639   TestError("\"\\q", "escape code");
1640   TestError("table ///", "documentation");
1641   TestError("@", "illegal");
1642   TestError("table 1", "expecting");
1643   TestError("table X { Y:[[int]]; }", "nested vector");
1644   TestError("table X { Y:1; }", "illegal type");
1645   TestError("table X { Y:int; Y:int; }", "field already");
1646   TestError("table Y {} table X { Y:int; }", "same as table");
1647   TestError("struct X { Y:string; }", "only scalar");
1648   TestError("table X { Y:string = \"\"; }", "default values");
1649   TestError("struct X { a:uint = 42; }", "default values");
1650   TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
1651   TestError("struct X { Y:int (deprecated); }", "deprecate");
1652   TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
1653             "missing type field");
1654   TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
1655             "type id");
1656   TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
1657   TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
1658   TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
1659             true);
1660   TestError(
1661       "struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
1662       "{ V:{ Y:1 } }",
1663       "wrong number");
1664   TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
1665             "unknown enum value");
1666   TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
1667   TestError("enum X:byte { Y } enum X {", "enum already");
1668   TestError("enum X:float {}", "underlying");
1669   TestError("enum X:byte { Y, Y }", "value already");
1670   TestError("enum X:byte { Y=2, Z=2 }", "unique");
1671   TestError("table X { Y:int; } table X {", "datatype already");
1672   TestError("struct X (force_align: 7) { Y:int; }", "force_align");
1673   TestError("struct X {}", "size 0");
1674   TestError("{}", "no root");
1675   TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
1676   TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
1677             "end of file");
1678   TestError("root_type X;", "unknown root");
1679   TestError("struct X { Y:int; } root_type X;", "a table");
1680   TestError("union X { Y }", "referenced");
1681   TestError("union Z { X } struct X { Y:int; }", "only tables");
1682   TestError("table X { Y:[int]; YLength:int; }", "clash");
1683   TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
1684   // float to integer conversion is forbidden
1685   TestError("table X { Y:int; } root_type X; { Y:1.0 }", "float");
1686   TestError("table X { Y:bool; } root_type X; { Y:1.0 }", "float");
1687   TestError("enum X:bool { Y = true }", "must be integral");
1688   // Array of non-scalar
1689   TestError("table X { x:int; } struct Y { y:[X:2]; }",
1690             "may contain only scalar or struct fields");
1691   // Non-snake case field names
1692   TestError("table X { Y: int; } root_type Y: {Y:1.0}", "snake_case");
1693 }
1694
1695 template<typename T>
1696 T TestValue(const char *json, const char *type_name,
1697             const char *decls = nullptr) {
1698   flatbuffers::Parser parser;
1699   parser.builder_.ForceDefaults(true);  // return defaults
1700   auto check_default = json ? false : true;
1701   if (check_default) { parser.opts.output_default_scalars_in_json = true; }
1702   // Simple schema.
1703   std::string schema = std::string(decls ? decls : "") + "\n" +
1704                        "table X { y:" + std::string(type_name) +
1705                        "; } root_type X;";
1706   auto schema_done = parser.Parse(schema.c_str());
1707   TEST_EQ_STR(parser.error_.c_str(), "");
1708   TEST_EQ(schema_done, true);
1709
1710   auto done = parser.Parse(check_default ? "{}" : json);
1711   TEST_EQ_STR(parser.error_.c_str(), "");
1712   TEST_EQ(done, true);
1713
1714   // Check with print.
1715   std::string print_back;
1716   parser.opts.indent_step = -1;
1717   TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back),
1718           true);
1719   // restore value from its default
1720   if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); }
1721
1722   auto root = flatbuffers::GetRoot<flatbuffers::Table>(
1723       parser.builder_.GetBufferPointer());
1724   return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
1725 }
1726
1727 bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
1728
1729 // Additional parser testing not covered elsewhere.
1730 void ValueTest() {
1731   // Test scientific notation numbers.
1732   TEST_EQ(
1733       FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
1734       true);
1735   // number in string
1736   TEST_EQ(FloatCompare(TestValue<float>("{ y:\"0.0314159e+2\" }", "float"),
1737                        3.14159f),
1738           true);
1739
1740   // Test conversion functions.
1741   TEST_EQ(FloatCompare(TestValue<float>("{ y:cos(rad(180)) }", "float"), -1),
1742           true);
1743
1744   // int embedded to string
1745   TEST_EQ(TestValue<int>("{ y:\"-876\" }", "int=-123"), -876);
1746   TEST_EQ(TestValue<int>("{ y:\"876\" }", "int=-123"), 876);
1747
1748   // Test negative hex constant.
1749   TEST_EQ(TestValue<int>("{ y:-0x8ea0 }", "int=-0x8ea0"), -36512);
1750   TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
1751
1752   // positive hex constant
1753   TEST_EQ(TestValue<int>("{ y:0x1abcdef }", "int=0x1"), 0x1abcdef);
1754   // with optional '+' sign
1755   TEST_EQ(TestValue<int>("{ y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
1756   // hex in string
1757   TEST_EQ(TestValue<int>("{ y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
1758
1759   // Make sure we do unsigned 64bit correctly.
1760   TEST_EQ(TestValue<uint64_t>("{ y:12335089644688340133 }", "ulong"),
1761           12335089644688340133ULL);
1762
1763   // bool in string
1764   TEST_EQ(TestValue<bool>("{ y:\"false\" }", "bool=true"), false);
1765   TEST_EQ(TestValue<bool>("{ y:\"true\" }", "bool=\"true\""), true);
1766   TEST_EQ(TestValue<bool>("{ y:'false' }", "bool=true"), false);
1767   TEST_EQ(TestValue<bool>("{ y:'true' }", "bool=\"true\""), true);
1768
1769   // check comments before and after json object
1770   TEST_EQ(TestValue<int>("/*before*/ { y:1 } /*after*/", "int"), 1);
1771   TEST_EQ(TestValue<int>("//before \n { y:1 } //after", "int"), 1);
1772 }
1773
1774 void NestedListTest() {
1775   flatbuffers::Parser parser1;
1776   TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
1777                         "root_type T;"
1778                         "{ F:[ [10,20], [30,40]] }"),
1779           true);
1780 }
1781
1782 void EnumStringsTest() {
1783   flatbuffers::Parser parser1;
1784   TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
1785                         "root_type T;"
1786                         "{ F:[ A, B, \"C\", \"A B C\" ] }"),
1787           true);
1788   flatbuffers::Parser parser2;
1789   TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
1790                         "root_type T;"
1791                         "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"),
1792           true);
1793   // unsigned bit_flags
1794   flatbuffers::Parser parser3;
1795   TEST_EQ(
1796       parser3.Parse("enum E:uint16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }"
1797                     " table T { F: E = \"F15 F08\"; }"
1798                     "root_type T;"),
1799       true);
1800 }
1801
1802 void EnumNamesTest() {
1803   TEST_EQ_STR("Red", EnumNameColor(Color_Red));
1804   TEST_EQ_STR("Green", EnumNameColor(Color_Green));
1805   TEST_EQ_STR("Blue", EnumNameColor(Color_Blue));
1806   // Check that Color to string don't crash while decode a mixture of Colors.
1807   // 1) Example::Color enum is enum with unfixed underlying type.
1808   // 2) Valid enum range: [0; 2^(ceil(log2(Color_ANY))) - 1].
1809   // Consequence: A value is out of this range will lead to UB (since C++17).
1810   // For details see C++17 standard or explanation on the SO:
1811   // stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class
1812   TEST_EQ_STR("", EnumNameColor(static_cast<Color>(0)));
1813   TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY - 1)));
1814   TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY + 1)));
1815 }
1816
1817 void EnumOutOfRangeTest() {
1818   TestError("enum X:byte { Y = 128 }", "enum value does not fit");
1819   TestError("enum X:byte { Y = -129 }", "enum value does not fit");
1820   TestError("enum X:byte { Y = 126, Z0, Z1 }", "enum value does not fit");
1821   TestError("enum X:ubyte { Y = -1 }", "enum value does not fit");
1822   TestError("enum X:ubyte { Y = 256 }", "enum value does not fit");
1823   TestError("enum X:ubyte { Y = 255, Z }", "enum value does not fit");
1824   TestError("table Y{} union X { Y = -1 }", "enum value does not fit");
1825   TestError("table Y{} union X { Y = 256 }", "enum value does not fit");
1826   TestError("table Y{} union X { Y = 255, Z:Y }", "enum value does not fit");
1827   TestError("enum X:int { Y = -2147483649 }", "enum value does not fit");
1828   TestError("enum X:int { Y = 2147483648 }", "enum value does not fit");
1829   TestError("enum X:uint { Y = -1 }", "enum value does not fit");
1830   TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit");
1831   TestError("enum X:long { Y = 9223372036854775808 }", "does not fit");
1832   TestError("enum X:long { Y = 9223372036854775807, Z }",
1833             "enum value does not fit");
1834   TestError("enum X:ulong { Y = -1 }", "does not fit");
1835   TestError("enum X:ubyte (bit_flags) { Y=8 }", "bit flag out");
1836   TestError("enum X:byte (bit_flags) { Y=7 }", "must be unsigned");  // -128
1837   // bit_flgs out of range
1838   TestError("enum X:ubyte (bit_flags) { Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8 }",
1839             "out of range");
1840 }
1841
1842 void EnumValueTest() {
1843   // json: "{ Y:0 }", schema: table X { y: "E"}
1844   // 0 in enum (V=0) E then Y=0 is valid.
1845   TEST_EQ(TestValue<int>("{ y:0 }", "E", "enum E:int { V }"), 0);
1846   TEST_EQ(TestValue<int>("{ y:V }", "E", "enum E:int { V }"), 0);
1847   // A default value of Y is 0.
1848   TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
1849   TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { V=5 }"), 5);
1850   // Generate json with defaults and check.
1851   TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
1852   // 5 in enum
1853   TEST_EQ(TestValue<int>("{ y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
1854   TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
1855   // Generate json with defaults and check.
1856   TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
1857   TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
1858   // u84 test
1859   TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1860                               "enum E:ulong { V = 13835058055282163712 }"),
1861           13835058055282163712ULL);
1862   TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
1863                               "enum E:ulong { V = 18446744073709551615 }"),
1864           18446744073709551615ULL);
1865   // Assign non-enum value to enum field. Is it right?
1866   TEST_EQ(TestValue<int>("{ y:7 }", "E", "enum E:int { V = 0 }"), 7);
1867   // Check that non-ascending values are valid.
1868   TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z=10, V=5 }"), 5);
1869 }
1870
1871 void IntegerOutOfRangeTest() {
1872   TestError("table T { F:byte; } root_type T; { F:128 }",
1873             "constant does not fit");
1874   TestError("table T { F:byte; } root_type T; { F:-129 }",
1875             "constant does not fit");
1876   TestError("table T { F:ubyte; } root_type T; { F:256 }",
1877             "constant does not fit");
1878   TestError("table T { F:ubyte; } root_type T; { F:-1 }",
1879             "constant does not fit");
1880   TestError("table T { F:short; } root_type T; { F:32768 }",
1881             "constant does not fit");
1882   TestError("table T { F:short; } root_type T; { F:-32769 }",
1883             "constant does not fit");
1884   TestError("table T { F:ushort; } root_type T; { F:65536 }",
1885             "constant does not fit");
1886   TestError("table T { F:ushort; } root_type T; { F:-1 }",
1887             "constant does not fit");
1888   TestError("table T { F:int; } root_type T; { F:2147483648 }",
1889             "constant does not fit");
1890   TestError("table T { F:int; } root_type T; { F:-2147483649 }",
1891             "constant does not fit");
1892   TestError("table T { F:uint; } root_type T; { F:4294967296 }",
1893             "constant does not fit");
1894   TestError("table T { F:uint; } root_type T; { F:-1 }",
1895             "constant does not fit");
1896   // Check fixed width aliases
1897   TestError("table X { Y:uint8; } root_type X; { Y: -1 }", "does not fit");
1898   TestError("table X { Y:uint8; } root_type X; { Y: 256 }", "does not fit");
1899   TestError("table X { Y:uint16; } root_type X; { Y: -1 }", "does not fit");
1900   TestError("table X { Y:uint16; } root_type X; { Y: 65536 }", "does not fit");
1901   TestError("table X { Y:uint32; } root_type X; { Y: -1 }", "");
1902   TestError("table X { Y:uint32; } root_type X; { Y: 4294967296 }",
1903             "does not fit");
1904   TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1905   TestError("table X { Y:uint64; } root_type X; { Y: -9223372036854775809 }",
1906             "does not fit");
1907   TestError("table X { Y:uint64; } root_type X; { Y: 18446744073709551616 }",
1908             "does not fit");
1909
1910   TestError("table X { Y:int8; } root_type X; { Y: -129 }", "does not fit");
1911   TestError("table X { Y:int8; } root_type X; { Y: 128 }", "does not fit");
1912   TestError("table X { Y:int16; } root_type X; { Y: -32769 }", "does not fit");
1913   TestError("table X { Y:int16; } root_type X; { Y: 32768 }", "does not fit");
1914   TestError("table X { Y:int32; } root_type X; { Y: -2147483649 }", "");
1915   TestError("table X { Y:int32; } root_type X; { Y: 2147483648 }",
1916             "does not fit");
1917   TestError("table X { Y:int64; } root_type X; { Y: -9223372036854775809 }",
1918             "does not fit");
1919   TestError("table X { Y:int64; } root_type X; { Y: 9223372036854775808 }",
1920             "does not fit");
1921   // check out-of-int64 as int8
1922   TestError("table X { Y:int8; } root_type X; { Y: -9223372036854775809 }",
1923             "does not fit");
1924   TestError("table X { Y:int8; } root_type X; { Y: 9223372036854775808 }",
1925             "does not fit");
1926
1927   // Check default values
1928   TestError("table X { Y:int64=-9223372036854775809; } root_type X; {}",
1929             "does not fit");
1930   TestError("table X { Y:int64= 9223372036854775808; } root_type X; {}",
1931             "does not fit");
1932   TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
1933   TestError("table X { Y:uint64=-9223372036854775809; } root_type X; {}",
1934             "does not fit");
1935   TestError("table X { Y:uint64= 18446744073709551616; } root_type X; {}",
1936             "does not fit");
1937 }
1938
1939 void IntegerBoundaryTest() {
1940   // Check numerical compatibility with non-C++ languages.
1941   // By the C++ standard, std::numerical_limits<int64_t>::min() ==
1942   // -9223372036854775807 (-2^63+1) or less* The Flatbuffers grammar and most of
1943   // the languages (C#, Java, Rust) expect that minimum values are: -128,
1944   // -32768,.., -9223372036854775808. Since C++20,
1945   // static_cast<int64>(0x8000000000000000ULL) is well-defined two's complement
1946   // cast. Therefore -9223372036854775808 should be valid negative value.
1947   TEST_EQ(flatbuffers::numeric_limits<int8_t>::min(), -128);
1948   TEST_EQ(flatbuffers::numeric_limits<int8_t>::max(), 127);
1949   TEST_EQ(flatbuffers::numeric_limits<int16_t>::min(), -32768);
1950   TEST_EQ(flatbuffers::numeric_limits<int16_t>::max(), 32767);
1951   TEST_EQ(flatbuffers::numeric_limits<int32_t>::min() + 1, -2147483647);
1952   TEST_EQ(flatbuffers::numeric_limits<int32_t>::max(), 2147483647ULL);
1953   TEST_EQ(flatbuffers::numeric_limits<int64_t>::min() + 1LL,
1954           -9223372036854775807LL);
1955   TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(), 9223372036854775807ULL);
1956   TEST_EQ(flatbuffers::numeric_limits<uint8_t>::max(), 255);
1957   TEST_EQ(flatbuffers::numeric_limits<uint16_t>::max(), 65535);
1958   TEST_EQ(flatbuffers::numeric_limits<uint32_t>::max(), 4294967295ULL);
1959   TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
1960           18446744073709551615ULL);
1961
1962   TEST_EQ(TestValue<int8_t>("{ y:127 }", "byte"), 127);
1963   TEST_EQ(TestValue<int8_t>("{ y:-128 }", "byte"), -128);
1964   TEST_EQ(TestValue<uint8_t>("{ y:255 }", "ubyte"), 255);
1965   TEST_EQ(TestValue<uint8_t>("{ y:0 }", "ubyte"), 0);
1966   TEST_EQ(TestValue<int16_t>("{ y:32767 }", "short"), 32767);
1967   TEST_EQ(TestValue<int16_t>("{ y:-32768 }", "short"), -32768);
1968   TEST_EQ(TestValue<uint16_t>("{ y:65535 }", "ushort"), 65535);
1969   TEST_EQ(TestValue<uint16_t>("{ y:0 }", "ushort"), 0);
1970   TEST_EQ(TestValue<int32_t>("{ y:2147483647 }", "int"), 2147483647);
1971   TEST_EQ(TestValue<int32_t>("{ y:-2147483648 }", "int") + 1, -2147483647);
1972   TEST_EQ(TestValue<uint32_t>("{ y:4294967295 }", "uint"), 4294967295);
1973   TEST_EQ(TestValue<uint32_t>("{ y:0 }", "uint"), 0);
1974   TEST_EQ(TestValue<int64_t>("{ y:9223372036854775807 }", "long"),
1975           9223372036854775807LL);
1976   TEST_EQ(TestValue<int64_t>("{ y:-9223372036854775808 }", "long") + 1LL,
1977           -9223372036854775807LL);
1978   TEST_EQ(TestValue<uint64_t>("{ y:18446744073709551615 }", "ulong"),
1979           18446744073709551615ULL);
1980   TEST_EQ(TestValue<uint64_t>("{ y:0 }", "ulong"), 0);
1981   TEST_EQ(TestValue<uint64_t>("{ y: 18446744073709551615 }", "uint64"),
1982           18446744073709551615ULL);
1983   // check that the default works
1984   TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
1985           18446744073709551615ULL);
1986 }
1987
1988 void ValidFloatTest() {
1989   // check rounding to infinity
1990   TEST_EQ(TestValue<float>("{ y:+3.4029e+38 }", "float"), +infinity_f);
1991   TEST_EQ(TestValue<float>("{ y:-3.4029e+38 }", "float"), -infinity_f);
1992   TEST_EQ(TestValue<double>("{ y:+1.7977e+308 }", "double"), +infinity_d);
1993   TEST_EQ(TestValue<double>("{ y:-1.7977e+308 }", "double"), -infinity_d);
1994
1995   TEST_EQ(
1996       FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
1997       true);
1998   // float in string
1999   TEST_EQ(FloatCompare(TestValue<float>("{ y:\" 0.0314159e+2  \" }", "float"),
2000                        3.14159f),
2001           true);
2002
2003   TEST_EQ(TestValue<float>("{ y:1 }", "float"), 1.0f);
2004   TEST_EQ(TestValue<float>("{ y:1.0 }", "float"), 1.0f);
2005   TEST_EQ(TestValue<float>("{ y:1. }", "float"), 1.0f);
2006   TEST_EQ(TestValue<float>("{ y:+1. }", "float"), 1.0f);
2007   TEST_EQ(TestValue<float>("{ y:-1. }", "float"), -1.0f);
2008   TEST_EQ(TestValue<float>("{ y:1.e0 }", "float"), 1.0f);
2009   TEST_EQ(TestValue<float>("{ y:1.e+0 }", "float"), 1.0f);
2010   TEST_EQ(TestValue<float>("{ y:1.e-0 }", "float"), 1.0f);
2011   TEST_EQ(TestValue<float>("{ y:0.125 }", "float"), 0.125f);
2012   TEST_EQ(TestValue<float>("{ y:.125 }", "float"), 0.125f);
2013   TEST_EQ(TestValue<float>("{ y:-.125 }", "float"), -0.125f);
2014   TEST_EQ(TestValue<float>("{ y:+.125 }", "float"), +0.125f);
2015   TEST_EQ(TestValue<float>("{ y:5 }", "float"), 5.0f);
2016   TEST_EQ(TestValue<float>("{ y:\"5\" }", "float"), 5.0f);
2017
2018 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
2019   // Old MSVC versions may have problem with this check.
2020   // https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
2021   TEST_EQ(TestValue<double>("{ y:6.9294956446009195e15 }", "double"),
2022           6929495644600920.0);
2023   // check nan's
2024   TEST_EQ(std::isnan(TestValue<double>("{ y:nan }", "double")), true);
2025   TEST_EQ(std::isnan(TestValue<float>("{ y:nan }", "float")), true);
2026   TEST_EQ(std::isnan(TestValue<float>("{ y:\"nan\" }", "float")), true);
2027   TEST_EQ(std::isnan(TestValue<float>("{ y:+nan }", "float")), true);
2028   TEST_EQ(std::isnan(TestValue<float>("{ y:-nan }", "float")), true);
2029   TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
2030   TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
2031   // check inf
2032   TEST_EQ(TestValue<float>("{ y:inf }", "float"), infinity_f);
2033   TEST_EQ(TestValue<float>("{ y:\"inf\" }", "float"), infinity_f);
2034   TEST_EQ(TestValue<float>("{ y:+inf }", "float"), infinity_f);
2035   TEST_EQ(TestValue<float>("{ y:-inf }", "float"), -infinity_f);
2036   TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinity_f);
2037   TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinity_f);
2038   TestValue<double>(
2039       "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
2040       "3.0e2] }",
2041       "[double]");
2042   TestValue<float>(
2043       "{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
2044       "3.0e2] }",
2045       "[float]");
2046
2047   // Test binary format of float point.
2048   // https://en.cppreference.com/w/cpp/language/floating_literal
2049   // 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
2050   TEST_EQ(TestValue<double>("{ y:0x12.34p-1 }", "double"), 9.1015625);
2051   // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
2052   TEST_EQ(TestValue<float>("{ y:-0x0.2p0 }", "float"), -0.125f);
2053   TEST_EQ(TestValue<float>("{ y:-0x.2p1 }", "float"), -0.25f);
2054   TEST_EQ(TestValue<float>("{ y:0x1.2p3 }", "float"), 9.0f);
2055   TEST_EQ(TestValue<float>("{ y:0x10.1p0 }", "float"), 16.0625f);
2056   TEST_EQ(TestValue<double>("{ y:0x1.2p3 }", "double"), 9.0);
2057   TEST_EQ(TestValue<double>("{ y:0x10.1p0 }", "double"), 16.0625);
2058   TEST_EQ(TestValue<double>("{ y:0xC.68p+2 }", "double"), 49.625);
2059   TestValue<double>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
2060   TestValue<float>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
2061
2062 #else   // FLATBUFFERS_HAS_NEW_STRTOD
2063   TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");
2064 #endif  // !FLATBUFFERS_HAS_NEW_STRTOD
2065 }
2066
2067 void InvalidFloatTest() {
2068   auto invalid_msg = "invalid number";
2069   auto comma_msg = "expecting: ,";
2070   TestError("table T { F:float; } root_type T; { F:1,0 }", "");
2071   TestError("table T { F:float; } root_type T; { F:. }", "");
2072   TestError("table T { F:float; } root_type T; { F:- }", invalid_msg);
2073   TestError("table T { F:float; } root_type T; { F:+ }", invalid_msg);
2074   TestError("table T { F:float; } root_type T; { F:-. }", invalid_msg);
2075   TestError("table T { F:float; } root_type T; { F:+. }", invalid_msg);
2076   TestError("table T { F:float; } root_type T; { F:.e }", "");
2077   TestError("table T { F:float; } root_type T; { F:-e }", invalid_msg);
2078   TestError("table T { F:float; } root_type T; { F:+e }", invalid_msg);
2079   TestError("table T { F:float; } root_type T; { F:-.e }", invalid_msg);
2080   TestError("table T { F:float; } root_type T; { F:+.e }", invalid_msg);
2081   TestError("table T { F:float; } root_type T; { F:-e1 }", invalid_msg);
2082   TestError("table T { F:float; } root_type T; { F:+e1 }", invalid_msg);
2083   TestError("table T { F:float; } root_type T; { F:1.0e+ }", invalid_msg);
2084   TestError("table T { F:float; } root_type T; { F:1.0e- }", invalid_msg);
2085   // exponent pP is mandatory for hex-float
2086   TestError("table T { F:float; } root_type T; { F:0x0 }", invalid_msg);
2087   TestError("table T { F:float; } root_type T; { F:-0x. }", invalid_msg);
2088   TestError("table T { F:float; } root_type T; { F:0x. }", invalid_msg);
2089   TestError("table T { F:float; } root_type T; { F:0Xe }", invalid_msg);
2090   TestError("table T { F:float; } root_type T; { F:\"0Xe\" }", invalid_msg);
2091   TestError("table T { F:float; } root_type T; { F:\"nan(1)\" }", invalid_msg);
2092   // eE not exponent in hex-float!
2093   TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
2094   TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
2095   TestError("table T { F:float; } root_type T; { F:0x0.0p }", invalid_msg);
2096   TestError("table T { F:float; } root_type T; { F:0x0.0p+ }", invalid_msg);
2097   TestError("table T { F:float; } root_type T; { F:0x0.0p- }", invalid_msg);
2098   TestError("table T { F:float; } root_type T; { F:0x0.0pa1 }", invalid_msg);
2099   TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
2100   TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
2101   TestError("table T { F:float; } root_type T; { F:0x0.0e+0 }", invalid_msg);
2102   TestError("table T { F:float; } root_type T; { F:0x0.0e-0 }", invalid_msg);
2103   TestError("table T { F:float; } root_type T; { F:0x0.0ep+ }", invalid_msg);
2104   TestError("table T { F:float; } root_type T; { F:0x0.0ep- }", invalid_msg);
2105   TestError("table T { F:float; } root_type T; { F:1.2.3 }", invalid_msg);
2106   TestError("table T { F:float; } root_type T; { F:1.2.e3 }", invalid_msg);
2107   TestError("table T { F:float; } root_type T; { F:1.2e.3 }", invalid_msg);
2108   TestError("table T { F:float; } root_type T; { F:1.2e0.3 }", invalid_msg);
2109   TestError("table T { F:float; } root_type T; { F:1.2e3. }", invalid_msg);
2110   TestError("table T { F:float; } root_type T; { F:1.2e3.0 }", invalid_msg);
2111   TestError("table T { F:float; } root_type T; { F:+-1.0 }", invalid_msg);
2112   TestError("table T { F:float; } root_type T; { F:1.0e+-1 }", invalid_msg);
2113   TestError("table T { F:float; } root_type T; { F:\"1.0e+-1\" }", invalid_msg);
2114   TestError("table T { F:float; } root_type T; { F:1.e0e }", comma_msg);
2115   TestError("table T { F:float; } root_type T; { F:0x1.p0e }", comma_msg);
2116   TestError("table T { F:float; } root_type T; { F:\" 0x10 \" }", invalid_msg);
2117   // floats in string
2118   TestError("table T { F:float; } root_type T; { F:\"1,2.\" }", invalid_msg);
2119   TestError("table T { F:float; } root_type T; { F:\"1.2e3.\" }", invalid_msg);
2120   TestError("table T { F:float; } root_type T; { F:\"0x1.p0e\" }", invalid_msg);
2121   TestError("table T { F:float; } root_type T; { F:\"0x1.0\" }", invalid_msg);
2122   TestError("table T { F:float; } root_type T; { F:\" 0x1.0\" }", invalid_msg);
2123   TestError("table T { F:float; } root_type T; { F:\"+ 0\" }", invalid_msg);
2124   // disable escapes for "number-in-string"
2125   TestError("table T { F:float; } root_type T; { F:\"\\f1.2e3.\" }", "invalid");
2126   TestError("table T { F:float; } root_type T; { F:\"\\t1.2e3.\" }", "invalid");
2127   TestError("table T { F:float; } root_type T; { F:\"\\n1.2e3.\" }", "invalid");
2128   TestError("table T { F:float; } root_type T; { F:\"\\r1.2e3.\" }", "invalid");
2129   TestError("table T { F:float; } root_type T; { F:\"4\\x005\" }", "invalid");
2130   TestError("table T { F:float; } root_type T; { F:\"\'12\'\" }", invalid_msg);
2131   // null is not a number constant!
2132   TestError("table T { F:float; } root_type T; { F:\"null\" }", invalid_msg);
2133   TestError("table T { F:float; } root_type T; { F:null }", invalid_msg);
2134 }
2135
2136 void GenerateTableTextTest() {
2137   std::string schemafile;
2138   std::string jsonfile;
2139   bool ok =
2140       flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2141                             false, &schemafile) &&
2142       flatbuffers::LoadFile((test_data_path + "monsterdata_test.json").c_str(),
2143                             false, &jsonfile);
2144   TEST_EQ(ok, true);
2145   auto include_test_path =
2146       flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2147   const char *include_directories[] = { test_data_path.c_str(),
2148                                         include_test_path.c_str(), nullptr };
2149   flatbuffers::IDLOptions opt;
2150   opt.indent_step = -1;
2151   flatbuffers::Parser parser(opt);
2152   ok = parser.Parse(schemafile.c_str(), include_directories) &&
2153        parser.Parse(jsonfile.c_str(), include_directories);
2154   TEST_EQ(ok, true);
2155   // Test root table
2156   const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
2157   const auto abilities = monster->testarrayofsortedstruct();
2158   TEST_EQ(abilities->size(), 3);
2159   TEST_EQ(abilities->Get(0)->id(), 0);
2160   TEST_EQ(abilities->Get(0)->distance(), 45);
2161   TEST_EQ(abilities->Get(1)->id(), 1);
2162   TEST_EQ(abilities->Get(1)->distance(), 21);
2163   TEST_EQ(abilities->Get(2)->id(), 5);
2164   TEST_EQ(abilities->Get(2)->distance(), 12);
2165
2166   std::string jsongen;
2167   auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster",
2168                                       &jsongen);
2169   TEST_EQ(result, true);
2170   // Test sub table
2171   const Vec3 *pos = monster->pos();
2172   jsongen.clear();
2173   result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
2174   TEST_EQ(result, true);
2175   TEST_EQ_STR(
2176       jsongen.c_str(),
2177       "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
2178   const Test &test3 = pos->test3();
2179   jsongen.clear();
2180   result =
2181       GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
2182   TEST_EQ(result, true);
2183   TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
2184   const Test *test4 = monster->test4()->Get(0);
2185   jsongen.clear();
2186   result =
2187       GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
2188   TEST_EQ(result, true);
2189   TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
2190 }
2191
2192 template<typename T>
2193 void NumericUtilsTestInteger(const char *lower, const char *upper) {
2194   T x;
2195   TEST_EQ(flatbuffers::StringToNumber("1q", &x), false);
2196   TEST_EQ(x, 0);
2197   TEST_EQ(flatbuffers::StringToNumber(upper, &x), false);
2198   TEST_EQ(x, flatbuffers::numeric_limits<T>::max());
2199   TEST_EQ(flatbuffers::StringToNumber(lower, &x), false);
2200   auto expval = flatbuffers::is_unsigned<T>::value
2201                     ? flatbuffers::numeric_limits<T>::max()
2202                     : flatbuffers::numeric_limits<T>::lowest();
2203   TEST_EQ(x, expval);
2204 }
2205
2206 template<typename T>
2207 void NumericUtilsTestFloat(const char *lower, const char *upper) {
2208   T f;
2209   TEST_EQ(flatbuffers::StringToNumber("", &f), false);
2210   TEST_EQ(flatbuffers::StringToNumber("1q", &f), false);
2211   TEST_EQ(f, 0);
2212   TEST_EQ(flatbuffers::StringToNumber(upper, &f), true);
2213   TEST_EQ(f, +flatbuffers::numeric_limits<T>::infinity());
2214   TEST_EQ(flatbuffers::StringToNumber(lower, &f), true);
2215   TEST_EQ(f, -flatbuffers::numeric_limits<T>::infinity());
2216 }
2217
2218 void NumericUtilsTest() {
2219   NumericUtilsTestInteger<uint64_t>("-1", "18446744073709551616");
2220   NumericUtilsTestInteger<uint8_t>("-1", "256");
2221   NumericUtilsTestInteger<int64_t>("-9223372036854775809",
2222                                    "9223372036854775808");
2223   NumericUtilsTestInteger<int8_t>("-129", "128");
2224   NumericUtilsTestFloat<float>("-3.4029e+38", "+3.4029e+38");
2225   NumericUtilsTestFloat<float>("-1.7977e+308", "+1.7977e+308");
2226 }
2227
2228 void IsAsciiUtilsTest() {
2229   char c = -128;
2230   for (int cnt = 0; cnt < 256; cnt++) {
2231     auto alpha = (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
2232     auto dec = (('0' <= c) && (c <= '9'));
2233     auto hex = (('a' <= c) && (c <= 'f')) || (('A' <= c) && (c <= 'F'));
2234     TEST_EQ(flatbuffers::is_alpha(c), alpha);
2235     TEST_EQ(flatbuffers::is_alnum(c), alpha || dec);
2236     TEST_EQ(flatbuffers::is_digit(c), dec);
2237     TEST_EQ(flatbuffers::is_xdigit(c), dec || hex);
2238     c += 1;
2239   }
2240 }
2241
2242 void UnicodeTest() {
2243   flatbuffers::Parser parser;
2244   // Without setting allow_non_utf8 = true, we treat \x sequences as byte
2245   // sequences which are then validated as UTF-8.
2246   TEST_EQ(parser.Parse("table T { F:string; }"
2247                        "root_type T;"
2248                        "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2249                        "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD8"
2250                        "3D\\uDE0E\" }"),
2251           true);
2252   std::string jsongen;
2253   parser.opts.indent_step = -1;
2254   auto result =
2255       GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2256   TEST_EQ(result, true);
2257   TEST_EQ_STR(jsongen.c_str(),
2258               "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2259               "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
2260 }
2261
2262 void UnicodeTestAllowNonUTF8() {
2263   flatbuffers::Parser parser;
2264   parser.opts.allow_non_utf8 = true;
2265   TEST_EQ(
2266       parser.Parse(
2267           "table T { F:string; }"
2268           "root_type T;"
2269           "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2270           "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2271       true);
2272   std::string jsongen;
2273   parser.opts.indent_step = -1;
2274   auto result =
2275       GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2276   TEST_EQ(result, true);
2277   TEST_EQ_STR(
2278       jsongen.c_str(),
2279       "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2280       "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
2281 }
2282
2283 void UnicodeTestGenerateTextFailsOnNonUTF8() {
2284   flatbuffers::Parser parser;
2285   // Allow non-UTF-8 initially to model what happens when we load a binary
2286   // flatbuffer from disk which contains non-UTF-8 strings.
2287   parser.opts.allow_non_utf8 = true;
2288   TEST_EQ(
2289       parser.Parse(
2290           "table T { F:string; }"
2291           "root_type T;"
2292           "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
2293           "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
2294       true);
2295   std::string jsongen;
2296   parser.opts.indent_step = -1;
2297   // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates
2298   // failure.
2299   parser.opts.allow_non_utf8 = false;
2300   auto result =
2301       GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2302   TEST_EQ(result, false);
2303 }
2304
2305 void UnicodeSurrogatesTest() {
2306   flatbuffers::Parser parser;
2307
2308   TEST_EQ(parser.Parse("table T { F:string (id: 0); }"
2309                        "root_type T;"
2310                        "{ F:\"\\uD83D\\uDCA9\"}"),
2311           true);
2312   auto root = flatbuffers::GetRoot<flatbuffers::Table>(
2313       parser.builder_.GetBufferPointer());
2314   auto string = root->GetPointer<flatbuffers::String *>(
2315       flatbuffers::FieldIndexToOffset(0));
2316   TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
2317 }
2318
2319 void UnicodeInvalidSurrogatesTest() {
2320   TestError(
2321       "table T { F:string; }"
2322       "root_type T;"
2323       "{ F:\"\\uD800\"}",
2324       "unpaired high surrogate");
2325   TestError(
2326       "table T { F:string; }"
2327       "root_type T;"
2328       "{ F:\"\\uD800abcd\"}",
2329       "unpaired high surrogate");
2330   TestError(
2331       "table T { F:string; }"
2332       "root_type T;"
2333       "{ F:\"\\uD800\\n\"}",
2334       "unpaired high surrogate");
2335   TestError(
2336       "table T { F:string; }"
2337       "root_type T;"
2338       "{ F:\"\\uD800\\uD800\"}",
2339       "multiple high surrogates");
2340   TestError(
2341       "table T { F:string; }"
2342       "root_type T;"
2343       "{ F:\"\\uDC00\"}",
2344       "unpaired low surrogate");
2345 }
2346
2347 void InvalidUTF8Test() {
2348   // "1 byte" pattern, under min length of 2 bytes
2349   TestError(
2350       "table T { F:string; }"
2351       "root_type T;"
2352       "{ F:\"\x80\"}",
2353       "illegal UTF-8 sequence");
2354   // 2 byte pattern, string too short
2355   TestError(
2356       "table T { F:string; }"
2357       "root_type T;"
2358       "{ F:\"\xDF\"}",
2359       "illegal UTF-8 sequence");
2360   // 3 byte pattern, string too short
2361   TestError(
2362       "table T { F:string; }"
2363       "root_type T;"
2364       "{ F:\"\xEF\xBF\"}",
2365       "illegal UTF-8 sequence");
2366   // 4 byte pattern, string too short
2367   TestError(
2368       "table T { F:string; }"
2369       "root_type T;"
2370       "{ F:\"\xF7\xBF\xBF\"}",
2371       "illegal UTF-8 sequence");
2372   // "5 byte" pattern, string too short
2373   TestError(
2374       "table T { F:string; }"
2375       "root_type T;"
2376       "{ F:\"\xFB\xBF\xBF\xBF\"}",
2377       "illegal UTF-8 sequence");
2378   // "6 byte" pattern, string too short
2379   TestError(
2380       "table T { F:string; }"
2381       "root_type T;"
2382       "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}",
2383       "illegal UTF-8 sequence");
2384   // "7 byte" pattern, string too short
2385   TestError(
2386       "table T { F:string; }"
2387       "root_type T;"
2388       "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}",
2389       "illegal UTF-8 sequence");
2390   // "5 byte" pattern, over max length of 4 bytes
2391   TestError(
2392       "table T { F:string; }"
2393       "root_type T;"
2394       "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}",
2395       "illegal UTF-8 sequence");
2396   // "6 byte" pattern, over max length of 4 bytes
2397   TestError(
2398       "table T { F:string; }"
2399       "root_type T;"
2400       "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}",
2401       "illegal UTF-8 sequence");
2402   // "7 byte" pattern, over max length of 4 bytes
2403   TestError(
2404       "table T { F:string; }"
2405       "root_type T;"
2406       "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}",
2407       "illegal UTF-8 sequence");
2408
2409   // Three invalid encodings for U+000A (\n, aka NEWLINE)
2410   TestError(
2411       "table T { F:string; }"
2412       "root_type T;"
2413       "{ F:\"\xC0\x8A\"}",
2414       "illegal UTF-8 sequence");
2415   TestError(
2416       "table T { F:string; }"
2417       "root_type T;"
2418       "{ F:\"\xE0\x80\x8A\"}",
2419       "illegal UTF-8 sequence");
2420   TestError(
2421       "table T { F:string; }"
2422       "root_type T;"
2423       "{ F:\"\xF0\x80\x80\x8A\"}",
2424       "illegal UTF-8 sequence");
2425
2426   // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
2427   TestError(
2428       "table T { F:string; }"
2429       "root_type T;"
2430       "{ F:\"\xE0\x81\xA9\"}",
2431       "illegal UTF-8 sequence");
2432   TestError(
2433       "table T { F:string; }"
2434       "root_type T;"
2435       "{ F:\"\xF0\x80\x81\xA9\"}",
2436       "illegal UTF-8 sequence");
2437
2438   // Invalid encoding for U+20AC (EURO SYMBOL)
2439   TestError(
2440       "table T { F:string; }"
2441       "root_type T;"
2442       "{ F:\"\xF0\x82\x82\xAC\"}",
2443       "illegal UTF-8 sequence");
2444
2445   // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in
2446   // UTF-8
2447   TestError(
2448       "table T { F:string; }"
2449       "root_type T;"
2450       // U+10400 "encoded" as U+D801 U+DC00
2451       "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}",
2452       "illegal UTF-8 sequence");
2453
2454   // Check independence of identifier from locale.
2455   std::string locale_ident;
2456   locale_ident += "table T { F";
2457   locale_ident += static_cast<char>(-32);  // unsigned 0xE0
2458   locale_ident += " :string; }";
2459   locale_ident += "root_type T;";
2460   locale_ident += "{}";
2461   TestError(locale_ident.c_str(), "");
2462 }
2463
2464 void UnknownFieldsTest() {
2465   flatbuffers::IDLOptions opts;
2466   opts.skip_unexpected_fields_in_json = true;
2467   flatbuffers::Parser parser(opts);
2468
2469   TEST_EQ(parser.Parse("table T { str:string; i:int;}"
2470                        "root_type T;"
2471                        "{ str:\"test\","
2472                        "unknown_string:\"test\","
2473                        "\"unknown_string\":\"test\","
2474                        "unknown_int:10,"
2475                        "unknown_float:1.0,"
2476                        "unknown_array: [ 1, 2, 3, 4],"
2477                        "unknown_object: { i: 10 },"
2478                        "\"unknown_object\": { \"i\": 10 },"
2479                        "i:10}"),
2480           true);
2481
2482   std::string jsongen;
2483   parser.opts.indent_step = -1;
2484   auto result =
2485       GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
2486   TEST_EQ(result, true);
2487   TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
2488 }
2489
2490 void ParseUnionTest() {
2491   // Unions must be parseable with the type field following the object.
2492   flatbuffers::Parser parser;
2493   TEST_EQ(parser.Parse("table T { A:int; }"
2494                        "union U { T }"
2495                        "table V { X:U; }"
2496                        "root_type V;"
2497                        "{ X:{ A:1 }, X_type: T }"),
2498           true);
2499   // Unions must be parsable with prefixed namespace.
2500   flatbuffers::Parser parser2;
2501   TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
2502                         "table B { e:U; } root_type B;"
2503                         "{ e_type: N_A, e: {} }"),
2504           true);
2505 }
2506
2507 void InvalidNestedFlatbufferTest() {
2508   // First, load and parse FlatBuffer schema (.fbs)
2509   std::string schemafile;
2510   TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
2511                                 false, &schemafile),
2512           true);
2513   auto include_test_path =
2514       flatbuffers::ConCatPathFileName(test_data_path, "include_test");
2515   const char *include_directories[] = { test_data_path.c_str(),
2516                                         include_test_path.c_str(), nullptr };
2517   flatbuffers::Parser parser1;
2518   TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
2519
2520   // "color" inside nested flatbuffer contains invalid enum value
2521   TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
2522                         "\"Leela\", color: \"nonexistent\"}}"),
2523           false);
2524 }
2525
2526 void EvolutionTest() {
2527   // VS10 does not support typed enums, exclude from tests
2528 #if !defined(_MSC_VER) || _MSC_VER >= 1700
2529   const int NUM_VERSIONS = 2;
2530   std::string schemas[NUM_VERSIONS];
2531   std::string jsonfiles[NUM_VERSIONS];
2532   std::vector<uint8_t> binaries[NUM_VERSIONS];
2533
2534   flatbuffers::IDLOptions idl_opts;
2535   idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2536   flatbuffers::Parser parser(idl_opts);
2537
2538   // Load all the schema versions and their associated data.
2539   for (int i = 0; i < NUM_VERSIONS; ++i) {
2540     std::string schema = test_data_path + "evolution_test/evolution_v" +
2541                          flatbuffers::NumToString(i + 1) + ".fbs";
2542     TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2543     std::string json = test_data_path + "evolution_test/evolution_v" +
2544                        flatbuffers::NumToString(i + 1) + ".json";
2545     TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2546
2547     TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2548     TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2549
2550     auto bufLen = parser.builder_.GetSize();
2551     auto buf = parser.builder_.GetBufferPointer();
2552     binaries[i].reserve(bufLen);
2553     std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2554   }
2555
2556   // Assert that all the verifiers for the different schema versions properly
2557   // verify any version data.
2558   for (int i = 0; i < NUM_VERSIONS; ++i) {
2559     flatbuffers::Verifier verifier(&binaries[i].front(), binaries[i].size());
2560     TEST_ASSERT(Evolution::V1::VerifyRootBuffer(verifier));
2561     TEST_ASSERT(Evolution::V2::VerifyRootBuffer(verifier));
2562   }
2563
2564   // Test backwards compatibility by reading old data with an evolved schema.
2565   auto root_v1_viewed_from_v2 = Evolution::V2::GetRoot(&binaries[0].front());
2566   // field 'k' is new in version 2, so it should be null.
2567   TEST_ASSERT(nullptr == root_v1_viewed_from_v2->k());
2568   // field 'l' is new in version 2 with a default of 56.
2569   TEST_EQ(root_v1_viewed_from_v2->l(), 56);
2570   // field 'c' of 'TableA' is new in version 2, so it should be null.
2571   TEST_ASSERT(nullptr == root_v1_viewed_from_v2->e()->c());
2572   // 'TableC' was added to field 'c' union in version 2, so it should be null.
2573   TEST_ASSERT(nullptr == root_v1_viewed_from_v2->c_as_TableC());
2574   // The field 'c' union should be of type 'TableB' regardless of schema version
2575   TEST_ASSERT(root_v1_viewed_from_v2->c_type() == Evolution::V2::Union::TableB);
2576   // The field 'f' was renamed to 'ff' in version 2, it should still be
2577   // readable.
2578   TEST_EQ(root_v1_viewed_from_v2->ff()->a(), 16);
2579
2580   // Test forwards compatibility by reading new data with an old schema.
2581   auto root_v2_viewed_from_v1 = Evolution::V1::GetRoot(&binaries[1].front());
2582   // The field 'c' union in version 2 is a new table (index = 3) and should
2583   // still be accessible, but not interpretable.
2584   TEST_EQ(static_cast<uint8_t>(root_v2_viewed_from_v1->c_type()), 3);
2585   TEST_NOTNULL(root_v2_viewed_from_v1->c());
2586   // The field 'd' enum in verison 2 has new members and should still be
2587   // accessible, but not interpretable.
2588   TEST_EQ(static_cast<int8_t>(root_v2_viewed_from_v1->d()), 3);
2589   // The field 'a' in version 2 is deprecated and should return the default
2590   // value (0) instead of the value stored in the in the buffer (42).
2591   TEST_EQ(root_v2_viewed_from_v1->a(), 0);
2592   // The field 'ff' was originally named 'f' in version 1, it should still be
2593   // readable.
2594   TEST_EQ(root_v2_viewed_from_v1->f()->a(), 35);
2595 #endif
2596 }
2597
2598 void UnionDeprecationTest() {
2599   const int NUM_VERSIONS = 2;
2600   std::string schemas[NUM_VERSIONS];
2601   std::string jsonfiles[NUM_VERSIONS];
2602   std::vector<uint8_t> binaries[NUM_VERSIONS];
2603
2604   flatbuffers::IDLOptions idl_opts;
2605   idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2606   flatbuffers::Parser parser(idl_opts);
2607
2608   // Load all the schema versions and their associated data.
2609   for (int i = 0; i < NUM_VERSIONS; ++i) {
2610     std::string schema = test_data_path + "evolution_test/evolution_v" +
2611                          flatbuffers::NumToString(i + 1) + ".fbs";
2612     TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
2613     std::string json = test_data_path + "evolution_test/evolution_v" +
2614                        flatbuffers::NumToString(i + 1) + ".json";
2615     TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
2616
2617     TEST_ASSERT(parser.Parse(schemas[i].c_str()));
2618     TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
2619
2620     auto bufLen = parser.builder_.GetSize();
2621     auto buf = parser.builder_.GetBufferPointer();
2622     binaries[i].reserve(bufLen);
2623     std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
2624   }
2625
2626   auto v2 = parser.LookupStruct("Evolution.V2.Root");
2627   TEST_NOTNULL(v2);
2628   auto j_type_field = v2->fields.Lookup("j_type");
2629   TEST_NOTNULL(j_type_field);
2630   TEST_ASSERT(j_type_field->deprecated);
2631 }
2632
2633 void UnionVectorTest() {
2634   // load FlatBuffer fbs schema and json.
2635   std::string schemafile, jsonfile;
2636   TEST_EQ(flatbuffers::LoadFile(
2637               (test_data_path + "union_vector/union_vector.fbs").c_str(), false,
2638               &schemafile),
2639           true);
2640   TEST_EQ(flatbuffers::LoadFile(
2641               (test_data_path + "union_vector/union_vector.json").c_str(),
2642               false, &jsonfile),
2643           true);
2644
2645   // parse schema.
2646   flatbuffers::IDLOptions idl_opts;
2647   idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
2648   flatbuffers::Parser parser(idl_opts);
2649   TEST_EQ(parser.Parse(schemafile.c_str()), true);
2650
2651   flatbuffers::FlatBufferBuilder fbb;
2652
2653   // union types.
2654   std::vector<uint8_t> types;
2655   types.push_back(static_cast<uint8_t>(Character_Belle));
2656   types.push_back(static_cast<uint8_t>(Character_MuLan));
2657   types.push_back(static_cast<uint8_t>(Character_BookFan));
2658   types.push_back(static_cast<uint8_t>(Character_Other));
2659   types.push_back(static_cast<uint8_t>(Character_Unused));
2660
2661   // union values.
2662   std::vector<flatbuffers::Offset<void>> characters;
2663   characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
2664   characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
2665   characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
2666   characters.push_back(fbb.CreateString("Other").Union());
2667   characters.push_back(fbb.CreateString("Unused").Union());
2668
2669   // create Movie.
2670   const auto movie_offset =
2671       CreateMovie(fbb, Character_Rapunzel,
2672                   fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
2673                   fbb.CreateVector(types), fbb.CreateVector(characters));
2674   FinishMovieBuffer(fbb, movie_offset);
2675
2676   flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
2677   TEST_EQ(VerifyMovieBuffer(verifier), true);
2678
2679   auto flat_movie = GetMovie(fbb.GetBufferPointer());
2680
2681   auto TestMovie = [](const Movie *movie) {
2682     TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
2683
2684     auto cts = movie->characters_type();
2685     TEST_EQ(movie->characters_type()->size(), 5);
2686     TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
2687     TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
2688     TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
2689     TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
2690     TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
2691
2692     auto rapunzel = movie->main_character_as_Rapunzel();
2693     TEST_NOTNULL(rapunzel);
2694     TEST_EQ(rapunzel->hair_length(), 6);
2695
2696     auto cs = movie->characters();
2697     TEST_EQ(cs->size(), 5);
2698     auto belle = cs->GetAs<BookReader>(0);
2699     TEST_EQ(belle->books_read(), 7);
2700     auto mu_lan = cs->GetAs<Attacker>(1);
2701     TEST_EQ(mu_lan->sword_attack_damage(), 5);
2702     auto book_fan = cs->GetAs<BookReader>(2);
2703     TEST_EQ(book_fan->books_read(), 2);
2704     auto other = cs->GetAsString(3);
2705     TEST_EQ_STR(other->c_str(), "Other");
2706     auto unused = cs->GetAsString(4);
2707     TEST_EQ_STR(unused->c_str(), "Unused");
2708   };
2709
2710   TestMovie(flat_movie);
2711
2712   // Also test the JSON we loaded above.
2713   TEST_EQ(parser.Parse(jsonfile.c_str()), true);
2714   auto jbuf = parser.builder_.GetBufferPointer();
2715   flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
2716   TEST_EQ(VerifyMovieBuffer(jverifier), true);
2717   TestMovie(GetMovie(jbuf));
2718
2719   auto movie_object = flat_movie->UnPack();
2720   TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
2721   TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
2722   TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
2723   TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
2724   TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
2725   TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
2726
2727   fbb.Clear();
2728   fbb.Finish(Movie::Pack(fbb, movie_object));
2729
2730   delete movie_object;
2731
2732   auto repacked_movie = GetMovie(fbb.GetBufferPointer());
2733
2734   TestMovie(repacked_movie);
2735
2736   // Generate text using mini-reflection.
2737   auto s =
2738       flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
2739   TEST_EQ_STR(
2740       s.c_str(),
2741       "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
2742       "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
2743       "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
2744       "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
2745
2746   flatbuffers::ToStringVisitor visitor("\n", true, "  ");
2747   IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
2748   TEST_EQ_STR(visitor.s.c_str(),
2749               "{\n"
2750               "  \"main_character_type\": \"Rapunzel\",\n"
2751               "  \"main_character\": {\n"
2752               "    \"hair_length\": 6\n"
2753               "  },\n"
2754               "  \"characters_type\": [\n"
2755               "    \"Belle\",\n"
2756               "    \"MuLan\",\n"
2757               "    \"BookFan\",\n"
2758               "    \"Other\",\n"
2759               "    \"Unused\"\n"
2760               "  ],\n"
2761               "  \"characters\": [\n"
2762               "    {\n"
2763               "      \"books_read\": 7\n"
2764               "    },\n"
2765               "    {\n"
2766               "      \"sword_attack_damage\": 5\n"
2767               "    },\n"
2768               "    {\n"
2769               "      \"books_read\": 2\n"
2770               "    },\n"
2771               "    \"Other\",\n"
2772               "    \"Unused\"\n"
2773               "  ]\n"
2774               "}");
2775
2776   // Generate text using parsed schema.
2777   std::string jsongen;
2778   auto result = GenerateText(parser, fbb.GetBufferPointer(), &jsongen);
2779   TEST_EQ(result, true);
2780   TEST_EQ_STR(jsongen.c_str(),
2781               "{\n"
2782               "  main_character_type: \"Rapunzel\",\n"
2783               "  main_character: {\n"
2784               "    hair_length: 6\n"
2785               "  },\n"
2786               "  characters_type: [\n"
2787               "    \"Belle\",\n"
2788               "    \"MuLan\",\n"
2789               "    \"BookFan\",\n"
2790               "    \"Other\",\n"
2791               "    \"Unused\"\n"
2792               "  ],\n"
2793               "  characters: [\n"
2794               "    {\n"
2795               "      books_read: 7\n"
2796               "    },\n"
2797               "    {\n"
2798               "      sword_attack_damage: 5\n"
2799               "    },\n"
2800               "    {\n"
2801               "      books_read: 2\n"
2802               "    },\n"
2803               "    \"Other\",\n"
2804               "    \"Unused\"\n"
2805               "  ]\n"
2806               "}\n");
2807
2808   // Simple test with reflection.
2809   parser.Serialize();
2810   auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
2811   auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
2812                                 fbb.GetBufferPointer(), fbb.GetSize());
2813   TEST_EQ(ok, true);
2814
2815   flatbuffers::Parser parser2(idl_opts);
2816   TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
2817                         "union Any { Bool }"
2818                         "table Root { a:Any; }"
2819                         "root_type Root;"),
2820           true);
2821   TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
2822 }
2823
2824 void ConformTest() {
2825   flatbuffers::Parser parser;
2826   TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
2827
2828   auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
2829                          const char *expected_err) {
2830     flatbuffers::Parser parser2;
2831     TEST_EQ(parser2.Parse(test), true);
2832     auto err = parser2.ConformTo(parser1);
2833     TEST_NOTNULL(strstr(err.c_str(), expected_err));
2834   };
2835
2836   test_conform(parser, "table T { A:byte; }", "types differ for field");
2837   test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
2838   test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
2839   test_conform(parser, "table T { B:float; }",
2840                "field renamed to different type");
2841   test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
2842 }
2843
2844 void ParseProtoBufAsciiTest() {
2845   // We can put the parser in a mode where it will accept JSON that looks more
2846   // like Protobuf ASCII, for users that have data in that format.
2847   // This uses no "" for field names (which we already support by default,
2848   // omits `,`, `:` before `{` and a couple of other features.
2849   flatbuffers::Parser parser;
2850   parser.opts.protobuf_ascii_alike = true;
2851   TEST_EQ(
2852       parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
2853       true);
2854   TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
2855   // Similarly, in text output, it should omit these.
2856   std::string text;
2857   auto ok = flatbuffers::GenerateText(
2858       parser, parser.builder_.GetBufferPointer(), &text);
2859   TEST_EQ(ok, true);
2860   TEST_EQ_STR(text.c_str(),
2861               "{\n  A [\n    1\n    2\n  ]\n  C {\n    B: 2\n  }\n}\n");
2862 }
2863
2864 void FlexBuffersTest() {
2865   flexbuffers::Builder slb(512,
2866                            flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
2867
2868   // Write the equivalent of:
2869   // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ],
2870   // foo: 100, bool: true, mymap: { foo: "Fred" } }
2871   // clang-format off
2872   #ifndef FLATBUFFERS_CPP98_STL
2873     // It's possible to do this without std::function support as well.
2874     slb.Map([&]() {
2875        slb.Vector("vec", [&]() {
2876         slb += -100;  // Equivalent to slb.Add(-100) or slb.Int(-100);
2877         slb += "Fred";
2878         slb.IndirectFloat(4.0f);
2879         auto i_f = slb.LastValue();
2880         uint8_t blob[] = { 77 };
2881         slb.Blob(blob, 1);
2882         slb += false;
2883         slb.ReuseValue(i_f);
2884       });
2885       int ints[] = { 1, 2, 3 };
2886       slb.Vector("bar", ints, 3);
2887       slb.FixedTypedVector("bar3", ints, 3);
2888       bool bools[] = {true, false, true, false};
2889       slb.Vector("bools", bools, 4);
2890       slb.Bool("bool", true);
2891       slb.Double("foo", 100);
2892       slb.Map("mymap", [&]() {
2893         slb.String("foo", "Fred");  // Testing key and string reuse.
2894       });
2895     });
2896     slb.Finish();
2897   #else
2898     // It's possible to do this without std::function support as well.
2899     slb.Map([](flexbuffers::Builder& slb2) {
2900        slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
2901         slb3 += -100;  // Equivalent to slb.Add(-100) or slb.Int(-100);
2902         slb3 += "Fred";
2903         slb3.IndirectFloat(4.0f);
2904         auto i_f = slb3.LastValue();
2905         uint8_t blob[] = { 77 };
2906         slb3.Blob(blob, 1);
2907         slb3 += false;
2908         slb3.ReuseValue(i_f);
2909       }, slb2);
2910       int ints[] = { 1, 2, 3 };
2911       slb2.Vector("bar", ints, 3);
2912       slb2.FixedTypedVector("bar3", ints, 3);
2913       slb2.Bool("bool", true);
2914       slb2.Double("foo", 100);
2915       slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
2916         slb3.String("foo", "Fred");  // Testing key and string reuse.
2917       }, slb2);
2918     }, slb);
2919     slb.Finish();
2920   #endif  // FLATBUFFERS_CPP98_STL
2921
2922   #ifdef FLATBUFFERS_TEST_VERBOSE
2923     for (size_t i = 0; i < slb.GetBuffer().size(); i++)
2924       printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
2925     printf("\n");
2926   #endif
2927   // clang-format on
2928
2929   auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
2930   TEST_EQ(map.size(), 7);
2931   auto vec = map["vec"].AsVector();
2932   TEST_EQ(vec.size(), 6);
2933   TEST_EQ(vec[0].AsInt64(), -100);
2934   TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
2935   TEST_EQ(vec[1].AsInt64(), 0);  // Number parsing failed.
2936   TEST_EQ(vec[2].AsDouble(), 4.0);
2937   TEST_EQ(vec[2].AsString().IsTheEmptyString(), true);  // Wrong Type.
2938   TEST_EQ_STR(vec[2].AsString().c_str(), "");     // This still works though.
2939   TEST_EQ_STR(vec[2].ToString().c_str(), "4.0");  // Or have it converted.
2940   // Few tests for templated version of As.
2941   TEST_EQ(vec[0].As<int64_t>(), -100);
2942   TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
2943   TEST_EQ(vec[1].As<int64_t>(), 0);  // Number parsing failed.
2944   TEST_EQ(vec[2].As<double>(), 4.0);
2945   // Test that the blob can be accessed.
2946   TEST_EQ(vec[3].IsBlob(), true);
2947   auto blob = vec[3].AsBlob();
2948   TEST_EQ(blob.size(), 1);
2949   TEST_EQ(blob.data()[0], 77);
2950   TEST_EQ(vec[4].IsBool(), true);   // Check if type is a bool
2951   TEST_EQ(vec[4].AsBool(), false);  // Check if value is false
2952   TEST_EQ(vec[5].AsDouble(), 4.0);  // This is shared with vec[2] !
2953   auto tvec = map["bar"].AsTypedVector();
2954   TEST_EQ(tvec.size(), 3);
2955   TEST_EQ(tvec[2].AsInt8(), 3);
2956   auto tvec3 = map["bar3"].AsFixedTypedVector();
2957   TEST_EQ(tvec3.size(), 3);
2958   TEST_EQ(tvec3[2].AsInt8(), 3);
2959   TEST_EQ(map["bool"].AsBool(), true);
2960   auto tvecb = map["bools"].AsTypedVector();
2961   TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
2962   TEST_EQ(map["foo"].AsUInt8(), 100);
2963   TEST_EQ(map["unknown"].IsNull(), true);
2964   auto mymap = map["mymap"].AsMap();
2965   // These should be equal by pointer equality, since key and value are shared.
2966   TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
2967   TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
2968   // We can mutate values in the buffer.
2969   TEST_EQ(vec[0].MutateInt(-99), true);
2970   TEST_EQ(vec[0].AsInt64(), -99);
2971   TEST_EQ(vec[1].MutateString("John"), true);  // Size must match.
2972   TEST_EQ_STR(vec[1].AsString().c_str(), "John");
2973   TEST_EQ(vec[1].MutateString("Alfred"), false);  // Too long.
2974   TEST_EQ(vec[2].MutateFloat(2.0f), true);
2975   TEST_EQ(vec[2].AsFloat(), 2.0f);
2976   TEST_EQ(vec[2].MutateFloat(3.14159), false);  // Double does not fit in float.
2977   TEST_EQ(vec[4].AsBool(), false);              // Is false before change
2978   TEST_EQ(vec[4].MutateBool(true), true);       // Can change a bool
2979   TEST_EQ(vec[4].AsBool(), true);               // Changed bool is now true
2980
2981   // Parse from JSON:
2982   flatbuffers::Parser parser;
2983   slb.Clear();
2984   auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
2985   TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
2986   auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
2987   auto jmap = jroot.AsMap();
2988   auto jvec = jmap["a"].AsVector();
2989   TEST_EQ(jvec[0].AsInt64(), 123);
2990   TEST_EQ(jvec[1].AsDouble(), 456.0);
2991   TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
2992   TEST_EQ(jmap["c"].IsBool(), true);   // Parsed correctly to a bool
2993   TEST_EQ(jmap["c"].AsBool(), true);   // Parsed correctly to true
2994   TEST_EQ(jmap["d"].IsBool(), true);   // Parsed correctly to a bool
2995   TEST_EQ(jmap["d"].AsBool(), false);  // Parsed correctly to false
2996   // And from FlexBuffer back to JSON:
2997   auto jsonback = jroot.ToString();
2998   TEST_EQ_STR(jsontest, jsonback.c_str());
2999
3000   slb.Clear();
3001   slb.Vector([&]() {
3002     for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
3003     slb.Vector([&]() {
3004       for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
3005       slb.Vector([] {});
3006     });
3007   });
3008   slb.Finish();
3009   TEST_EQ(slb.GetSize(), 664);
3010 }
3011
3012 void FlexBuffersDeprecatedTest() {
3013   // FlexBuffers as originally designed had a flaw involving the
3014   // FBT_VECTOR_STRING datatype, and this test documents/tests the fix for it.
3015   // Discussion: https://github.com/google/flatbuffers/issues/5627
3016   flexbuffers::Builder slb;
3017   // FBT_VECTOR_* are "typed vectors" where all elements are of the same type.
3018   // Problem is, when storing FBT_STRING elements, it relies on that type to
3019   // get the bit-width for the size field of the string, which in this case
3020   // isn't present, and instead defaults to 8-bit. This means that any strings
3021   // stored inside such a vector, when accessed thru the old API that returns
3022   // a String reference, will appear to be truncated if the string stored is
3023   // actually >=256 bytes.
3024   std::string test_data(300, 'A');
3025   auto start = slb.StartVector();
3026   // This one will have a 16-bit size field.
3027   slb.String(test_data);
3028   // This one will have an 8-bit size field.
3029   slb.String("hello");
3030   // We're asking this to be serialized as a typed vector (true), but not
3031   // fixed size (false). The type will be FBT_VECTOR_STRING with a bit-width
3032   // of whatever the offsets in the vector need, the bit-widths of the strings
3033   // are not stored(!) <- the actual design flaw.
3034   // Note that even in the fixed code, we continue to serialize the elements of
3035   // FBT_VECTOR_STRING as FBT_STRING, since there may be old code out there
3036   // reading new data that we want to continue to function.
3037   // Thus, FBT_VECTOR_STRING, while deprecated, will always be represented the
3038   // same way, the fix lies on the reading side.
3039   slb.EndVector(start, true, false);
3040   slb.Finish();
3041   // So now lets read this data back.
3042   // For existing data, since we have no way of knowing what the actual
3043   // bit-width of the size field of the string is, we are going to ignore this
3044   // field, and instead treat these strings as FBT_KEY (null-terminated), so we
3045   // can deal with strings of arbitrary length. This of course truncates strings
3046   // with embedded nulls, but we think that that is preferrable over truncating
3047   // strings >= 256 bytes.
3048   auto vec = flexbuffers::GetRoot(slb.GetBuffer()).AsTypedVector();
3049   // Even though this was serialized as FBT_VECTOR_STRING, it is read as
3050   // FBT_VECTOR_KEY:
3051   TEST_EQ(vec.ElementType(), flexbuffers::FBT_KEY);
3052   // Access the long string. Previously, this would return a string of size 1,
3053   // since it would read the high-byte of the 16-bit length.
3054   // This should now correctly test the full 300 bytes, using AsKey():
3055   TEST_EQ_STR(vec[0].AsKey(), test_data.c_str());
3056   // Old code that called AsString will continue to work, as the String
3057   // accessor objects now use a cached size that can come from a key as well.
3058   TEST_EQ_STR(vec[0].AsString().c_str(), test_data.c_str());
3059   // Short strings work as before:
3060   TEST_EQ_STR(vec[1].AsKey(), "hello");
3061   TEST_EQ_STR(vec[1].AsString().c_str(), "hello");
3062   // So, while existing code and data mostly "just work" with the fixes applied
3063   // to AsTypedVector and AsString, what do you do going forward?
3064   // Code accessing existing data doesn't necessarily need to change, though
3065   // you could consider using AsKey instead of AsString for a) documenting
3066   // that you are accessing keys, or b) a speedup if you don't actually use
3067   // the string size.
3068   // For new data, or data that doesn't need to be backwards compatible,
3069   // instead serialize as FBT_VECTOR (call EndVector with typed = false, then
3070   // read elements with AsString), or, for maximum compactness, use
3071   // FBT_VECTOR_KEY (call slb.Key above instead, read with AsKey or AsString).
3072 }
3073
3074 void TypeAliasesTest() {
3075   flatbuffers::FlatBufferBuilder builder;
3076
3077   builder.Finish(CreateTypeAliases(
3078       builder, flatbuffers::numeric_limits<int8_t>::min(),
3079       flatbuffers::numeric_limits<uint8_t>::max(),
3080       flatbuffers::numeric_limits<int16_t>::min(),
3081       flatbuffers::numeric_limits<uint16_t>::max(),
3082       flatbuffers::numeric_limits<int32_t>::min(),
3083       flatbuffers::numeric_limits<uint32_t>::max(),
3084       flatbuffers::numeric_limits<int64_t>::min(),
3085       flatbuffers::numeric_limits<uint64_t>::max(), 2.3f, 2.3));
3086
3087   auto p = builder.GetBufferPointer();
3088   auto ta = flatbuffers::GetRoot<TypeAliases>(p);
3089
3090   TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
3091   TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
3092   TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
3093   TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
3094   TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
3095   TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
3096   TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
3097   TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
3098   TEST_EQ(ta->f32(), 2.3f);
3099   TEST_EQ(ta->f64(), 2.3);
3100   using namespace flatbuffers;  // is_same
3101   static_assert(is_same<decltype(ta->i8()), int8_t>::value, "invalid type");
3102   static_assert(is_same<decltype(ta->i16()), int16_t>::value, "invalid type");
3103   static_assert(is_same<decltype(ta->i32()), int32_t>::value, "invalid type");
3104   static_assert(is_same<decltype(ta->i64()), int64_t>::value, "invalid type");
3105   static_assert(is_same<decltype(ta->u8()), uint8_t>::value, "invalid type");
3106   static_assert(is_same<decltype(ta->u16()), uint16_t>::value, "invalid type");
3107   static_assert(is_same<decltype(ta->u32()), uint32_t>::value, "invalid type");
3108   static_assert(is_same<decltype(ta->u64()), uint64_t>::value, "invalid type");
3109   static_assert(is_same<decltype(ta->f32()), float>::value, "invalid type");
3110   static_assert(is_same<decltype(ta->f64()), double>::value, "invalid type");
3111 }
3112
3113 void EndianSwapTest() {
3114   TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
3115   TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
3116           0x78563412);
3117   TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
3118           0xEFCDAB9078563412);
3119   TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
3120 }
3121
3122 void UninitializedVectorTest() {
3123   flatbuffers::FlatBufferBuilder builder;
3124
3125   Test *buf = nullptr;
3126   auto vector_offset =
3127       builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
3128   TEST_NOTNULL(buf);
3129   buf[0] = Test(10, 20);
3130   buf[1] = Test(30, 40);
3131
3132   auto required_name = builder.CreateString("myMonster");
3133   auto monster_builder = MonsterBuilder(builder);
3134   monster_builder.add_name(
3135       required_name);  // required field mandated for monster.
3136   monster_builder.add_test4(vector_offset);
3137   builder.Finish(monster_builder.Finish());
3138
3139   auto p = builder.GetBufferPointer();
3140   auto uvt = flatbuffers::GetRoot<Monster>(p);
3141   TEST_NOTNULL(uvt);
3142   auto vec = uvt->test4();
3143   TEST_NOTNULL(vec);
3144   auto test_0 = vec->Get(0);
3145   auto test_1 = vec->Get(1);
3146   TEST_EQ(test_0->a(), 10);
3147   TEST_EQ(test_0->b(), 20);
3148   TEST_EQ(test_1->a(), 30);
3149   TEST_EQ(test_1->b(), 40);
3150 }
3151
3152 void EqualOperatorTest() {
3153   MonsterT a;
3154   MonsterT b;
3155   TEST_EQ(b == a, true);
3156   TEST_EQ(b != a, false);
3157
3158   b.mana = 33;
3159   TEST_EQ(b == a, false);
3160   TEST_EQ(b != a, true);
3161   b.mana = 150;
3162   TEST_EQ(b == a, true);
3163   TEST_EQ(b != a, false);
3164
3165   b.inventory.push_back(3);
3166   TEST_EQ(b == a, false);
3167   TEST_EQ(b != a, true);
3168   b.inventory.clear();
3169   TEST_EQ(b == a, true);
3170   TEST_EQ(b != a, false);
3171
3172   b.test.type = Any_Monster;
3173   TEST_EQ(b == a, false);
3174   TEST_EQ(b != a, true);
3175 }
3176
3177 // For testing any binaries, e.g. from fuzzing.
3178 void LoadVerifyBinaryTest() {
3179   std::string binary;
3180   if (flatbuffers::LoadFile(
3181           (test_data_path + "fuzzer/your-filename-here").c_str(), true,
3182           &binary)) {
3183     flatbuffers::Verifier verifier(
3184         reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
3185     TEST_EQ(VerifyMonsterBuffer(verifier), true);
3186   }
3187 }
3188
3189 void CreateSharedStringTest() {
3190   flatbuffers::FlatBufferBuilder builder;
3191   const auto one1 = builder.CreateSharedString("one");
3192   const auto two = builder.CreateSharedString("two");
3193   const auto one2 = builder.CreateSharedString("one");
3194   TEST_EQ(one1.o, one2.o);
3195   const auto onetwo = builder.CreateSharedString("onetwo");
3196   TEST_EQ(onetwo.o != one1.o, true);
3197   TEST_EQ(onetwo.o != two.o, true);
3198
3199   // Support for embedded nulls
3200   const char chars_b[] = { 'a', '\0', 'b' };
3201   const char chars_c[] = { 'a', '\0', 'c' };
3202   const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3203   const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
3204   const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
3205   TEST_EQ(null_b1.o != null_c.o, true);  // Issue#5058 repro
3206   TEST_EQ(null_b1.o, null_b2.o);
3207
3208   // Put the strings into an array for round trip verification.
3209   const flatbuffers::Offset<flatbuffers::String> array[7] = {
3210     one1, two, one2, onetwo, null_b1, null_c, null_b2
3211   };
3212   const auto vector_offset =
3213       builder.CreateVector(array, flatbuffers::uoffset_t(7));
3214   MonsterBuilder monster_builder(builder);
3215   monster_builder.add_name(two);
3216   monster_builder.add_testarrayofstring(vector_offset);
3217   builder.Finish(monster_builder.Finish());
3218
3219   // Read the Monster back.
3220   const auto *monster =
3221       flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
3222   TEST_EQ_STR(monster->name()->c_str(), "two");
3223   const auto *testarrayofstring = monster->testarrayofstring();
3224   TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
3225   const auto &a = *testarrayofstring;
3226   TEST_EQ_STR(a[0]->c_str(), "one");
3227   TEST_EQ_STR(a[1]->c_str(), "two");
3228   TEST_EQ_STR(a[2]->c_str(), "one");
3229   TEST_EQ_STR(a[3]->c_str(), "onetwo");
3230   TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
3231   TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
3232   TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
3233
3234   // Make sure String::operator< works, too, since it is related to
3235   // StringOffsetCompare.
3236   TEST_EQ((*a[0]) < (*a[1]), true);
3237   TEST_EQ((*a[1]) < (*a[0]), false);
3238   TEST_EQ((*a[1]) < (*a[2]), false);
3239   TEST_EQ((*a[2]) < (*a[1]), true);
3240   TEST_EQ((*a[4]) < (*a[3]), true);
3241   TEST_EQ((*a[5]) < (*a[4]), false);
3242   TEST_EQ((*a[5]) < (*a[4]), false);
3243   TEST_EQ((*a[6]) < (*a[5]), true);
3244 }
3245
3246 #if !defined(FLATBUFFERS_SPAN_MINIMAL)
3247 void FlatbuffersSpanTest() {
3248   // Compile-time checking of non-const [] to const [] conversions.
3249   using flatbuffers::internal::is_span_convertable;
3250   (void)is_span_convertable<int, 1, int, 1>::type(123);
3251   (void)is_span_convertable<const int, 1, int, 1>::type(123);
3252   (void)is_span_convertable<const int64_t, 1, int64_t, 1>::type(123);
3253   (void)is_span_convertable<const uint64_t, 1, uint64_t, 1>::type(123);
3254   (void)is_span_convertable<const int, 1, const int, 1>::type(123);
3255   (void)is_span_convertable<const int64_t, 1, const int64_t, 1>::type(123);
3256   (void)is_span_convertable<const uint64_t, 1, const uint64_t, 1>::type(123);
3257
3258   using flatbuffers::span;
3259   span<char, 0> c1;
3260   TEST_EQ(c1.size(), 0);
3261   span<char, flatbuffers::dynamic_extent> c2;
3262   TEST_EQ(c2.size(), 0);
3263   span<char> c3;
3264   TEST_EQ(c3.size(), 0);
3265   TEST_ASSERT(c1.empty() && c2.empty() && c3.empty());
3266
3267   int i_data7[7] = { 0, 1, 2, 3, 4, 5, 6 };
3268   span<int, 7> i1(&i_data7[0], 7);
3269   span<int> i2(i1);  // make dynamic from static
3270   TEST_EQ(i1.size(), 7);
3271   TEST_EQ(i1.empty(), false);
3272   TEST_EQ(i1.size(), i2.size());
3273   TEST_EQ(i1.data(), i_data7);
3274   TEST_EQ(i1[2], 2);
3275   // Make const span from a non-const one.
3276   span<const int, 7> i3(i1);
3277   // Construct from a C-array.
3278   span<int, 7> i4(i_data7);
3279   span<const int, 7> i5(i_data7);
3280   span<int> i6(i_data7);
3281   span<const int> i7(i_data7);
3282   TEST_EQ(i7.size(), 7);
3283   // Check construction from a const array.
3284   const int i_cdata5[5] = { 4, 3, 2, 1, 0 };
3285   span<const int, 5> i8(i_cdata5);
3286   span<const int> i9(i_cdata5);
3287   TEST_EQ(i9.size(), 5);
3288   // Construction from a (ptr, size) pair.
3289   span<int, 7> i10(i_data7, 7);
3290   span<int> i11(i_data7, 7);
3291   TEST_EQ(i11.size(), 7);
3292   span<const int, 5> i12(i_cdata5, 5);
3293   span<const int> i13(i_cdata5, 5);
3294   TEST_EQ(i13.size(), 5);
3295   // Construction from std::array.
3296   std::array<int, 6> i_arr6 = { { 0, 1, 2, 3, 4, 5 } };
3297   span<int, 6> i14(i_arr6);
3298   span<const int, 6> i15(i_arr6);
3299   span<int> i16(i_arr6);
3300   span<const int> i17(i_arr6);
3301   TEST_EQ(i17.size(), 6);
3302   const std::array<int, 8> i_carr8 = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
3303   span<const int, 8> i18(i_carr8);
3304   span<const int> i19(i_carr8);
3305   TEST_EQ(i18.size(), 8);
3306   TEST_EQ(i19.size(), 8);
3307   TEST_EQ(i19[7], 7);
3308   // Check compatibility with flatbuffers::Array.
3309   int fbs_int3_underlaying[3] = { 0 };
3310   int fbs_int3_data[3] = { 1, 2, 3 };
3311   auto &fbs_int3 = flatbuffers::CastToArray(fbs_int3_underlaying);
3312   fbs_int3.CopyFromSpan(fbs_int3_data);
3313   TEST_EQ(fbs_int3.Get(1), 2);
3314   const int fbs_cint3_data[3] = { 2, 3, 4 };
3315   fbs_int3.CopyFromSpan(fbs_cint3_data);
3316   TEST_EQ(fbs_int3.Get(1), 3);
3317   // Check with Array<Enum, N>
3318   enum class Dummy : uint16_t { Zero = 0, One, Two };
3319   Dummy fbs_dummy3_underlaying[3] = {};
3320   Dummy fbs_dummy3_data[3] = { Dummy::One, Dummy::Two, Dummy::Two };
3321   auto &fbs_dummy3 = flatbuffers::CastToArray(fbs_dummy3_underlaying);
3322   fbs_dummy3.CopyFromSpan(fbs_dummy3_data);
3323   TEST_EQ(fbs_dummy3.Get(1), Dummy::Two);
3324 }
3325 #else
3326 void FlatbuffersSpanTest() {}
3327 #endif
3328
3329 void FixedLengthArrayTest() {
3330   // VS10 does not support typed enums, exclude from tests
3331 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3332   // Generate an ArrayTable containing one ArrayStruct.
3333   flatbuffers::FlatBufferBuilder fbb;
3334   MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
3335   TEST_NOTNULL(nStruct0.mutable_a());
3336   nStruct0.mutable_a()->Mutate(0, 1);
3337   nStruct0.mutable_a()->Mutate(1, 2);
3338   TEST_NOTNULL(nStruct0.mutable_c());
3339   nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3340   nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3341   TEST_NOTNULL(nStruct0.mutable_d());
3342   nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
3343   nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
3344   MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
3345   TEST_NOTNULL(nStruct1.mutable_a());
3346   nStruct1.mutable_a()->Mutate(0, 3);
3347   nStruct1.mutable_a()->Mutate(1, 4);
3348   TEST_NOTNULL(nStruct1.mutable_c());
3349   nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
3350   nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
3351   TEST_NOTNULL(nStruct1.mutable_d());
3352   nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
3353   nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
3354   MyGame::Example::ArrayStruct aStruct(2, 12, 1);
3355   TEST_NOTNULL(aStruct.b());
3356   TEST_NOTNULL(aStruct.mutable_b());
3357   TEST_NOTNULL(aStruct.mutable_d());
3358   TEST_NOTNULL(aStruct.mutable_f());
3359   for (int i = 0; i < aStruct.b()->size(); i++)
3360     aStruct.mutable_b()->Mutate(i, i + 1);
3361   aStruct.mutable_d()->Mutate(0, nStruct0);
3362   aStruct.mutable_d()->Mutate(1, nStruct1);
3363   auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
3364   MyGame::Example::FinishArrayTableBuffer(fbb, aTable);
3365
3366   // Verify correctness of the ArrayTable.
3367   flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
3368   MyGame::Example::VerifyArrayTableBuffer(verifier);
3369   auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
3370   auto mArStruct = p->mutable_a();
3371   TEST_NOTNULL(mArStruct);
3372   TEST_NOTNULL(mArStruct->b());
3373   TEST_NOTNULL(mArStruct->d());
3374   TEST_NOTNULL(mArStruct->f());
3375   TEST_NOTNULL(mArStruct->mutable_b());
3376   TEST_NOTNULL(mArStruct->mutable_d());
3377   TEST_NOTNULL(mArStruct->mutable_f());
3378   mArStruct->mutable_b()->Mutate(14, -14);
3379   TEST_EQ(mArStruct->a(), 2);
3380   TEST_EQ(mArStruct->b()->size(), 15);
3381   TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14);
3382   TEST_EQ(mArStruct->c(), 12);
3383   TEST_NOTNULL(mArStruct->d()->Get(0));
3384   TEST_NOTNULL(mArStruct->d()->Get(0)->a());
3385   TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
3386   TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
3387   TEST_NOTNULL(mArStruct->d()->Get(1));
3388   TEST_NOTNULL(mArStruct->d()->Get(1)->a());
3389   TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
3390   TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
3391   TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
3392   TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
3393   mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
3394   TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
3395   TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
3396   TEST_NOTNULL(mArStruct->d()->Get(0)->c());
3397   TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
3398   TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
3399   TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3400           mArStruct->d()->Get(0)->d()->Get(0));
3401   TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3402           mArStruct->d()->Get(0)->d()->Get(1));
3403   TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
3404   TEST_NOTNULL(mArStruct->d()->Get(1)->c());
3405   TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
3406   TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
3407   TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
3408           mArStruct->d()->Get(1)->d()->Get(0));
3409   TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
3410           mArStruct->d()->Get(1)->d()->Get(1));
3411   for (int i = 0; i < mArStruct->b()->size() - 1; i++)
3412     TEST_EQ(mArStruct->b()->Get(i), i + 1);
3413   // Check alignment
3414   TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
3415   TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
3416
3417   // Check if default constructor set all memory zero
3418   const size_t arr_size = sizeof(MyGame::Example::ArrayStruct);
3419   char non_zero_memory[arr_size];
3420   // set memory chunk of size ArrayStruct to 1's
3421   std::memset(static_cast<void *>(non_zero_memory), 1, arr_size);
3422   // after placement-new it should be all 0's
3423 #  if defined(_MSC_VER) && defined(_DEBUG)
3424 #    undef new
3425 #  endif
3426   MyGame::Example::ArrayStruct *ap =
3427       new (non_zero_memory) MyGame::Example::ArrayStruct;
3428 #  if defined(_MSC_VER) && defined(_DEBUG)
3429 #    define new DEBUG_NEW
3430 #  endif
3431   (void)ap;
3432   for (size_t i = 0; i < arr_size; ++i) { TEST_EQ(non_zero_memory[i], 0); }
3433 #endif
3434 }
3435
3436 #if !defined(FLATBUFFERS_SPAN_MINIMAL) && \
3437     (!defined(_MSC_VER) || _MSC_VER >= 1700)
3438 void FixedLengthArrayConstructorTest() {
3439   const int32_t nested_a[2] = { 1, 2 };
3440   MyGame::Example::TestEnum nested_c[2] = { MyGame::Example::TestEnum::A,
3441                                             MyGame::Example::TestEnum::B };
3442   const int64_t int64_2[2] = { -2, -1 };
3443
3444   std::array<MyGame::Example::NestedStruct, 2> init_d = {
3445     { MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
3446                                     nested_c, int64_2),
3447       MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::A,
3448                                     nested_c,
3449                                     std::array<int64_t, 2>{ { 12, 13 } }) }
3450   };
3451
3452   MyGame::Example::ArrayStruct arr_struct(
3453       8.125,
3454       std::array<int32_t, 0xF>{
3455           { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
3456       -17, init_d, 10, int64_2);
3457   TEST_EQ(arr_struct.a(), 8.125);
3458   TEST_EQ(arr_struct.b()->Get(2), 3);
3459   TEST_EQ(arr_struct.c(), -17);
3460
3461   TEST_NOTNULL(arr_struct.d());
3462   const auto &arr_d_0 = *arr_struct.d()->Get(0);
3463   TEST_EQ(arr_d_0.a()->Get(0), 1);
3464   TEST_EQ(arr_d_0.a()->Get(1), 2);
3465   TEST_EQ(arr_d_0.b(), MyGame::Example::TestEnum::B);
3466   TEST_EQ(arr_d_0.c()->Get(0), MyGame::Example::TestEnum::A);
3467   TEST_EQ(arr_d_0.c()->Get(1), MyGame::Example::TestEnum::B);
3468   TEST_EQ(arr_d_0.d()->Get(0), -2);
3469   TEST_EQ(arr_d_0.d()->Get(1), -1);
3470   const auto &arr_d_1 = *arr_struct.d()->Get(1);
3471   TEST_EQ(arr_d_1.a()->Get(0), 1);
3472   TEST_EQ(arr_d_1.a()->Get(1), 2);
3473   TEST_EQ(arr_d_1.b(), MyGame::Example::TestEnum::A);
3474   TEST_EQ(arr_d_1.c()->Get(0), MyGame::Example::TestEnum::A);
3475   TEST_EQ(arr_d_1.c()->Get(1), MyGame::Example::TestEnum::B);
3476   TEST_EQ(arr_d_1.d()->Get(0), 12);
3477   TEST_EQ(arr_d_1.d()->Get(1), 13);
3478
3479   TEST_EQ(arr_struct.e(), 10);
3480   TEST_EQ(arr_struct.f()->Get(0), -2);
3481   TEST_EQ(arr_struct.f()->Get(1), -1);
3482 }
3483 #else
3484 void FixedLengthArrayConstructorTest() {}
3485 #endif
3486
3487 void NativeTypeTest() {
3488   const int N = 3;
3489
3490   Geometry::ApplicationDataT src_data;
3491   src_data.vectors.reserve(N);
3492
3493   for (int i = 0; i < N; ++i) {
3494     src_data.vectors.push_back(
3495         Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
3496   }
3497
3498   flatbuffers::FlatBufferBuilder fbb;
3499   fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
3500
3501   auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
3502
3503   for (int i = 0; i < N; ++i) {
3504     Native::Vector3D &v = dstDataT->vectors[i];
3505     TEST_EQ(v.x, 10 * i + 0.1f);
3506     TEST_EQ(v.y, 10 * i + 0.2f);
3507     TEST_EQ(v.z, 10 * i + 0.3f);
3508   }
3509 }
3510
3511 void FixedLengthArrayJsonTest(bool binary) {
3512   // VS10 does not support typed enums, exclude from tests
3513 #if !defined(_MSC_VER) || _MSC_VER >= 1700
3514   // load FlatBuffer schema (.fbs) and JSON from disk
3515   std::string schemafile;
3516   std::string jsonfile;
3517   TEST_EQ(
3518       flatbuffers::LoadFile(
3519           (test_data_path + "arrays_test." + (binary ? "bfbs" : "fbs")).c_str(),
3520           binary, &schemafile),
3521       true);
3522   TEST_EQ(flatbuffers::LoadFile((test_data_path + "arrays_test.golden").c_str(),
3523                                 false, &jsonfile),
3524           true);
3525
3526   // parse schema first, so we can use it to parse the data after
3527   flatbuffers::Parser parserOrg, parserGen;
3528   if (binary) {
3529     flatbuffers::Verifier verifier(
3530         reinterpret_cast<const uint8_t *>(schemafile.c_str()),
3531         schemafile.size());
3532     TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3533     TEST_EQ(parserOrg.Deserialize((const uint8_t *)schemafile.c_str(),
3534                                   schemafile.size()),
3535             true);
3536     TEST_EQ(parserGen.Deserialize((const uint8_t *)schemafile.c_str(),
3537                                   schemafile.size()),
3538             true);
3539   } else {
3540     TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
3541     TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
3542   }
3543   TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3544
3545   // First, verify it, just in case:
3546   flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3547                                     parserOrg.builder_.GetSize());
3548   TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
3549
3550   // Export to JSON
3551   std::string jsonGen;
3552   TEST_EQ(
3553       GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3554       true);
3555
3556   // Import from JSON
3557   TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3558
3559   // Verify buffer from generated JSON
3560   flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3561                                     parserGen.builder_.GetSize());
3562   TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
3563
3564   // Compare generated buffer to original
3565   TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3566   TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3567                       parserGen.builder_.GetBufferPointer(),
3568                       parserOrg.builder_.GetSize()),
3569           0);
3570 #else
3571   (void)binary;
3572 #endif
3573 }
3574
3575 void TestEmbeddedBinarySchema() {
3576   // load JSON from disk
3577   std::string jsonfile;
3578   TEST_EQ(flatbuffers::LoadFile(
3579               (test_data_path + "monsterdata_test.golden").c_str(), false,
3580               &jsonfile),
3581           true);
3582
3583   // parse schema first, so we can use it to parse the data after
3584   flatbuffers::Parser parserOrg, parserGen;
3585   flatbuffers::Verifier verifier(MyGame::Example::MonsterBinarySchema::data(),
3586                                  MyGame::Example::MonsterBinarySchema::size());
3587   TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
3588   TEST_EQ(parserOrg.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3589                                 MyGame::Example::MonsterBinarySchema::size()),
3590           true);
3591   TEST_EQ(parserGen.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
3592                                 MyGame::Example::MonsterBinarySchema::size()),
3593           true);
3594   TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
3595
3596   // First, verify it, just in case:
3597   flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
3598                                     parserOrg.builder_.GetSize());
3599   TEST_EQ(VerifyMonsterBuffer(verifierOrg), true);
3600
3601   // Export to JSON
3602   std::string jsonGen;
3603   TEST_EQ(
3604       GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
3605       true);
3606
3607   // Import from JSON
3608   TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
3609
3610   // Verify buffer from generated JSON
3611   flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
3612                                     parserGen.builder_.GetSize());
3613   TEST_EQ(VerifyMonsterBuffer(verifierGen), true);
3614
3615   // Compare generated buffer to original
3616   TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
3617   TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
3618                       parserGen.builder_.GetBufferPointer(),
3619                       parserOrg.builder_.GetSize()),
3620           0);
3621 }
3622
3623 void OptionalScalarsTest() {
3624   // Simple schemas and a "has optional scalar" sentinal.
3625   std::vector<std::string> schemas;
3626   schemas.push_back("table Monster { mana : int; }");
3627   schemas.push_back("table Monster { mana : int = 42; }");
3628   schemas.push_back("table Monster { mana : int =  null; }");
3629   schemas.push_back("table Monster { mana : long; }");
3630   schemas.push_back("table Monster { mana : long = 42; }");
3631   schemas.push_back("table Monster { mana : long = null; }");
3632   schemas.push_back("table Monster { mana : float; }");
3633   schemas.push_back("table Monster { mana : float = 42; }");
3634   schemas.push_back("table Monster { mana : float = null; }");
3635   schemas.push_back("table Monster { mana : double; }");
3636   schemas.push_back("table Monster { mana : double = 42; }");
3637   schemas.push_back("table Monster { mana : double = null; }");
3638   schemas.push_back("table Monster { mana : bool; }");
3639   schemas.push_back("table Monster { mana : bool = 42; }");
3640   schemas.push_back("table Monster { mana : bool = null; }");
3641   schemas.push_back(
3642       "enum Enum: int {A=0, B=1} "
3643       "table Monster { mana : Enum; }");
3644   schemas.push_back(
3645       "enum Enum: int {A=0, B=1} "
3646       "table Monster { mana : Enum = B; }");
3647   schemas.push_back(
3648       "enum Enum: int {A=0, B=1} "
3649       "table Monster { mana : Enum = null; }");
3650
3651   // Check the FieldDef is correctly set.
3652   for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3653     const bool has_null = schema->find("null") != std::string::npos;
3654     flatbuffers::Parser parser;
3655     TEST_ASSERT(parser.Parse(schema->c_str()));
3656     const auto *mana = parser.structs_.Lookup("Monster")->fields.Lookup("mana");
3657     TEST_EQ(mana->optional, has_null);
3658   }
3659
3660   // Test if nullable scalars are allowed for each language.
3661   for (unsigned lang = 1; lang < flatbuffers::IDLOptions::kMAX; lang <<= 1) {
3662     flatbuffers::IDLOptions opts;
3663     opts.lang_to_generate = lang;
3664     if (false == flatbuffers::Parser::SupportsOptionalScalars(opts)) {
3665       continue;
3666     }
3667     for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
3668       flatbuffers::Parser parser(opts);
3669       auto done = parser.Parse(schema->c_str());
3670       TEST_EQ_STR(parser.error_.c_str(), "");
3671       TEST_ASSERT(done);
3672     }
3673   }
3674
3675   // test C++ nullable
3676   flatbuffers::FlatBufferBuilder fbb;
3677   FinishScalarStuffBuffer(
3678       fbb, optional_scalars::CreateScalarStuff(fbb, 1, static_cast<int8_t>(2)));
3679   auto opts = optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
3680   TEST_ASSERT(!opts->maybe_bool());
3681   TEST_ASSERT(!opts->maybe_f32().has_value());
3682   TEST_ASSERT(opts->maybe_i8().has_value());
3683   TEST_EQ(opts->maybe_i8().value(), 2);
3684   TEST_ASSERT(opts->mutate_maybe_i8(3));
3685   TEST_ASSERT(opts->maybe_i8().has_value());
3686   TEST_EQ(opts->maybe_i8().value(), 3);
3687   TEST_ASSERT(!opts->mutate_maybe_i16(-10));
3688
3689   optional_scalars::ScalarStuffT obj;
3690   TEST_ASSERT(!obj.maybe_bool);
3691   TEST_ASSERT(!obj.maybe_f32.has_value());
3692   opts->UnPackTo(&obj);
3693   TEST_ASSERT(!obj.maybe_bool);
3694   TEST_ASSERT(!obj.maybe_f32.has_value());
3695   TEST_ASSERT(obj.maybe_i8.has_value() && obj.maybe_i8.value() == 3);
3696   TEST_ASSERT(obj.maybe_i8 && *obj.maybe_i8 == 3);
3697   obj.maybe_i32 = -1;
3698   obj.maybe_enum = optional_scalars::OptionalByte_Two;
3699
3700   fbb.Clear();
3701   FinishScalarStuffBuffer(fbb, optional_scalars::ScalarStuff::Pack(fbb, &obj));
3702   opts = optional_scalars::GetMutableScalarStuff(fbb.GetBufferPointer());
3703   TEST_ASSERT(opts->maybe_i8().has_value());
3704   TEST_EQ(opts->maybe_i8().value(), 3);
3705   TEST_ASSERT(opts->maybe_i32().has_value());
3706   TEST_EQ(opts->maybe_i32().value(), -1);
3707   TEST_EQ(opts->maybe_enum().value(), optional_scalars::OptionalByte_Two);
3708   TEST_ASSERT(opts->maybe_i32() == flatbuffers::Optional<int64_t>(-1));
3709 }
3710
3711 void ParseFlexbuffersFromJsonWithNullTest() {
3712   // Test nulls are handled appropriately through flexbuffers to exercise other
3713   // code paths of ParseSingleValue in the optional scalars change.
3714   // TODO(cneo): Json -> Flatbuffers test once some language can generate code
3715   // with optional scalars.
3716   {
3717     char json[] = "{\"opt_field\": 123 }";
3718     flatbuffers::Parser parser;
3719     flexbuffers::Builder flexbuild;
3720     parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3721     auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3722     TEST_EQ(root.AsMap()["opt_field"].AsInt64(), 123);
3723   }
3724   {
3725     char json[] = "{\"opt_field\": 123.4 }";
3726     flatbuffers::Parser parser;
3727     flexbuffers::Builder flexbuild;
3728     parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3729     auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3730     TEST_EQ(root.AsMap()["opt_field"].AsDouble(), 123.4);
3731   }
3732   {
3733     char json[] = "{\"opt_field\": null }";
3734     flatbuffers::Parser parser;
3735     flexbuffers::Builder flexbuild;
3736     parser.ParseFlexBuffer(json, nullptr, &flexbuild);
3737     auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
3738     TEST_ASSERT(!root.AsMap().IsTheEmptyMap());
3739     TEST_ASSERT(root.AsMap()["opt_field"].IsNull());
3740     TEST_EQ(root.ToString(), std::string("{ opt_field: null }"));
3741   }
3742 }
3743
3744 void FieldIdentifierTest() {
3745   using flatbuffers::Parser;
3746   TEST_EQ(true, Parser().Parse("table T{ f: int (id:0); }"));
3747   // non-integer `id` should be rejected
3748   TEST_EQ(false, Parser().Parse("table T{ f: int (id:text); }"));
3749   TEST_EQ(false, Parser().Parse("table T{ f: int (id:\"text\"); }"));
3750   TEST_EQ(false, Parser().Parse("table T{ f: int (id:0text); }"));
3751   TEST_EQ(false, Parser().Parse("table T{ f: int (id:1.0); }"));
3752   TEST_EQ(false, Parser().Parse("table T{ f: int (id:-1); g: int (id:0); }"));
3753   TEST_EQ(false, Parser().Parse("table T{ f: int (id:129496726); }"));
3754   // A unuion filed occupys two ids: enumerator + pointer (offset).
3755   TEST_EQ(false,
3756           Parser().Parse("union X{} table T{ u: X(id:0); table F{x:int;\n}"));
3757   // Positive tests for unions
3758   TEST_EQ(true, Parser().Parse("union X{} table T{ u: X (id:1); }"));
3759   TEST_EQ(true, Parser().Parse("union X{} table T{ u: X; }"));
3760 }
3761
3762 int FlatBufferTests() {
3763   // clang-format off
3764
3765   // Run our various test suites:
3766
3767   std::string rawbuf;
3768   auto flatbuf1 = CreateFlatBufferTest(rawbuf);
3769   #if !defined(FLATBUFFERS_CPP98_STL)
3770     auto flatbuf = std::move(flatbuf1);  // Test move assignment.
3771   #else
3772     auto &flatbuf = flatbuf1;
3773   #endif // !defined(FLATBUFFERS_CPP98_STL)
3774
3775   TriviallyCopyableTest();
3776
3777   AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
3778                        rawbuf.length());
3779   AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
3780
3781   MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
3782
3783   ObjectFlatBuffersTest(flatbuf.data());
3784
3785   MiniReflectFlatBuffersTest(flatbuf.data());
3786   MiniReflectFixedLengthArrayTest();
3787
3788   SizePrefixedTest();
3789
3790   #ifndef FLATBUFFERS_NO_FILE_TESTS
3791     #ifdef FLATBUFFERS_TEST_PATH_PREFIX
3792       test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
3793                        test_data_path;
3794     #endif
3795     ParseAndGenerateTextTest(false);
3796     ParseAndGenerateTextTest(true);
3797     FixedLengthArrayJsonTest(false);
3798     FixedLengthArrayJsonTest(true);
3799     ReflectionTest(flatbuf.data(), flatbuf.size());
3800     ParseProtoTest();
3801     ParseProtoTestWithSuffix();
3802     ParseProtoTestWithIncludes();
3803     EvolutionTest();
3804     UnionDeprecationTest();
3805     UnionVectorTest();
3806     LoadVerifyBinaryTest();
3807     GenerateTableTextTest();
3808     TestEmbeddedBinarySchema();
3809   #endif
3810   // clang-format on
3811
3812   FuzzTest1();
3813   FuzzTest2();
3814
3815   ErrorTest();
3816   ValueTest();
3817   EnumValueTest();
3818   EnumStringsTest();
3819   EnumNamesTest();
3820   EnumOutOfRangeTest();
3821   IntegerOutOfRangeTest();
3822   IntegerBoundaryTest();
3823   UnicodeTest();
3824   UnicodeTestAllowNonUTF8();
3825   UnicodeTestGenerateTextFailsOnNonUTF8();
3826   UnicodeSurrogatesTest();
3827   UnicodeInvalidSurrogatesTest();
3828   InvalidUTF8Test();
3829   UnknownFieldsTest();
3830   ParseUnionTest();
3831   InvalidNestedFlatbufferTest();
3832   ConformTest();
3833   ParseProtoBufAsciiTest();
3834   TypeAliasesTest();
3835   EndianSwapTest();
3836   CreateSharedStringTest();
3837   JsonDefaultTest();
3838   JsonEnumsTest();
3839   FlexBuffersTest();
3840   FlexBuffersDeprecatedTest();
3841   UninitializedVectorTest();
3842   EqualOperatorTest();
3843   NumericUtilsTest();
3844   IsAsciiUtilsTest();
3845   ValidFloatTest();
3846   InvalidFloatTest();
3847   TestMonsterExtraFloats();
3848   FixedLengthArrayTest();
3849   NativeTypeTest();
3850   OptionalScalarsTest();
3851   ParseFlexbuffersFromJsonWithNullTest();
3852   FlatbuffersSpanTest();
3853   FixedLengthArrayConstructorTest();
3854   FieldIdentifierTest();
3855   return 0;
3856 }
3857
3858 int main(int /*argc*/, const char * /*argv*/[]) {
3859   InitTestEngine();
3860
3861   std::string req_locale;
3862   if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
3863                                            &req_locale)) {
3864     TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
3865                      req_locale.c_str());
3866     req_locale = flatbuffers::RemoveStringQuotes(req_locale);
3867     std::string the_locale;
3868     TEST_ASSERT_FUNC(
3869         flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
3870     TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
3871   }
3872
3873   FlatBufferTests();
3874   FlatBufferBuilderTest();
3875
3876   if (!testing_fails) {
3877     TEST_OUTPUT_LINE("ALL TESTS PASSED");
3878   } else {
3879     TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
3880   }
3881   return CloseTestEngine();
3882 }