...

Text file src/github.com/google/flatbuffers/tests/test.cpp

Documentation: github.com/google/flatbuffers/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#include <stdint.h>
    17
    18#include <cmath>
    19#include <limits>
    20#include <memory>
    21#include <string>
    22
    23#include "alignment_test.h"
    24#include "evolution_test.h"
    25#include "flatbuffers/flatbuffers.h"
    26#include "flatbuffers/idl.h"
    27#include "flatbuffers/minireflect.h"
    28#include "flatbuffers/reflection_generated.h"
    29#include "flatbuffers/registry.h"
    30#include "flatbuffers/util.h"
    31#include "fuzz_test.h"
    32#include "json_test.h"
    33#include "key_field_test.h"
    34#include "monster_test.h"
    35#include "monster_test_generated.h"
    36#include "native_inline_table_test_generated.h"
    37#include "optional_scalars_test.h"
    38#include "parser_test.h"
    39#include "proto_test.h"
    40#include "reflection_test.h"
    41#include "union_vector/union_vector_generated.h"
    42#include "union_underlying_type_test_generated.h"
    43#if !defined(_MSC_VER) || _MSC_VER >= 1700
    44#  include "arrays_test_generated.h"
    45#endif
    46#include "64bit/offset64_test.h"
    47#include "flexbuffers_test.h"
    48#include "is_quiet_nan.h"
    49#include "monster_test_bfbs_generated.h"  // Generated using --bfbs-comments --bfbs-builtins --cpp --bfbs-gen-embed
    50#include "native_type_test_generated.h"
    51#include "test_assert.h"
    52#include "util_test.h"
    53
    54void FlatBufferBuilderTest();
    55
    56namespace flatbuffers {
    57namespace tests {
    58namespace {
    59
    60// clang-format off
    61// Check that char* and uint8_t* are interoperable types.
    62// The reinterpret_cast<> between the pointers are used to simplify data loading.
    63static_assert(flatbuffers::is_same<uint8_t, char>::value ||
    64              flatbuffers::is_same<uint8_t, unsigned char>::value,
    65              "unexpected uint8_t type");
    66
    67#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
    68  // Ensure IEEE-754 support if tests of floats with NaN/Inf will run.
    69  static_assert(std::numeric_limits<float>::is_iec559 &&
    70                std::numeric_limits<double>::is_iec559,
    71                "IEC-559 (IEEE-754) standard required");
    72#endif
    73// clang-format on
    74
    75using namespace MyGame::Example;
    76
    77void TriviallyCopyableTest() {
    78  // clang-format off
    79  #if __GNUG__ && __GNUC__ < 5 && \
    80      !(defined(__clang__) && __clang_major__ >= 16)
    81    TEST_EQ(__has_trivial_copy(Vec3), true);
    82  #else
    83    #if __cplusplus >= 201103L
    84      TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
    85    #endif
    86  #endif
    87  // clang-format on
    88}
    89
    90// Guard against -Wunused-function on platforms without file tests.
    91#ifndef FLATBUFFERS_NO_FILE_TESTS
    92void GenerateTableTextTest(const std::string &tests_data_path) {
    93  std::string schemafile;
    94  std::string jsonfile;
    95  bool ok =
    96      flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(),
    97                            false, &schemafile) &&
    98      flatbuffers::LoadFile((tests_data_path + "monsterdata_test.json").c_str(),
    99                            false, &jsonfile);
   100  TEST_EQ(ok, true);
   101  auto include_test_path =
   102      flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
   103  const char *include_directories[] = { tests_data_path.c_str(),
   104                                        include_test_path.c_str(), nullptr };
   105  flatbuffers::IDLOptions opt;
   106  opt.indent_step = -1;
   107  flatbuffers::Parser parser(opt);
   108  ok = parser.Parse(schemafile.c_str(), include_directories) &&
   109       parser.Parse(jsonfile.c_str(), include_directories);
   110  TEST_EQ(ok, true);
   111  // Test root table
   112  const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
   113  const auto abilities = monster->testarrayofsortedstruct();
   114  TEST_EQ(abilities->size(), 3);
   115  TEST_EQ(abilities->Get(0)->id(), 0);
   116  TEST_EQ(abilities->Get(0)->distance(), 45);
   117  TEST_EQ(abilities->Get(1)->id(), 1);
   118  TEST_EQ(abilities->Get(1)->distance(), 21);
   119  TEST_EQ(abilities->Get(2)->id(), 5);
   120  TEST_EQ(abilities->Get(2)->distance(), 12);
   121
   122  std::string jsongen;
   123  auto result = GenTextFromTable(parser, monster, "MyGame.Example.Monster",
   124                                      &jsongen);
   125  TEST_NULL(result);
   126  // Test sub table
   127  const Vec3 *pos = monster->pos();
   128  jsongen.clear();
   129  result = GenTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
   130  TEST_NULL(result);
   131  TEST_EQ_STR(
   132      jsongen.c_str(),
   133      "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
   134  const Test &test3 = pos->test3();
   135  jsongen.clear();
   136  result =
   137      GenTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
   138  TEST_NULL(result);
   139  TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
   140  const Test *test4 = monster->test4()->Get(0);
   141  jsongen.clear();
   142  result =
   143      GenTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
   144  TEST_NULL(result);
   145  TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
   146}
   147
   148void MultiFileNameClashTest(const std::string &tests_data_path) {
   149  const auto name_clash_path =
   150      flatbuffers::ConCatPathFileName(tests_data_path, "name_clash_test");
   151  const char *include_directories[] = { name_clash_path.c_str() };
   152
   153  // Load valid 2 file Flatbuffer schema
   154  const auto valid_path =
   155      flatbuffers::ConCatPathFileName(name_clash_path, "valid_test1.fbs");
   156  std::string valid_schema;
   157  TEST_ASSERT(flatbuffers::LoadFile(valid_path.c_str(), false, &valid_schema));
   158  // Clashing table and union names in different namespaces must be parsable
   159  TEST_ASSERT(
   160      flatbuffers::Parser().Parse(valid_schema.c_str(), include_directories));
   161
   162  flatbuffers::Parser p;
   163  TEST_ASSERT(p.Parse(valid_schema.c_str(), include_directories));
   164
   165  // Load invalid 2 file Flatbuffer schema
   166  const auto invalid_path =
   167      flatbuffers::ConCatPathFileName(name_clash_path, "invalid_test1.fbs");
   168  std::string invalid_schema;
   169  TEST_ASSERT(
   170      flatbuffers::LoadFile(invalid_path.c_str(), false, &invalid_schema));
   171  // Clashing table and union names in same namespace must fail to parse
   172  TEST_EQ(
   173      flatbuffers::Parser().Parse(invalid_schema.c_str(), include_directories),
   174      false);
   175}
   176
   177void InvalidNestedFlatbufferTest(const std::string &tests_data_path) {
   178  // First, load and parse FlatBuffer schema (.fbs)
   179  std::string schemafile;
   180  TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(),
   181                                false, &schemafile),
   182          true);
   183  auto include_test_path =
   184      flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
   185  const char *include_directories[] = { tests_data_path.c_str(),
   186                                        include_test_path.c_str(), nullptr };
   187  flatbuffers::Parser parser1;
   188  TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
   189
   190  // "color" inside nested flatbuffer contains invalid enum value
   191  TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
   192                        "\"Leela\", color: \"nonexistent\"}}"),
   193          false);
   194}
   195
   196void UnionVectorTest(const std::string &tests_data_path) {
   197  // load FlatBuffer fbs schema and json.
   198  std::string schemafile, jsonfile;
   199  TEST_EQ(flatbuffers::LoadFile(
   200              (tests_data_path + "union_vector/union_vector.fbs").c_str(),
   201              false, &schemafile),
   202          true);
   203  TEST_EQ(flatbuffers::LoadFile(
   204              (tests_data_path + "union_vector/union_vector.json").c_str(),
   205              false, &jsonfile),
   206          true);
   207
   208  // parse schema.
   209  flatbuffers::IDLOptions idl_opts;
   210  idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
   211  flatbuffers::Parser parser(idl_opts);
   212  TEST_EQ(parser.Parse(schemafile.c_str()), true);
   213
   214  flatbuffers::FlatBufferBuilder fbb;
   215
   216  // union types.
   217  std::vector<uint8_t> types;
   218  types.push_back(static_cast<uint8_t>(Character_Belle));
   219  types.push_back(static_cast<uint8_t>(Character_MuLan));
   220  types.push_back(static_cast<uint8_t>(Character_BookFan));
   221  types.push_back(static_cast<uint8_t>(Character_Other));
   222  types.push_back(static_cast<uint8_t>(Character_Unused));
   223
   224  // union values.
   225  std::vector<flatbuffers::Offset<void>> characters;
   226  characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
   227  characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
   228  characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
   229  characters.push_back(fbb.CreateString("Other").Union());
   230  characters.push_back(fbb.CreateString("Unused").Union());
   231
   232  // create Movie.
   233  const auto movie_offset =
   234      CreateMovie(fbb, Character_Rapunzel,
   235                  fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
   236                  fbb.CreateVector(types), fbb.CreateVector(characters));
   237  FinishMovieBuffer(fbb, movie_offset);
   238
   239  flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
   240  TEST_EQ(VerifyMovieBuffer(verifier), true);
   241
   242  auto flat_movie = GetMovie(fbb.GetBufferPointer());
   243
   244  auto TestMovie = [](const Movie *movie) {
   245    TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
   246
   247    auto cts = movie->characters_type();
   248    TEST_EQ(movie->characters_type()->size(), 5);
   249    TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
   250    TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
   251    TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
   252    TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
   253    TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
   254
   255    auto rapunzel = movie->main_character_as_Rapunzel();
   256    TEST_NOTNULL(rapunzel);
   257    TEST_EQ(rapunzel->hair_length(), 6);
   258
   259    auto cs = movie->characters();
   260    TEST_EQ(cs->size(), 5);
   261    auto belle = cs->GetAs<BookReader>(0);
   262    TEST_EQ(belle->books_read(), 7);
   263    auto mu_lan = cs->GetAs<Attacker>(1);
   264    TEST_EQ(mu_lan->sword_attack_damage(), 5);
   265    auto book_fan = cs->GetAs<BookReader>(2);
   266    TEST_EQ(book_fan->books_read(), 2);
   267    auto other = cs->GetAsString(3);
   268    TEST_EQ_STR(other->c_str(), "Other");
   269    auto unused = cs->GetAsString(4);
   270    TEST_EQ_STR(unused->c_str(), "Unused");
   271  };
   272
   273  TestMovie(flat_movie);
   274
   275  // Also test the JSON we loaded above.
   276  TEST_EQ(parser.Parse(jsonfile.c_str()), true);
   277  auto jbuf = parser.builder_.GetBufferPointer();
   278  flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
   279  TEST_EQ(VerifyMovieBuffer(jverifier), true);
   280  TestMovie(GetMovie(jbuf));
   281
   282  auto movie_object = flat_movie->UnPack();
   283  TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
   284  TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
   285  TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
   286  TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
   287  TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
   288  TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
   289
   290  fbb.Clear();
   291  fbb.Finish(Movie::Pack(fbb, movie_object));
   292
   293  delete movie_object;
   294
   295  auto repacked_movie = GetMovie(fbb.GetBufferPointer());
   296
   297  TestMovie(repacked_movie);
   298
   299  // Generate text using mini-reflection.
   300  auto s =
   301      flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
   302  TEST_EQ_STR(
   303      s.c_str(),
   304      "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
   305      "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
   306      "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
   307      "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
   308
   309  flatbuffers::ToStringVisitor visitor("\n", true, "  ");
   310  IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
   311  TEST_EQ_STR(visitor.s.c_str(),
   312              "{\n"
   313              "  \"main_character_type\": \"Rapunzel\",\n"
   314              "  \"main_character\": {\n"
   315              "    \"hair_length\": 6\n"
   316              "  },\n"
   317              "  \"characters_type\": [\n"
   318              "    \"Belle\",\n"
   319              "    \"MuLan\",\n"
   320              "    \"BookFan\",\n"
   321              "    \"Other\",\n"
   322              "    \"Unused\"\n"
   323              "  ],\n"
   324              "  \"characters\": [\n"
   325              "    {\n"
   326              "      \"books_read\": 7\n"
   327              "    },\n"
   328              "    {\n"
   329              "      \"sword_attack_damage\": 5\n"
   330              "    },\n"
   331              "    {\n"
   332              "      \"books_read\": 2\n"
   333              "    },\n"
   334              "    \"Other\",\n"
   335              "    \"Unused\"\n"
   336              "  ]\n"
   337              "}");
   338
   339  // Generate text using parsed schema.
   340  std::string jsongen;
   341  auto result = GenText(parser, fbb.GetBufferPointer(), &jsongen);
   342  TEST_NULL(result);
   343  TEST_EQ_STR(jsongen.c_str(),
   344              "{\n"
   345              "  main_character_type: \"Rapunzel\",\n"
   346              "  main_character: {\n"
   347              "    hair_length: 6\n"
   348              "  },\n"
   349              "  characters_type: [\n"
   350              "    \"Belle\",\n"
   351              "    \"MuLan\",\n"
   352              "    \"BookFan\",\n"
   353              "    \"Other\",\n"
   354              "    \"Unused\"\n"
   355              "  ],\n"
   356              "  characters: [\n"
   357              "    {\n"
   358              "      books_read: 7\n"
   359              "    },\n"
   360              "    {\n"
   361              "      sword_attack_damage: 5\n"
   362              "    },\n"
   363              "    {\n"
   364              "      books_read: 2\n"
   365              "    },\n"
   366              "    \"Other\",\n"
   367              "    \"Unused\"\n"
   368              "  ]\n"
   369              "}\n");
   370
   371  // Simple test with reflection.
   372  parser.Serialize();
   373  auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
   374  auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
   375                                fbb.GetBufferPointer(), fbb.GetSize());
   376  TEST_EQ(ok, true);
   377
   378  flatbuffers::Parser parser2(idl_opts);
   379  TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
   380                        "union Any { Bool }"
   381                        "table Root { a:Any; }"
   382                        "root_type Root;"),
   383          true);
   384  TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
   385}
   386#endif
   387
   388void EndianSwapTest() {
   389  TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
   390  TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
   391          0x78563412);
   392  TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
   393          0xEFCDAB9078563412);
   394  TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
   395}
   396
   397void UninitializedVectorTest() {
   398  flatbuffers::FlatBufferBuilder builder;
   399
   400  Test *buf = nullptr;
   401  auto vector_offset =
   402      builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
   403  TEST_NOTNULL(buf);
   404  buf[0] = Test(10, 20);
   405  buf[1] = Test(30, 40);
   406
   407  auto required_name = builder.CreateString("myMonster");
   408  auto monster_builder = MonsterBuilder(builder);
   409  monster_builder.add_name(
   410      required_name);  // required field mandated for monster.
   411  monster_builder.add_test4(vector_offset);
   412  builder.Finish(monster_builder.Finish());
   413
   414  auto p = builder.GetBufferPointer();
   415  auto uvt = flatbuffers::GetRoot<Monster>(p);
   416  TEST_NOTNULL(uvt);
   417  auto vec = uvt->test4();
   418  TEST_NOTNULL(vec);
   419  auto test_0 = vec->Get(0);
   420  auto test_1 = vec->Get(1);
   421  TEST_EQ(test_0->a(), 10);
   422  TEST_EQ(test_0->b(), 20);
   423  TEST_EQ(test_1->a(), 30);
   424  TEST_EQ(test_1->b(), 40);
   425}
   426
   427void EqualOperatorTest() {
   428  MonsterT a;
   429  MonsterT b;
   430  // We have to reset the fields that are NaN to zero to allow the equality
   431  // to evaluate to true.
   432  TEST_EQ(std::isnan(a.nan_default), true);
   433  TEST_EQ(std::isnan(b.nan_default), true);
   434  a.nan_default = 0;
   435  b.nan_default = 0;
   436  TEST_EQ(b == a, true);
   437  TEST_EQ(b != a, false);
   438
   439  b.mana = 33;
   440  TEST_EQ(b == a, false);
   441  TEST_EQ(b != a, true);
   442  b.mana = 150;
   443  TEST_EQ(b == a, true);
   444  TEST_EQ(b != a, false);
   445
   446  b.inventory.push_back(3);
   447  TEST_EQ(b == a, false);
   448  TEST_EQ(b != a, true);
   449  b.inventory.clear();
   450  TEST_EQ(b == a, true);
   451  TEST_EQ(b != a, false);
   452
   453  a.enemy.reset(new MonsterT());
   454  a.enemy->nan_default = 0;
   455  TEST_EQ(b != a, true);
   456  a.enemy->mana = 33;
   457  TEST_EQ(b == a, false);
   458  TEST_EQ(b != a, true);
   459
   460  b.enemy.reset(new MonsterT());
   461  b.enemy->nan_default = 0;
   462  TEST_EQ(b == a, false);
   463  TEST_EQ(b != a, true);
   464  b.enemy->mana = 33;
   465  TEST_EQ(b == a, true);
   466  TEST_EQ(b != a, false);
   467
   468  a.enemy.reset(nullptr);
   469  TEST_EQ(b == a, false);
   470  TEST_EQ(b != a, true);
   471  b.enemy->mana = 150;
   472  TEST_EQ(b == a, false);
   473  TEST_EQ(b != a, true);
   474  a.enemy.reset(new MonsterT());
   475  a.enemy->nan_default = 0;
   476  TEST_EQ(b == a, true);
   477  TEST_EQ(b != a, false);
   478
   479  b.enemy.reset(nullptr);
   480
   481  b.test.type = Any_Monster;
   482  TEST_EQ(b == a, false);
   483  TEST_EQ(b != a, true);
   484
   485  // Test that vector of tables are compared by value and not by reference.
   486  {
   487    // Two tables are equal by default.
   488    MonsterT a, b;
   489    a.nan_default = 0;
   490    b.nan_default = 0;
   491    TEST_EQ(a == b, true);
   492
   493    // Adding only a table to one of the monster vectors should make it not
   494    // equal (due to size mistmatch).
   495    a.testarrayoftables.push_back(
   496        flatbuffers::unique_ptr<MonsterT>(new MonsterT));
   497    a.testarrayoftables.back()->nan_default = 0;
   498    TEST_EQ(a == b, false);
   499
   500    // Adding an equalivant table to the other monster vector should make it
   501    // equal again.
   502    b.testarrayoftables.push_back(
   503        flatbuffers::unique_ptr<MonsterT>(new MonsterT));
   504    b.testarrayoftables.back()->nan_default = 0;
   505    TEST_EQ(a == b, true);
   506
   507    // Create two new monsters that are different.
   508    auto c = flatbuffers::unique_ptr<MonsterT>(new MonsterT);
   509    auto d = flatbuffers::unique_ptr<MonsterT>(new MonsterT);
   510    c->nan_default = 0;
   511    d->nan_default = 0;
   512    c->hp = 1;
   513    d->hp = 2;
   514    TEST_EQ(c == d, false);
   515
   516    // Adding them to the original monsters should also make them different.
   517    a.testarrayoftables.push_back(std::move(c));
   518    b.testarrayoftables.push_back(std::move(d));
   519    TEST_EQ(a == b, false);
   520
   521    // Remove the mismatching monsters to get back to equality
   522    a.testarrayoftables.pop_back();
   523    b.testarrayoftables.pop_back();
   524    TEST_EQ(a == b, true);
   525
   526    // Check that nullptr are OK.
   527    a.testarrayoftables.push_back(nullptr);
   528    b.testarrayoftables.push_back(
   529        flatbuffers::unique_ptr<MonsterT>(new MonsterT));
   530    TEST_EQ(a == b, false);
   531  }
   532}
   533
   534void CreateSharedStringTest() {
   535  flatbuffers::FlatBufferBuilder builder;
   536  const auto one1 = builder.CreateSharedString("one");
   537  const auto two = builder.CreateSharedString("two");
   538  const auto one2 = builder.CreateSharedString("one");
   539  TEST_EQ(one1.o, one2.o);
   540  const auto onetwo = builder.CreateSharedString("onetwo");
   541  TEST_EQ(onetwo.o != one1.o, true);
   542  TEST_EQ(onetwo.o != two.o, true);
   543
   544  // Support for embedded nulls
   545  const char chars_b[] = { 'a', '\0', 'b' };
   546  const char chars_c[] = { 'a', '\0', 'c' };
   547  const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
   548  const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
   549  const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
   550  TEST_EQ(null_b1.o != null_c.o, true);  // Issue#5058 repro
   551  TEST_EQ(null_b1.o, null_b2.o);
   552
   553  // Put the strings into an array for round trip verification.
   554  std::array<flatbuffers::Offset<flatbuffers::String>, 7> array = {
   555    one1, two, one2, onetwo, null_b1, null_c, null_b2
   556  };
   557  const auto vector_offset =
   558      builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(array);
   559  MonsterBuilder monster_builder(builder);
   560  monster_builder.add_name(two);
   561  monster_builder.add_testarrayofstring(vector_offset);
   562  builder.Finish(monster_builder.Finish());
   563
   564  // Read the Monster back.
   565  const auto *monster =
   566      flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
   567  TEST_EQ_STR(monster->name()->c_str(), "two");
   568  const auto *testarrayofstring = monster->testarrayofstring();
   569  TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
   570  const auto &a = *testarrayofstring;
   571  TEST_EQ_STR(a[0]->c_str(), "one");
   572  TEST_EQ_STR(a[1]->c_str(), "two");
   573  TEST_EQ_STR(a[2]->c_str(), "one");
   574  TEST_EQ_STR(a[3]->c_str(), "onetwo");
   575  TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
   576  TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
   577  TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
   578
   579  // Make sure String::operator< works, too, since it is related to
   580  // StringOffsetCompare.
   581  TEST_EQ((*a[0]) < (*a[1]), true);
   582  TEST_EQ((*a[1]) < (*a[0]), false);
   583  TEST_EQ((*a[1]) < (*a[2]), false);
   584  TEST_EQ((*a[2]) < (*a[1]), true);
   585  TEST_EQ((*a[4]) < (*a[3]), true);
   586  TEST_EQ((*a[5]) < (*a[4]), false);
   587  TEST_EQ((*a[5]) < (*a[4]), false);
   588  TEST_EQ((*a[6]) < (*a[5]), true);
   589}
   590
   591#if !defined(FLATBUFFERS_USE_STD_SPAN) && !defined(FLATBUFFERS_SPAN_MINIMAL)
   592void FlatbuffersSpanTest() {
   593  // Compile-time checking of non-const [] to const [] conversions.
   594  using flatbuffers::internal::is_span_convertible;
   595  (void)is_span_convertible<int, 1, int, 1>::type(123);
   596  (void)is_span_convertible<const int, 1, int, 1>::type(123);
   597  (void)is_span_convertible<const int64_t, 1, int64_t, 1>::type(123);
   598  (void)is_span_convertible<const uint64_t, 1, uint64_t, 1>::type(123);
   599  (void)is_span_convertible<const int, 1, const int, 1>::type(123);
   600  (void)is_span_convertible<const int64_t, 1, const int64_t, 1>::type(123);
   601  (void)is_span_convertible<const uint64_t, 1, const uint64_t, 1>::type(123);
   602
   603  using flatbuffers::span;
   604  span<char, 0> c1;
   605  TEST_EQ(c1.size(), 0);
   606  span<char, flatbuffers::dynamic_extent> c2;
   607  TEST_EQ(c2.size(), 0);
   608  span<char> c3;
   609  TEST_EQ(c3.size(), 0);
   610  TEST_ASSERT(c1.empty() && c2.empty() && c3.empty());
   611
   612  int i_data7[7] = { 0, 1, 2, 3, 4, 5, 6 };
   613  span<int, 7> i1(&i_data7[0], 7);
   614  span<int> i2(i1);  // make dynamic from static
   615  TEST_EQ(i1.size(), 7);
   616  TEST_EQ(i1.empty(), false);
   617  TEST_EQ(i1.size(), i2.size());
   618  TEST_EQ(i1.data(), i_data7);
   619  TEST_EQ(i1[2], 2);
   620  // Make const span from a non-const one.
   621  span<const int, 7> i3(i1);
   622  // Construct from a C-array.
   623  span<int, 7> i4(i_data7);
   624  span<const int, 7> i5(i_data7);
   625  span<int> i6(i_data7);
   626  span<const int> i7(i_data7);
   627  TEST_EQ(i7.size(), 7);
   628  // Check construction from a const array.
   629  const int i_cdata5[5] = { 4, 3, 2, 1, 0 };
   630  span<const int, 5> i8(i_cdata5);
   631  span<const int> i9(i_cdata5);
   632  TEST_EQ(i9.size(), 5);
   633  // Construction from a (ptr, size) pair.
   634  span<int, 7> i10(i_data7, 7);
   635  span<int> i11(i_data7, 7);
   636  TEST_EQ(i11.size(), 7);
   637  span<const int, 5> i12(i_cdata5, 5);
   638  span<const int> i13(i_cdata5, 5);
   639  TEST_EQ(i13.size(), 5);
   640  // Construction from std::array.
   641  std::array<int, 6> i_arr6 = { { 0, 1, 2, 3, 4, 5 } };
   642  span<int, 6> i14(i_arr6);
   643  span<const int, 6> i15(i_arr6);
   644  span<int> i16(i_arr6);
   645  span<const int> i17(i_arr6);
   646  TEST_EQ(i17.size(), 6);
   647  const std::array<int, 8> i_carr8 = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
   648  span<const int, 8> i18(i_carr8);
   649  span<const int> i19(i_carr8);
   650  TEST_EQ(i18.size(), 8);
   651  TEST_EQ(i19.size(), 8);
   652  TEST_EQ(i19[7], 7);
   653  // Check compatibility with flatbuffers::Array.
   654  int fbs_int3_underlaying[3] = { 0 };
   655  int fbs_int3_data[3] = { 1, 2, 3 };
   656  auto &fbs_int3 = flatbuffers::CastToArray(fbs_int3_underlaying);
   657  fbs_int3.CopyFromSpan(fbs_int3_data);
   658  TEST_EQ(fbs_int3.Get(1), 2);
   659  const int fbs_cint3_data[3] = { 2, 3, 4 };
   660  fbs_int3.CopyFromSpan(fbs_cint3_data);
   661  TEST_EQ(fbs_int3.Get(1), 3);
   662  // Check with Array<Enum, N>
   663  enum class Dummy : uint16_t { Zero = 0, One, Two };
   664  Dummy fbs_dummy3_underlaying[3] = {};
   665  Dummy fbs_dummy3_data[3] = { Dummy::One, Dummy::Two, Dummy::Two };
   666  auto &fbs_dummy3 = flatbuffers::CastToArray(fbs_dummy3_underlaying);
   667  fbs_dummy3.CopyFromSpan(fbs_dummy3_data);
   668  TEST_EQ(fbs_dummy3.Get(1), Dummy::Two);
   669}
   670#else
   671void FlatbuffersSpanTest() {}
   672#endif
   673
   674// VS10 does not support typed enums, exclude from tests
   675#if !defined(_MSC_VER) || _MSC_VER >= 1700
   676void FixedLengthArrayTest() {
   677  // Generate an ArrayTable containing one ArrayStruct.
   678  flatbuffers::FlatBufferBuilder fbb;
   679  MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
   680  TEST_NOTNULL(nStruct0.mutable_a());
   681  nStruct0.mutable_a()->Mutate(0, 1);
   682  nStruct0.mutable_a()->Mutate(1, 2);
   683  TEST_NOTNULL(nStruct0.mutable_c());
   684  nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
   685  nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
   686  TEST_NOTNULL(nStruct0.mutable_d());
   687  nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
   688  nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
   689  MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
   690  TEST_NOTNULL(nStruct1.mutable_a());
   691  nStruct1.mutable_a()->Mutate(0, 3);
   692  nStruct1.mutable_a()->Mutate(1, 4);
   693  TEST_NOTNULL(nStruct1.mutable_c());
   694  nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
   695  nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
   696  TEST_NOTNULL(nStruct1.mutable_d());
   697  nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
   698  nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
   699  MyGame::Example::ArrayStruct aStruct(2, 12, 1);
   700  TEST_NOTNULL(aStruct.b());
   701  TEST_NOTNULL(aStruct.mutable_b());
   702  TEST_NOTNULL(aStruct.mutable_d());
   703  TEST_NOTNULL(aStruct.mutable_f());
   704  for (int i = 0; i < aStruct.b()->size(); i++)
   705    aStruct.mutable_b()->Mutate(i, i + 1);
   706  aStruct.mutable_d()->Mutate(0, nStruct0);
   707  aStruct.mutable_d()->Mutate(1, nStruct1);
   708  auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
   709  MyGame::Example::FinishArrayTableBuffer(fbb, aTable);
   710  // Verify correctness of the ArrayTable.
   711  flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
   712  TEST_ASSERT(MyGame::Example::VerifyArrayTableBuffer(verifier));
   713  // Do test.
   714  auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
   715  auto mArStruct = p->mutable_a();
   716  TEST_NOTNULL(mArStruct);
   717  TEST_NOTNULL(mArStruct->b());
   718  TEST_NOTNULL(mArStruct->d());
   719  TEST_NOTNULL(mArStruct->f());
   720  TEST_NOTNULL(mArStruct->mutable_b());
   721  TEST_NOTNULL(mArStruct->mutable_d());
   722  TEST_NOTNULL(mArStruct->mutable_f());
   723  TEST_EQ(mArStruct->a(), 2);
   724  TEST_EQ(mArStruct->b()->size(), 15);
   725  mArStruct->mutable_b()->Mutate(14, -14);
   726  TEST_EQ(mArStruct->b()->Get(14), -14);
   727  TEST_EQ(mArStruct->c(), 12);
   728  TEST_NOTNULL(mArStruct->d()->Get(0));
   729  TEST_NOTNULL(mArStruct->d()->Get(0)->a());
   730  TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
   731  TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
   732  TEST_NOTNULL(mArStruct->d()->Get(1));
   733  TEST_NOTNULL(mArStruct->d()->Get(1)->a());
   734  TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
   735  TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
   736  TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
   737  TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
   738  mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
   739  TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
   740  TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
   741  TEST_NOTNULL(mArStruct->d()->Get(0)->c());
   742  TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
   743  TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
   744  TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
   745          mArStruct->d()->Get(0)->d()->Get(0));
   746  TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
   747          mArStruct->d()->Get(0)->d()->Get(1));
   748  TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
   749  TEST_NOTNULL(mArStruct->d()->Get(1)->c());
   750  TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
   751  TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
   752  TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
   753          mArStruct->d()->Get(1)->d()->Get(0));
   754  TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
   755          mArStruct->d()->Get(1)->d()->Get(1));
   756  for (int i = 0; i < mArStruct->b()->size() - 1; i++)
   757    TEST_EQ(mArStruct->b()->Get(i), i + 1);
   758  // Check alignment
   759  TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
   760  TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
   761
   762  // Check if default constructor set all memory zero
   763  const size_t arr_size = sizeof(MyGame::Example::ArrayStruct);
   764  char non_zero_memory[arr_size];
   765  // set memory chunk of size ArrayStruct to 1's
   766  std::memset(static_cast<void *>(non_zero_memory), 1, arr_size);
   767  // after placement-new it should be all 0's
   768#  if defined(_MSC_VER) && defined(_DEBUG)
   769#    undef new
   770#  endif
   771  MyGame::Example::ArrayStruct *ap =
   772      new (non_zero_memory) MyGame::Example::ArrayStruct;
   773#  if defined(_MSC_VER) && defined(_DEBUG)
   774#    define new DEBUG_NEW
   775#  endif
   776  (void)ap;
   777  for (size_t i = 0; i < arr_size; ++i) { TEST_EQ(non_zero_memory[i], 0); }
   778}
   779#else
   780void FixedLengthArrayTest() {}
   781#endif  // !defined(_MSC_VER) || _MSC_VER >= 1700
   782
   783#if !defined(FLATBUFFERS_SPAN_MINIMAL) && \
   784    (!defined(_MSC_VER) || _MSC_VER >= 1700)
   785void FixedLengthArrayConstructorTest() {
   786  const int32_t nested_a[2] = { 1, 2 };
   787  MyGame::Example::TestEnum nested_c[2] = { MyGame::Example::TestEnum::A,
   788                                            MyGame::Example::TestEnum::B };
   789  const int64_t int64_2[2] = { -2, -1 };
   790
   791  std::array<MyGame::Example::NestedStruct, 2> init_d = {
   792    { MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
   793                                    nested_c, int64_2),
   794      MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::A,
   795                                    nested_c,
   796                                    std::array<int64_t, 2>{ { 12, 13 } }) }
   797  };
   798
   799  MyGame::Example::ArrayStruct arr_struct(
   800      8.125,
   801      std::array<int32_t, 0xF>{
   802          { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
   803      -17, init_d, 10, int64_2);
   804  TEST_EQ(arr_struct.a(), 8.125);
   805  TEST_EQ(arr_struct.b()->Get(2), 3);
   806  TEST_EQ(arr_struct.c(), -17);
   807
   808  TEST_NOTNULL(arr_struct.d());
   809  const auto &arr_d_0 = *arr_struct.d()->Get(0);
   810  TEST_EQ(arr_d_0.a()->Get(0), 1);
   811  TEST_EQ(arr_d_0.a()->Get(1), 2);
   812  TEST_EQ(arr_d_0.b(), MyGame::Example::TestEnum::B);
   813  TEST_EQ(arr_d_0.c()->Get(0), MyGame::Example::TestEnum::A);
   814  TEST_EQ(arr_d_0.c()->Get(1), MyGame::Example::TestEnum::B);
   815  TEST_EQ(arr_d_0.d()->Get(0), -2);
   816  TEST_EQ(arr_d_0.d()->Get(1), -1);
   817  const auto &arr_d_1 = *arr_struct.d()->Get(1);
   818  TEST_EQ(arr_d_1.a()->Get(0), 1);
   819  TEST_EQ(arr_d_1.a()->Get(1), 2);
   820  TEST_EQ(arr_d_1.b(), MyGame::Example::TestEnum::A);
   821  TEST_EQ(arr_d_1.c()->Get(0), MyGame::Example::TestEnum::A);
   822  TEST_EQ(arr_d_1.c()->Get(1), MyGame::Example::TestEnum::B);
   823  TEST_EQ(arr_d_1.d()->Get(0), 12);
   824  TEST_EQ(arr_d_1.d()->Get(1), 13);
   825
   826  TEST_EQ(arr_struct.e(), 10);
   827  TEST_EQ(arr_struct.f()->Get(0), -2);
   828  TEST_EQ(arr_struct.f()->Get(1), -1);
   829}
   830#else
   831void FixedLengthArrayConstructorTest() {}
   832#endif
   833
   834void FixedLengthArrayOperatorEqualTest() {
   835  const int32_t nested_a[2] = { 1, 2 };
   836  MyGame::Example::TestEnum nested_c[2] = { MyGame::Example::TestEnum::A,
   837                                            MyGame::Example::TestEnum::B };
   838
   839  MyGame::Example::TestEnum nested_cc[2] = { MyGame::Example::TestEnum::A,
   840                                             MyGame::Example::TestEnum::C };
   841  const int64_t int64_2[2] = { -2, -1 };
   842
   843  std::array<MyGame::Example::NestedStruct, 2> init_d = {
   844    { MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
   845                                    nested_c, int64_2),
   846      MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
   847                                    nested_c,
   848                                    std::array<int64_t, 2>{ { -2, -1 } }) }
   849  };
   850
   851  auto different = MyGame::Example::NestedStruct(
   852      nested_a, MyGame::Example::TestEnum::B, nested_cc,
   853      std::array<int64_t, 2>{ { -2, -1 } });
   854
   855  TEST_ASSERT(init_d[0] == init_d[1]);
   856  TEST_ASSERT(init_d[0] != different);
   857
   858  std::array<MyGame::Example::ArrayStruct, 3> arr_struct = {
   859    MyGame::Example::ArrayStruct(
   860        8.125,
   861        std::array<int32_t, 0xF>{
   862            { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
   863        -17, init_d, 10, int64_2),
   864
   865    MyGame::Example::ArrayStruct(
   866        8.125,
   867        std::array<int32_t, 0xF>{
   868            { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
   869        -17, init_d, 10, int64_2),
   870
   871    MyGame::Example::ArrayStruct(
   872        8.125,
   873        std::array<int32_t, 0xF>{
   874            { 1000, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
   875        -17, init_d, 10, int64_2)
   876  };
   877
   878  TEST_ASSERT(arr_struct[0] == arr_struct[1]);
   879  TEST_ASSERT(arr_struct[1] != arr_struct[2]);
   880}
   881
   882void NativeTypeTest() {
   883  const int N = 3;
   884
   885  Geometry::ApplicationDataT src_data;
   886  src_data.vectors.reserve(N);
   887  src_data.vectors_alt.reserve(N);
   888
   889  for (int i = 0; i < N; ++i) {
   890    src_data.vectors.push_back(
   891        Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
   892    src_data.vectors_alt.push_back(
   893        Native::Vector3D(20 * i + 0.1f, 20 * i + 0.2f, 20 * i + 0.3f));
   894  }
   895
   896  flatbuffers::FlatBufferBuilder fbb;
   897  fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
   898
   899  auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
   900
   901  for (int i = 0; i < N; ++i) {
   902    const Native::Vector3D &v = dstDataT->vectors[i];
   903    TEST_EQ(v.x, 10 * i + 0.1f);
   904    TEST_EQ(v.y, 10 * i + 0.2f);
   905    TEST_EQ(v.z, 10 * i + 0.3f);
   906
   907    const Native::Vector3D &v2 = dstDataT->vectors_alt[i];
   908    TEST_EQ(v2.x, 20 * i + 0.1f);
   909    TEST_EQ(v2.y, 20 * i + 0.2f);
   910    TEST_EQ(v2.z, 20 * i + 0.3f);
   911  }
   912}
   913
   914// Guard against -Wunused-function on platforms without file tests.
   915#ifndef FLATBUFFERS_NO_FILE_TESTS
   916// VS10 does not support typed enums, exclude from tests
   917#  if !defined(_MSC_VER) || _MSC_VER >= 1700
   918void FixedLengthArrayJsonTest(const std::string &tests_data_path, bool binary) {
   919  // load FlatBuffer schema (.fbs) and JSON from disk
   920  std::string schemafile;
   921  std::string jsonfile;
   922  TEST_EQ(flatbuffers::LoadFile(
   923              (tests_data_path + "arrays_test." + (binary ? "bfbs" : "fbs"))
   924                  .c_str(),
   925              binary, &schemafile),
   926          true);
   927  TEST_EQ(
   928      flatbuffers::LoadFile((tests_data_path + "arrays_test.golden").c_str(),
   929                            false, &jsonfile),
   930      true);
   931
   932  // parse schema first, so we can use it to parse the data after
   933  flatbuffers::Parser parserOrg, parserGen;
   934  if (binary) {
   935    flatbuffers::Verifier verifier(
   936        reinterpret_cast<const uint8_t *>(schemafile.c_str()),
   937        schemafile.size());
   938    TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
   939    TEST_EQ(parserOrg.Deserialize(
   940                reinterpret_cast<const uint8_t *>(schemafile.c_str()),
   941                schemafile.size()),
   942            true);
   943    TEST_EQ(parserGen.Deserialize(
   944                reinterpret_cast<const uint8_t *>(schemafile.c_str()),
   945                schemafile.size()),
   946            true);
   947  } else {
   948    TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
   949    TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
   950  }
   951  TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
   952
   953  // First, verify it, just in case:
   954  flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
   955                                    parserOrg.builder_.GetSize());
   956  TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
   957
   958  // Export to JSON
   959  std::string jsonGen;
   960  TEST_NULL(
   961      GenText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen));
   962
   963  // Import from JSON
   964  TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
   965
   966  // Verify buffer from generated JSON
   967  flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
   968                                    parserGen.builder_.GetSize());
   969  TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
   970
   971  // Compare generated buffer to original
   972  TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
   973  TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
   974                      parserGen.builder_.GetBufferPointer(),
   975                      parserOrg.builder_.GetSize()),
   976          0);
   977}
   978
   979void FixedLengthArraySpanTest(const std::string &tests_data_path) {
   980  // load FlatBuffer schema (.fbs) and JSON from disk
   981  std::string schemafile;
   982  std::string jsonfile;
   983  TEST_EQ(flatbuffers::LoadFile((tests_data_path + "arrays_test.fbs").c_str(),
   984                                false, &schemafile),
   985          true);
   986  TEST_EQ(
   987      flatbuffers::LoadFile((tests_data_path + "arrays_test.golden").c_str(),
   988                            false, &jsonfile),
   989      true);
   990
   991  // parse schema first, so we can use it to parse the data after
   992  flatbuffers::Parser parser;
   993  TEST_EQ(parser.Parse(schemafile.c_str()), true);
   994  TEST_EQ(parser.Parse(jsonfile.c_str()), true);
   995  auto &fbb = parser.builder_;
   996  auto verifier = flatbuffers::Verifier(fbb.GetBufferPointer(), fbb.GetSize());
   997  TEST_EQ(true, VerifyArrayTableBuffer(verifier));
   998
   999  auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
  1000  TEST_NOTNULL(p);
  1001  auto table_struct = p->mutable_a();
  1002  TEST_NOTNULL(table_struct);
  1003  TEST_EQ(2, table_struct->d()->size());
  1004  TEST_NOTNULL(table_struct->d());
  1005  TEST_NOTNULL(table_struct->mutable_d());
  1006  // test array of structs
  1007  auto const_d = flatbuffers::make_span(*table_struct->d());
  1008  auto mutable_d = flatbuffers::make_span(*table_struct->mutable_d());
  1009  TEST_EQ(2, const_d.size());
  1010  TEST_EQ(2, mutable_d.size());
  1011  TEST_ASSERT(const_d[0] == mutable_d[0]);
  1012  TEST_ASSERT(const_d[1] == mutable_d[1]);
  1013  mutable_d[0] = const_d[0];  // mutate
  1014  // test scalars
  1015  auto &const_nested = const_d[0];
  1016  auto &mutable_nested = mutable_d[0];
  1017  static_assert(sizeof(MyGame::Example::TestEnum) == sizeof(uint8_t),
  1018                "TestEnum's underlaying type must by byte");
  1019  TEST_NOTNULL(const_nested.d());
  1020  TEST_NOTNULL(mutable_nested.d());
  1021  {
  1022    flatbuffers::span<const MyGame::Example::TestEnum, 2> const_d_c =
  1023        flatbuffers::make_span(*const_nested.c());
  1024    auto mutable_d_c = flatbuffers::make_span(*mutable_nested.mutable_c());
  1025    TEST_EQ(2, const_d_c.size());
  1026    TEST_EQ(2, mutable_d_c.size());
  1027    TEST_EQ(MyGame::Example::TestEnum::C, const_d_c[0]);
  1028    TEST_EQ(MyGame::Example::TestEnum::B, const_d_c[1]);
  1029    TEST_ASSERT(mutable_d_c.end() == std::copy(const_d_c.begin(),
  1030                                               const_d_c.end(),
  1031                                               mutable_d_c.begin()));
  1032    TEST_ASSERT(
  1033        std::equal(const_d_c.begin(), const_d_c.end(), mutable_d_c.begin()));
  1034  }
  1035  // test little endian array of int32
  1036#    if FLATBUFFERS_LITTLEENDIAN
  1037  {
  1038    flatbuffers::span<const int32_t, 2> const_d_a =
  1039        flatbuffers::make_span(*const_nested.a());
  1040    auto mutable_d_a = flatbuffers::make_span(*mutable_nested.mutable_a());
  1041    TEST_EQ(2, const_d_a.size());
  1042    TEST_EQ(2, mutable_d_a.size());
  1043    TEST_EQ(-1, const_d_a[0]);
  1044    TEST_EQ(2, const_d_a[1]);
  1045    TEST_ASSERT(mutable_d_a.end() == std::copy(const_d_a.begin(),
  1046                                               const_d_a.end(),
  1047                                               mutable_d_a.begin()));
  1048    TEST_ASSERT(
  1049        std::equal(const_d_a.begin(), const_d_a.end(), mutable_d_a.begin()));
  1050  }
  1051#    endif
  1052}
  1053#  else
  1054void FixedLengthArrayJsonTest(bool /*binary*/) {}
  1055void FixedLengthArraySpanTest() {}
  1056#  endif
  1057
  1058void TestEmbeddedBinarySchema(const std::string &tests_data_path) {
  1059  // load JSON from disk
  1060  std::string jsonfile;
  1061  TEST_EQ(flatbuffers::LoadFile(
  1062              (tests_data_path + "monsterdata_test.golden").c_str(), false,
  1063              &jsonfile),
  1064          true);
  1065
  1066  // parse schema first, so we can use it to parse the data after
  1067  flatbuffers::Parser parserOrg, parserGen;
  1068  flatbuffers::Verifier verifier(MyGame::Example::MonsterBinarySchema::data(),
  1069                                 MyGame::Example::MonsterBinarySchema::size());
  1070  TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
  1071  TEST_EQ(parserOrg.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
  1072                                MyGame::Example::MonsterBinarySchema::size()),
  1073          true);
  1074  TEST_EQ(parserGen.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
  1075                                MyGame::Example::MonsterBinarySchema::size()),
  1076          true);
  1077  TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
  1078
  1079  // First, verify it, just in case:
  1080  flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
  1081                                    parserOrg.builder_.GetSize());
  1082  TEST_EQ(VerifyMonsterBuffer(verifierOrg), true);
  1083
  1084  // Export to JSON
  1085  std::string jsonGen;
  1086  TEST_NULL(
  1087      GenText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen));
  1088
  1089  // Import from JSON
  1090  TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
  1091
  1092  // Verify buffer from generated JSON
  1093  flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
  1094                                    parserGen.builder_.GetSize());
  1095  TEST_EQ(VerifyMonsterBuffer(verifierGen), true);
  1096
  1097  // Compare generated buffer to original
  1098  TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
  1099  TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
  1100                      parserGen.builder_.GetBufferPointer(),
  1101                      parserOrg.builder_.GetSize()),
  1102          0);
  1103}
  1104#endif
  1105
  1106template<typename T> void EmbeddedSchemaAccessByType() {
  1107  // Get the binary schema from the Type itself.
  1108  // Verify the schema is OK.
  1109  flatbuffers::Verifier verifierEmbeddedSchema(
  1110      T::TableType::BinarySchema::data(), T::TableType::BinarySchema::size());
  1111  TEST_EQ(reflection::VerifySchemaBuffer(verifierEmbeddedSchema), true);
  1112
  1113  // Reflect it.
  1114  auto schema = reflection::GetSchema(T::TableType::BinarySchema::data());
  1115
  1116  // This should equal the expected root table.
  1117  TEST_EQ_STR(schema->root_table()->name()->c_str(), "MyGame.Example.Monster");
  1118}
  1119
  1120void EmbeddedSchemaAccess() {
  1121  // Get the binary schema for the monster.
  1122  // Verify the schema is OK.
  1123  flatbuffers::Verifier verifierEmbeddedSchema(Monster::BinarySchema::data(),
  1124                                               Monster::BinarySchema::size());
  1125  TEST_EQ(reflection::VerifySchemaBuffer(verifierEmbeddedSchema), true);
  1126
  1127  // Reflect it.
  1128  auto schema = reflection::GetSchema(Monster::BinarySchema::data());
  1129
  1130  // This should equal the expected root table.
  1131  TEST_EQ_STR(schema->root_table()->name()->c_str(), "MyGame.Example.Monster");
  1132
  1133  // Repeat above, but do so through a template parameter:
  1134  EmbeddedSchemaAccessByType<StatT>();
  1135}
  1136
  1137void NestedVerifierTest() {
  1138  // Create a nested monster.
  1139  flatbuffers::FlatBufferBuilder nested_builder;
  1140  FinishMonsterBuffer(
  1141      nested_builder,
  1142      CreateMonster(nested_builder, nullptr, 0, 0,
  1143                    nested_builder.CreateString("NestedMonster")));
  1144
  1145  // Verify the nested monster
  1146  flatbuffers::Verifier verifier(nested_builder.GetBufferPointer(),
  1147                                 nested_builder.GetSize());
  1148  TEST_EQ(true, VerifyMonsterBuffer(verifier));
  1149
  1150  {
  1151    // Create the outer monster.
  1152    flatbuffers::FlatBufferBuilder builder;
  1153
  1154    // Add the nested monster as a vector of bytes.
  1155    auto nested_monster_bytes = builder.CreateVector(
  1156        nested_builder.GetBufferPointer(), nested_builder.GetSize());
  1157
  1158    auto name = builder.CreateString("OuterMonster");
  1159
  1160    MonsterBuilder mon_builder(builder);
  1161    mon_builder.add_name(name);
  1162    mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
  1163    FinishMonsterBuffer(builder, mon_builder.Finish());
  1164
  1165    // Verify the root monster, which includes verifing the nested monster
  1166    flatbuffers::Verifier verifier(builder.GetBufferPointer(),
  1167                                   builder.GetSize());
  1168    TEST_EQ(true, VerifyMonsterBuffer(verifier));
  1169  }
  1170
  1171  {
  1172    // Create the outer monster.
  1173    flatbuffers::FlatBufferBuilder builder;
  1174
  1175    // Purposely invalidate the nested flatbuffer setting its length to 1, an
  1176    // invalid length.
  1177    uint8_t invalid_nested_buffer[1];
  1178    auto nested_monster_bytes = builder.CreateVector(invalid_nested_buffer, 1);
  1179
  1180    auto name = builder.CreateString("OuterMonster");
  1181
  1182    MonsterBuilder mon_builder(builder);
  1183    mon_builder.add_name(name);
  1184    mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
  1185    FinishMonsterBuffer(builder, mon_builder.Finish());
  1186
  1187    // Verify the root monster fails, since the included nested monster fails.
  1188    flatbuffers::Verifier verifier(builder.GetBufferPointer(),
  1189                                   builder.GetSize());
  1190    TEST_EQ(false, VerifyMonsterBuffer(verifier));
  1191
  1192    // Verify the root monster succeeds, since we've disabled checking nested
  1193    // flatbuffers
  1194    flatbuffers::Verifier::Options options;
  1195    options.check_nested_flatbuffers = false;
  1196    flatbuffers::Verifier no_check_nested(builder.GetBufferPointer(),
  1197                                          builder.GetSize(), options);
  1198    TEST_EQ(true, VerifyMonsterBuffer(no_check_nested));
  1199  }
  1200
  1201  {
  1202    // Create the outer monster.
  1203    flatbuffers::FlatBufferBuilder builder;
  1204
  1205    // Purposely invalidate the nested flatbuffer setting its length to 0, an
  1206    // invalid length.
  1207    uint8_t *invalid_nested_buffer = nullptr;
  1208    auto nested_monster_bytes = builder.CreateVector(invalid_nested_buffer, 0);
  1209
  1210    auto name = builder.CreateString("OuterMonster");
  1211
  1212    MonsterBuilder mon_builder(builder);
  1213    mon_builder.add_name(name);
  1214    mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
  1215    FinishMonsterBuffer(builder, mon_builder.Finish());
  1216
  1217    // Verify the root monster fails, since the included nested monster fails.
  1218    flatbuffers::Verifier verifier(builder.GetBufferPointer(),
  1219                                   builder.GetSize());
  1220    TEST_EQ(false, VerifyMonsterBuffer(verifier));
  1221  }
  1222}
  1223
  1224template<class T, class Container>
  1225void TestIterators(const std::vector<T> &expected, const Container &tested) {
  1226  TEST_ASSERT(tested.rbegin().base() == tested.end());
  1227  TEST_ASSERT(tested.crbegin().base() == tested.cend());
  1228  TEST_ASSERT(tested.rend().base() == tested.begin());
  1229  TEST_ASSERT(tested.crend().base() == tested.cbegin());
  1230
  1231  size_t k = 0;
  1232  for (auto it = tested.begin(); it != tested.end(); ++it, ++k) {
  1233    const auto &e = expected.at(k);
  1234    TEST_EQ(*it, e);
  1235  }
  1236  TEST_EQ(k, expected.size());
  1237
  1238  k = expected.size();
  1239  for (auto it = tested.rbegin(); it != tested.rend(); ++it, --k) {
  1240    const auto &e = expected.at(k - 1);
  1241    TEST_EQ(*it, e);
  1242  }
  1243  TEST_EQ(k, 0);
  1244}
  1245
  1246void FlatbuffersIteratorsTest() {
  1247  {
  1248    flatbuffers::FlatBufferBuilder fbb;
  1249    const std::vector<unsigned char> inv_data = { 1, 2, 3 };
  1250    {
  1251      auto mon_name = fbb.CreateString("MyMonster");  // key, mandatory
  1252      auto inv_vec = fbb.CreateVector(inv_data);
  1253      auto empty_i64_vec =
  1254          fbb.CreateVector(static_cast<const int64_t *>(nullptr), 0);
  1255      MonsterBuilder mb(fbb);
  1256      mb.add_name(mon_name);
  1257      mb.add_inventory(inv_vec);
  1258      mb.add_vector_of_longs(empty_i64_vec);
  1259      FinishMonsterBuffer(fbb, mb.Finish());
  1260    }
  1261    const auto &mon = *flatbuffers::GetRoot<Monster>(fbb.GetBufferPointer());
  1262
  1263    TEST_EQ_STR("MyMonster", mon.name()->c_str());
  1264    TEST_ASSERT(mon.inventory());
  1265    TEST_ASSERT(mon.vector_of_longs());
  1266    TestIterators(inv_data, *mon.inventory());
  1267    TestIterators(std::vector<int64_t>(), *mon.vector_of_longs());
  1268  }
  1269
  1270  {
  1271    flatbuffers::FlatBufferBuilder fbb;
  1272    MyGame::Example::ArrayStruct aStruct;
  1273    MyGame::Example::FinishArrayTableBuffer(
  1274        fbb, MyGame::Example::CreateArrayTable(fbb, &aStruct));
  1275    const auto &array_table =
  1276        *flatbuffers::GetRoot<ArrayTable>(fbb.GetBufferPointer());
  1277    TEST_ASSERT(array_table.a());
  1278    auto &int_15 = *array_table.a()->b();
  1279    TestIterators(std::vector<int>(15, 0), int_15);
  1280  }
  1281}
  1282
  1283void PrivateAnnotationsLeaks() {
  1284  // Simple schemas and a "has optional scalar" sentinal.
  1285  std::vector<std::string> schemas;
  1286  std::vector<std::string> failure_schemas;
  1287
  1288  // (private) (table/struct)
  1289  schemas.push_back(
  1290      "table Monster (private) { mana: int; }"
  1291      "struct ABC (private) { mana: int; }");
  1292
  1293  // (public) (table/struct)
  1294  schemas.push_back(
  1295      "table Monster { mana: int; }"
  1296      "struct ABC { mana: int; }");
  1297
  1298  // (private) (union) containing (private) (table/struct)
  1299  schemas.push_back(
  1300      "table Monster (private) { mana: int; } "
  1301      "struct ABC (private) { mana: int; } "
  1302      "union Any (private) { Monster, ABC } ");
  1303
  1304  // (public) (union) containing (public) (table/struct)
  1305  schemas.push_back(
  1306      "table Monster { mana: int; }"
  1307      "struct ABC { mana: int; }"
  1308      "union Any { Monster, ABC }");
  1309
  1310  // (private) (table/struct/enum)
  1311  schemas.push_back(
  1312      "table Monster (private) { mana: int; }"
  1313      "struct ABC (private) { mana: int; }"
  1314      "enum Race:byte (private) { None = -1, Human = 0, }");
  1315
  1316  // (public) (table/struct/enum)
  1317  schemas.push_back(
  1318      "table Monster { mana: int; }"
  1319      "struct ABC { mana: int; }"
  1320      "enum Race:byte { None = -1, Human = 0, }");
  1321
  1322  // (private) (union) containing (private) (table/struct)
  1323  schemas.push_back(
  1324      "table Monster (private) { mana: int; }"
  1325      "struct ABC (private) { mana: int; }"
  1326      "enum Race:byte (private) { None = -1, Human = 0, }"
  1327      "union Any (private) { Monster, ABC }");
  1328
  1329  // (public) (union) containing (public) (table/struct)
  1330  schemas.push_back(
  1331      "table Monster { mana: int; }"
  1332      "struct ABC { mana: int; }"
  1333      "enum Race:byte { None = -1, Human = 0, }"
  1334      "union Any { Monster, ABC }");
  1335
  1336  // (private) (table), (public struct)
  1337  schemas.push_back(
  1338      "table Monster (private) { mana: int; }"
  1339      "struct ABC { mana: int; }");
  1340
  1341  // (private) (table), (public) (struct/enum)
  1342  schemas.push_back(
  1343      "table Monster (private) { mana: int; }"
  1344      "struct ABC { mana: int; }"
  1345      "enum Race:byte { None = -1, Human = 0, }");
  1346
  1347  // (public) (struct) containing (public) (enum)
  1348  schemas.push_back(
  1349      "enum Race:byte { None = -1, Human = 0, }"
  1350      "table Monster { mana: int; }"
  1351      "struct ABC { mana: int; type: Race; }");
  1352
  1353  // (public) (union) containing (private) (table) & (public) (struct)
  1354  failure_schemas.push_back(
  1355      "table Monster (private) { mana: int; }"
  1356      "struct ABC { mana: int; }"
  1357      "union Any { Monster, ABC }");
  1358
  1359  // (public) (union) containing (private) (table/struct)
  1360  failure_schemas.push_back(
  1361      "table Monster (private) { mana: int; }"
  1362      "struct ABC (private) { mana: int; }"
  1363      "enum Race:byte { None = -1, Human = 0, }"
  1364      "union Any { Monster, ABC }");
  1365
  1366  // (public) (table) containing (private) (struct)
  1367  failure_schemas.push_back(
  1368      "table Monster { mana: int; ab: ABC; }"
  1369      "struct ABC (private) { mana: int; }");
  1370
  1371  // (public) (struct) containing (private) (enum)
  1372  failure_schemas.push_back(
  1373      "enum Race:byte (private) { None = -1, Human = 0, }"
  1374      "table Monster { mana: int; }"
  1375      "struct ABC { mana: int; type: Race; }");
  1376
  1377  flatbuffers::IDLOptions opts;
  1378  opts.lang_to_generate = flatbuffers::IDLOptions::Language::kSwift;
  1379  opts.no_leak_private_annotations = true;
  1380
  1381  for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
  1382    flatbuffers::Parser parser(opts);
  1383    TEST_ASSERT(parser.Parse(schema->c_str()));
  1384  }
  1385
  1386  for (auto schema = failure_schemas.begin(); schema < failure_schemas.end();
  1387       schema++) {
  1388    flatbuffers::Parser parser(opts);
  1389    TEST_EQ(false, parser.Parse(schema->c_str()));
  1390  }
  1391
  1392  opts.no_leak_private_annotations = false;
  1393
  1394  for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
  1395    flatbuffers::Parser parser(opts);
  1396    TEST_ASSERT(parser.Parse(schema->c_str()));
  1397  }
  1398
  1399  for (auto schema = failure_schemas.begin(); schema < failure_schemas.end();
  1400       schema++) {
  1401    flatbuffers::Parser parser(opts);
  1402    TEST_ASSERT(parser.Parse(schema->c_str()));
  1403  }
  1404}
  1405
  1406void VectorSpanTest() {
  1407  flatbuffers::FlatBufferBuilder builder;
  1408
  1409  auto mloc = CreateMonster(
  1410      builder, nullptr, 0, 0, builder.CreateString("Monster"),
  1411      builder.CreateVector<uint8_t>({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }));
  1412
  1413  FinishMonsterBuffer(builder, mloc);
  1414
  1415  auto monster = GetMonster(builder.GetBufferPointer());
  1416  auto mutable_monster = GetMutableMonster(builder.GetBufferPointer());
  1417
  1418  {  // using references
  1419    TEST_NOTNULL(monster->inventory());
  1420
  1421    flatbuffers::span<const uint8_t> const_inventory =
  1422        flatbuffers::make_span(*monster->inventory());
  1423    TEST_EQ(const_inventory.size(), 10);
  1424    TEST_EQ(const_inventory[0], 0);
  1425    TEST_EQ(const_inventory[9], 9);
  1426
  1427    flatbuffers::span<uint8_t> mutable_inventory =
  1428        flatbuffers::make_span(*mutable_monster->mutable_inventory());
  1429    TEST_EQ(mutable_inventory.size(), 10);
  1430    TEST_EQ(mutable_inventory[0], 0);
  1431    TEST_EQ(mutable_inventory[9], 9);
  1432
  1433    mutable_inventory[0] = 42;
  1434    TEST_EQ(mutable_inventory[0], 42);
  1435
  1436    mutable_inventory[0] = 0;
  1437    TEST_EQ(mutable_inventory[0], 0);
  1438  }
  1439
  1440  {  // using pointers
  1441    TEST_EQ(flatbuffers::VectorLength(monster->inventory()), 10);
  1442
  1443    flatbuffers::span<const uint8_t> const_inventory =
  1444        flatbuffers::make_span(monster->inventory());
  1445    TEST_EQ(const_inventory.size(), 10);
  1446    TEST_EQ(const_inventory[0], 0);
  1447    TEST_EQ(const_inventory[9], 9);
  1448
  1449    flatbuffers::span<uint8_t> mutable_inventory =
  1450        flatbuffers::make_span(mutable_monster->mutable_inventory());
  1451    TEST_EQ(mutable_inventory.size(), 10);
  1452    TEST_EQ(mutable_inventory[0], 0);
  1453    TEST_EQ(mutable_inventory[9], 9);
  1454
  1455    mutable_inventory[0] = 42;
  1456    TEST_EQ(mutable_inventory[0], 42);
  1457
  1458    mutable_inventory[0] = 0;
  1459    TEST_EQ(mutable_inventory[0], 0);
  1460  }
  1461
  1462  {
  1463    TEST_ASSERT(nullptr == monster->testnestedflatbuffer());
  1464
  1465    TEST_EQ(flatbuffers::VectorLength(monster->testnestedflatbuffer()), 0);
  1466
  1467    flatbuffers::span<const uint8_t> const_nested =
  1468        flatbuffers::make_span(monster->testnestedflatbuffer());
  1469    TEST_ASSERT(const_nested.empty());
  1470
  1471    flatbuffers::span<uint8_t> mutable_nested =
  1472        flatbuffers::make_span(mutable_monster->mutable_testnestedflatbuffer());
  1473    TEST_ASSERT(mutable_nested.empty());
  1474  }
  1475}
  1476
  1477void NativeInlineTableVectorTest() {
  1478  TestNativeInlineTableT test;
  1479  for (int i = 0; i < 10; ++i) {
  1480    NativeInlineTableT t;
  1481    t.a = i;
  1482    test.t.push_back(t);
  1483  }
  1484
  1485  flatbuffers::FlatBufferBuilder fbb;
  1486  auto offset = TestNativeInlineTable::Pack(fbb, &test);
  1487  fbb.Finish(offset);
  1488
  1489  auto *root =
  1490      flatbuffers::GetRoot<TestNativeInlineTable>(fbb.GetBufferPointer());
  1491  TestNativeInlineTableT unpacked;
  1492  root->UnPackTo(&unpacked);
  1493
  1494  for (int i = 0; i < 10; ++i) { TEST_ASSERT(unpacked.t[i] == test.t[i]); }
  1495
  1496  TEST_ASSERT(unpacked.t == test.t);
  1497}
  1498
  1499// Guard against -Wunused-function on platforms without file tests.
  1500#ifndef FLATBUFFERS_NO_FILE_TESTS
  1501void DoNotRequireEofTest(const std::string &tests_data_path) {
  1502  std::string schemafile;
  1503  bool ok = flatbuffers::LoadFile(
  1504      (tests_data_path + "monster_test.fbs").c_str(), false, &schemafile);
  1505  TEST_EQ(ok, true);
  1506  auto include_test_path =
  1507      flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
  1508  const char *include_directories[] = { tests_data_path.c_str(),
  1509                                        include_test_path.c_str(), nullptr };
  1510  flatbuffers::IDLOptions opt;
  1511  opt.require_json_eof = false;
  1512  flatbuffers::Parser parser(opt);
  1513  ok = parser.Parse(schemafile.c_str(), include_directories);
  1514  TEST_EQ(ok, true);
  1515
  1516  const char *str = R"(Some text at the beginning. {
  1517      "name": "Blob",
  1518      "hp": 5
  1519    }{
  1520      "name": "Imp",
  1521      "hp": 10
  1522    }
  1523    Some extra text at the end too.
  1524  )";
  1525  const char *tableStart = std::strchr(str, '{');
  1526  ok = parser.ParseJson(tableStart);
  1527  TEST_EQ(ok, true);
  1528
  1529  const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
  1530  TEST_EQ_STR(monster->name()->c_str(), "Blob");
  1531  TEST_EQ(monster->hp(), 5);
  1532
  1533  tableStart += parser.BytesConsumed();
  1534
  1535  ok = parser.ParseJson(tableStart);
  1536  TEST_EQ(ok, true);
  1537
  1538  monster = GetMonster(parser.builder_.GetBufferPointer());
  1539  TEST_EQ_STR(monster->name()->c_str(), "Imp");
  1540  TEST_EQ(monster->hp(), 10);
  1541}
  1542#endif
  1543
  1544void UnionUnderlyingTypeTest() {
  1545    using namespace UnionUnderlyingType;
  1546    TEST_ASSERT(sizeof(ABC) == sizeof(uint32_t));
  1547    TEST_ASSERT(ABC::ABC_A == 555);
  1548    TEST_ASSERT(ABC::ABC_B == 666);
  1549    TEST_ASSERT(ABC::ABC_C == 777);
  1550
  1551    DT buffer;
  1552    AT a;
  1553    a.a = 42;
  1554    BT b;
  1555    b.b = "foo";
  1556    CT c;
  1557    c.c = true;
  1558    buffer.test_union = ABCUnion();
  1559    buffer.test_union.Set(a);
  1560    buffer.test_vector_of_union.resize(3);
  1561    buffer.test_vector_of_union[0].Set(a);
  1562    buffer.test_vector_of_union[1].Set(b);
  1563    buffer.test_vector_of_union[2].Set(c);
  1564
  1565    flatbuffers::FlatBufferBuilder fbb;
  1566    auto offset = D::Pack(fbb, &buffer);
  1567    fbb.Finish(offset);
  1568
  1569    auto *root =
  1570    flatbuffers::GetRoot<D>(fbb.GetBufferPointer());
  1571    DT unpacked;
  1572    root->UnPackTo(&unpacked);
  1573
  1574    TEST_ASSERT(unpacked.test_union == buffer.test_union);
  1575    TEST_ASSERT(unpacked.test_vector_of_union == buffer.test_vector_of_union);
  1576
  1577}
  1578
  1579static void Offset64Tests() {
  1580  Offset64Test();
  1581  Offset64SerializedFirst();
  1582  Offset64NestedFlatBuffer();
  1583  Offset64CreateDirect();
  1584  Offset64Evolution();
  1585  Offset64VectorOfStructs();
  1586  Offset64SizePrefix();
  1587  Offset64ManyVectors();
  1588}
  1589
  1590int FlatBufferTests(const std::string &tests_data_path) {
  1591  // Run our various test suites:
  1592
  1593  std::string rawbuf;
  1594  auto flatbuf1 = CreateFlatBufferTest(rawbuf);
  1595  auto flatbuf = std::move(flatbuf1);  // Test move assignment.
  1596
  1597  AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
  1598                       rawbuf.length());
  1599  AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
  1600
  1601  MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
  1602
  1603  ObjectFlatBuffersTest(flatbuf.data());
  1604  UnPackTo(flatbuf.data());
  1605
  1606  MiniReflectFlatBuffersTest(flatbuf.data());
  1607  MiniReflectFixedLengthArrayTest();
  1608
  1609  SizePrefixedTest();
  1610
  1611  AlignmentTest();
  1612
  1613#ifndef FLATBUFFERS_NO_FILE_TESTS
  1614  ParseAndGenerateTextTest(tests_data_path, false);
  1615  ParseAndGenerateTextTest(tests_data_path, true);
  1616  FixedLengthArrayJsonTest(tests_data_path, false);
  1617  FixedLengthArrayJsonTest(tests_data_path, true);
  1618  ReflectionTest(tests_data_path, flatbuf.data(), flatbuf.size());
  1619  ParseProtoTest(tests_data_path);
  1620  EvolutionTest(tests_data_path);
  1621  UnionDeprecationTest(tests_data_path);
  1622  UnionVectorTest(tests_data_path);
  1623  GenerateTableTextTest(tests_data_path);
  1624  TestEmbeddedBinarySchema(tests_data_path);
  1625  JsonOptionalTest(tests_data_path, false);
  1626  JsonOptionalTest(tests_data_path, true);
  1627  MultiFileNameClashTest(tests_data_path);
  1628  InvalidNestedFlatbufferTest(tests_data_path);
  1629  JsonDefaultTest(tests_data_path);
  1630  JsonEnumsTest(tests_data_path);
  1631  TestMonsterExtraFloats(tests_data_path);
  1632  ParseIncorrectMonsterJsonTest(tests_data_path);
  1633  FixedLengthArraySpanTest(tests_data_path);
  1634  DoNotRequireEofTest(tests_data_path);
  1635  JsonUnionStructTest();
  1636#else
  1637  // Guard against -Wunused-parameter.
  1638  (void)tests_data_path;
  1639#endif
  1640
  1641  UtilConvertCase();
  1642
  1643  FuzzTest1();
  1644  FuzzTest2();
  1645
  1646  TriviallyCopyableTest();
  1647  ErrorTest();
  1648  ValueTest();
  1649  EnumValueTest();
  1650  NestedListTest();
  1651  EnumStringsTest();
  1652  EnumNamesTest();
  1653  EnumOutOfRangeTest();
  1654  IntegerOutOfRangeTest();
  1655  IntegerBoundaryTest();
  1656  UnicodeTest();
  1657  UnicodeTestAllowNonUTF8();
  1658  UnicodeTestGenerateTextFailsOnNonUTF8();
  1659  UnicodeSurrogatesTest();
  1660  UnicodeInvalidSurrogatesTest();
  1661  InvalidUTF8Test();
  1662  UnknownFieldsTest();
  1663  ParseUnionTest();
  1664  ValidSameNameDifferentNamespaceTest();
  1665  ConformTest();
  1666  ParseProtoBufAsciiTest();
  1667  TypeAliasesTest();
  1668  EndianSwapTest();
  1669  CreateSharedStringTest();
  1670  FlexBuffersTest();
  1671  FlexBuffersReuseBugTest();
  1672  FlexBuffersDeprecatedTest();
  1673  UninitializedVectorTest();
  1674  EqualOperatorTest();
  1675  NumericUtilsTest();
  1676  IsAsciiUtilsTest();
  1677  ValidFloatTest();
  1678  InvalidFloatTest();
  1679  FixedLengthArrayTest();
  1680  NativeTypeTest();
  1681  OptionalScalarsTest();
  1682  ParseFlexbuffersFromJsonWithNullTest();
  1683  FlatbuffersSpanTest();
  1684  FixedLengthArrayConstructorTest();
  1685  FixedLengthArrayOperatorEqualTest();
  1686  FieldIdentifierTest();
  1687  StringVectorDefaultsTest();
  1688  FlexBuffersFloatingPointTest();
  1689  FlatbuffersIteratorsTest();
  1690  WarningsAsErrorsTest();
  1691  NestedVerifierTest();
  1692  PrivateAnnotationsLeaks();
  1693  JsonUnsortedArrayTest();
  1694  VectorSpanTest();
  1695  NativeInlineTableVectorTest();
  1696  FixedSizedScalarKeyInStructTest();
  1697  StructKeyInStructTest();
  1698  NestedStructKeyInStructTest();
  1699  FixedSizedStructArrayKeyInStructTest();
  1700  EmbeddedSchemaAccess();
  1701  Offset64Tests();
  1702  UnionUnderlyingTypeTest();
  1703  return 0;
  1704}
  1705}  // namespace
  1706}  // namespace tests
  1707}  // namespace flatbuffers
  1708
  1709int main(int argc, const char *argv[]) {
  1710  std::string tests_data_path = "tests/";
  1711
  1712  for (int argi = 1; argi < argc; argi++) {
  1713    std::string arg = argv[argi];
  1714    if (arg == "--test_path") {
  1715      if (++argi >= argc) {
  1716        fprintf(stderr, "error: missing path following: %s\n", arg.c_str());
  1717        exit(1);
  1718      }
  1719      // Override default path if provided one.
  1720      tests_data_path = argv[argi];
  1721
  1722    } else {
  1723      fprintf(stderr, "error: Unknown argument: %s\n", arg.c_str());
  1724      exit(1);
  1725    }
  1726  }
  1727
  1728  InitTestEngine();
  1729
  1730  std::string req_locale;
  1731  if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
  1732                                           &req_locale)) {
  1733    TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
  1734                     req_locale.c_str());
  1735    req_locale = flatbuffers::RemoveStringQuotes(req_locale);
  1736    std::string the_locale;
  1737    TEST_ASSERT_FUNC(
  1738        flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
  1739    TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
  1740  }
  1741
  1742#ifdef FLATBUFFERS_TEST_PATH_PREFIX
  1743  tests_data_path =
  1744      FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) + tests_data_path;
  1745#endif
  1746
  1747  flatbuffers::tests::FlatBufferTests(tests_data_path);
  1748  FlatBufferBuilderTest();
  1749
  1750  if (!testing_fails) {
  1751    TEST_OUTPUT_LINE("ALL TESTS PASSED");
  1752  } else {
  1753    TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
  1754  }
  1755  return CloseTestEngine();
  1756}

View as plain text