• 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 
m1_name()20 inline std::string m1_name() { return "Cyberdemon"; }
m2_name()21 inline std::string m2_name() { return "Imp"; }
m1_color()22 inline MyGame::Example::Color m1_color() {
23   return MyGame::Example::Color_Red;
24 }
m2_color()25 inline MyGame::Example::Color m2_color() {
26   return MyGame::Example::Color_Green;
27 }
m1_color_check()28 inline void m1_color_check() {
29   // Ensure that all compilation units see the same monster_test_generated.h.
30   extern void CheckTestGeneratedIsValid(const MyGame::Example::Color&);
31   CheckTestGeneratedIsValid(m1_color());
32 }
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,
38                           size_t &offset);
39 
40 void free_raw(flatbuffers::grpc::MessageBuilder &mbb, uint8_t *buf);
41 void free_raw(flatbuffers::FlatBufferBuilder &fbb, uint8_t *buf);
42 
43 bool verify(const flatbuffers::DetachedBuffer &buf,
44             const std::string &expected_name, Color color);
45 bool verify(const uint8_t *buf, size_t offset, const std::string &expected_name,
46             Color color);
47 
48 bool release_n_verify(flatbuffers::FlatBufferBuilder &fbb,
49                       const std::string &expected_name, Color color);
50 bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb,
51                       const std::string &expected_name, Color color);
52 
53 // Invokes this function when testing the following Builder types
54 // FlatBufferBuilder, TestHeapBuilder, and GrpcLikeMessageBuilder
55 template<class Builder>
builder_move_assign_after_releaseraw_test(Builder b1)56 void builder_move_assign_after_releaseraw_test(Builder b1) {
57   auto root_offset1 = populate1(b1);
58   b1.Finish(root_offset1);
59   size_t size, offset;
60 
61   uint8_t *rr = b1.ReleaseRaw(size, offset);
62   std::shared_ptr<uint8_t> raw(
63       rr, [size](uint8_t *ptr) {
64         flatbuffers::DefaultAllocator::dealloc(ptr, size);
65       });
66   Builder src;
67   auto root_offset2 = populate2(src);
68   src.Finish(root_offset2);
69   auto src_size = src.GetSize();
70   // Move into a released builder.
71   b1 = std::move(src);
72   TEST_EQ_FUNC(b1.GetSize(), src_size);
73   TEST_ASSERT_FUNC(release_n_verify(b1, m2_name(), m2_color()));
74   TEST_EQ_FUNC(src.GetSize(), 0);
75 }
76 
77 void builder_move_assign_after_releaseraw_test(
78     flatbuffers::grpc::MessageBuilder b1);
79 
80 template<class DestBuilder, class SrcBuilder = DestBuilder>
81 struct BuilderTests {
empty_builder_movector_testBuilderTests82   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 
nonempty_builder_movector_testBuilderTests91   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 
builder_movector_before_finish_testBuilderTests100   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 
builder_movector_after_finish_testBuilderTests109   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 
builder_move_assign_before_finish_testBuilderTests120   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 
builder_move_assign_after_finish_testBuilderTests131   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 
builder_move_assign_after_release_testBuilderTests145   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 
164   static void builder_swap_before_finish_test(
165       bool run = std::is_same<DestBuilder, SrcBuilder>::value) {
166     /// Swap is allowed only when lhs and rhs are the same concrete type.
167     if (run) {
168       SrcBuilder src;
169       auto root_offset1 = populate1(src);
170       auto size1 = src.GetSize();
171       DestBuilder dst;
172       auto root_offset2 = populate2(dst);
173       auto size2 = dst.GetSize();
174       src.Swap(dst);
175       src.Finish(root_offset2);
176       dst.Finish(root_offset1);
177       TEST_EQ_FUNC(src.GetSize() > size2, true);
178       TEST_EQ_FUNC(dst.GetSize() > size1, true);
179       TEST_ASSERT_FUNC(release_n_verify(src, m2_name(), m2_color()));
180       TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color()));
181     }
182   }
183 
184   static void builder_swap_after_finish_test(
185       bool run = std::is_same<DestBuilder, SrcBuilder>::value) {
186     /// Swap is allowed only when lhs and rhs are the same concrete type.
187     if (run) {
188       SrcBuilder src;
189       auto root_offset1 = populate1(src);
190       src.Finish(root_offset1);
191       auto size1 = src.GetSize();
192       DestBuilder dst;
193       auto root_offset2 = populate2(dst);
194       dst.Finish(root_offset2);
195       auto size2 = dst.GetSize();
196       src.Swap(dst);
197       TEST_EQ_FUNC(src.GetSize(), size2);
198       TEST_EQ_FUNC(dst.GetSize(), size1);
199       TEST_ASSERT_FUNC(release_n_verify(src, m2_name(), m2_color()));
200       TEST_ASSERT_FUNC(release_n_verify(dst, m1_name(), m1_color()));
201     }
202   }
203 
all_testsBuilderTests204   static void all_tests() {
205     empty_builder_movector_test();
206     nonempty_builder_movector_test();
207     builder_movector_before_finish_test();
208     builder_movector_after_finish_test();
209     builder_move_assign_before_finish_test();
210     builder_move_assign_after_finish_test();
211     builder_move_assign_after_release_test();
212     builder_move_assign_after_releaseraw_test(DestBuilder());
213     builder_swap_before_finish_test();
214     builder_swap_after_finish_test();
215   }
216 };
217 
218 enum BuilderReuseTestSelector {
219   REUSABLE_AFTER_RELEASE = 1,
220   REUSABLE_AFTER_RELEASE_RAW = 2,
221   REUSABLE_AFTER_RELEASE_MESSAGE = 3,
222   REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN = 4,
223   REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN = 5,
224   REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN = 6
225 };
226 
227 typedef std::set<BuilderReuseTestSelector> TestSelector;
228 
229 template<class DestBuilder, class SrcBuilder> struct BuilderReuseTests {
builder_reusable_after_release_testBuilderReuseTests230   static void builder_reusable_after_release_test(TestSelector selector) {
231     if (!selector.count(REUSABLE_AFTER_RELEASE)) { return; }
232 
233     DestBuilder fbb;
234     std::vector<flatbuffers::DetachedBuffer> buffers;
235     for (int i = 0; i < 5; ++i) {
236       auto root_offset1 = populate1(fbb);
237       fbb.Finish(root_offset1);
238       buffers.push_back(fbb.Release());
239       TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color()));
240     }
241   }
242 
builder_reusable_after_releaseraw_testBuilderReuseTests243   static void builder_reusable_after_releaseraw_test(TestSelector selector) {
244     if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) { return; }
245 
246     DestBuilder fbb;
247     for (int i = 0; i < 5; ++i) {
248       auto root_offset1 = populate1(fbb);
249       fbb.Finish(root_offset1);
250       size_t size, offset;
251       uint8_t *buf = release_raw_base(fbb, size, offset);
252       TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color()));
253       free_raw(fbb, buf);
254     }
255   }
256 
builder_reusable_after_release_and_move_assign_testBuilderReuseTests257   static void builder_reusable_after_release_and_move_assign_test(
258       TestSelector selector) {
259     if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) { return; }
260 
261     DestBuilder dst;
262     std::vector<flatbuffers::DetachedBuffer> buffers;
263     for (int i = 0; i < 5; ++i) {
264       auto root_offset1 = populate1(dst);
265       dst.Finish(root_offset1);
266       buffers.push_back(dst.Release());
267       TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color()));
268       SrcBuilder src;
269       dst = std::move(src);
270       TEST_EQ_FUNC(src.GetSize(), 0);
271     }
272   }
273 
builder_reusable_after_releaseraw_and_move_assign_testBuilderReuseTests274   static void builder_reusable_after_releaseraw_and_move_assign_test(
275       TestSelector selector) {
276     if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) { return; }
277 
278     DestBuilder dst;
279     for (int i = 0; i < 5; ++i) {
280       auto root_offset1 = populate1(dst);
281       dst.Finish(root_offset1);
282       size_t size, offset;
283       uint8_t *buf = release_raw_base(dst, size, offset);
284       TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color()));
285       free_raw(dst, buf);
286       SrcBuilder src;
287       dst = std::move(src);
288       TEST_EQ_FUNC(src.GetSize(), 0);
289     }
290   }
291 
run_testsBuilderReuseTests292   static void run_tests(TestSelector selector) {
293     builder_reusable_after_release_test(selector);
294     builder_reusable_after_releaseraw_test(selector);
295     builder_reusable_after_release_and_move_assign_test(selector);
296     builder_reusable_after_releaseraw_and_move_assign_test(selector);
297   }
298 };
299 
300 #endif  // TEST_BUILDER_H
301