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