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 // clang-format off 58 #if !defined(FLATBUFFERS_CPP98_STL) 59 // clang-format on 60 // Invokes this function when testing the following Builder types 61 // FlatBufferBuilder, TestHeapBuilder, and GrpcLikeMessageBuilder 62 template<class Builder> 63 void builder_move_assign_after_releaseraw_test(Builder b1) { 64 auto root_offset1 = populate1(b1); 65 b1.Finish(root_offset1); 66 size_t size, offset; 67 std::shared_ptr<uint8_t> raw( 68 b1.ReleaseRaw(size, offset), [size](uint8_t *ptr) { 69 flatbuffers::DefaultAllocator::dealloc(ptr, size); 70 }); 71 Builder src; 72 auto root_offset2 = populate2(src); 73 src.Finish(root_offset2); 74 auto src_size = src.GetSize(); 75 // Move into a released builder. 76 b1 = std::move(src); 77 TEST_EQ_FUNC(b1.GetSize(), src_size); 78 TEST_ASSERT_FUNC(release_n_verify(b1, m2_name(), m2_color())); 79 TEST_EQ_FUNC(src.GetSize(), 0); 80 } 81 // clang-format off 82 #endif // !defined(FLATBUFFERS_CPP98_STL) 83 // clang-format on 84 85 void builder_move_assign_after_releaseraw_test( 86 flatbuffers::grpc::MessageBuilder b1); 87 88 template<class DestBuilder, class SrcBuilder = DestBuilder> 89 struct BuilderTests { 90 // clang-format off 91 #if !defined(FLATBUFFERS_CPP98_STL) 92 // clang-format on 93 static void empty_builder_movector_test() { 94 SrcBuilder src; 95 size_t src_size = src.GetSize(); 96 DestBuilder dst(std::move(src)); 97 size_t dst_size = dst.GetSize(); 98 TEST_EQ_FUNC(src_size, 0); 99 TEST_EQ_FUNC(src_size, dst_size); 100 } 101 102 static void nonempty_builder_movector_test() { 103 SrcBuilder src; 104 populate1(src); 105 size_t src_size = src.GetSize(); 106 DestBuilder dst(std::move(src)); 107 TEST_EQ_FUNC(src_size, dst.GetSize()); 108 TEST_EQ_FUNC(src.GetSize(), 0); 109 } 110 111 static void builder_movector_before_finish_test() { 112 SrcBuilder src; 113 auto root_offset1 = populate1(src); 114 DestBuilder dst(std::move(src)); 115 dst.Finish(root_offset1); 116 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 117 TEST_EQ_FUNC(src.GetSize(), 0); 118 } 119 120 static void builder_movector_after_finish_test() { 121 SrcBuilder src; 122 auto root_offset1 = populate1(src); 123 src.Finish(root_offset1); 124 auto src_size = src.GetSize(); 125 DestBuilder dst(std::move(src)); 126 TEST_EQ_FUNC(dst.GetSize(), src_size); 127 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 128 TEST_EQ_FUNC(src.GetSize(), 0); 129 } 130 131 static void builder_move_assign_before_finish_test() { 132 SrcBuilder src; 133 auto root_offset1 = populate1(src); 134 DestBuilder dst; 135 populate2(dst); 136 dst = std::move(src); 137 dst.Finish(root_offset1); 138 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 139 TEST_EQ_FUNC(src.GetSize(), 0); 140 } 141 142 static void builder_move_assign_after_finish_test() { 143 SrcBuilder src; 144 auto root_offset1 = populate1(src); 145 src.Finish(root_offset1); 146 auto src_size = src.GetSize(); 147 DestBuilder dst; 148 auto root_offset2 = populate2(dst); 149 dst.Finish(root_offset2); 150 dst = std::move(src); 151 TEST_EQ_FUNC(dst.GetSize(), src_size); 152 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 153 TEST_EQ_FUNC(src.GetSize(), 0); 154 } 155 156 static void builder_move_assign_after_release_test() { 157 DestBuilder dst; 158 auto root_offset1 = populate1(dst); 159 dst.Finish(root_offset1); 160 { 161 flatbuffers::DetachedBuffer dst_detached = dst.Release(); 162 // detached buffer is deleted 163 } 164 SrcBuilder src; 165 auto root_offset2 = populate2(src); 166 src.Finish(root_offset2); 167 auto src_size = src.GetSize(); 168 // Move into a released builder. 169 dst = std::move(src); 170 TEST_EQ_FUNC(dst.GetSize(), src_size); 171 TEST_ASSERT_FUNC(release_n_verify(dst, m2_name(), m2_color())); 172 TEST_EQ_FUNC(src.GetSize(), 0); 173 } 174 // clang-format off 175 #endif // !defined(FLATBUFFERS_CPP98_STL) 176 // clang-format on 177 178 static void builder_swap_before_finish_test( 179 bool run = is_same<DestBuilder, SrcBuilder>::value) { 180 /// Swap is allowed only when lhs and rhs are the same concrete type. 181 if (run) { 182 SrcBuilder src; 183 auto root_offset1 = populate1(src); 184 auto size1 = src.GetSize(); 185 DestBuilder dst; 186 auto root_offset2 = populate2(dst); 187 auto size2 = dst.GetSize(); 188 src.Swap(dst); 189 src.Finish(root_offset2); 190 dst.Finish(root_offset1); 191 TEST_EQ_FUNC(src.GetSize() > size2, true); 192 TEST_EQ_FUNC(dst.GetSize() > size1, true); 193 TEST_ASSERT_FUNC(release_n_verify(src, m2_name(), m2_color())); 194 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 195 } 196 } 197 198 static void builder_swap_after_finish_test( 199 bool run = is_same<DestBuilder, SrcBuilder>::value) { 200 /// Swap is allowed only when lhs and rhs are the same concrete type. 201 if (run) { 202 SrcBuilder src; 203 auto root_offset1 = populate1(src); 204 src.Finish(root_offset1); 205 auto size1 = src.GetSize(); 206 DestBuilder dst; 207 auto root_offset2 = populate2(dst); 208 dst.Finish(root_offset2); 209 auto size2 = dst.GetSize(); 210 src.Swap(dst); 211 TEST_EQ_FUNC(src.GetSize(), size2); 212 TEST_EQ_FUNC(dst.GetSize(), size1); 213 TEST_ASSERT_FUNC(release_n_verify(src, m2_name(), m2_color())); 214 TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color())); 215 } 216 } 217 218 static void all_tests() { 219 // clang-format off 220 #if !defined(FLATBUFFERS_CPP98_STL) 221 // clang-format on 222 empty_builder_movector_test(); 223 nonempty_builder_movector_test(); 224 builder_movector_before_finish_test(); 225 builder_movector_after_finish_test(); 226 builder_move_assign_before_finish_test(); 227 builder_move_assign_after_finish_test(); 228 builder_move_assign_after_release_test(); 229 builder_move_assign_after_releaseraw_test(DestBuilder()); 230 // clang-format off 231 #endif // !defined(FLATBUFFERS_CPP98_STL) 232 // clang-format on 233 builder_swap_before_finish_test(); 234 builder_swap_after_finish_test(); 235 } 236 }; 237 238 enum BuilderReuseTestSelector { 239 REUSABLE_AFTER_RELEASE = 1, 240 REUSABLE_AFTER_RELEASE_RAW = 2, 241 REUSABLE_AFTER_RELEASE_MESSAGE = 3, 242 REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN = 4, 243 REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN = 5, 244 REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN = 6 245 }; 246 247 typedef std::set<BuilderReuseTestSelector> TestSelector; 248 249 template<class DestBuilder, class SrcBuilder> struct BuilderReuseTests { 250 static void builder_reusable_after_release_test(TestSelector selector) { 251 if (!selector.count(REUSABLE_AFTER_RELEASE)) { return; } 252 253 DestBuilder fbb; 254 std::vector<flatbuffers::DetachedBuffer> buffers; 255 for (int i = 0; i < 5; ++i) { 256 auto root_offset1 = populate1(fbb); 257 fbb.Finish(root_offset1); 258 buffers.push_back(fbb.Release()); 259 TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color())); 260 } 261 } 262 263 static void builder_reusable_after_releaseraw_test(TestSelector selector) { 264 if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) { return; } 265 266 DestBuilder fbb; 267 for (int i = 0; i < 5; ++i) { 268 auto root_offset1 = populate1(fbb); 269 fbb.Finish(root_offset1); 270 size_t size, offset; 271 uint8_t *buf = release_raw_base(fbb, size, offset); 272 TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color())); 273 free_raw(fbb, buf); 274 } 275 } 276 277 // clang-format off 278 #if !defined(FLATBUFFERS_CPP98_STL) 279 // clang-format on 280 static void builder_reusable_after_release_and_move_assign_test( 281 TestSelector selector) { 282 if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) { return; } 283 284 DestBuilder dst; 285 std::vector<flatbuffers::DetachedBuffer> buffers; 286 for (int i = 0; i < 5; ++i) { 287 auto root_offset1 = populate1(dst); 288 dst.Finish(root_offset1); 289 buffers.push_back(dst.Release()); 290 TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color())); 291 SrcBuilder src; 292 dst = std::move(src); 293 TEST_EQ_FUNC(src.GetSize(), 0); 294 } 295 } 296 297 static void builder_reusable_after_releaseraw_and_move_assign_test( 298 TestSelector selector) { 299 if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) { return; } 300 301 DestBuilder dst; 302 for (int i = 0; i < 5; ++i) { 303 auto root_offset1 = populate1(dst); 304 dst.Finish(root_offset1); 305 size_t size, offset; 306 uint8_t *buf = release_raw_base(dst, size, offset); 307 TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color())); 308 free_raw(dst, buf); 309 SrcBuilder src; 310 dst = std::move(src); 311 TEST_EQ_FUNC(src.GetSize(), 0); 312 } 313 } 314 // clang-format off 315 #endif // !defined(FLATBUFFERS_CPP98_STL) 316 // clang-format on 317 318 static void run_tests(TestSelector selector) { 319 builder_reusable_after_release_test(selector); 320 builder_reusable_after_releaseraw_test(selector); 321 // clang-format off 322 #if !defined(FLATBUFFERS_CPP98_STL) 323 // clang-format on 324 builder_reusable_after_release_and_move_assign_test(selector); 325 builder_reusable_after_releaseraw_and_move_assign_test(selector); 326 // clang-format off 327 #endif // !defined(FLATBUFFERS_CPP98_STL) 328 // clang-format on 329 } 330 }; 331 332 #endif // TEST_BUILDER_H 333