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