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