1 #ifndef TEST_BUILDER_H 2 #define TEST_BUILDER_H 3 4 #include <set> 5 #include <type_traits> 6 7 #include "flatbuffers/flatbuffers.h" 8 #include "monster_test_generated.h" 9 #include "test_assert.h" 10 11 using MyGame::Example::Color; 12 using MyGame::Example::Monster; 13 14 namespace flatbuffers { 15 namespace grpc { 16 class MessageBuilder; 17 } 18 } // namespace flatbuffers 19 20 template<class T, class U> struct is_same { static const bool value = false; }; 21 22 template<class T> struct is_same<T, T> { static const bool value = true; }; 23 24 inline std::string m1_name() { return "Cyberdemon"; } 25 inline std::string m2_name() { return "Imp"; } 26 inline MyGame::Example::Color m1_color() { 27 return MyGame::Example::Color_Red; 28 } 29 inline MyGame::Example::Color m2_color() { 30 return MyGame::Example::Color_Green; 31 } 32 inline void m1_color_check() { 33 // Ensure that all compilation units see the same monster_test_generated.h. 34 extern void CheckTestGeneratedIsValid(const MyGame::Example::Color&); 35 CheckTestGeneratedIsValid(m1_color()); 36 } 37 38 flatbuffers::Offset<Monster> populate1(flatbuffers::FlatBufferBuilder &builder); 39 flatbuffers::Offset<Monster> populate2(flatbuffers::FlatBufferBuilder &builder); 40 41 uint8_t *release_raw_base(flatbuffers::FlatBufferBuilder &fbb, size_t &size, 42 size_t &offset); 43 44 void free_raw(flatbuffers::grpc::MessageBuilder &mbb, uint8_t *buf); 45 void free_raw(flatbuffers::FlatBufferBuilder &fbb, uint8_t *buf); 46 47 bool verify(const flatbuffers::DetachedBuffer &buf, 48 const std::string &expected_name, Color color); 49 bool verify(const uint8_t *buf, size_t offset, const std::string &expected_name, 50 Color color); 51 52 bool release_n_verify(flatbuffers::FlatBufferBuilder &fbb, 53 const std::string &expected_name, Color color); 54 bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb, 55 const std::string &expected_name, Color color); 56 57 // Invokes this function when testing the following Builder types 58 // FlatBufferBuilder, TestHeapBuilder, and GrpcLikeMessageBuilder 59 template<class Builder> 60 void builder_move_assign_after_releaseraw_test(Builder b1) { 61 auto root_offset1 = populate1(b1); 62 b1.Finish(root_offset1); 63 size_t size, offset; 64 65 uint8_t *rr = b1.ReleaseRaw(size, offset); 66 std::shared_ptr<uint8_t> raw( 67 rr, [size](uint8_t *ptr) { 68 flatbuffers::DefaultAllocator::dealloc(ptr, size); 69 }); 70 Builder src; 71 auto root_offset2 = populate2(src); 72 src.Finish(root_offset2); 73 auto src_size = src.GetSize(); 74 // Move into a released builder. 75 b1 = std::move(src); 76 TEST_EQ_FUNC(b1.GetSize(), src_size); 77 TEST_ASSERT_FUNC(release_n_verify(b1, m2_name(), m2_color())); 78 TEST_EQ_FUNC(src.GetSize(), 0); 79 } 80 81 void builder_move_assign_after_releaseraw_test( 82 flatbuffers::grpc::MessageBuilder b1); 83 84 template<class DestBuilder, class SrcBuilder = DestBuilder> 85 struct BuilderTests { 86 static void empty_builder_movector_test() { 87 SrcBuilder src; 88 size_t src_size = src.GetSize(); 89 DestBuilder dst(std::move(src)); 90 size_t dst_size = dst.GetSize(); 91 TEST_EQ_FUNC(src_size, 0); 92 TEST_EQ_FUNC(src_size, dst_size); 93 } 94 95 static void nonempty_builder_movector_test() { 96 SrcBuilder src; 97 populate1(src); 98 size_t src_size = src.GetSize(); 99 DestBuilder dst(std::move(src)); 100 TEST_EQ_FUNC(src_size, dst.GetSize()); 101 TEST_EQ_FUNC(src.GetSize(), 0); 102 } 103 104 static void builder_movector_before_finish_test() { 105 SrcBuilder src; 106 auto root_offset1 = populate1(src); 107 DestBuilder dst(std::move(src)); 108 dst.Finish(root_offset1); 109 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 110 TEST_EQ_FUNC(src.GetSize(), 0); 111 } 112 113 static void builder_movector_after_finish_test() { 114 SrcBuilder src; 115 auto root_offset1 = populate1(src); 116 src.Finish(root_offset1); 117 auto src_size = src.GetSize(); 118 DestBuilder dst(std::move(src)); 119 TEST_EQ_FUNC(dst.GetSize(), src_size); 120 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 121 TEST_EQ_FUNC(src.GetSize(), 0); 122 } 123 124 static void builder_move_assign_before_finish_test() { 125 SrcBuilder src; 126 auto root_offset1 = populate1(src); 127 DestBuilder dst; 128 populate2(dst); 129 dst = std::move(src); 130 dst.Finish(root_offset1); 131 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 132 TEST_EQ_FUNC(src.GetSize(), 0); 133 } 134 135 static void builder_move_assign_after_finish_test() { 136 SrcBuilder src; 137 auto root_offset1 = populate1(src); 138 src.Finish(root_offset1); 139 auto src_size = src.GetSize(); 140 DestBuilder dst; 141 auto root_offset2 = populate2(dst); 142 dst.Finish(root_offset2); 143 dst = std::move(src); 144 TEST_EQ_FUNC(dst.GetSize(), src_size); 145 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 146 TEST_EQ_FUNC(src.GetSize(), 0); 147 } 148 149 static void builder_move_assign_after_release_test() { 150 DestBuilder dst; 151 auto root_offset1 = populate1(dst); 152 dst.Finish(root_offset1); 153 { 154 flatbuffers::DetachedBuffer dst_detached = dst.Release(); 155 // detached buffer is deleted 156 } 157 SrcBuilder src; 158 auto root_offset2 = populate2(src); 159 src.Finish(root_offset2); 160 auto src_size = src.GetSize(); 161 // Move into a released builder. 162 dst = std::move(src); 163 TEST_EQ_FUNC(dst.GetSize(), src_size); 164 TEST_ASSERT_FUNC(release_n_verify(dst, m2_name(), m2_color())); 165 TEST_EQ_FUNC(src.GetSize(), 0); 166 } 167 168 static void builder_swap_before_finish_test( 169 bool run = is_same<DestBuilder, SrcBuilder>::value) { 170 /// Swap is allowed only when lhs and rhs are the same concrete type. 171 if (run) { 172 SrcBuilder src; 173 auto root_offset1 = populate1(src); 174 auto size1 = src.GetSize(); 175 DestBuilder dst; 176 auto root_offset2 = populate2(dst); 177 auto size2 = dst.GetSize(); 178 src.Swap(dst); 179 src.Finish(root_offset2); 180 dst.Finish(root_offset1); 181 TEST_EQ_FUNC(src.GetSize() > size2, true); 182 TEST_EQ_FUNC(dst.GetSize() > size1, true); 183 TEST_ASSERT_FUNC(release_n_verify(src, m2_name(), m2_color())); 184 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 185 } 186 } 187 188 static void builder_swap_after_finish_test( 189 bool run = is_same<DestBuilder, SrcBuilder>::value) { 190 /// Swap is allowed only when lhs and rhs are the same concrete type. 191 if (run) { 192 SrcBuilder src; 193 auto root_offset1 = populate1(src); 194 src.Finish(root_offset1); 195 auto size1 = src.GetSize(); 196 DestBuilder dst; 197 auto root_offset2 = populate2(dst); 198 dst.Finish(root_offset2); 199 auto size2 = dst.GetSize(); 200 src.Swap(dst); 201 TEST_EQ_FUNC(src.GetSize(), size2); 202 TEST_EQ_FUNC(dst.GetSize(), size1); 203 TEST_ASSERT_FUNC(release_n_verify(src, m2_name(), m2_color())); 204 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 205 } 206 } 207 208 static void all_tests() { 209 empty_builder_movector_test(); 210 nonempty_builder_movector_test(); 211 builder_movector_before_finish_test(); 212 builder_movector_after_finish_test(); 213 builder_move_assign_before_finish_test(); 214 builder_move_assign_after_finish_test(); 215 builder_move_assign_after_release_test(); 216 builder_move_assign_after_releaseraw_test(DestBuilder()); 217 builder_swap_before_finish_test(); 218 builder_swap_after_finish_test(); 219 } 220 }; 221 222 enum BuilderReuseTestSelector { 223 REUSABLE_AFTER_RELEASE = 1, 224 REUSABLE_AFTER_RELEASE_RAW = 2, 225 REUSABLE_AFTER_RELEASE_MESSAGE = 3, 226 REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN = 4, 227 REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN = 5, 228 REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN = 6 229 }; 230 231 typedef std::set<BuilderReuseTestSelector> TestSelector; 232 233 template<class DestBuilder, class SrcBuilder> struct BuilderReuseTests { 234 static void builder_reusable_after_release_test(TestSelector selector) { 235 if (!selector.count(REUSABLE_AFTER_RELEASE)) { return; } 236 237 DestBuilder fbb; 238 std::vector<flatbuffers::DetachedBuffer> buffers; 239 for (int i = 0; i < 5; ++i) { 240 auto root_offset1 = populate1(fbb); 241 fbb.Finish(root_offset1); 242 buffers.push_back(fbb.Release()); 243 TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color())); 244 } 245 } 246 247 static void builder_reusable_after_releaseraw_test(TestSelector selector) { 248 if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) { return; } 249 250 DestBuilder fbb; 251 for (int i = 0; i < 5; ++i) { 252 auto root_offset1 = populate1(fbb); 253 fbb.Finish(root_offset1); 254 size_t size, offset; 255 uint8_t *buf = release_raw_base(fbb, size, offset); 256 TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color())); 257 free_raw(fbb, buf); 258 } 259 } 260 261 static void builder_reusable_after_release_and_move_assign_test( 262 TestSelector selector) { 263 if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) { return; } 264 265 DestBuilder dst; 266 std::vector<flatbuffers::DetachedBuffer> buffers; 267 for (int i = 0; i < 5; ++i) { 268 auto root_offset1 = populate1(dst); 269 dst.Finish(root_offset1); 270 buffers.push_back(dst.Release()); 271 TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color())); 272 SrcBuilder src; 273 dst = std::move(src); 274 TEST_EQ_FUNC(src.GetSize(), 0); 275 } 276 } 277 278 static void builder_reusable_after_releaseraw_and_move_assign_test( 279 TestSelector selector) { 280 if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) { return; } 281 282 DestBuilder dst; 283 for (int i = 0; i < 5; ++i) { 284 auto root_offset1 = populate1(dst); 285 dst.Finish(root_offset1); 286 size_t size, offset; 287 uint8_t *buf = release_raw_base(dst, size, offset); 288 TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color())); 289 free_raw(dst, buf); 290 SrcBuilder src; 291 dst = std::move(src); 292 TEST_EQ_FUNC(src.GetSize(), 0); 293 } 294 } 295 296 static void run_tests(TestSelector selector) { 297 builder_reusable_after_release_test(selector); 298 builder_reusable_after_releaseraw_test(selector); 299 builder_reusable_after_release_and_move_assign_test(selector); 300 builder_reusable_after_releaseraw_and_move_assign_test(selector); 301 } 302 }; 303 304 #endif // TEST_BUILDER_H 305