...

Text file src/github.com/google/flatbuffers/grpc/tests/message_builder_test.cpp

Documentation: github.com/google/flatbuffers/grpc/tests

     1#include "flatbuffers/grpc.h"
     2#include "monster_test_generated.h"
     3#include "test_assert.h"
     4#include "test_builder.h"
     5
     6using MyGame::Example::Any_NONE;
     7using MyGame::Example::CreateStat;
     8using MyGame::Example::Vec3;
     9
    10bool verify(flatbuffers::grpc::Message<Monster> &msg,
    11            const std::string &expected_name, Color expected_color) {
    12  const Monster *monster = msg.GetRoot();
    13  const auto name = monster->name()->str();
    14  const auto color = monster->color();
    15  TEST_EQ(name, expected_name);
    16  TEST_EQ(color, expected_color);
    17  return (name == expected_name) && (color == expected_color);
    18}
    19
    20bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb,
    21                      const std::string &expected_name, Color expected_color) {
    22  flatbuffers::grpc::Message<Monster> msg = mbb.ReleaseMessage<Monster>();
    23  return verify(msg, expected_name, expected_color);
    24}
    25
    26void builder_move_assign_after_releaseraw_test(
    27    flatbuffers::grpc::MessageBuilder dst) {
    28  auto root_offset1 = populate1(dst);
    29  dst.Finish(root_offset1);
    30  size_t size, offset;
    31  ::grpc::Slice slice;
    32  dst.ReleaseRaw(size, offset, slice);
    33  flatbuffers::FlatBufferBuilder src;
    34  auto root_offset2 = populate2(src);
    35  src.Finish(root_offset2);
    36  auto src_size = src.GetSize();
    37  // Move into a released builder.
    38  dst = std::move(src);
    39  TEST_EQ(dst.GetSize(), src_size);
    40  TEST_ASSERT(release_n_verify(dst, m2_name(), m2_color()));
    41  TEST_EQ(src.GetSize(), 0);
    42}
    43
    44template<class SrcBuilder>
    45struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> {
    46  static void builder_reusable_after_release_message_test(
    47      TestSelector selector) {
    48    if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE)) { return; }
    49
    50    flatbuffers::grpc::MessageBuilder mb;
    51    std::vector<flatbuffers::grpc::Message<Monster>> buffers;
    52    for (int i = 0; i < 5; ++i) {
    53      auto root_offset1 = populate1(mb);
    54      mb.Finish(root_offset1);
    55      buffers.push_back(mb.ReleaseMessage<Monster>());
    56      TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color()));
    57    }
    58  }
    59
    60  static void builder_reusable_after_release_test(TestSelector selector) {
    61    if (!selector.count(REUSABLE_AFTER_RELEASE)) { return; }
    62
    63    // FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)) in
    64    // SliceAllocator::allocate in the second iteration.
    65
    66    flatbuffers::grpc::MessageBuilder mb;
    67    std::vector<flatbuffers::DetachedBuffer> buffers;
    68    for (int i = 0; i < 2; ++i) {
    69      auto root_offset1 = populate1(mb);
    70      mb.Finish(root_offset1);
    71      buffers.push_back(mb.Release());
    72      TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color()));
    73    }
    74  }
    75
    76  static void builder_reusable_after_releaseraw_test(TestSelector selector) {
    77    if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) { return; }
    78
    79    flatbuffers::grpc::MessageBuilder mb;
    80    for (int i = 0; i < 5; ++i) {
    81      auto root_offset1 = populate1(mb);
    82      mb.Finish(root_offset1);
    83      size_t size, offset;
    84      ::grpc::Slice slice;
    85      const uint8_t *buf = mb.ReleaseRaw(size, offset, slice);
    86      TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color()));
    87    }
    88  }
    89
    90  static void builder_reusable_after_release_and_move_assign_test(
    91      TestSelector selector) {
    92    if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) { return; }
    93
    94    // FIXME: Release-move_assign loop fails assert(p ==
    95    // GRPC_SLICE_START_PTR(slice_)) in DetachedBuffer destructor after all the
    96    // iterations
    97
    98    flatbuffers::grpc::MessageBuilder dst;
    99    std::vector<flatbuffers::DetachedBuffer> buffers;
   100
   101    for (int i = 0; i < 2; ++i) {
   102      auto root_offset1 = populate1(dst);
   103      dst.Finish(root_offset1);
   104      buffers.push_back(dst.Release());
   105      TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color()));
   106
   107      // bring dst back to life.
   108      SrcBuilder src;
   109      dst = std::move(src);
   110      TEST_EQ_FUNC(dst.GetSize(), 0);
   111      TEST_EQ_FUNC(src.GetSize(), 0);
   112    }
   113  }
   114
   115  static void builder_reusable_after_release_message_and_move_assign_test(
   116      TestSelector selector) {
   117    if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN)) {
   118      return;
   119    }
   120
   121    flatbuffers::grpc::MessageBuilder dst;
   122    std::vector<flatbuffers::grpc::Message<Monster>> buffers;
   123
   124    for (int i = 0; i < 5; ++i) {
   125      auto root_offset1 = populate1(dst);
   126      dst.Finish(root_offset1);
   127      buffers.push_back(dst.ReleaseMessage<Monster>());
   128      TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color()));
   129
   130      // bring dst back to life.
   131      SrcBuilder src;
   132      dst = std::move(src);
   133      TEST_EQ_FUNC(dst.GetSize(), 0);
   134      TEST_EQ_FUNC(src.GetSize(), 0);
   135    }
   136  }
   137
   138  static void builder_reusable_after_releaseraw_and_move_assign_test(
   139      TestSelector selector) {
   140    if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) { return; }
   141
   142    flatbuffers::grpc::MessageBuilder dst;
   143    for (int i = 0; i < 5; ++i) {
   144      auto root_offset1 = populate1(dst);
   145      dst.Finish(root_offset1);
   146      size_t size, offset;
   147      ::grpc::Slice slice;
   148      const uint8_t *buf = dst.ReleaseRaw(size, offset, slice);
   149      TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color()));
   150
   151      SrcBuilder src;
   152      dst = std::move(src);
   153      TEST_EQ_FUNC(dst.GetSize(), 0);
   154      TEST_EQ_FUNC(src.GetSize(), 0);
   155    }
   156  }
   157
   158  static void run_tests(TestSelector selector) {
   159    builder_reusable_after_release_test(selector);
   160    builder_reusable_after_release_message_test(selector);
   161    builder_reusable_after_releaseraw_test(selector);
   162    builder_reusable_after_release_and_move_assign_test(selector);
   163    builder_reusable_after_releaseraw_and_move_assign_test(selector);
   164    builder_reusable_after_release_message_and_move_assign_test(selector);
   165  }
   166};
   167
   168void slice_allocator_tests() {
   169  // move-construct no-delete test
   170  {
   171    size_t size = 2048;
   172    flatbuffers::grpc::SliceAllocator sa1;
   173    uint8_t *buf = sa1.allocate(size);
   174    TEST_ASSERT_FUNC(buf != 0);
   175    buf[0] = 100;
   176    buf[size - 1] = 200;
   177    flatbuffers::grpc::SliceAllocator sa2(std::move(sa1));
   178    // buf should not be deleted after move-construct
   179    TEST_EQ_FUNC(buf[0], 100);
   180    TEST_EQ_FUNC(buf[size - 1], 200);
   181    // buf is freed here
   182  }
   183
   184  // move-assign test
   185  {
   186    flatbuffers::grpc::SliceAllocator sa1, sa2;
   187    uint8_t *buf = sa1.allocate(2048);
   188    sa1 = std::move(sa2);
   189    // sa1 deletes previously allocated memory in move-assign.
   190    // So buf is no longer usable here.
   191    TEST_ASSERT_FUNC(buf != 0);
   192  }
   193}
   194
   195/// This function does not populate exactly the first half of the table. But it
   196/// could.
   197void populate_first_half(MyGame::Example::MonsterBuilder &wrapper,
   198                         flatbuffers::Offset<flatbuffers::String> name_offset) {
   199  wrapper.add_name(name_offset);
   200  wrapper.add_color(m1_color());
   201}
   202
   203/// This function does not populate exactly the second half of the table. But it
   204/// could.
   205void populate_second_half(MyGame::Example::MonsterBuilder &wrapper) {
   206  wrapper.add_hp(77);
   207  wrapper.add_mana(88);
   208  Vec3 vec3;
   209  wrapper.add_pos(&vec3);
   210}
   211
   212/// This function is a hack to update the FlatBufferBuilder reference (fbb_) in
   213/// the MonsterBuilder object. This function will break if fbb_ is not the first
   214/// member in MonsterBuilder. In that case, some offset must be added. This
   215/// function is used exclusively for testing correctness of move operations
   216/// between FlatBufferBuilders. If MonsterBuilder had a fbb_ pointer, this hack
   217/// would be unnecessary. That involves a code-generator change though.
   218void test_only_hack_update_fbb_reference(
   219    MyGame::Example::MonsterBuilder &monsterBuilder,
   220    flatbuffers::grpc::MessageBuilder &mb) {
   221  *reinterpret_cast<flatbuffers::FlatBufferBuilder **>(&monsterBuilder) = &mb;
   222}
   223
   224/// This test validates correctness of move conversion of FlatBufferBuilder to a
   225/// MessageBuilder DURING a table construction. Half of the table is constructed
   226/// using FlatBufferBuilder and the other half of the table is constructed using
   227/// a MessageBuilder.
   228void builder_move_ctor_conversion_before_finish_half_n_half_table_test() {
   229  for (size_t initial_size = 4; initial_size <= 2048; initial_size *= 2) {
   230    flatbuffers::FlatBufferBuilder fbb(initial_size);
   231    auto name_offset = fbb.CreateString(m1_name());
   232    MyGame::Example::MonsterBuilder monsterBuilder(
   233        fbb);  // starts a table in FlatBufferBuilder
   234    populate_first_half(monsterBuilder, name_offset);
   235    flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
   236    test_only_hack_update_fbb_reference(monsterBuilder, mb);  // hack
   237    populate_second_half(monsterBuilder);
   238    mb.Finish(monsterBuilder.Finish());  // ends the table in MessageBuilder
   239    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color()));
   240    TEST_EQ_FUNC(fbb.GetSize(), 0);
   241  }
   242}
   243
   244/// This test populates a COMPLETE inner table before move conversion and later
   245/// populates more members in the outer table.
   246void builder_move_ctor_conversion_before_finish_test() {
   247  for (size_t initial_size = 1; initial_size <= 2048; initial_size += 1) {
   248    flatbuffers::FlatBufferBuilder fbb(initial_size);
   249    auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0);
   250    flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
   251    auto monster_offset =
   252        CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name()), 0,
   253                      m1_color(), Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset);
   254    mb.Finish(monster_offset);
   255    {
   256      auto mon = flatbuffers::GetRoot<Monster>(mb.GetBufferPointer());
   257      TEST_NOTNULL(mon);
   258      TEST_NOTNULL(mon->name());
   259      TEST_EQ_STR(mon->name()->c_str(), m1_name().c_str());
   260      TEST_EQ(mon->color(), m1_color());
   261    }
   262    TEST_EQ(1, MyGame::Example::Color_Red);
   263    TEST_EQ(1, m1_color());
   264    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color()));
   265    TEST_EQ_FUNC(fbb.GetSize(), 0);
   266  }
   267}
   268
   269/// This test validates correctness of move conversion of FlatBufferBuilder to a
   270/// MessageBuilder DURING a table construction. Half of the table is constructed
   271/// using FlatBufferBuilder and the other half of the table is constructed using
   272/// a MessageBuilder.
   273void builder_move_assign_conversion_before_finish_half_n_half_table_test() {
   274  flatbuffers::FlatBufferBuilder fbb;
   275  flatbuffers::grpc::MessageBuilder mb;
   276
   277  for (int i = 0; i < 5; ++i) {
   278    flatbuffers::FlatBufferBuilder fbb;
   279    auto name_offset = fbb.CreateString(m1_name());
   280    MyGame::Example::MonsterBuilder monsterBuilder(
   281        fbb);  // starts a table in FlatBufferBuilder
   282    populate_first_half(monsterBuilder, name_offset);
   283    mb = std::move(fbb);
   284    test_only_hack_update_fbb_reference(monsterBuilder, mb);  // hack
   285    populate_second_half(monsterBuilder);
   286    mb.Finish(monsterBuilder.Finish());  // ends the table in MessageBuilder
   287    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color()));
   288    TEST_EQ_FUNC(fbb.GetSize(), 0);
   289  }
   290}
   291
   292/// This test populates a COMPLETE inner table before move conversion and later
   293/// populates more members in the outer table.
   294void builder_move_assign_conversion_before_finish_test() {
   295  flatbuffers::FlatBufferBuilder fbb;
   296  flatbuffers::grpc::MessageBuilder mb;
   297
   298  for (int i = 0; i < 5; ++i) {
   299    auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0);
   300    mb = std::move(fbb);
   301    auto monster_offset =
   302        CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name()), 0,
   303                      m1_color(), Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset);
   304    mb.Finish(monster_offset);
   305    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color()));
   306    TEST_EQ_FUNC(fbb.GetSize(), 0);
   307  }
   308}
   309
   310/// This test populates data, finishes the buffer, and does move conversion
   311/// after.
   312void builder_move_ctor_conversion_after_finish_test() {
   313  flatbuffers::FlatBufferBuilder fbb;
   314  fbb.Finish(populate1(fbb));
   315  flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
   316  TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color()));
   317  TEST_EQ_FUNC(fbb.GetSize(), 0);
   318}
   319
   320/// This test populates data, finishes the buffer, and does move conversion
   321/// after.
   322void builder_move_assign_conversion_after_finish_test() {
   323  flatbuffers::FlatBufferBuilder fbb;
   324  flatbuffers::grpc::MessageBuilder mb;
   325
   326  for (int i = 0; i < 5; ++i) {
   327    fbb.Finish(populate1(fbb));
   328    mb = std::move(fbb);
   329    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color()));
   330    TEST_EQ_FUNC(fbb.GetSize(), 0);
   331  }
   332}
   333
   334void message_builder_tests() {
   335  using flatbuffers::FlatBufferBuilder;
   336  using flatbuffers::grpc::MessageBuilder;
   337
   338  slice_allocator_tests();
   339
   340#ifndef __APPLE__
   341  builder_move_ctor_conversion_before_finish_half_n_half_table_test();
   342  builder_move_assign_conversion_before_finish_half_n_half_table_test();
   343#endif  // __APPLE__
   344  builder_move_ctor_conversion_before_finish_test();
   345  builder_move_assign_conversion_before_finish_test();
   346
   347  builder_move_ctor_conversion_after_finish_test();
   348  builder_move_assign_conversion_after_finish_test();
   349
   350  BuilderTests<MessageBuilder, MessageBuilder>::all_tests();
   351  BuilderTests<MessageBuilder, FlatBufferBuilder>::all_tests();
   352
   353  BuilderReuseTestSelector tests[6] = {
   354    // REUSABLE_AFTER_RELEASE,                 // Assertion failed:
   355    // (GRPC_SLICE_IS_EMPTY(slice_))
   356    // REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN, // Assertion failed: (p ==
   357    // GRPC_SLICE_START_PTR(slice_)
   358
   359    REUSABLE_AFTER_RELEASE_RAW, REUSABLE_AFTER_RELEASE_MESSAGE,
   360    REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN,
   361    REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN
   362  };
   363
   364  BuilderReuseTests<MessageBuilder, MessageBuilder>::run_tests(
   365      TestSelector(tests, tests + 6));
   366  BuilderReuseTests<MessageBuilder, FlatBufferBuilder>::run_tests(
   367      TestSelector(tests, tests + 6));
   368}

View as plain text