Home | History | Annotate | Download | only in tests
      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 
     17 #include "flatbuffers/flatbuffers.h"
     18 #include "flatbuffers/idl.h"
     19 #include "flatbuffers/util.h"
     20 
     21 #include "monster_test_generated.h"
     22 #include "namespace_test/namespace_test1_generated.h"
     23 #include "namespace_test/namespace_test2_generated.h"
     24 #include "union_vector/union_vector_generated.h"
     25 
     26 #ifndef FLATBUFFERS_CPP98_STL
     27   #include <random>
     28 #endif
     29 
     30 #include "flatbuffers/flexbuffers.h"
     31 
     32 using namespace MyGame::Example;
     33 
     34 #ifdef __ANDROID__
     35   #include <android/log.h>
     36   #define TEST_OUTPUT_LINE(...) \
     37     __android_log_print(ANDROID_LOG_INFO, "FlatBuffers", __VA_ARGS__)
     38   #define FLATBUFFERS_NO_FILE_TESTS
     39 #else
     40   #define TEST_OUTPUT_LINE(...) \
     41     { printf(__VA_ARGS__); printf("\n"); }
     42 #endif
     43 
     44 int testing_fails = 0;
     45 
     46 void TestFail(const char *expval, const char *val, const char *exp,
     47               const char *file, int line) {
     48   TEST_OUTPUT_LINE("TEST FAILED: %s:%d, %s (%s) != %s", file, line,
     49                    exp, expval, val);
     50   assert(0);
     51   testing_fails++;
     52 }
     53 
     54 void TestEqStr(const char *expval, const char *val, const char *exp,
     55                const char *file, int line) {
     56   if (strcmp(expval, val) != 0) {
     57     TestFail(expval, val, exp, file, line);
     58   }
     59 }
     60 
     61 template<typename T, typename U>
     62 void TestEq(T expval, U val, const char *exp, const char *file, int line) {
     63   if (U(expval) != val) {
     64     TestFail(flatbuffers::NumToString(expval).c_str(),
     65              flatbuffers::NumToString(val).c_str(),
     66              exp, file, line);
     67   }
     68 }
     69 
     70 #define TEST_EQ(exp, val) TestEq(exp,         val,   #exp, __FILE__, __LINE__)
     71 #define TEST_NOTNULL(exp) TestEq(exp == NULL, false, #exp, __FILE__, __LINE__)
     72 #define TEST_EQ_STR(exp, val) TestEqStr(exp,  val,   #exp, __FILE__, __LINE__)
     73 
     74 // Include simple random number generator to ensure results will be the
     75 // same cross platform.
     76 // http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
     77 uint32_t lcg_seed = 48271;
     78 uint32_t lcg_rand() {
     79     return lcg_seed = ((uint64_t)lcg_seed * 279470273UL) % 4294967291UL;
     80 }
     81 void lcg_reset() { lcg_seed = 48271; }
     82 
     83 // example of how to build up a serialized buffer algorithmically:
     84 flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) {
     85   flatbuffers::FlatBufferBuilder builder;
     86 
     87   auto vec = Vec3(1, 2, 3, 0, Color_Red, Test(10, 20));
     88 
     89   auto name = builder.CreateString("MyMonster");
     90 
     91   unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
     92   auto inventory = builder.CreateVector(inv_data, 10);
     93 
     94   // Alternatively, create the vector first, and fill in data later:
     95   // unsigned char *inv_buf = nullptr;
     96   // auto inventory = builder.CreateUninitializedVector<unsigned char>(
     97   //                                                              10, &inv_buf);
     98   // memcpy(inv_buf, inv_data, 10);
     99 
    100   Test tests[] = { Test(10, 20), Test(30, 40) };
    101   auto testv = builder.CreateVectorOfStructs(tests, 2);
    102 
    103   // create monster with very few fields set:
    104   // (same functionality as CreateMonster below, but sets fields manually)
    105   flatbuffers::Offset<Monster> mlocs[3];
    106   auto fred = builder.CreateString("Fred");
    107   auto barney = builder.CreateString("Barney");
    108   auto wilma = builder.CreateString("Wilma");
    109   MonsterBuilder mb1(builder);
    110   mb1.add_name(fred);
    111   mlocs[0] = mb1.Finish();
    112   MonsterBuilder mb2(builder);
    113   mb2.add_name(barney);
    114   mb2.add_hp(1000);
    115   mlocs[1] = mb2.Finish();
    116   MonsterBuilder mb3(builder);
    117   mb3.add_name(wilma);
    118   mlocs[2] = mb3.Finish();
    119 
    120   // Create an array of strings. Also test string pooling, and lambdas.
    121   const char *names[] = { "bob", "fred", "bob", "fred" };
    122   auto vecofstrings =
    123       builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(4,
    124         [&](size_t i) {
    125     return builder.CreateSharedString(names[i]);
    126   });
    127 
    128   // Creating vectors of strings in one convenient call.
    129   std::vector<std::string> names2;
    130   names2.push_back("jane");
    131   names2.push_back("mary");
    132   auto vecofstrings2 = builder.CreateVectorOfStrings(names2);
    133 
    134   // Create an array of sorted tables, can be used with binary search when read:
    135   auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3);
    136 
    137   // shortcut for creating monster with all fields set:
    138   auto mloc = CreateMonster(builder, &vec, 150, 80, name, inventory, Color_Blue,
    139                             Any_Monster, mlocs[1].Union(), // Store a union.
    140                             testv, vecofstrings, vecoftables, 0, 0, 0, false,
    141                             0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f,
    142                             vecofstrings2);
    143 
    144   FinishMonsterBuffer(builder, mloc);
    145 
    146   #ifdef FLATBUFFERS_TEST_VERBOSE
    147   // print byte data for debugging:
    148   auto p = builder.GetBufferPointer();
    149   for (flatbuffers::uoffset_t i = 0; i < builder.GetSize(); i++)
    150     printf("%d ", p[i]);
    151   #endif
    152 
    153   // return the buffer for the caller to use.
    154   auto bufferpointer =
    155     reinterpret_cast<const char *>(builder.GetBufferPointer());
    156   buffer.assign(bufferpointer, bufferpointer + builder.GetSize());
    157 
    158   return builder.ReleaseBufferPointer();
    159 }
    160 
    161 //  example of accessing a buffer loaded in memory:
    162 void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
    163                           bool pooled = true) {
    164 
    165   // First, verify the buffers integrity (optional)
    166   flatbuffers::Verifier verifier(flatbuf, length);
    167   TEST_EQ(VerifyMonsterBuffer(verifier), true);
    168 
    169   std::vector<uint8_t> test_buff;
    170   test_buff.resize(length * 2);
    171   std::memcpy(&test_buff[0], flatbuf , length);
    172   std::memcpy(&test_buff[length], flatbuf , length);
    173 
    174   flatbuffers::Verifier verifierl(&test_buff[0], length - 1);
    175   TEST_EQ(VerifyMonsterBuffer(verifierl), false);
    176   TEST_EQ(verifierl.GetComputedSize(), 0);
    177 
    178   flatbuffers::Verifier verifier1(&test_buff[0], length);
    179   TEST_EQ(VerifyMonsterBuffer(verifier1), true);
    180   TEST_EQ(verifier1.GetComputedSize(), length);
    181 
    182   flatbuffers::Verifier verifier2(&test_buff[length], length);
    183   TEST_EQ(VerifyMonsterBuffer(verifier2), true);
    184   TEST_EQ(verifier2.GetComputedSize(), length);
    185 
    186   TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0);
    187   TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true);
    188   TEST_EQ(strcmp(MonsterExtension(), "mon"), 0);
    189 
    190   // Access the buffer from the root.
    191   auto monster = GetMonster(flatbuf);
    192 
    193   TEST_EQ(monster->hp(), 80);
    194   TEST_EQ(monster->mana(), 150);  // default
    195   TEST_EQ_STR(monster->name()->c_str(), "MyMonster");
    196   // Can't access the following field, it is deprecated in the schema,
    197   // which means accessors are not generated:
    198   // monster.friendly()
    199 
    200   auto pos = monster->pos();
    201   TEST_NOTNULL(pos);
    202   TEST_EQ(pos->z(), 3);
    203   TEST_EQ(pos->test3().a(), 10);
    204   TEST_EQ(pos->test3().b(), 20);
    205 
    206   auto inventory = monster->inventory();
    207   TEST_EQ(VectorLength(inventory), 10UL);  // Works even if inventory is null.
    208   TEST_NOTNULL(inventory);
    209   unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    210   for (auto it = inventory->begin(); it != inventory->end(); ++it)
    211     TEST_EQ(*it, inv_data[it - inventory->begin()]);
    212 
    213   TEST_EQ(monster->color(), Color_Blue);
    214 
    215   // Example of accessing a union:
    216   TEST_EQ(monster->test_type(), Any_Monster);  // First make sure which it is.
    217   auto monster2 = reinterpret_cast<const Monster *>(monster->test());
    218   TEST_NOTNULL(monster2);
    219   TEST_EQ_STR(monster2->name()->c_str(), "Fred");
    220 
    221   // Example of accessing a vector of strings:
    222   auto vecofstrings = monster->testarrayofstring();
    223   TEST_EQ(vecofstrings->Length(), 4U);
    224   TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
    225   TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
    226   if (pooled) {
    227     // These should have pointer equality because of string pooling.
    228     TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
    229     TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
    230   }
    231 
    232   auto vecofstrings2 = monster->testarrayofstring2();
    233   if (vecofstrings2) {
    234     TEST_EQ(vecofstrings2->Length(), 2U);
    235     TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
    236     TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
    237   }
    238 
    239   // Example of accessing a vector of tables:
    240   auto vecoftables = monster->testarrayoftables();
    241   TEST_EQ(vecoftables->Length(), 3U);
    242   for (auto it = vecoftables->begin(); it != vecoftables->end(); ++it)
    243     TEST_EQ(strlen(it->name()->c_str()) >= 4, true);
    244   TEST_EQ_STR(vecoftables->Get(0)->name()->c_str(), "Barney");
    245   TEST_EQ(vecoftables->Get(0)->hp(), 1000);
    246   TEST_EQ_STR(vecoftables->Get(1)->name()->c_str(), "Fred");
    247   TEST_EQ_STR(vecoftables->Get(2)->name()->c_str(), "Wilma");
    248   TEST_NOTNULL(vecoftables->LookupByKey("Barney"));
    249   TEST_NOTNULL(vecoftables->LookupByKey("Fred"));
    250   TEST_NOTNULL(vecoftables->LookupByKey("Wilma"));
    251 
    252   // Since Flatbuffers uses explicit mechanisms to override the default
    253   // compiler alignment, double check that the compiler indeed obeys them:
    254   // (Test consists of a short and byte):
    255   TEST_EQ(flatbuffers::AlignOf<Test>(), 2UL);
    256   TEST_EQ(sizeof(Test), 4UL);
    257 
    258   auto tests = monster->test4();
    259   TEST_NOTNULL(tests);
    260   auto test_0 = tests->Get(0);
    261   auto test_1 = tests->Get(1);
    262   TEST_EQ(test_0->a(), 10);
    263   TEST_EQ(test_0->b(), 20);
    264   TEST_EQ(test_1->a(), 30);
    265   TEST_EQ(test_1->b(), 40);
    266   for (auto it = tests->begin(); it != tests->end(); ++it) {
    267     TEST_EQ(it->a() == 10 || it->a() == 30, true);  // Just testing iterators.
    268   }
    269 
    270   // Checking for presence of fields:
    271   TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
    272   TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
    273 
    274   // Obtaining a buffer from a root:
    275   TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
    276 }
    277 
    278 // Change a FlatBuffer in-place, after it has been constructed.
    279 void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
    280   // Get non-const pointer to root.
    281   auto monster = GetMutableMonster(flatbuf);
    282 
    283   // Each of these tests mutates, then tests, then set back to the original,
    284   // so we can test that the buffer in the end still passes our original test.
    285   auto hp_ok = monster->mutate_hp(10);
    286   TEST_EQ(hp_ok, true);  // Field was present.
    287   TEST_EQ(monster->hp(), 10);
    288   monster->mutate_hp(80);
    289 
    290   auto mana_ok = monster->mutate_mana(10);
    291   TEST_EQ(mana_ok, false);  // Field was NOT present, because default value.
    292 
    293   // Mutate structs.
    294   auto pos = monster->mutable_pos();
    295   auto test3 = pos->mutable_test3();  // Struct inside a struct.
    296   test3.mutate_a(50);                 // Struct fields never fail.
    297   TEST_EQ(test3.a(), 50);
    298   test3.mutate_a(10);
    299 
    300   // Mutate vectors.
    301   auto inventory = monster->mutable_inventory();
    302   inventory->Mutate(9, 100);
    303   TEST_EQ(inventory->Get(9), 100);
    304   inventory->Mutate(9, 9);
    305 
    306   auto tables = monster->mutable_testarrayoftables();
    307   auto first = tables->GetMutableObject(0);
    308   TEST_EQ(first->hp(), 1000);
    309   first->mutate_hp(0);
    310   TEST_EQ(first->hp(), 0);
    311   first->mutate_hp(1000);
    312 
    313   // Run the verifier and the regular test to make sure we didn't trample on
    314   // anything.
    315   AccessFlatBufferTest(flatbuf, length);
    316 }
    317 
    318 // Unpack a FlatBuffer into objects.
    319 void ObjectFlatBuffersTest(uint8_t *flatbuf) {
    320   // Optional: we can specify resolver and rehasher functions to turn hashed
    321   // strings into object pointers and back, to implement remote references
    322   // and such.
    323   auto resolver = flatbuffers::resolver_function_t(
    324                     [](void **pointer_adr, flatbuffers::hash_value_t hash) {
    325     (void)pointer_adr;
    326     (void)hash;
    327     // Don't actually do anything, leave variable null.
    328   });
    329   auto rehasher = flatbuffers::rehasher_function_t(
    330                     [](void *pointer) -> flatbuffers::hash_value_t {
    331     (void)pointer;
    332     return 0;
    333   });
    334 
    335   // Turn a buffer into C++ objects.
    336   auto monster1 = UnPackMonster(flatbuf, &resolver);
    337 
    338   // Re-serialize the data.
    339   flatbuffers::FlatBufferBuilder fbb1;
    340   fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
    341               MonsterIdentifier());
    342 
    343   // Unpack again, and re-serialize again.
    344   auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
    345   flatbuffers::FlatBufferBuilder fbb2;
    346   fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
    347               MonsterIdentifier());
    348 
    349   // Now we've gone full round-trip, the two buffers should match.
    350   auto len1 = fbb1.GetSize();
    351   auto len2 = fbb2.GetSize();
    352   TEST_EQ(len1, len2);
    353   TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(),
    354                  len1), 0);
    355 
    356   // Test it with the original buffer test to make sure all data survived.
    357   AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
    358 
    359   // Test accessing fields, similar to AccessFlatBufferTest above.
    360   TEST_EQ(monster2->hp, 80);
    361   TEST_EQ(monster2->mana, 150);  // default
    362   TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
    363 
    364   auto &pos = monster2->pos;
    365   TEST_NOTNULL(pos);
    366   TEST_EQ(pos->z(), 3);
    367   TEST_EQ(pos->test3().a(), 10);
    368   TEST_EQ(pos->test3().b(), 20);
    369 
    370   auto &inventory = monster2->inventory;
    371   TEST_EQ(inventory.size(), 10UL);
    372   unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    373   for (auto it = inventory.begin(); it != inventory.end(); ++it)
    374     TEST_EQ(*it, inv_data[it - inventory.begin()]);
    375 
    376   TEST_EQ(monster2->color, Color_Blue);
    377 
    378   auto monster3 = monster2->test.AsMonster();
    379   TEST_NOTNULL(monster3);
    380   TEST_EQ_STR(monster3->name.c_str(), "Fred");
    381 
    382   auto &vecofstrings = monster2->testarrayofstring;
    383   TEST_EQ(vecofstrings.size(), 4U);
    384   TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
    385   TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
    386 
    387   auto &vecofstrings2 = monster2->testarrayofstring2;
    388   TEST_EQ(vecofstrings2.size(), 2U);
    389   TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
    390   TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
    391 
    392   auto &vecoftables = monster2->testarrayoftables;
    393   TEST_EQ(vecoftables.size(), 3U);
    394   TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
    395   TEST_EQ(vecoftables[0]->hp, 1000);
    396   TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
    397   TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
    398 
    399   auto &tests = monster2->test4;
    400   TEST_EQ(tests[0].a(), 10);
    401   TEST_EQ(tests[0].b(), 20);
    402   TEST_EQ(tests[1].a(), 30);
    403   TEST_EQ(tests[1].b(), 40);
    404 }
    405 
    406 // Prefix a FlatBuffer with a size field.
    407 void SizePrefixedTest() {
    408   // Create size prefixed buffer.
    409   flatbuffers::FlatBufferBuilder fbb;
    410   fbb.FinishSizePrefixed(CreateMonster(fbb, 0, 200, 300,
    411                                        fbb.CreateString("bob")));
    412 
    413   // Verify it.
    414   flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
    415   TEST_EQ(verifier.VerifySizePrefixedBuffer<Monster>(nullptr), true);
    416 
    417   // Access it.
    418   auto m = flatbuffers::GetSizePrefixedRoot<MyGame::Example::Monster>(
    419                                                         fbb.GetBufferPointer());
    420   TEST_EQ(m->mana(), 200);
    421   TEST_EQ(m->hp(), 300);
    422   TEST_EQ_STR(m->name()->c_str(), "bob");
    423 }
    424 
    425 // example of parsing text straight into a buffer, and generating
    426 // text back from it:
    427 void ParseAndGenerateTextTest() {
    428   // load FlatBuffer schema (.fbs) and JSON from disk
    429   std::string schemafile;
    430   std::string jsonfile;
    431   TEST_EQ(flatbuffers::LoadFile(
    432     "tests/monster_test.fbs", false, &schemafile), true);
    433   TEST_EQ(flatbuffers::LoadFile(
    434     "tests/monsterdata_test.golden", false, &jsonfile), true);
    435 
    436   // parse schema first, so we can use it to parse the data after
    437   flatbuffers::Parser parser;
    438   const char *include_directories[] = { "tests", nullptr };
    439   TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
    440   TEST_EQ(parser.Parse(jsonfile.c_str(), include_directories), true);
    441 
    442   // here, parser.builder_ contains a binary buffer that is the parsed data.
    443 
    444   // First, verify it, just in case:
    445   flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
    446                                  parser.builder_.GetSize());
    447   TEST_EQ(VerifyMonsterBuffer(verifier), true);
    448 
    449   // to ensure it is correct, we now generate text back from the binary,
    450   // and compare the two:
    451   std::string jsongen;
    452   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
    453   TEST_EQ(result, true);
    454 
    455   if (jsongen != jsonfile) {
    456     printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
    457     TEST_NOTNULL(NULL);
    458   }
    459 }
    460 
    461 void ReflectionTest(uint8_t *flatbuf, size_t length) {
    462   // Load a binary schema.
    463   std::string bfbsfile;
    464   TEST_EQ(flatbuffers::LoadFile(
    465     "tests/monster_test.bfbs", true, &bfbsfile), true);
    466 
    467   // Verify it, just in case:
    468   flatbuffers::Verifier verifier(
    469     reinterpret_cast<const uint8_t *>(bfbsfile.c_str()), bfbsfile.length());
    470   TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
    471 
    472   // Make sure the schema is what we expect it to be.
    473   auto &schema = *reflection::GetSchema(bfbsfile.c_str());
    474   auto root_table = schema.root_table();
    475   TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
    476   auto fields = root_table->fields();
    477   auto hp_field_ptr = fields->LookupByKey("hp");
    478   TEST_NOTNULL(hp_field_ptr);
    479   auto &hp_field = *hp_field_ptr;
    480   TEST_EQ_STR(hp_field.name()->c_str(), "hp");
    481   TEST_EQ(hp_field.id(), 2);
    482   TEST_EQ(hp_field.type()->base_type(), reflection::Short);
    483   auto friendly_field_ptr = fields->LookupByKey("friendly");
    484   TEST_NOTNULL(friendly_field_ptr);
    485   TEST_NOTNULL(friendly_field_ptr->attributes());
    486   TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
    487 
    488   // Make sure the table index is what we expect it to be.
    489   auto pos_field_ptr = fields->LookupByKey("pos");
    490   TEST_NOTNULL(pos_field_ptr);
    491   TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
    492   auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
    493   TEST_NOTNULL(pos_table_ptr);
    494   TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
    495 
    496   // Now use it to dynamically access a buffer.
    497   auto &root = *flatbuffers::GetAnyRoot(flatbuf);
    498 
    499   // Verify the buffer first using reflection based verification
    500   TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
    501           true);
    502 
    503   auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
    504   TEST_EQ(hp, 80);
    505 
    506   // Rather than needing to know the type, we can also get the value of
    507   // any field as an int64_t/double/string, regardless of what it actually is.
    508   auto hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
    509   TEST_EQ(hp_int64, 80);
    510   auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
    511   TEST_EQ(hp_double, 80.0);
    512   auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
    513   TEST_EQ_STR(hp_string.c_str(), "80");
    514 
    515   // Get struct field through reflection
    516   auto pos_struct = flatbuffers::GetFieldStruct(root, *pos_field_ptr);
    517   TEST_NOTNULL(pos_struct);
    518   TEST_EQ(flatbuffers::GetAnyFieldF(
    519     *pos_struct, *pos_table_ptr->fields()->LookupByKey("z")), 3.0f);
    520 
    521   auto test3_field = pos_table_ptr->fields()->LookupByKey("test3");
    522   auto test3_struct = flatbuffers::GetFieldStruct(*pos_struct, *test3_field);
    523   TEST_NOTNULL(test3_struct);
    524   auto test3_object = schema.objects()->Get(test3_field->type()->index());
    525 
    526   TEST_EQ(flatbuffers::GetAnyFieldF(
    527     *test3_struct, *test3_object->fields()->LookupByKey("a")), 10);
    528 
    529   // We can also modify it.
    530   flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
    531   hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
    532   TEST_EQ(hp, 200);
    533 
    534   // We can also set fields generically:
    535   flatbuffers::SetAnyFieldI(&root, hp_field, 300);
    536   hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
    537   TEST_EQ(hp_int64, 300);
    538   flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
    539   hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
    540   TEST_EQ(hp_int64, 300);
    541   flatbuffers::SetAnyFieldS(&root, hp_field, "300");
    542   hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
    543   TEST_EQ(hp_int64, 300);
    544 
    545   // Test buffer is valid after the modifications
    546   TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
    547           true);
    548 
    549   // Reset it, for further tests.
    550   flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
    551 
    552   // More advanced functionality: changing the size of items in-line!
    553   // First we put the FlatBuffer inside an std::vector.
    554   std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
    555   // Find the field we want to modify.
    556   auto &name_field = *fields->LookupByKey("name");
    557   // Get the root.
    558   // This time we wrap the result from GetAnyRoot in a smartpointer that
    559   // will keep rroot valid as resizingbuf resizes.
    560   auto rroot = flatbuffers::piv(flatbuffers::GetAnyRoot(resizingbuf.data()),
    561                                 resizingbuf);
    562   SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
    563             &resizingbuf);
    564   // Here resizingbuf has changed, but rroot is still valid.
    565   TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
    566   // Now lets extend a vector by 100 elements (10 -> 110).
    567   auto &inventory_field = *fields->LookupByKey("inventory");
    568   auto rinventory = flatbuffers::piv(
    569                      flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field),
    570                      resizingbuf);
    571   flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
    572                                      &resizingbuf);
    573   // rinventory still valid, so lets read from it.
    574   TEST_EQ(rinventory->Get(10), 50);
    575 
    576   // For reflection uses not covered already, there is a more powerful way:
    577   // we can simply generate whatever object we want to add/modify in a
    578   // FlatBuffer of its own, then add that to an existing FlatBuffer:
    579   // As an example, let's add a string to an array of strings.
    580   // First, find our field:
    581   auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
    582   // Find the vector value:
    583   auto rtestarrayofstring = flatbuffers::piv(
    584          flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
    585            **rroot, testarrayofstring_field),
    586          resizingbuf);
    587   // It's a vector of 2 strings, to which we add one more, initialized to
    588   // offset 0.
    589   flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
    590         schema, 3, 0, *rtestarrayofstring, &resizingbuf);
    591   // Here we just create a buffer that contans a single string, but this
    592   // could also be any complex set of tables and other values.
    593   flatbuffers::FlatBufferBuilder stringfbb;
    594   stringfbb.Finish(stringfbb.CreateString("hank"));
    595   // Add the contents of it to our existing FlatBuffer.
    596   // We do this last, so the pointer doesn't get invalidated (since it is
    597   // at the end of the buffer):
    598   auto string_ptr = flatbuffers::AddFlatBuffer(resizingbuf,
    599                                                stringfbb.GetBufferPointer(),
    600                                                stringfbb.GetSize());
    601   // Finally, set the new value in the vector.
    602   rtestarrayofstring->MutateOffset(2, string_ptr);
    603   TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
    604   TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
    605   // Test integrity of all resize operations above.
    606   flatbuffers::Verifier resize_verifier(
    607         reinterpret_cast<const uint8_t *>(resizingbuf.data()),
    608         resizingbuf.size());
    609   TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
    610 
    611   // Test buffer is valid using reflection as well
    612   TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), resizingbuf.data(),
    613                               resizingbuf.size()), true);
    614 
    615   // As an additional test, also set it on the name field.
    616   // Note: unlike the name change above, this just overwrites the offset,
    617   // rather than changing the string in-place.
    618   SetFieldT(*rroot, name_field, string_ptr);
    619   TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
    620 
    621   // Using reflection, rather than mutating binary FlatBuffers, we can also copy
    622   // tables and other things out of other FlatBuffers into a FlatBufferBuilder,
    623   // either part or whole.
    624   flatbuffers::FlatBufferBuilder fbb;
    625   auto root_offset = flatbuffers::CopyTable(fbb, schema, *root_table,
    626                                             *flatbuffers::GetAnyRoot(flatbuf),
    627                                             true);
    628   fbb.Finish(root_offset, MonsterIdentifier());
    629   // Test that it was copied correctly:
    630   AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
    631 
    632   // Test buffer is valid using reflection as well
    633   TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
    634                               fbb.GetBufferPointer(), fbb.GetSize()), true);
    635 }
    636 
    637 // Parse a .proto schema, output as .fbs
    638 void ParseProtoTest() {
    639   // load the .proto and the golden file from disk
    640   std::string protofile;
    641   std::string goldenfile;
    642   TEST_EQ(flatbuffers::LoadFile(
    643     "tests/prototest/test.proto", false, &protofile), true);
    644   TEST_EQ(flatbuffers::LoadFile(
    645     "tests/prototest/test.golden", false, &goldenfile), true);
    646 
    647   flatbuffers::IDLOptions opts;
    648   opts.include_dependence_headers = false;
    649   opts.proto_mode = true;
    650 
    651   // Parse proto.
    652   flatbuffers::Parser parser(opts);
    653   const char *include_directories[] = { "tests/prototest", nullptr };
    654   TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
    655 
    656   // Generate fbs.
    657   auto fbs = flatbuffers::GenerateFBS(parser, "test");
    658 
    659   // Ensure generated file is parsable.
    660   flatbuffers::Parser parser2;
    661   TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
    662 
    663   if (fbs != goldenfile) {
    664     printf("%s----------------\n%s", fbs.c_str(), goldenfile.c_str());
    665     TEST_NOTNULL(NULL);
    666   }
    667 }
    668 
    669 template<typename T> void CompareTableFieldValue(flatbuffers::Table *table,
    670                                                  flatbuffers::voffset_t voffset,
    671                                                  T val) {
    672   T read = table->GetField(voffset, static_cast<T>(0));
    673   TEST_EQ(read, val);
    674 }
    675 
    676 // Low level stress/fuzz test: serialize/deserialize a variety of
    677 // different kinds of data in different combinations
    678 void FuzzTest1() {
    679 
    680   // Values we're testing against: chosen to ensure no bits get chopped
    681   // off anywhere, and also be different from eachother.
    682   const uint8_t  bool_val   = true;
    683   const int8_t   char_val   = -127;  // 0x81
    684   const uint8_t  uchar_val  = 0xFF;
    685   const int16_t  short_val  = -32222; // 0x8222;
    686   const uint16_t ushort_val = 0xFEEE;
    687   const int32_t  int_val    = 0x83333333;
    688   const uint32_t uint_val   = 0xFDDDDDDD;
    689   const int64_t  long_val   = 0x8444444444444444LL;
    690   const uint64_t ulong_val  = 0xFCCCCCCCCCCCCCCCULL;
    691   const float    float_val  = 3.14159f;
    692   const double   double_val = 3.14159265359;
    693 
    694   const int test_values_max = 11;
    695   const flatbuffers::voffset_t fields_per_object = 4;
    696   const int num_fuzz_objects = 10000;  // The higher, the more thorough :)
    697 
    698   flatbuffers::FlatBufferBuilder builder;
    699 
    700   lcg_reset();  // Keep it deterministic.
    701 
    702   flatbuffers::uoffset_t objects[num_fuzz_objects];
    703 
    704   // Generate num_fuzz_objects random objects each consisting of
    705   // fields_per_object fields, each of a random type.
    706   for (int i = 0; i < num_fuzz_objects; i++) {
    707     auto start = builder.StartTable();
    708     for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
    709       int choice = lcg_rand() % test_values_max;
    710       auto off = flatbuffers::FieldIndexToOffset(f);
    711       switch (choice) {
    712         case 0:  builder.AddElement<uint8_t >(off, bool_val,   0); break;
    713         case 1:  builder.AddElement<int8_t  >(off, char_val,   0); break;
    714         case 2:  builder.AddElement<uint8_t >(off, uchar_val,  0); break;
    715         case 3:  builder.AddElement<int16_t >(off, short_val,  0); break;
    716         case 4:  builder.AddElement<uint16_t>(off, ushort_val, 0); break;
    717         case 5:  builder.AddElement<int32_t >(off, int_val,    0); break;
    718         case 6:  builder.AddElement<uint32_t>(off, uint_val,   0); break;
    719         case 7:  builder.AddElement<int64_t >(off, long_val,   0); break;
    720         case 8:  builder.AddElement<uint64_t>(off, ulong_val,  0); break;
    721         case 9:  builder.AddElement<float   >(off, float_val,  0); break;
    722         case 10: builder.AddElement<double  >(off, double_val, 0); break;
    723       }
    724     }
    725     objects[i] = builder.EndTable(start, fields_per_object);
    726   }
    727   builder.PreAlign<flatbuffers::largest_scalar_t>(0);  // Align whole buffer.
    728 
    729   lcg_reset();  // Reset.
    730 
    731   uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
    732 
    733   // Test that all objects we generated are readable and return the
    734   // expected values. We generate random objects in the same order
    735   // so this is deterministic.
    736   for (int i = 0; i < num_fuzz_objects; i++) {
    737     auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
    738     for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
    739       int choice = lcg_rand() % test_values_max;
    740       flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
    741       switch (choice) {
    742         case 0:  CompareTableFieldValue(table, off, bool_val  ); break;
    743         case 1:  CompareTableFieldValue(table, off, char_val  ); break;
    744         case 2:  CompareTableFieldValue(table, off, uchar_val ); break;
    745         case 3:  CompareTableFieldValue(table, off, short_val ); break;
    746         case 4:  CompareTableFieldValue(table, off, ushort_val); break;
    747         case 5:  CompareTableFieldValue(table, off, int_val   ); break;
    748         case 6:  CompareTableFieldValue(table, off, uint_val  ); break;
    749         case 7:  CompareTableFieldValue(table, off, long_val  ); break;
    750         case 8:  CompareTableFieldValue(table, off, ulong_val ); break;
    751         case 9:  CompareTableFieldValue(table, off, float_val ); break;
    752         case 10: CompareTableFieldValue(table, off, double_val); break;
    753       }
    754     }
    755   }
    756 }
    757 
    758 // High level stress/fuzz test: generate a big schema and
    759 // matching json data in random combinations, then parse both,
    760 // generate json back from the binary, and compare with the original.
    761 void FuzzTest2() {
    762   lcg_reset();  // Keep it deterministic.
    763 
    764   const int num_definitions = 30;
    765   const int num_struct_definitions = 5;  // Subset of num_definitions.
    766   const int fields_per_definition = 15;
    767   const int instances_per_definition = 5;
    768   const int deprecation_rate = 10;        // 1 in deprecation_rate fields will
    769                                           // be deprecated.
    770 
    771   std::string schema = "namespace test;\n\n";
    772 
    773   struct RndDef {
    774     std::string instances[instances_per_definition];
    775 
    776     // Since we're generating schema and corresponding data in tandem,
    777     // this convenience function adds strings to both at once.
    778     static void Add(RndDef (&definitions_l)[num_definitions],
    779                     std::string &schema_l,
    780                     const int instances_per_definition_l,
    781                     const char *schema_add, const char *instance_add,
    782                     int definition) {
    783       schema_l += schema_add;
    784       for (int i = 0; i < instances_per_definition_l; i++)
    785         definitions_l[definition].instances[i] += instance_add;
    786     }
    787   };
    788 
    789   #define AddToSchemaAndInstances(schema_add, instance_add) \
    790     RndDef::Add(definitions, schema, instances_per_definition, \
    791                 schema_add, instance_add, definition)
    792 
    793   #define Dummy() \
    794     RndDef::Add(definitions, schema, instances_per_definition, \
    795                 "byte", "1", definition)
    796 
    797   RndDef definitions[num_definitions];
    798 
    799   // We are going to generate num_definitions, the first
    800   // num_struct_definitions will be structs, the rest tables. For each
    801   // generate random fields, some of which may be struct/table types
    802   // referring to previously generated structs/tables.
    803   // Simultanenously, we generate instances_per_definition JSON data
    804   // definitions, which will have identical structure to the schema
    805   // being generated. We generate multiple instances such that when creating
    806   // hierarchy, we get some variety by picking one randomly.
    807   for (int definition = 0; definition < num_definitions; definition++) {
    808     std::string definition_name = "D" + flatbuffers::NumToString(definition);
    809 
    810     bool is_struct = definition < num_struct_definitions;
    811 
    812     AddToSchemaAndInstances(
    813       ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
    814       "{\n");
    815 
    816     for (int field = 0; field < fields_per_definition; field++) {
    817       const bool is_last_field = field == fields_per_definition - 1;
    818 
    819       // Deprecate 1 in deprecation_rate fields. Only table fields can be
    820       // deprecated.
    821       // Don't deprecate the last field to avoid dangling commas in JSON.
    822       const bool deprecated = !is_struct &&
    823                               !is_last_field &&
    824                               (lcg_rand() % deprecation_rate == 0);
    825 
    826       std::string field_name = "f" + flatbuffers::NumToString(field);
    827       AddToSchemaAndInstances(("  " + field_name + ":").c_str(),
    828                               deprecated ? "" : (field_name + ": ").c_str());
    829       // Pick random type:
    830       int base_type = lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1);
    831       switch (base_type) {
    832         case flatbuffers::BASE_TYPE_STRING:
    833           if (is_struct) {
    834             Dummy();  // No strings in structs.
    835           } else {
    836             AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
    837           }
    838           break;
    839         case flatbuffers::BASE_TYPE_VECTOR:
    840           if (is_struct) {
    841             Dummy();  // No vectors in structs.
    842           }
    843           else {
    844             AddToSchemaAndInstances("[ubyte]",
    845                                     deprecated ? "" : "[\n0,\n1,\n255\n]");
    846           }
    847           break;
    848         case flatbuffers::BASE_TYPE_NONE:
    849         case flatbuffers::BASE_TYPE_UTYPE:
    850         case flatbuffers::BASE_TYPE_STRUCT:
    851         case flatbuffers::BASE_TYPE_UNION:
    852           if (definition) {
    853             // Pick a random previous definition and random data instance of
    854             // that definition.
    855             int defref = lcg_rand() % definition;
    856             int instance = lcg_rand() % instances_per_definition;
    857             AddToSchemaAndInstances(
    858               ("D" + flatbuffers::NumToString(defref)).c_str(),
    859               deprecated
    860                 ? ""
    861                 : definitions[defref].instances[instance].c_str());
    862           } else {
    863             // If this is the first definition, we have no definition we can
    864             // refer to.
    865             Dummy();
    866           }
    867           break;
    868         case flatbuffers::BASE_TYPE_BOOL:
    869           AddToSchemaAndInstances("bool", deprecated
    870                                   ? ""
    871                                   : (lcg_rand() % 2 ? "true" : "false"));
    872           break;
    873         default:
    874           // All the scalar types.
    875           schema += flatbuffers::kTypeNames[base_type];
    876 
    877           if (!deprecated) {
    878             // We want each instance to use its own random value.
    879             for (int inst = 0; inst < instances_per_definition; inst++)
    880               definitions[definition].instances[inst] +=
    881               flatbuffers::NumToString(lcg_rand() % 128).c_str();
    882           }
    883       }
    884       AddToSchemaAndInstances(
    885         deprecated ? "(deprecated);\n" : ";\n",
    886         deprecated ? "" : is_last_field ? "\n" : ",\n");
    887     }
    888     AddToSchemaAndInstances("}\n\n", "}");
    889   }
    890 
    891   schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
    892   schema += ";\n";
    893 
    894   flatbuffers::Parser parser;
    895 
    896   // Will not compare against the original if we don't write defaults
    897   parser.builder_.ForceDefaults(true);
    898 
    899   // Parse the schema, parse the generated data, then generate text back
    900   // from the binary and compare against the original.
    901   TEST_EQ(parser.Parse(schema.c_str()), true);
    902 
    903   const std::string &json =
    904     definitions[num_definitions - 1].instances[0] + "\n";
    905 
    906   TEST_EQ(parser.Parse(json.c_str()), true);
    907 
    908   std::string jsongen;
    909   parser.opts.indent_step = 0;
    910   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
    911   TEST_EQ(result, true);
    912 
    913   if (jsongen != json) {
    914     // These strings are larger than a megabyte, so we show the bytes around
    915     // the first bytes that are different rather than the whole string.
    916     size_t len = std::min(json.length(), jsongen.length());
    917     for (size_t i = 0; i < len; i++) {
    918       if (json[i] != jsongen[i]) {
    919         i -= std::min(static_cast<size_t>(10), i); // show some context;
    920         size_t end = std::min(len, i + 20);
    921         for (; i < end; i++)
    922           printf("at %d: found \"%c\", expected \"%c\"\n",
    923                static_cast<int>(i), jsongen[i], json[i]);
    924         break;
    925       }
    926     }
    927     TEST_NOTNULL(NULL);
    928   }
    929 
    930   printf("%dk schema tested with %dk of json\n",
    931          static_cast<int>(schema.length() / 1024),
    932          static_cast<int>(json.length() / 1024));
    933 }
    934 
    935 // Test that parser errors are actually generated.
    936 void TestError(const char *src, const char *error_substr,
    937                bool strict_json = false) {
    938   flatbuffers::IDLOptions opts;
    939   opts.strict_json = strict_json;
    940   flatbuffers::Parser parser(opts);
    941   TEST_EQ(parser.Parse(src), false);  // Must signal error
    942   // Must be the error we're expecting
    943   TEST_NOTNULL(strstr(parser.error_.c_str(), error_substr));
    944 }
    945 
    946 // Test that parsing errors occur as we'd expect.
    947 // Also useful for coverage, making sure these paths are run.
    948 void ErrorTest() {
    949   // In order they appear in idl_parser.cpp
    950   TestError("table X { Y:byte; } root_type X; { Y: 999 }", "bit field");
    951   TestError(".0", "floating point");
    952   TestError("\"\0", "illegal");
    953   TestError("\"\\q", "escape code");
    954   TestError("table ///", "documentation");
    955   TestError("@", "illegal");
    956   TestError("table 1", "expecting");
    957   TestError("table X { Y:[[int]]; }", "nested vector");
    958   TestError("table X { Y:1; }", "illegal type");
    959   TestError("table X { Y:int; Y:int; }", "field already");
    960   TestError("struct X { Y:string; }", "only scalar");
    961   TestError("struct X { Y:int (deprecated); }", "deprecate");
    962   TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
    963             "missing type field");
    964   TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
    965             "type id");
    966   TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
    967   TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
    968   TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
    969             true);
    970   TestError("struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
    971             "{ V:{ Y:1 } }", "wrong number");
    972   TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
    973             "unknown enum value");
    974   TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
    975   TestError("enum X:byte { Y } enum X {", "enum already");
    976   TestError("enum X:float {}", "underlying");
    977   TestError("enum X:byte { Y, Y }", "value already");
    978   TestError("enum X:byte { Y=2, Z=1 }", "ascending");
    979   TestError("enum X:byte (bit_flags) { Y=8 }", "bit flag out");
    980   TestError("table X { Y:int; } table X {", "datatype already");
    981   TestError("struct X (force_align: 7) { Y:int; }", "force_align");
    982   TestError("{}", "no root");
    983   TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "one json");
    984   TestError("root_type X;", "unknown root");
    985   TestError("struct X { Y:int; } root_type X;", "a table");
    986   TestError("union X { Y }", "referenced");
    987   TestError("union Z { X } struct X { Y:int; }", "only tables");
    988   TestError("table X { Y:[int]; YLength:int; }", "clash");
    989   TestError("table X { Y:string = 1; }", "scalar");
    990   TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
    991 }
    992 
    993 template<typename T> T TestValue(const char *json, const char *type_name) {
    994   flatbuffers::Parser parser;
    995 
    996   // Simple schema.
    997   TEST_EQ(parser.Parse(std::string("table X { Y:" + std::string(type_name) +
    998                                    "; } root_type X;").c_str()), true);
    999 
   1000   TEST_EQ(parser.Parse(json), true);
   1001   auto root = flatbuffers::GetRoot<flatbuffers::Table>(
   1002                 parser.builder_.GetBufferPointer());
   1003   return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
   1004 }
   1005 
   1006 bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
   1007 
   1008 // Additional parser testing not covered elsewhere.
   1009 void ValueTest() {
   1010   // Test scientific notation numbers.
   1011   TEST_EQ(FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }","float"),
   1012                        (float)3.14159), true);
   1013 
   1014   // Test conversion functions.
   1015   TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }","float"), -1),
   1016           true);
   1017 
   1018   // Test negative hex constant.
   1019   TEST_EQ(TestValue<int>("{ Y:-0x80 }","int"), -128);
   1020 
   1021   // Make sure we do unsigned 64bit correctly.
   1022   TEST_EQ(TestValue<uint64_t>("{ Y:12335089644688340133 }","ulong"),
   1023                               12335089644688340133ULL);
   1024 }
   1025 
   1026 void EnumStringsTest() {
   1027   flatbuffers::Parser parser1;
   1028   TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
   1029                         "root_type T;"
   1030                         "{ F:[ A, B, \"C\", \"A B C\" ] }"), true);
   1031   flatbuffers::Parser parser2;
   1032   TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
   1033                         "root_type T;"
   1034                         "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"), true);
   1035 }
   1036 
   1037 void IntegerOutOfRangeTest() {
   1038   TestError("table T { F:byte; } root_type T; { F:256 }",
   1039             "constant does not fit");
   1040   TestError("table T { F:byte; } root_type T; { F:-257 }",
   1041             "constant does not fit");
   1042   TestError("table T { F:ubyte; } root_type T; { F:256 }",
   1043             "constant does not fit");
   1044   TestError("table T { F:ubyte; } root_type T; { F:-257 }",
   1045             "constant does not fit");
   1046   TestError("table T { F:short; } root_type T; { F:65536 }",
   1047             "constant does not fit");
   1048   TestError("table T { F:short; } root_type T; { F:-65537 }",
   1049             "constant does not fit");
   1050   TestError("table T { F:ushort; } root_type T; { F:65536 }",
   1051             "constant does not fit");
   1052   TestError("table T { F:ushort; } root_type T; { F:-65537 }",
   1053             "constant does not fit");
   1054   TestError("table T { F:int; } root_type T; { F:4294967296 }",
   1055             "constant does not fit");
   1056   TestError("table T { F:int; } root_type T; { F:-4294967297 }",
   1057             "constant does not fit");
   1058   TestError("table T { F:uint; } root_type T; { F:4294967296 }",
   1059             "constant does not fit");
   1060   TestError("table T { F:uint; } root_type T; { F:-4294967297 }",
   1061             "constant does not fit");
   1062 }
   1063 
   1064 void UnicodeTest() {
   1065   flatbuffers::Parser parser;
   1066   // Without setting allow_non_utf8 = true, we treat \x sequences as byte sequences
   1067   // which are then validated as UTF-8.
   1068   TEST_EQ(parser.Parse("table T { F:string; }"
   1069                        "root_type T;"
   1070                        "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
   1071                        "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD83D\\uDE0E\" }"),
   1072           true);
   1073   std::string jsongen;
   1074   parser.opts.indent_step = -1;
   1075   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
   1076   TEST_EQ(result, true);
   1077   TEST_EQ(jsongen,
   1078           std::string(
   1079             "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
   1080             "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}"));
   1081 }
   1082 
   1083 void UnicodeTestAllowNonUTF8() {
   1084   flatbuffers::Parser parser;
   1085   parser.opts.allow_non_utf8 = true;
   1086   TEST_EQ(parser.Parse("table T { F:string; }"
   1087                        "root_type T;"
   1088                        "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
   1089                        "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"), true);
   1090   std::string jsongen;
   1091   parser.opts.indent_step = -1;
   1092   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
   1093   TEST_EQ(result, true);
   1094   TEST_EQ(jsongen,
   1095           std::string(
   1096             "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
   1097             "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}"));
   1098 }
   1099 
   1100 void UnicodeTestGenerateTextFailsOnNonUTF8() {
   1101   flatbuffers::Parser parser;
   1102   // Allow non-UTF-8 initially to model what happens when we load a binary flatbuffer from disk
   1103   // which contains non-UTF-8 strings.
   1104   parser.opts.allow_non_utf8 = true;
   1105   TEST_EQ(parser.Parse("table T { F:string; }"
   1106                        "root_type T;"
   1107                        "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
   1108                        "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"), true);
   1109   std::string jsongen;
   1110   parser.opts.indent_step = -1;
   1111   // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates failure.
   1112   parser.opts.allow_non_utf8 = false;
   1113   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
   1114   TEST_EQ(result, false);
   1115 }
   1116 
   1117 void UnicodeSurrogatesTest() {
   1118   flatbuffers::Parser parser;
   1119 
   1120   TEST_EQ(
   1121     parser.Parse(
   1122       "table T { F:string (id: 0); }"
   1123       "root_type T;"
   1124       "{ F:\"\\uD83D\\uDCA9\"}"), true);
   1125   auto root = flatbuffers::GetRoot<flatbuffers::Table>(
   1126     parser.builder_.GetBufferPointer());
   1127   auto string = root->GetPointer<flatbuffers::String *>(
   1128     flatbuffers::FieldIndexToOffset(0));
   1129   TEST_EQ(strcmp(string->c_str(), "\xF0\x9F\x92\xA9"), 0);
   1130 }
   1131 
   1132 void UnicodeInvalidSurrogatesTest() {
   1133   TestError(
   1134     "table T { F:string; }"
   1135     "root_type T;"
   1136     "{ F:\"\\uD800\"}", "unpaired high surrogate");
   1137   TestError(
   1138     "table T { F:string; }"
   1139     "root_type T;"
   1140     "{ F:\"\\uD800abcd\"}", "unpaired high surrogate");
   1141   TestError(
   1142     "table T { F:string; }"
   1143     "root_type T;"
   1144     "{ F:\"\\uD800\\n\"}", "unpaired high surrogate");
   1145   TestError(
   1146     "table T { F:string; }"
   1147     "root_type T;"
   1148     "{ F:\"\\uD800\\uD800\"}", "multiple high surrogates");
   1149   TestError(
   1150     "table T { F:string; }"
   1151     "root_type T;"
   1152     "{ F:\"\\uDC00\"}", "unpaired low surrogate");
   1153 }
   1154 
   1155 void InvalidUTF8Test() {
   1156   // "1 byte" pattern, under min length of 2 bytes
   1157   TestError(
   1158     "table T { F:string; }"
   1159     "root_type T;"
   1160     "{ F:\"\x80\"}", "illegal UTF-8 sequence");
   1161   // 2 byte pattern, string too short
   1162   TestError(
   1163     "table T { F:string; }"
   1164     "root_type T;"
   1165     "{ F:\"\xDF\"}", "illegal UTF-8 sequence");
   1166   // 3 byte pattern, string too short
   1167   TestError(
   1168     "table T { F:string; }"
   1169     "root_type T;"
   1170     "{ F:\"\xEF\xBF\"}", "illegal UTF-8 sequence");
   1171   // 4 byte pattern, string too short
   1172   TestError(
   1173     "table T { F:string; }"
   1174     "root_type T;"
   1175     "{ F:\"\xF7\xBF\xBF\"}", "illegal UTF-8 sequence");
   1176   // "5 byte" pattern, string too short
   1177   TestError(
   1178     "table T { F:string; }"
   1179     "root_type T;"
   1180     "{ F:\"\xFB\xBF\xBF\xBF\"}", "illegal UTF-8 sequence");
   1181   // "6 byte" pattern, string too short
   1182   TestError(
   1183     "table T { F:string; }"
   1184     "root_type T;"
   1185     "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}", "illegal UTF-8 sequence");
   1186   // "7 byte" pattern, string too short
   1187   TestError(
   1188     "table T { F:string; }"
   1189     "root_type T;"
   1190     "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}", "illegal UTF-8 sequence");
   1191   // "5 byte" pattern, over max length of 4 bytes
   1192   TestError(
   1193     "table T { F:string; }"
   1194     "root_type T;"
   1195     "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}", "illegal UTF-8 sequence");
   1196   // "6 byte" pattern, over max length of 4 bytes
   1197   TestError(
   1198     "table T { F:string; }"
   1199     "root_type T;"
   1200     "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}", "illegal UTF-8 sequence");
   1201   // "7 byte" pattern, over max length of 4 bytes
   1202   TestError(
   1203     "table T { F:string; }"
   1204     "root_type T;"
   1205     "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}", "illegal UTF-8 sequence");
   1206 
   1207   // Three invalid encodings for U+000A (\n, aka NEWLINE)
   1208   TestError(
   1209     "table T { F:string; }"
   1210     "root_type T;"
   1211     "{ F:\"\xC0\x8A\"}", "illegal UTF-8 sequence");
   1212   TestError(
   1213     "table T { F:string; }"
   1214     "root_type T;"
   1215     "{ F:\"\xE0\x80\x8A\"}", "illegal UTF-8 sequence");
   1216   TestError(
   1217     "table T { F:string; }"
   1218     "root_type T;"
   1219     "{ F:\"\xF0\x80\x80\x8A\"}", "illegal UTF-8 sequence");
   1220 
   1221   // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
   1222   TestError(
   1223     "table T { F:string; }"
   1224     "root_type T;"
   1225     "{ F:\"\xE0\x81\xA9\"}", "illegal UTF-8 sequence");
   1226   TestError(
   1227     "table T { F:string; }"
   1228     "root_type T;"
   1229     "{ F:\"\xF0\x80\x81\xA9\"}", "illegal UTF-8 sequence");
   1230 
   1231   // Invalid encoding for U+20AC (EURO SYMBOL)
   1232   TestError(
   1233     "table T { F:string; }"
   1234     "root_type T;"
   1235     "{ F:\"\xF0\x82\x82\xAC\"}", "illegal UTF-8 sequence");
   1236 
   1237   // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in UTF-8
   1238   TestError(
   1239     "table T { F:string; }"
   1240     "root_type T;"
   1241     // U+10400 "encoded" as U+D801 U+DC00
   1242     "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}", "illegal UTF-8 sequence");
   1243 }
   1244 
   1245 void UnknownFieldsTest() {
   1246   flatbuffers::IDLOptions opts;
   1247   opts.skip_unexpected_fields_in_json = true;
   1248   flatbuffers::Parser parser(opts);
   1249 
   1250   TEST_EQ(parser.Parse("table T { str:string; i:int;}"
   1251                        "root_type T;"
   1252                        "{ str:\"test\","
   1253                        "unknown_string:\"test\","
   1254                        "\"unknown_string\":\"test\","
   1255                        "unknown_int:10,"
   1256                        "unknown_float:1.0,"
   1257                        "unknown_array: [ 1, 2, 3, 4],"
   1258                        "unknown_object: { i: 10 },"
   1259                        "\"unknown_object\": { \"i\": 10 },"
   1260                        "i:10}"), true);
   1261 
   1262   std::string jsongen;
   1263   parser.opts.indent_step = -1;
   1264   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
   1265   TEST_EQ(result, true);
   1266   TEST_EQ(jsongen == "{str: \"test\",i: 10}", true);
   1267 }
   1268 
   1269 void ParseUnionTest() {
   1270   // Unions must be parseable with the type field following the object.
   1271   flatbuffers::Parser parser;
   1272   TEST_EQ(parser.Parse("table T { A:int; }"
   1273                        "union U { T }"
   1274                        "table V { X:U; }"
   1275                        "root_type V;"
   1276                        "{ X:{ A:1 }, X_type: T }"), true);
   1277   // Unions must be parsable with prefixed namespace.
   1278   flatbuffers::Parser parser2;
   1279   TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
   1280                         "table B { e:U; } root_type B;"
   1281                         "{ e_type: N_A, e: {} }"), true);
   1282 }
   1283 
   1284 void UnionVectorTest() {
   1285   // load FlatBuffer fbs schema.
   1286   // TODO: load a JSON file with such a vector when JSON support is ready.
   1287   std::string schemafile;
   1288   TEST_EQ(flatbuffers::LoadFile(
   1289     "tests/union_vector/union_vector.fbs", false, &schemafile), true);
   1290 
   1291   // parse schema.
   1292   flatbuffers::IDLOptions idl_opts;
   1293   idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kCpp;
   1294   flatbuffers::Parser parser(idl_opts);
   1295   const char *include_directories[] = { "tests/union_vector", nullptr };
   1296   TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
   1297 
   1298   flatbuffers::FlatBufferBuilder fbb;
   1299 
   1300   // union types.
   1301   std::vector<uint8_t> types;
   1302   types.push_back(static_cast<uint8_t>(Character_Belle));
   1303   types.push_back(static_cast<uint8_t>(Character_Rapunzel));
   1304   types.push_back(static_cast<uint8_t>(Character_MuLan));
   1305 
   1306   // union values.
   1307   std::vector<flatbuffers::Offset<void>> characters;
   1308   characters.push_back(CreateBelle(fbb, /*books_read=*/7).Union());
   1309   characters.push_back(CreateRapunzel(fbb, /*hair_length=*/6).Union());
   1310   characters.push_back(CreateMuLan(fbb, /*sword_attack_damage=*/5).Union());
   1311 
   1312   // create Movie.
   1313   const auto movie_offset =
   1314       CreateMovie(fbb, fbb.CreateVector(types), fbb.CreateVector(characters));
   1315   FinishMovieBuffer(fbb, movie_offset);
   1316   uint8_t *buf = fbb.GetBufferPointer();
   1317 
   1318   flatbuffers::Verifier verifier(buf, fbb.GetSize());
   1319   TEST_EQ(VerifyMovieBuffer(verifier), true);
   1320 
   1321   const Movie *movie = GetMovie(buf);
   1322   TEST_EQ(movie->characters_type()->size(), 3);
   1323   TEST_EQ(
   1324       movie->characters_type()->GetEnum<Character>(0) == Character_Belle,
   1325       true);
   1326   TEST_EQ(
   1327       movie->characters_type()->GetEnum<Character>(1) == Character_Rapunzel,
   1328       true);
   1329   TEST_EQ(
   1330       movie->characters_type()->GetEnum<Character>(2) == Character_MuLan,
   1331       true);
   1332 
   1333   TEST_EQ(movie->characters()->size(), 3);
   1334   const Belle *belle =
   1335       reinterpret_cast<const Belle*>(movie->characters()->Get(0));
   1336   TEST_EQ(belle->books_read(), 7);
   1337   const Rapunzel *rapunzel =
   1338       reinterpret_cast<const Rapunzel*>(movie->characters()->Get(1));
   1339   TEST_EQ(rapunzel->hair_length(), 6);
   1340   const MuLan *mu_lan =
   1341       reinterpret_cast<const MuLan*>(movie->characters()->Get(2));
   1342   TEST_EQ(mu_lan->sword_attack_damage(), 5);
   1343 }
   1344 
   1345 void ConformTest() {
   1346   flatbuffers::Parser parser;
   1347   TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
   1348 
   1349   auto test_conform = [&](const char *test, const char *expected_err) {
   1350     flatbuffers::Parser parser2;
   1351     TEST_EQ(parser2.Parse(test), true);
   1352     auto err = parser2.ConformTo(parser);
   1353     TEST_NOTNULL(strstr(err.c_str(), expected_err));
   1354   };
   1355 
   1356   test_conform("table T { A:byte; }", "types differ for field");
   1357   test_conform("table T { B:int; A:int; }", "offsets differ for field");
   1358   test_conform("table T { A:int = 1; }", "defaults differ for field");
   1359   test_conform("table T { B:float; }", "field renamed to different type");
   1360   test_conform("enum E:byte { B, A }", "values differ for enum");
   1361 }
   1362 
   1363 void FlexBuffersTest() {
   1364   flexbuffers::Builder slb(512,
   1365                            flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
   1366 
   1367   // Write the equivalent of:
   1368   // { vec: [ -100, "Fred", 4.0 ], bar: [ 1, 2, 3 ], foo: 100 }
   1369   slb.Map([&]() {
   1370      slb.Vector("vec", [&]() {
   1371       slb += -100;  // Equivalent to slb.Add(-100) or slb.Int(-100);
   1372       slb += "Fred";
   1373       slb.IndirectFloat(4.0f);
   1374     });
   1375     int ints[] = { 1, 2, 3 };
   1376     slb.Vector("bar", ints, 3);
   1377     slb.FixedTypedVector("bar3", ints, 3);
   1378     slb.Double("foo", 100);
   1379     slb.Map("mymap", [&]() {
   1380       slb.String("foo", "Fred");  // Testing key and string reuse.
   1381     });
   1382   });
   1383   slb.Finish();
   1384 
   1385   for (size_t i = 0; i < slb.GetBuffer().size(); i++)
   1386     printf("%d ", slb.GetBuffer().data()[i]);
   1387   printf("\n");
   1388 
   1389   auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
   1390   TEST_EQ(map.size(), 5);
   1391   auto vec = map["vec"].AsVector();
   1392   TEST_EQ(vec.size(), 3);
   1393   TEST_EQ(vec[0].AsInt64(), -100);
   1394   TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
   1395   TEST_EQ(vec[1].AsInt64(), 0);  // Number parsing failed.
   1396   TEST_EQ(vec[2].AsDouble(), 4.0);
   1397   TEST_EQ(vec[2].AsString().IsTheEmptyString(), true);  // Wrong Type.
   1398   TEST_EQ_STR(vec[2].AsString().c_str(), "");  // This still works though.
   1399   TEST_EQ_STR(vec[2].ToString().c_str(), "4");  // Or have it converted.
   1400   auto tvec = map["bar"].AsTypedVector();
   1401   TEST_EQ(tvec.size(), 3);
   1402   TEST_EQ(tvec[2].AsInt8(), 3);
   1403   auto tvec3 = map["bar3"].AsFixedTypedVector();
   1404   TEST_EQ(tvec3.size(), 3);
   1405   TEST_EQ(tvec3[2].AsInt8(), 3);
   1406   TEST_EQ(map["foo"].AsUInt8(), 100);
   1407   TEST_EQ(map["unknown"].IsNull(), true);
   1408   auto mymap = map["mymap"].AsMap();
   1409   // These should be equal by pointer equality, since key and value are shared.
   1410   TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[2].AsKey());
   1411   TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
   1412   // We can mutate values in the buffer.
   1413   TEST_EQ(vec[0].MutateInt(-99), true);
   1414   TEST_EQ(vec[0].AsInt64(), -99);
   1415   TEST_EQ(vec[1].MutateString("John"), true);  // Size must match.
   1416   TEST_EQ_STR(vec[1].AsString().c_str(), "John");
   1417   TEST_EQ(vec[1].MutateString("Alfred"), false);  // Too long.
   1418   TEST_EQ(vec[2].MutateFloat(2.0f), true);
   1419   TEST_EQ(vec[2].AsFloat(), 2.0f);
   1420   TEST_EQ(vec[2].MutateFloat(3.14159), false);  // Double does not fit in float.
   1421 }
   1422 
   1423 int main(int /*argc*/, const char * /*argv*/[]) {
   1424   // Run our various test suites:
   1425 
   1426   std::string rawbuf;
   1427   auto flatbuf = CreateFlatBufferTest(rawbuf);
   1428   AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
   1429                        rawbuf.length());
   1430   AccessFlatBufferTest(flatbuf.get(), rawbuf.length());
   1431 
   1432   MutateFlatBuffersTest(flatbuf.get(), rawbuf.length());
   1433 
   1434   ObjectFlatBuffersTest(flatbuf.get());
   1435 
   1436   SizePrefixedTest();
   1437 
   1438   #ifndef FLATBUFFERS_NO_FILE_TESTS
   1439   ParseAndGenerateTextTest();
   1440   ReflectionTest(flatbuf.get(), rawbuf.length());
   1441   ParseProtoTest();
   1442   UnionVectorTest();
   1443   #endif
   1444 
   1445   FuzzTest1();
   1446   FuzzTest2();
   1447 
   1448   ErrorTest();
   1449   ValueTest();
   1450   EnumStringsTest();
   1451   IntegerOutOfRangeTest();
   1452   UnicodeTest();
   1453   UnicodeTestAllowNonUTF8();
   1454   UnicodeTestGenerateTextFailsOnNonUTF8();
   1455   UnicodeSurrogatesTest();
   1456   UnicodeInvalidSurrogatesTest();
   1457   InvalidUTF8Test();
   1458   UnknownFieldsTest();
   1459   ParseUnionTest();
   1460   ConformTest();
   1461 
   1462   FlexBuffersTest();
   1463 
   1464   if (!testing_fails) {
   1465     TEST_OUTPUT_LINE("ALL TESTS PASSED");
   1466     return 0;
   1467   } else {
   1468     TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
   1469     return 1;
   1470   }
   1471 }
   1472 
   1473