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
11using MyGame::Example::Color;
12using MyGame::Example::Monster;
13
14namespace flatbuffers {
15namespace grpc {
16class MessageBuilder;
17}
18} // namespace flatbuffers
19
20inline std::string m1_name() { return "Cyberdemon"; }
21inline std::string m2_name() { return "Imp"; }
22inline MyGame::Example::Color m1_color() {
23 return MyGame::Example::Color_Red;
24}
25inline MyGame::Example::Color m2_color() {
26 return MyGame::Example::Color_Green;
27}
28inline 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
34flatbuffers::Offset<Monster> populate1(flatbuffers::FlatBufferBuilder &builder);
35flatbuffers::Offset<Monster> populate2(flatbuffers::FlatBufferBuilder &builder);
36
37uint8_t *release_raw_base(flatbuffers::FlatBufferBuilder &fbb, size_t &size,
38 size_t &offset);
39
40void free_raw(flatbuffers::grpc::MessageBuilder &mbb, uint8_t *buf);
41void free_raw(flatbuffers::FlatBufferBuilder &fbb, uint8_t *buf);
42
43bool verify(const flatbuffers::DetachedBuffer &buf,
44 const std::string &expected_name, Color color);
45bool verify(const uint8_t *buf, size_t offset, const std::string &expected_name,
46 Color color);
47
48bool release_n_verify(flatbuffers::FlatBufferBuilder &fbb,
49 const std::string &expected_name, Color color);
50bool 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
55template<class Builder>
56void 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
77void builder_move_assign_after_releaseraw_test(
78 flatbuffers::grpc::MessageBuilder b1);
79
80template<class DestBuilder, class SrcBuilder = DestBuilder>
81struct BuilderTests {
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
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
204 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
218enum 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
227typedef std::set<BuilderReuseTestSelector> TestSelector;
228
229template<class DestBuilder, class SrcBuilder> struct BuilderReuseTests {
230 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
243 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
257 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
274 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
292 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
View as plain text