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