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