#ifndef TEST_BUILDER_H #define TEST_BUILDER_H #include #include "monster_test_generated.h" #include "flatbuffers/flatbuffers.h" #include "test_assert.h" using namespace MyGame::Example; namespace flatbuffers { namespace grpc { class MessageBuilder; } } extern const std::string m1_name; extern const Color m1_color; extern const std::string m2_name; extern const Color m2_color; flatbuffers::Offset populate1(flatbuffers::FlatBufferBuilder &builder); flatbuffers::Offset populate2(flatbuffers::FlatBufferBuilder &builder); uint8_t *release_raw_base(flatbuffers::FlatBufferBuilder &fbb, size_t &size, size_t &offset); void free_raw(flatbuffers::grpc::MessageBuilder &mbb, uint8_t *buf); void free_raw(flatbuffers::FlatBufferBuilder &fbb, uint8_t *buf); bool verify(const flatbuffers::DetachedBuffer &buf, const std::string &expected_name, Color color); bool verify(const uint8_t *buf, size_t offset, const std::string &expected_name, Color color); bool release_n_verify(flatbuffers::FlatBufferBuilder &fbb, const std::string &expected_name, Color color); bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb, const std::string &expected_name, Color color); template struct BuilderTests { static void empty_builder_movector_test() { Builder b1; size_t b1_size = b1.GetSize(); Builder b2(std::move(b1)); size_t b2_size = b2.GetSize(); TEST_EQ_FUNC(b1_size, 0); TEST_EQ_FUNC(b1_size, b2_size); } static void nonempty_builder_movector_test() { Builder b1; populate1(b1); size_t b1_size = b1.GetSize(); Builder b2(std::move(b1)); TEST_EQ_FUNC(b1_size, b2.GetSize()); TEST_EQ_FUNC(b1.GetSize(), 0); } static void builder_movector_before_finish_test() { Builder b1; auto root_offset1 = populate1(b1); Builder b2(std::move(b1)); b2.Finish(root_offset1); TEST_ASSERT_FUNC(release_n_verify(b2, m1_name, m1_color)); TEST_EQ_FUNC(b1.GetSize(), 0); } static void builder_movector_after_finish_test() { Builder b1; auto root_offset1 = populate1(b1); b1.Finish(root_offset1); auto b1_size = b1.GetSize(); Builder b2(std::move(b1)); TEST_EQ_FUNC(b2.GetSize(), b1_size); TEST_ASSERT_FUNC(release_n_verify(b2, m1_name, m1_color)); TEST_EQ_FUNC(b1.GetSize(), 0); } static void builder_move_assign_before_finish_test() { Builder b1; auto root_offset1 = populate1(b1); Builder b2; populate2(b2); b2 = std::move(b1); b2.Finish(root_offset1); TEST_ASSERT_FUNC(release_n_verify(b2, m1_name, m1_color)); TEST_EQ_FUNC(b1.GetSize(), 0); } static void builder_move_assign_after_finish_test() { Builder b1; auto root_offset1 = populate1(b1); b1.Finish(root_offset1); auto b1_size = b1.GetSize(); Builder b2; auto root_offset2 = populate2(b2); b2.Finish(root_offset2); b2 = std::move(b1); TEST_EQ_FUNC(b2.GetSize(), b1_size); TEST_ASSERT_FUNC(release_n_verify(b2, m1_name, m1_color)); TEST_EQ_FUNC(b1.GetSize(), 0); } static void builder_swap_before_finish_test() { Builder b1; auto root_offset1 = populate1(b1); auto size1 = b1.GetSize(); Builder b2; auto root_offset2 = populate2(b2); auto size2 = b2.GetSize(); b1.Swap(b2); b1.Finish(root_offset2); b2.Finish(root_offset1); TEST_EQ_FUNC(b1.GetSize() > size2, true); TEST_EQ_FUNC(b2.GetSize() > size1, true); TEST_ASSERT_FUNC(release_n_verify(b1, m2_name, m2_color)); TEST_ASSERT_FUNC(release_n_verify(b2, m1_name, m1_color)); } static void builder_swap_after_finish_test() { Builder b1; auto root_offset1 = populate1(b1); b1.Finish(root_offset1); auto size1 = b1.GetSize(); Builder b2; auto root_offset2 = populate2(b2); b2.Finish(root_offset2); auto size2 = b2.GetSize(); b1.Swap(b2); TEST_EQ_FUNC(b1.GetSize(), size2); TEST_EQ_FUNC(b2.GetSize(), size1); TEST_ASSERT_FUNC(release_n_verify(b1, m2_name, m2_color)); TEST_ASSERT_FUNC(release_n_verify(b2, m1_name, m1_color)); } static void builder_move_assign_after_release_test() { Builder b1; auto root_offset1 = populate1(b1); b1.Finish(root_offset1); { flatbuffers::DetachedBuffer b1_detached = b1.Release(); // detached buffer is deleted } Builder b2; auto root_offset2 = populate2(b2); b2.Finish(root_offset2); auto b2_size = b2.GetSize(); // Move into a released builder. b1 = std::move(b2); TEST_EQ_FUNC(b1.GetSize(), b2_size); TEST_ASSERT_FUNC(release_n_verify(b1, m2_name, m2_color)); TEST_EQ_FUNC(b2.GetSize(), 0); } static void builder_move_assign_after_releaseraw_test() { Builder b1; auto root_offset1 = populate1(b1); b1.Finish(root_offset1); size_t size, offset; uint8_t *buf = release_raw_base(b1, size, offset); TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color)); free_raw(b1, buf); Builder b2; auto root_offset2 = populate2(b2); b2.Finish(root_offset2); auto b2_size = b2.GetSize(); // Move into a released builder. b1 = std::move(b2); TEST_EQ_FUNC(b1.GetSize(), b2_size); TEST_ASSERT_FUNC(release_n_verify(b1, m2_name, m2_color)); TEST_EQ_FUNC(b2.GetSize(), 0); } static void all_tests() { empty_builder_movector_test(); nonempty_builder_movector_test(); builder_movector_before_finish_test(); builder_movector_after_finish_test(); builder_move_assign_before_finish_test(); builder_move_assign_after_finish_test(); builder_swap_before_finish_test(); builder_swap_after_finish_test(); builder_move_assign_after_release_test(); builder_move_assign_after_releaseraw_test(); } }; enum BuilderReuseTestSelector { REUSABLE_AFTER_RELEASE = 1, REUSABLE_AFTER_RELEASE_RAW = 2, REUSABLE_AFTER_RELEASE_MESSAGE = 3, REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN = 4, REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN = 5, REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN = 6 }; typedef std::set TestSelector; template struct BuilderReuseTests { static void builder_reusable_after_release_test(TestSelector selector) { if (!selector.count(REUSABLE_AFTER_RELEASE)) { return; } Builder b1; std::vector buffers; for (int i = 0; i < 5; ++i) { auto root_offset1 = populate1(b1); b1.Finish(root_offset1); buffers.push_back(b1.Release()); TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color)); } } static void builder_reusable_after_releaseraw_test(TestSelector selector) { if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) { return; } Builder b1; for (int i = 0; i < 5; ++i) { auto root_offset1 = populate1(b1); b1.Finish(root_offset1); size_t size, offset; uint8_t *buf = release_raw_base(b1, size, offset); TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color)); free_raw(b1, buf); } } static void builder_reusable_after_release_and_move_assign_test(TestSelector selector) { if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) { return; } Builder b1; std::vector buffers; for (int i = 0; i < 5; ++i) { auto root_offset1 = populate1(b1); b1.Finish(root_offset1); buffers.push_back(b1.Release()); TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color)); Builder b2; b1 = std::move(b2); TEST_EQ_FUNC(b2.GetSize(), 0); } } static void builder_reusable_after_releaseraw_and_move_assign_test(TestSelector selector) { if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) { return; } Builder b1; for (int i = 0; i < 5; ++i) { auto root_offset1 = populate1(b1); b1.Finish(root_offset1); size_t size, offset; uint8_t *buf = release_raw_base(b1, size, offset); TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color)); free_raw(b1, buf); Builder b2; b1 = std::move(b2); TEST_EQ_FUNC(b2.GetSize(), 0); } } static void run_tests(TestSelector selector) { builder_reusable_after_release_test(selector); builder_reusable_after_releaseraw_test(selector); builder_reusable_after_release_and_move_assign_test(selector); builder_reusable_after_releaseraw_and_move_assign_test(selector); } }; #endif // TEST_BUILDER_H