• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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