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