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