...

Text file src/github.com/google/flatbuffers/tests/64bit/offset64_test.cpp

Documentation: github.com/google/flatbuffers/tests/64bit

     1#include "offset64_test.h"
     2
     3#include <stdint.h>
     4
     5#include <cstdint>
     6#include <fstream>
     7#include <limits>
     8#include <ostream>
     9
    10#include "flatbuffers/base.h"
    11#include "flatbuffers/buffer.h"
    12#include "flatbuffers/flatbuffer_builder.h"
    13#include "flatbuffers/flatbuffers.h"
    14#include "tests/64bit/evolution/v1_generated.h"
    15#include "tests/64bit/evolution/v2_generated.h"
    16#include "tests/64bit/test_64bit_generated.h"
    17#include "tests/test_assert.h"
    18
    19namespace flatbuffers {
    20namespace tests {
    21
    22void Offset64Test() {
    23  FlatBufferBuilder64 builder;
    24
    25  const size_t far_vector_size = 1LL << 2;
    26  // Make a large number if wanting to test a real large buffer.
    27  const size_t big_vector_size = 1LL << 2;
    28
    29  {
    30    // First create the vectors that will be copied to the buffer.
    31    std::vector<uint8_t> far_data;
    32    far_data.resize(far_vector_size);
    33    far_data[0] = 4;
    34    far_data[far_vector_size - 1] = 2;
    35
    36    std::vector<uint8_t> big_data;
    37    big_data.resize(big_vector_size);
    38    big_data[0] = 8;
    39    big_data[big_vector_size - 1] = 3;
    40
    41    // Then serialize all the fields that have 64-bit offsets, as these must be
    42    // serialized before any 32-bit fields are added to the buffer.
    43    const Offset64<Vector<uint8_t>> far_vector_offset =
    44        builder.CreateVector64<Vector>(far_data);
    45
    46    const Offset64<String> far_string_offset =
    47        builder.CreateString<Offset64>("some far string");
    48
    49    const Offset64<Vector64<uint8_t>> big_vector_offset =
    50        builder.CreateVector64(big_data);
    51
    52    // Now that we are done with the 64-bit fields, we can create and add the
    53    // normal fields.
    54    const Offset<String> near_string_offset =
    55        builder.CreateString("some near string");
    56
    57    // Finish by building the root table by passing in all the offsets.
    58    const Offset<RootTable> root_table_offset =
    59        CreateRootTable(builder, far_vector_offset, 0, far_string_offset,
    60                        big_vector_offset, near_string_offset);
    61
    62    // Finish the buffer.
    63    builder.Finish(root_table_offset);
    64
    65    Verifier::Options options;
    66    // Allow the verifier to verify 64-bit buffers.
    67    options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
    68    options.assert = true;
    69
    70    Verifier verifier(builder.GetBufferPointer(), builder.GetSize(), options);
    71
    72    TEST_EQ(VerifyRootTableBuffer(verifier), true);
    73  }
    74
    75  {
    76    const RootTable *root_table = GetRootTable(builder.GetBufferPointer());
    77
    78    // Expect the far vector to be properly sized.
    79    TEST_EQ(root_table->far_vector()->size(), far_vector_size);
    80    TEST_EQ(root_table->far_vector()->Get(0), 4);
    81    TEST_EQ(root_table->far_vector()->Get(far_vector_size - 1), 2);
    82
    83    TEST_EQ_STR(root_table->far_string()->c_str(), "some far string");
    84
    85    // Expect the big vector to be properly sized.
    86    TEST_EQ(root_table->big_vector()->size(), big_vector_size);
    87    TEST_EQ(root_table->big_vector()->Get(0), 8);
    88    TEST_EQ(root_table->big_vector()->Get(big_vector_size - 1), 3);
    89
    90    TEST_EQ_STR(root_table->near_string()->c_str(), "some near string");
    91  }
    92}
    93
    94void Offset64SerializedFirst() {
    95  FlatBufferBuilder64 fbb;
    96
    97  // First create the vectors that will be copied to the buffer.
    98  std::vector<uint8_t> data;
    99  data.resize(64);
   100
   101  // Then serialize all the fields that have 64-bit offsets, as these must be
   102  // serialized before any 32-bit fields are added to the buffer.
   103  fbb.CreateVector64(data);
   104
   105  // TODO(derekbailey): figure out how to test assertions.
   106  // Uncommenting this line should fail the test with an assertion.
   107  // fbb.CreateString("some near string");
   108
   109  fbb.CreateVector64(data);
   110}
   111
   112void Offset64NestedFlatBuffer() {
   113  FlatBufferBuilder64 fbb;
   114
   115  // First serialize a nested buffer.
   116  const Offset<String> near_string_offset =
   117      fbb.CreateString("nested: some near string");
   118
   119  // Finish by building the root table by passing in all the offsets.
   120  const Offset<RootTable> root_table_offset =
   121      CreateRootTable(fbb, 0, 0, 0, 0, near_string_offset, 0);
   122
   123  // Finish the buffer.
   124  fbb.Finish(root_table_offset);
   125
   126  // Ensure the buffer is valid.
   127  const RootTable *root_table = GetRootTable(fbb.GetBufferPointer());
   128  TEST_EQ_STR(root_table->near_string()->c_str(), "nested: some near string");
   129
   130  // Copy the data out of the builder.
   131  std::vector<uint8_t> nested_data{ fbb.GetBufferPointer(),
   132                                    fbb.GetBufferPointer() + fbb.GetSize() };
   133
   134  {
   135    // Clear so we can reuse the builder.
   136    fbb.Clear();
   137
   138    const Offset64<Vector64<uint8_t>> nested_flatbuffer_offset =
   139        fbb.CreateVector64<Vector64>(nested_data);
   140
   141    // Now that we are done with the 64-bit fields, we can create and add the
   142    // normal fields.
   143    const Offset<String> near_string_offset =
   144        fbb.CreateString("some near string");
   145
   146    // Finish by building the root table by passing in all the offsets.
   147    const Offset<RootTable> root_table_offset = CreateRootTable(
   148        fbb, 0, 0, 0, 0, near_string_offset, nested_flatbuffer_offset);
   149
   150    // Finish the buffer.
   151    fbb.Finish(root_table_offset);
   152
   153    Verifier::Options options;
   154    // Allow the verifier to verify 64-bit buffers.
   155    options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
   156    options.assert = true;
   157
   158    Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize(), options);
   159
   160    TEST_EQ(VerifyRootTableBuffer(verifier), true);
   161  }
   162
   163  {
   164    const RootTable *root_table = GetRootTable(fbb.GetBufferPointer());
   165
   166    // Test that the parent buffer field is ok.
   167    TEST_EQ_STR(root_table->near_string()->c_str(), "some near string");
   168
   169    // Expect nested buffer to be properly sized.
   170    TEST_EQ(root_table->nested_root()->size(), nested_data.size());
   171
   172    // Expect the direct accessors to the nested buffer work.
   173    TEST_EQ_STR(root_table->nested_root_nested_root()->near_string()->c_str(),
   174                "nested: some near string");
   175  }
   176}
   177
   178void Offset64CreateDirect() {
   179  FlatBufferBuilder64 fbb;
   180
   181  // Create a vector of some data
   182  std::vector<uint8_t> data{ 0, 1, 2 };
   183
   184  // Call the "Direct" creation method to ensure that things are added to the
   185  // buffer in the correct order, Offset64 first followed by any Offsets.
   186  const Offset<RootTable> root_table_offset = CreateRootTableDirect(
   187      fbb, &data, 0, "some far string", &data, "some near string");
   188
   189  // Finish the buffer.
   190  fbb.Finish(root_table_offset);
   191
   192  Verifier::Options options;
   193  // Allow the verifier to verify 64-bit buffers.
   194  options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
   195  options.assert = true;
   196
   197  Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize(), options);
   198
   199  TEST_EQ(VerifyRootTableBuffer(verifier), true);
   200
   201  // Verify the data.
   202  const RootTable *root_table = GetRootTable(fbb.GetBufferPointer());
   203  TEST_EQ(root_table->far_vector()->size(), data.size());
   204  TEST_EQ(root_table->big_vector()->size(), data.size());
   205  TEST_EQ_STR(root_table->far_string()->c_str(), "some far string");
   206  TEST_EQ_STR(root_table->near_string()->c_str(), "some near string");
   207}
   208
   209void Offset64Evolution() {
   210  // Some common data for the tests.
   211  const std::vector<uint8_t> data = { 1, 2, 3, 4 };
   212  const std::vector<uint8_t> big_data = { 6, 7, 8, 9, 10 };
   213
   214  // Built V1 read V2
   215  {
   216    // Use the 32-bit builder since V1 doesn't have any 64-bit offsets.
   217    FlatBufferBuilder builder;
   218
   219    builder.Finish(v1::CreateRootTableDirect(builder, 1234, &data));
   220
   221    // Use each version to get a view at the root table.
   222    auto v1_root = v1::GetRootTable(builder.GetBufferPointer());
   223    auto v2_root = v2::GetRootTable(builder.GetBufferPointer());
   224
   225    // Test field equivalents for fields common to V1 and V2.
   226    TEST_EQ(v1_root->a(), v2_root->a());
   227
   228    TEST_EQ(v1_root->b(), v2_root->b());
   229    TEST_EQ(v1_root->b()->Get(2), 3);
   230    TEST_EQ(v2_root->b()->Get(2), 3);
   231
   232    // This field is added in V2, so it should be null since V1 couldn't have
   233    // written it.
   234    TEST_ASSERT(v2_root->big_vector() == nullptr);
   235  }
   236
   237  // Built V2 read V1
   238  {
   239    // Use the 64-bit builder since V2 has 64-bit offsets.
   240    FlatBufferBuilder64 builder;
   241
   242    builder.Finish(v2::CreateRootTableDirect(builder, 1234, &data, &big_data));
   243
   244    // Use each version to get a view at the root table.
   245    auto v1_root = v1::GetRootTable(builder.GetBufferPointer());
   246    auto v2_root = v2::GetRootTable(builder.GetBufferPointer());
   247
   248    // Test field equivalents for fields common to V1 and V2.
   249    TEST_EQ(v1_root->a(), v2_root->a());
   250
   251    TEST_EQ(v1_root->b(), v2_root->b());
   252    TEST_EQ(v1_root->b()->Get(2), 3);
   253    TEST_EQ(v2_root->b()->Get(2), 3);
   254
   255    // Test that V2 can read the big vector, which V1 doesn't even have
   256    // accessors for (i.e. v1_root->big_vector() doesn't exist).
   257    TEST_ASSERT(v2_root->big_vector() != nullptr);
   258    TEST_EQ(v2_root->big_vector()->size(), big_data.size());
   259    TEST_EQ(v2_root->big_vector()->Get(2), 8);
   260  }
   261
   262  // Built V2 read V1, bigger than max 32-bit buffer sized.
   263  // This checks that even a large buffer can still be read by V1.
   264  {
   265    // Use the 64-bit builder since V2 has 64-bit offsets.
   266    FlatBufferBuilder64 builder;
   267
   268    std::vector<uint8_t> giant_data;
   269    giant_data.resize(1LL << 3);
   270    giant_data[2] = 42;
   271
   272    builder.Finish(
   273        v2::CreateRootTableDirect(builder, 1234, &data, &giant_data));
   274
   275    // Use each version to get a view at the root table.
   276    auto v1_root = v1::GetRootTable(builder.GetBufferPointer());
   277    auto v2_root = v2::GetRootTable(builder.GetBufferPointer());
   278
   279    // Test field equivalents for fields common to V1 and V2.
   280    TEST_EQ(v1_root->a(), v2_root->a());
   281
   282    TEST_EQ(v1_root->b(), v2_root->b());
   283    TEST_EQ(v1_root->b()->Get(2), 3);
   284    TEST_EQ(v2_root->b()->Get(2), 3);
   285
   286    // Test that V2 can read the big vector, which V1 doesn't even have
   287    // accessors for (i.e. v1_root->big_vector() doesn't exist).
   288    TEST_ASSERT(v2_root->big_vector() != nullptr);
   289    TEST_EQ(v2_root->big_vector()->size(), giant_data.size());
   290    TEST_EQ(v2_root->big_vector()->Get(2), 42);
   291  }
   292}
   293
   294void Offset64VectorOfStructs() {
   295  FlatBufferBuilder64 builder;
   296
   297  std::vector<LeafStruct> far_leaves;
   298  far_leaves.emplace_back(LeafStruct{ 123, 4.567 });
   299  far_leaves.emplace_back(LeafStruct{ 987, 6.543 });
   300
   301  std::vector<LeafStruct> big_leaves;
   302  big_leaves.emplace_back(LeafStruct{ 72, 72.8 });
   303  big_leaves.emplace_back(LeafStruct{ 82, 82.8 });
   304  big_leaves.emplace_back(LeafStruct{ 92, 92.8 });
   305
   306  // Add the two vectors of leaf structs.
   307  const Offset<RootTable> root_table_offset =
   308      CreateRootTableDirect(builder, nullptr, 0, nullptr, nullptr, nullptr,
   309                            nullptr, &far_leaves, &big_leaves);
   310
   311  // Finish the buffer.
   312  builder.Finish(root_table_offset);
   313
   314  Verifier::Options options;
   315  // Allow the verifier to verify 64-bit buffers.
   316  options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
   317  options.assert = true;
   318
   319  Verifier verifier(builder.GetBufferPointer(), builder.GetSize(), options);
   320
   321  TEST_EQ(VerifyRootTableBuffer(verifier), true);
   322
   323  // Verify the data.
   324  const RootTable *root_table = GetRootTable(builder.GetBufferPointer());
   325  TEST_EQ(root_table->far_struct_vector()->size(), far_leaves.size());
   326  TEST_EQ(root_table->far_struct_vector()->Get(0)->a(), 123);
   327  TEST_EQ(root_table->far_struct_vector()->Get(0)->b(), 4.567);
   328  TEST_EQ(root_table->far_struct_vector()->Get(1)->a(), 987);
   329  TEST_EQ(root_table->far_struct_vector()->Get(1)->b(), 6.543);
   330
   331  TEST_EQ(root_table->big_struct_vector()->size(), big_leaves.size());
   332  TEST_EQ(root_table->big_struct_vector()->Get(0)->a(), 72);
   333  TEST_EQ(root_table->big_struct_vector()->Get(0)->b(), 72.8);
   334  TEST_EQ(root_table->big_struct_vector()->Get(1)->a(), 82);
   335  TEST_EQ(root_table->big_struct_vector()->Get(1)->b(), 82.8);
   336  TEST_EQ(root_table->big_struct_vector()->Get(2)->a(), 92);
   337  TEST_EQ(root_table->big_struct_vector()->Get(2)->b(), 92.8);
   338}
   339
   340void Offset64SizePrefix() {
   341  FlatBufferBuilder64 builder;
   342
   343  // First serialize a nested buffer.
   344  const Offset<String> near_string_offset =
   345      builder.CreateString("some near string");
   346
   347  // Finish by building the root table by passing in all the offsets.
   348  const Offset<RootTable> root_table_offset =
   349      CreateRootTable(builder, 0, 0, 0, 0, near_string_offset, 0);
   350
   351  // Finish the buffer.
   352  FinishSizePrefixedRootTableBuffer(builder, root_table_offset);
   353
   354  TEST_EQ(GetPrefixedSize<uoffset64_t>(builder.GetBufferPointer()),
   355          builder.GetSize() - sizeof(uoffset64_t));
   356
   357  Verifier::Options options;
   358  // Allow the verifier to verify 64-bit buffers.
   359  options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
   360  options.assert = true;
   361
   362  Verifier verifier(builder.GetBufferPointer(), builder.GetSize(), options);
   363
   364  TEST_EQ(VerifySizePrefixedRootTableBuffer(verifier), true);
   365
   366  const RootTable *root_table =
   367      GetSizePrefixedRootTable(builder.GetBufferPointer());
   368
   369  // Verify the fields.
   370  TEST_EQ_STR(root_table->near_string()->c_str(), "some near string");
   371}
   372
   373void Offset64ManyVectors() {
   374  FlatBufferBuilder64 builder;
   375
   376  // Setup some data to serialize.
   377  std::vector<int8_t> data;
   378  data.resize(20);
   379  data.front() = 42;
   380  data.back() = 18;
   381
   382  const size_t kNumVectors = 20;
   383
   384  // First serialize all the 64-bit address vectors. We need to store all the
   385  // offsets to later add to a wrapper table. We cannot serialize one vector and
   386  // then add it to a table immediately, as it would violate the strict ordering
   387  // of putting all 64-bit things at the tail of the buffer.
   388  std::array<Offset64<Vector<int8_t>>, kNumVectors> offsets_64bit;
   389  for (size_t i = 0; i < kNumVectors; ++i) {
   390    offsets_64bit[i] = builder.CreateVector64<Vector>(data);
   391  }
   392
   393  // Create some unrelated, 64-bit offset value for later testing.
   394  const Offset64<String> far_string_offset =
   395      builder.CreateString<Offset64>("some far string");
   396
   397  // Now place all the offsets into their own wrapper tables. Again, we have to
   398  // store the offsets before we can add them to the root table vector.
   399  std::array<Offset<WrapperTable>, kNumVectors> offsets_wrapper;
   400  for (size_t i = 0; i < kNumVectors; ++i) {
   401    offsets_wrapper[i] = CreateWrapperTable(builder, offsets_64bit[i]);
   402  }
   403
   404  // Now create the 32-bit vector that is stored in the root table.
   405  // TODO(derekbailey): the array type wasn't auto deduced, see if that could be
   406  // fixed.
   407  const Offset<Vector<Offset<WrapperTable>>> many_vectors_offset =
   408      builder.CreateVector<Offset<WrapperTable>>(offsets_wrapper);
   409
   410  // Finish by building using the root table builder, to exercise a different
   411  // code path than the other tests.
   412  RootTableBuilder root_table_builder(builder);
   413  root_table_builder.add_many_vectors(many_vectors_offset);
   414  root_table_builder.add_far_string(far_string_offset);
   415  const Offset<RootTable> root_table_offset = root_table_builder.Finish();
   416
   417  // Finish the buffer.
   418  FinishRootTableBuffer(builder, root_table_offset);
   419
   420  Verifier::Options options;
   421  // Allow the verifier to verify 64-bit buffers.
   422  options.max_size = FLATBUFFERS_MAX_64_BUFFER_SIZE;
   423  options.assert = true;
   424
   425  Verifier verifier(builder.GetBufferPointer(), builder.GetSize(), options);
   426
   427  TEST_EQ(VerifyRootTableBuffer(verifier), true);
   428
   429  const RootTable *root_table = GetRootTable(builder.GetBufferPointer());
   430
   431  // Verify the fields.
   432  TEST_EQ_STR(root_table->far_string()->c_str(), "some far string");
   433  TEST_EQ(root_table->many_vectors()->size(), kNumVectors);
   434
   435  // Spot check one of the vectors.
   436  TEST_EQ(root_table->many_vectors()->Get(12)->vector()->size(), 20);
   437  TEST_EQ(root_table->many_vectors()->Get(12)->vector()->Get(0), 42);
   438  TEST_EQ(root_table->many_vectors()->Get(12)->vector()->Get(19), 18);
   439}
   440
   441}  // namespace tests
   442}  // namespace flatbuffers

View as plain text