| #ifndef TEST_BUILDER_H |
| #define TEST_BUILDER_H |
| |
| #include <set> |
| #include <type_traits> |
| |
| #include "flatbuffers/flatbuffers.h" |
| #include "monster_test_generated.h" |
| #include "test_assert.h" |
| |
| using MyGame::Example::Color; |
| using MyGame::Example::Monster; |
| |
| namespace flatbuffers { |
| namespace grpc { |
| class MessageBuilder; |
| } |
| } // namespace flatbuffers |
| |
| inline std::string m1_name() { return "Cyberdemon"; } |
| inline std::string m2_name() { return "Imp"; } |
| inline MyGame::Example::Color m1_color() { |
| return MyGame::Example::Color_Red; |
| } |
| inline MyGame::Example::Color m2_color() { |
| return MyGame::Example::Color_Green; |
| } |
| inline void m1_color_check() { |
| // Ensure that all compilation units see the same monster_test_generated.h. |
| extern void CheckTestGeneratedIsValid(const MyGame::Example::Color&); |
| CheckTestGeneratedIsValid(m1_color()); |
| } |
| |
| flatbuffers::Offset<Monster> populate1(flatbuffers::FlatBufferBuilder &builder); |
| flatbuffers::Offset<Monster> 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); |
| |
| // Invokes this function when testing the following Builder types |
| // FlatBufferBuilder, TestHeapBuilder, and GrpcLikeMessageBuilder |
| template<class Builder> |
| void builder_move_assign_after_releaseraw_test(Builder b1) { |
| auto root_offset1 = populate1(b1); |
| b1.Finish(root_offset1); |
| size_t size, offset; |
| |
| uint8_t *rr = b1.ReleaseRaw(size, offset); |
| std::shared_ptr<uint8_t> raw( |
| rr, [size](uint8_t *ptr) { |
| flatbuffers::DefaultAllocator::dealloc(ptr, size); |
| }); |
| Builder src; |
| auto root_offset2 = populate2(src); |
| src.Finish(root_offset2); |
| auto src_size = src.GetSize(); |
| // Move into a released builder. |
| b1 = std::move(src); |
| TEST_EQ_FUNC(b1.GetSize(), src_size); |
| TEST_ASSERT_FUNC(release_n_verify(b1, m2_name(), m2_color())); |
| TEST_EQ_FUNC(src.GetSize(), 0); |
| } |
| |
| void builder_move_assign_after_releaseraw_test( |
| flatbuffers::grpc::MessageBuilder b1); |
| |
| template<class DestBuilder, class SrcBuilder = DestBuilder> |
| struct BuilderTests { |
| static void empty_builder_movector_test() { |
| SrcBuilder src; |
| size_t src_size = src.GetSize(); |
| DestBuilder dst(std::move(src)); |
| size_t dst_size = dst.GetSize(); |
| TEST_EQ_FUNC(src_size, 0); |
| TEST_EQ_FUNC(src_size, dst_size); |
| } |
| |
| static void nonempty_builder_movector_test() { |
| SrcBuilder src; |
| populate1(src); |
| size_t src_size = src.GetSize(); |
| DestBuilder dst(std::move(src)); |
| TEST_EQ_FUNC(src_size, dst.GetSize()); |
| TEST_EQ_FUNC(src.GetSize(), 0); |
| } |
| |
| static void builder_movector_before_finish_test() { |
| SrcBuilder src; |
| auto root_offset1 = populate1(src); |
| DestBuilder dst(std::move(src)); |
| dst.Finish(root_offset1); |
| TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); |
| TEST_EQ_FUNC(src.GetSize(), 0); |
| } |
| |
| static void builder_movector_after_finish_test() { |
| SrcBuilder src; |
| auto root_offset1 = populate1(src); |
| src.Finish(root_offset1); |
| auto src_size = src.GetSize(); |
| DestBuilder dst(std::move(src)); |
| TEST_EQ_FUNC(dst.GetSize(), src_size); |
| TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); |
| TEST_EQ_FUNC(src.GetSize(), 0); |
| } |
| |
| static void builder_move_assign_before_finish_test() { |
| SrcBuilder src; |
| auto root_offset1 = populate1(src); |
| DestBuilder dst; |
| populate2(dst); |
| dst = std::move(src); |
| dst.Finish(root_offset1); |
| TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); |
| TEST_EQ_FUNC(src.GetSize(), 0); |
| } |
| |
| static void builder_move_assign_after_finish_test() { |
| SrcBuilder src; |
| auto root_offset1 = populate1(src); |
| src.Finish(root_offset1); |
| auto src_size = src.GetSize(); |
| DestBuilder dst; |
| auto root_offset2 = populate2(dst); |
| dst.Finish(root_offset2); |
| dst = std::move(src); |
| TEST_EQ_FUNC(dst.GetSize(), src_size); |
| TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); |
| TEST_EQ_FUNC(src.GetSize(), 0); |
| } |
| |
| static void builder_move_assign_after_release_test() { |
| DestBuilder dst; |
| auto root_offset1 = populate1(dst); |
| dst.Finish(root_offset1); |
| { |
| flatbuffers::DetachedBuffer dst_detached = dst.Release(); |
| // detached buffer is deleted |
| } |
| SrcBuilder src; |
| auto root_offset2 = populate2(src); |
| src.Finish(root_offset2); |
| auto src_size = src.GetSize(); |
| // Move into a released builder. |
| dst = std::move(src); |
| TEST_EQ_FUNC(dst.GetSize(), src_size); |
| TEST_ASSERT_FUNC(release_n_verify(dst, m2_name(), m2_color())); |
| TEST_EQ_FUNC(src.GetSize(), 0); |
| } |
| |
| static void builder_swap_before_finish_test( |
| bool run = std::is_same<DestBuilder, SrcBuilder>::value) { |
| /// Swap is allowed only when lhs and rhs are the same concrete type. |
| if (run) { |
| SrcBuilder src; |
| auto root_offset1 = populate1(src); |
| auto size1 = src.GetSize(); |
| DestBuilder dst; |
| auto root_offset2 = populate2(dst); |
| auto size2 = dst.GetSize(); |
| src.Swap(dst); |
| src.Finish(root_offset2); |
| dst.Finish(root_offset1); |
| TEST_EQ_FUNC(src.GetSize() > size2, true); |
| TEST_EQ_FUNC(dst.GetSize() > size1, true); |
| TEST_ASSERT_FUNC(release_n_verify(src, m2_name(), m2_color())); |
| TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); |
| } |
| } |
| |
| static void builder_swap_after_finish_test( |
| bool run = std::is_same<DestBuilder, SrcBuilder>::value) { |
| /// Swap is allowed only when lhs and rhs are the same concrete type. |
| if (run) { |
| SrcBuilder src; |
| auto root_offset1 = populate1(src); |
| src.Finish(root_offset1); |
| auto size1 = src.GetSize(); |
| DestBuilder dst; |
| auto root_offset2 = populate2(dst); |
| dst.Finish(root_offset2); |
| auto size2 = dst.GetSize(); |
| src.Swap(dst); |
| TEST_EQ_FUNC(src.GetSize(), size2); |
| TEST_EQ_FUNC(dst.GetSize(), size1); |
| TEST_ASSERT_FUNC(release_n_verify(src, m2_name(), m2_color())); |
| TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); |
| } |
| } |
| |
| 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_move_assign_after_release_test(); |
| builder_move_assign_after_releaseraw_test(DestBuilder()); |
| builder_swap_before_finish_test(); |
| builder_swap_after_finish_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<BuilderReuseTestSelector> TestSelector; |
| |
| template<class DestBuilder, class SrcBuilder> struct BuilderReuseTests { |
| static void builder_reusable_after_release_test(TestSelector selector) { |
| if (!selector.count(REUSABLE_AFTER_RELEASE)) { return; } |
| |
| DestBuilder fbb; |
| std::vector<flatbuffers::DetachedBuffer> buffers; |
| for (int i = 0; i < 5; ++i) { |
| auto root_offset1 = populate1(fbb); |
| fbb.Finish(root_offset1); |
| buffers.push_back(fbb.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; } |
| |
| DestBuilder fbb; |
| for (int i = 0; i < 5; ++i) { |
| auto root_offset1 = populate1(fbb); |
| fbb.Finish(root_offset1); |
| size_t size, offset; |
| uint8_t *buf = release_raw_base(fbb, size, offset); |
| TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color())); |
| free_raw(fbb, buf); |
| } |
| } |
| |
| static void builder_reusable_after_release_and_move_assign_test( |
| TestSelector selector) { |
| if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) { return; } |
| |
| DestBuilder dst; |
| std::vector<flatbuffers::DetachedBuffer> buffers; |
| for (int i = 0; i < 5; ++i) { |
| auto root_offset1 = populate1(dst); |
| dst.Finish(root_offset1); |
| buffers.push_back(dst.Release()); |
| TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color())); |
| SrcBuilder src; |
| dst = std::move(src); |
| TEST_EQ_FUNC(src.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; } |
| |
| DestBuilder dst; |
| for (int i = 0; i < 5; ++i) { |
| auto root_offset1 = populate1(dst); |
| dst.Finish(root_offset1); |
| size_t size, offset; |
| uint8_t *buf = release_raw_base(dst, size, offset); |
| TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color())); |
| free_raw(dst, buf); |
| SrcBuilder src; |
| dst = std::move(src); |
| TEST_EQ_FUNC(src.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 |