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