test/zserio/AnyHolderTest.cpp
Line | Count | Source |
1 | | #include <memory> |
2 | | #include <tuple> |
3 | | #include <vector> |
4 | | |
5 | | #include "gtest/gtest.h" |
6 | | #include "zserio/AnyHolder.h" |
7 | | #include "zserio/pmr/MemoryResource.h" |
8 | | #include "zserio/pmr/PolymorphicAllocator.h" |
9 | | |
10 | | #include "TrackingAllocator.h" |
11 | | |
12 | | namespace zserio |
13 | | { |
14 | | |
15 | | namespace |
16 | | { |
17 | | |
18 | | class SmallObject |
19 | | { |
20 | | public: |
21 | | SmallObject() : |
22 | | m_value(0) |
23 | 2 | {} |
24 | | |
25 | | bool operator==(const SmallObject& other) const |
26 | 52 | { |
27 | 52 | return m_value == other.m_value; |
28 | 52 | } |
29 | | |
30 | | private: |
31 | | int m_value; |
32 | | }; |
33 | | |
34 | | struct BigObject |
35 | | { |
36 | 10 | BigObject() = default; |
37 | | |
38 | | BigObject(NoInitT, const BigObject&) |
39 | 13 | {} |
40 | | |
41 | | bool operator==(const BigObject& other) const |
42 | 60 | { |
43 | 60 | return std::tie(value1, value2, value3, value4) == |
44 | 60 | std::tie(other.value1, other.value2, other.value3, other.value4); |
45 | 60 | } |
46 | | |
47 | | uint64_t value1 = 1; |
48 | | uint64_t value2 = 2; |
49 | | uint64_t value3 = 3; |
50 | | uint64_t value4 = 4; |
51 | | }; |
52 | | |
53 | | } // namespace |
54 | | |
55 | | class AnyHolderTest : public ::testing::Test |
56 | | { |
57 | | protected: |
58 | | template <typename T, typename ALLOC> |
59 | | void testAnyHolder(const T& value, const ALLOC& allocator) |
60 | 8 | { |
61 | 8 | testEmptyConstructor<ALLOC>(); |
62 | 8 | testAllocatorConstructor(allocator); |
63 | 8 | testLvalueConstructor(value, allocator); |
64 | 8 | testLvalueConstructorNoInit(value, allocator); |
65 | 8 | testRvalueConstructor(value, allocator); |
66 | 8 | testRvalueConstructorNoInit(value, allocator); |
67 | 8 | testCopyConstructor(value, allocator); |
68 | 8 | testCopyConstructorNoInit(value, allocator); |
69 | 8 | testCopyConstructorWithAllocator(value, allocator); |
70 | 8 | testCopyConstructorWithAllocatorNoInit(value, allocator); |
71 | 8 | testCopyAssignmentOperator(value, allocator); |
72 | 8 | testCopyAssignmentOperatorNoInit(value, allocator); |
73 | 8 | testMoveConstructor(value, allocator); |
74 | 8 | testMoveConstructorNoInit(value, allocator); |
75 | 8 | testMoveConstructorWithAllocator(value, allocator); |
76 | 8 | testMoveConstructorWithAllocatorNoInit(value, allocator); |
77 | 8 | testMoveAssignmentOperator(value, allocator); |
78 | 8 | testMoveAssignmentOperatorNoInit(value, allocator); |
79 | 8 | testMoveAssignmentValueOperator(value, allocator); |
80 | 8 | testReset(value, allocator); |
81 | 8 | testSetGet(value, allocator); |
82 | 8 | testIsType(value, allocator); |
83 | 8 | testHasValue(value, allocator); |
84 | 8 | } |
85 | | |
86 | | private: |
87 | | template <typename ALLOC> |
88 | | void testEmptyConstructor() |
89 | 8 | { |
90 | 8 | AnyHolder<ALLOC> any; |
91 | 8 | ASSERT_FALSE(any.hasValue()); |
92 | 8 | } |
93 | | |
94 | | template <typename ALLOC> |
95 | | void testAllocatorConstructor(const ALLOC& allocator) |
96 | 8 | { |
97 | 8 | AnyHolder<ALLOC> any(allocator); |
98 | 8 | ASSERT_FALSE(any.hasValue()); |
99 | 8 | ASSERT_EQ(allocator, any.get_allocator()); |
100 | 8 | } |
101 | | |
102 | | template <typename T, typename ALLOC> |
103 | | void testLvalueConstructor(const T& value, const ALLOC& allocator) |
104 | 8 | { |
105 | 8 | const void* origAddress = &value; |
106 | 8 | AnyHolder<ALLOC> any(value, allocator); |
107 | | |
108 | 8 | const T& anyValue = any.template get<T>(); |
109 | 8 | ASSERT_NE(origAddress, &anyValue); |
110 | 8 | ASSERT_EQ(value, anyValue); |
111 | 8 | } |
112 | | |
113 | | template <typename T, typename ALLOC> |
114 | | void testLvalueConstructorNoInit(const T& value, const ALLOC& allocator) |
115 | 8 | { |
116 | 8 | const void* origAddress = &value; |
117 | 8 | AnyHolder<ALLOC> any(NoInit, value, allocator); |
118 | | |
119 | 8 | const T& anyValue = any.template get<T>(); |
120 | 8 | ASSERT_NE(origAddress, &anyValue); |
121 | 8 | ASSERT_EQ(value, anyValue); |
122 | 8 | } |
123 | | |
124 | | template <typename ALLOC> |
125 | | void testRvalueConstructor(const std::vector<int>& value, const ALLOC& allocator) |
126 | 2 | { |
127 | 2 | std::vector<int> origValue(value); |
128 | 2 | const void* origAddress = origValue.data(); |
129 | 2 | AnyHolder<ALLOC> any(std::move(origValue), allocator); |
130 | | |
131 | 2 | const std::vector<int>& anyValue = any.template get<std::vector<int>>(); |
132 | 2 | ASSERT_EQ(origAddress, anyValue.data()); |
133 | 2 | ASSERT_EQ(value, anyValue); |
134 | 2 | } |
135 | | |
136 | | template <typename T, typename ALLOC> |
137 | | void testRvalueConstructor(const T& value, const ALLOC& allocator) |
138 | 6 | { |
139 | 6 | T origValue(value); |
140 | 6 | AnyHolder<ALLOC> any(std::move(origValue), allocator); |
141 | | |
142 | 6 | const T& anyValue = any.template get<T>(); |
143 | 6 | ASSERT_EQ(value, anyValue); |
144 | 6 | } |
145 | | |
146 | | template <typename ALLOC> |
147 | | void testRvalueConstructorNoInit(const std::vector<int>& value, const ALLOC& allocator) |
148 | 2 | { |
149 | 2 | std::vector<int> origValue(value); |
150 | 2 | const void* origAddress = origValue.data(); |
151 | 2 | AnyHolder<ALLOC> any(NoInit, std::move(origValue), allocator); |
152 | | |
153 | 2 | const std::vector<int>& anyValue = any.template get<std::vector<int>>(); |
154 | 2 | ASSERT_EQ(origAddress, anyValue.data()); |
155 | 2 | ASSERT_EQ(value, anyValue); |
156 | 2 | } |
157 | | |
158 | | template <typename T, typename ALLOC> |
159 | | void testRvalueConstructorNoInit(const T& value, const ALLOC& allocator) |
160 | 6 | { |
161 | 6 | T origValue(value); |
162 | 6 | AnyHolder<ALLOC> any(NoInit, std::move(origValue), allocator); |
163 | | |
164 | 6 | const T& anyValue = any.template get<T>(); |
165 | 6 | ASSERT_EQ(value, anyValue); |
166 | 6 | } |
167 | | |
168 | | template <typename T, typename ALLOC> |
169 | | void testCopyConstructor(const T& value, const ALLOC& allocator) |
170 | 8 | { |
171 | 8 | AnyHolder<ALLOC> any(allocator); |
172 | | |
173 | | // copy empty holder |
174 | 8 | AnyHolder<ALLOC> anyEmptyCopy(any); |
175 | 8 | ASSERT_FALSE(anyEmptyCopy.hasValue()); |
176 | | |
177 | | // copy filled holder |
178 | 8 | any.set(value); |
179 | 8 | AnyHolder<ALLOC> anyCopy(any); |
180 | 8 | ASSERT_EQ(value, anyCopy.template get<T>()); |
181 | 8 | } |
182 | | |
183 | | template <typename T, typename ALLOC> |
184 | | void testCopyConstructorNoInit(const T& value, const ALLOC& allocator) |
185 | 8 | { |
186 | 8 | AnyHolder<ALLOC> any(allocator); |
187 | | |
188 | | // copy empty holder |
189 | 8 | AnyHolder<ALLOC> anyEmptyCopy(NoInit, any); |
190 | 8 | ASSERT_FALSE(anyEmptyCopy.hasValue()); |
191 | | |
192 | | // copy filled holder |
193 | 8 | any.set(value); |
194 | 8 | AnyHolder<ALLOC> anyCopy(NoInit, any); |
195 | 8 | ASSERT_EQ(value, anyCopy.template get<T>()); |
196 | 8 | } |
197 | | |
198 | | template <typename T, typename ALLOC> |
199 | | void testCopyConstructorWithAllocator(const T& value, const ALLOC& allocator) |
200 | 8 | { |
201 | 8 | AnyHolder<ALLOC> any(allocator); |
202 | | |
203 | | // copy empty holder |
204 | 8 | AnyHolder<ALLOC> anyEmptyCopy(any); |
205 | 8 | ASSERT_FALSE(anyEmptyCopy.hasValue()); |
206 | | |
207 | | // copy filled holder |
208 | 8 | any.set(value); |
209 | 8 | const size_t numAllocations = allocator.numAllocs(); |
210 | 8 | const ALLOC newAllocator; |
211 | 8 | AnyHolder<ALLOC> anyCopy(any, newAllocator); |
212 | 8 | ASSERT_EQ(value, anyCopy.template get<T>()); |
213 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocation and deallocations in old allocator |
214 | 8 | } |
215 | | |
216 | | template <typename T, typename ALLOC> |
217 | | void testCopyConstructorWithAllocatorNoInit(const T& value, const ALLOC& allocator) |
218 | 8 | { |
219 | 8 | AnyHolder<ALLOC> any(allocator); |
220 | | |
221 | | // copy empty holder |
222 | 8 | AnyHolder<ALLOC> anyEmptyCopy(NoInit, any); |
223 | 8 | ASSERT_FALSE(anyEmptyCopy.hasValue()); |
224 | | |
225 | | // copy filled holder |
226 | 8 | any.set(value); |
227 | 8 | const size_t numAllocations = allocator.numAllocs(); |
228 | 8 | const ALLOC newAllocator; |
229 | 8 | AnyHolder<ALLOC> anyCopy(NoInit, any, newAllocator); |
230 | 8 | ASSERT_EQ(value, anyCopy.template get<T>()); |
231 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocation and deallocations in old allocator |
232 | 8 | } |
233 | | |
234 | | template <typename T, typename ALLOC> |
235 | | void testCopyAssignmentOperator(const T& value, const ALLOC& allocator) |
236 | 8 | { |
237 | 8 | AnyHolder<ALLOC> any(allocator); |
238 | | |
239 | | // assignment empty holder |
240 | 8 | AnyHolder<ALLOC> anyEmpty; |
241 | 8 | anyEmpty = any; |
242 | 8 | ASSERT_FALSE(anyEmpty.hasValue()); |
243 | | |
244 | | // assignment filled holder to itself |
245 | 8 | any.set(value); |
246 | 8 | AnyHolder<ALLOC>& anyRef(any); |
247 | 8 | anyRef = any; |
248 | 8 | ASSERT_EQ(value, anyRef.template get<T>()); |
249 | | |
250 | | // assignment filled holder |
251 | 8 | AnyHolder<ALLOC> anyCopy; |
252 | 8 | anyCopy = any; |
253 | 8 | ASSERT_EQ(value, anyCopy.template get<T>()); |
254 | 8 | } |
255 | | |
256 | | template <typename T, typename ALLOC> |
257 | | void testCopyAssignmentOperatorNoInit(const T& value, const ALLOC& allocator) |
258 | 8 | { |
259 | 8 | AnyHolder<ALLOC> any(allocator); |
260 | | |
261 | | // assignment empty holder |
262 | 8 | AnyHolder<ALLOC> anyEmpty; |
263 | 8 | anyEmpty.assign(NoInit, any); |
264 | 8 | ASSERT_FALSE(anyEmpty.hasValue()); |
265 | | |
266 | | // assignment filled holder to itself |
267 | 8 | any.set(value); |
268 | 8 | AnyHolder<ALLOC>& anyRef(any); |
269 | 8 | anyRef.assign(NoInit, any); |
270 | 8 | ASSERT_EQ(value, anyRef.template get<T>()); |
271 | | |
272 | | // assignment filled holder |
273 | 8 | AnyHolder<ALLOC> anyCopy; |
274 | 8 | anyCopy.assign(NoInit, any); |
275 | 8 | ASSERT_EQ(value, anyCopy.template get<T>()); |
276 | 8 | } |
277 | | |
278 | | template <typename T, typename ALLOC> |
279 | | void testMoveConstructor(const T& value, const ALLOC& allocator) |
280 | 8 | { |
281 | 8 | { |
282 | | // move empty holder |
283 | 8 | AnyHolder<ALLOC> any(allocator); |
284 | 8 | AnyHolder<ALLOC> anyMove(std::move(any)); |
285 | 8 | ASSERT_FALSE(anyMove.hasValue()); |
286 | 8 | } |
287 | | |
288 | 8 | { |
289 | | // move filled holder |
290 | 8 | AnyHolder<ALLOC> any(allocator); |
291 | 8 | any.set(value); |
292 | 8 | const size_t numAllocations = allocator.numAllocs(); |
293 | 8 | AnyHolder<ALLOC> anyMove(std::move(any)); |
294 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
295 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocations and deallocations |
296 | 8 | } |
297 | 8 | } |
298 | | |
299 | | template <typename T, typename ALLOC> |
300 | | void testMoveConstructorNoInit(const T& value, const ALLOC& allocator) |
301 | 8 | { |
302 | 8 | { |
303 | | // move empty holder |
304 | 8 | AnyHolder<ALLOC> any(allocator); |
305 | 8 | AnyHolder<ALLOC> anyMove(NoInit, std::move(any)); |
306 | 8 | ASSERT_FALSE(anyMove.hasValue()); |
307 | 8 | } |
308 | | |
309 | 8 | { |
310 | | // move filled holder |
311 | 8 | AnyHolder<ALLOC> any(allocator); |
312 | 8 | any.set(value); |
313 | 8 | const size_t numAllocations = allocator.numAllocs(); |
314 | 8 | AnyHolder<ALLOC> anyMove(NoInit, std::move(any)); |
315 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
316 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocations and deallocations |
317 | 8 | } |
318 | 8 | } |
319 | | |
320 | | template <typename T, typename ALLOC> |
321 | | void testMoveConstructorWithAllocator(const T& value, const ALLOC& allocator) |
322 | 8 | { |
323 | 8 | { |
324 | | // empty holder with the same allocator |
325 | 8 | AnyHolder<ALLOC> any(allocator); |
326 | 8 | AnyHolder<ALLOC> anyMove(std::move(any)); |
327 | 8 | ASSERT_FALSE(anyMove.hasValue()); |
328 | 8 | } |
329 | | |
330 | 8 | { |
331 | | // empty holder with the different allocator |
332 | 8 | AnyHolder<ALLOC> any(allocator); |
333 | 8 | const ALLOC newAllocator; |
334 | 8 | AnyHolder<ALLOC> anyMove(std::move(any), newAllocator); |
335 | 8 | ASSERT_FALSE(anyMove.hasValue()); |
336 | 8 | } |
337 | | |
338 | 8 | { |
339 | | // filled holder with the same allocator |
340 | 8 | AnyHolder<ALLOC> any(allocator); |
341 | 8 | any.set(value); |
342 | 8 | const size_t numAllocations = allocator.numAllocs(); |
343 | 8 | AnyHolder<ALLOC> anyMove(std::move(any), allocator); |
344 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
345 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocations and deallocations |
346 | 8 | } |
347 | | |
348 | 8 | { |
349 | | // filled holder with the different allocator |
350 | 8 | AnyHolder<ALLOC> any(allocator); |
351 | 8 | any.set(value); |
352 | 8 | const size_t numAllocations = allocator.numAllocs(); |
353 | 8 | const ALLOC newAllocator; |
354 | 8 | AnyHolder<ALLOC> anyMove(std::move(any), newAllocator); |
355 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
356 | 8 | ASSERT_TRUE(numAllocations >= allocator.numAllocs()); // no furher allocations |
357 | 8 | } |
358 | 8 | } |
359 | | |
360 | | template <typename T, typename ALLOC> |
361 | | void testMoveConstructorWithAllocatorNoInit(const T& value, const ALLOC& allocator) |
362 | 8 | { |
363 | 8 | { |
364 | | // empty holder with the same allocator |
365 | 8 | AnyHolder<ALLOC> any(allocator); |
366 | 8 | AnyHolder<ALLOC> anyMove(NoInit, std::move(any)); |
367 | 8 | ASSERT_FALSE(anyMove.hasValue()); |
368 | 8 | } |
369 | | |
370 | 8 | { |
371 | | // empty holder with the different allocator |
372 | 8 | AnyHolder<ALLOC> any(allocator); |
373 | 8 | const ALLOC newAllocator; |
374 | 8 | AnyHolder<ALLOC> anyMove(NoInit, std::move(any), newAllocator); |
375 | 8 | ASSERT_FALSE(anyMove.hasValue()); |
376 | 8 | } |
377 | | |
378 | 8 | { |
379 | | // filled holder with the same allocator |
380 | 8 | AnyHolder<ALLOC> any(allocator); |
381 | 8 | any.set(value); |
382 | 8 | const size_t numAllocations = allocator.numAllocs(); |
383 | 8 | AnyHolder<ALLOC> anyMove(NoInit, std::move(any), allocator); |
384 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
385 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocations and deallocations |
386 | 8 | } |
387 | | |
388 | 8 | { |
389 | | // filled holder with the different allocator |
390 | 8 | AnyHolder<ALLOC> any(allocator); |
391 | 8 | any.set(value); |
392 | 8 | const size_t numAllocations = allocator.numAllocs(); |
393 | 8 | const ALLOC newAllocator; |
394 | 8 | AnyHolder<ALLOC> anyMove(NoInit, std::move(any), newAllocator); |
395 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
396 | 8 | ASSERT_TRUE(numAllocations >= allocator.numAllocs()); // no furher allocations |
397 | 8 | } |
398 | 8 | } |
399 | | |
400 | | template <typename T, typename ALLOC> |
401 | | void testMoveAssignmentOperator(const T& value, const ALLOC& allocator) |
402 | 8 | { |
403 | 8 | { |
404 | | // assignment empty holder |
405 | 8 | AnyHolder<ALLOC> any(allocator); |
406 | 8 | AnyHolder<ALLOC> anyMove; |
407 | 8 | anyMove = std::move(any); |
408 | 8 | ASSERT_FALSE(anyMove.hasValue()); |
409 | 8 | } |
410 | | |
411 | 8 | { |
412 | | // assignment filled holder to itself |
413 | 8 | AnyHolder<ALLOC> any(allocator); |
414 | 8 | any.set(value); |
415 | 8 | const size_t numAllocations = allocator.numAllocs(); |
416 | 8 | AnyHolder<ALLOC>& anyRef = any; |
417 | 8 | anyRef = std::move(any); |
418 | 8 | ASSERT_EQ(value, anyRef.template get<T>()); |
419 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocations and deallocations |
420 | 8 | } |
421 | | |
422 | 8 | { |
423 | | // assignment filled holder |
424 | 8 | AnyHolder<ALLOC> any(allocator); |
425 | 8 | any.set(value); |
426 | 8 | const size_t numAllocations = allocator.numAllocs(); |
427 | 8 | AnyHolder<ALLOC> anyMove; |
428 | 8 | anyMove = std::move(any); |
429 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
430 | 8 | ASSERT_TRUE(numAllocations >= allocator.numAllocs()); // no furher allocations |
431 | 8 | } |
432 | 8 | } |
433 | | |
434 | | template <typename T, typename ALLOC> |
435 | | void testMoveAssignmentOperatorNoInit(const T& value, const ALLOC& allocator) |
436 | 8 | { |
437 | 8 | { |
438 | | // assignment empty holder |
439 | 8 | AnyHolder<ALLOC> any(allocator); |
440 | 8 | AnyHolder<ALLOC> anyMove; |
441 | 8 | anyMove.assign(NoInit, std::move(any)); |
442 | 8 | ASSERT_FALSE(anyMove.hasValue()); |
443 | 8 | } |
444 | | |
445 | 8 | { |
446 | | // assignment filled holder to itself |
447 | 8 | AnyHolder<ALLOC> any(allocator); |
448 | 8 | any.set(value); |
449 | 8 | const size_t numAllocations = allocator.numAllocs(); |
450 | 8 | AnyHolder<ALLOC>& anyRef = any; |
451 | 8 | anyRef.assign(NoInit, std::move(any)); |
452 | 8 | ASSERT_EQ(value, anyRef.template get<T>()); |
453 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocations and deallocations |
454 | 8 | } |
455 | | |
456 | 8 | { |
457 | | // assignment filled holder |
458 | 8 | AnyHolder<ALLOC> any(allocator); |
459 | 8 | any.set(value); |
460 | 8 | const size_t numAllocations = allocator.numAllocs(); |
461 | 8 | AnyHolder<ALLOC> anyMove; |
462 | 8 | anyMove.assign(NoInit, std::move(any)); |
463 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
464 | 8 | ASSERT_TRUE(numAllocations >= allocator.numAllocs()); // no furher allocations |
465 | 8 | } |
466 | 8 | } |
467 | | |
468 | | template <typename T, typename ALLOC> |
469 | | void testMoveAssignmentValueOperator(const T& value, const ALLOC& allocator) |
470 | 8 | { |
471 | 8 | { |
472 | | // assignment empty holder |
473 | 8 | const T valueCopy(value); |
474 | 8 | AnyHolder<ALLOC> any(allocator); |
475 | 8 | const size_t numAllocations = allocator.numAllocs(); |
476 | 8 | AnyHolder<ALLOC> anyMove; |
477 | 8 | anyMove = std::move(valueCopy); |
478 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
479 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocations and deallocations |
480 | 8 | } |
481 | | |
482 | 8 | { |
483 | | // assignment filled holder |
484 | 8 | const T valueCopy(value); |
485 | 8 | AnyHolder<ALLOC> any(allocator); |
486 | 8 | any.set(value); |
487 | 8 | const size_t numAllocations = allocator.numAllocs(); |
488 | 8 | AnyHolder<ALLOC> anyMove; |
489 | 8 | anyMove = std::move(valueCopy); |
490 | 8 | ASSERT_EQ(value, anyMove.template get<T>()); |
491 | 8 | ASSERT_EQ(numAllocations, allocator.numAllocs()); // no allocations and deallocations |
492 | 8 | } |
493 | 8 | } |
494 | | |
495 | | template <typename T, typename ALLOC> |
496 | | void testReset(const T& value, const ALLOC& allocator) |
497 | 8 | { |
498 | 8 | AnyHolder<ALLOC> any(value, allocator); |
499 | 8 | ASSERT_TRUE(any.hasValue()); |
500 | | |
501 | 8 | any.reset(); |
502 | 8 | ASSERT_FALSE(any.hasValue()); |
503 | | |
504 | 8 | any = value; |
505 | 8 | ASSERT_TRUE(any.hasValue()); |
506 | 8 | ASSERT_EQ(value, any.template get<T>()); |
507 | 8 | } |
508 | | |
509 | | template <typename T, typename ALLOC> |
510 | | void testSetGet(const T& value, const ALLOC& allocator) |
511 | 8 | { |
512 | 8 | AnyHolder<ALLOC> any(allocator); |
513 | 8 | ASSERT_THROW(any.template get<int>(), zserio::CppRuntimeException); |
514 | | |
515 | 8 | any.set(value); |
516 | 8 | ASSERT_EQ(value, any.template get<T>()); |
517 | | |
518 | 8 | const int intValue = 0xDEAD; |
519 | 8 | any.set(intValue); |
520 | 8 | ASSERT_EQ(intValue, any.template get<int>()); |
521 | 8 | ASSERT_THROW(any.template get<float>(), CppRuntimeException); |
522 | | |
523 | 8 | const float floatValue = 3.14F; |
524 | 8 | any.set(floatValue); |
525 | 8 | ASSERT_THROW(any.template get<int>(), CppRuntimeException); |
526 | 8 | ASSERT_EQ(floatValue, any.template get<float>()); |
527 | | |
528 | 8 | const BigObject bigObjectValue; |
529 | 8 | any.set(bigObjectValue); |
530 | 8 | ASSERT_THROW(any.template get<int>(), CppRuntimeException); |
531 | 8 | ASSERT_EQ(bigObjectValue, any.template get<BigObject>()); |
532 | 8 | } |
533 | | |
534 | | template <typename T, typename ALLOC> |
535 | | void testIsType(const T& value, const ALLOC& allocator) |
536 | 8 | { |
537 | 8 | AnyHolder<ALLOC> any(allocator); |
538 | 8 | ASSERT_FALSE(any.template isType<int>()); |
539 | | |
540 | 8 | any.set(value); |
541 | 8 | ASSERT_TRUE(any.template isType<T>()); |
542 | | |
543 | 8 | const int intValue = 0xDEAD; |
544 | 8 | any.set(intValue); |
545 | 8 | ASSERT_TRUE(any.template isType<int>()); |
546 | | |
547 | 8 | const float floatValue = 3.14F; |
548 | 8 | any.set(floatValue); |
549 | 8 | ASSERT_TRUE(any.template isType<float>()); |
550 | 8 | ASSERT_FALSE(any.template isType<int>()); |
551 | 8 | } |
552 | | |
553 | | template <typename T, typename ALLOC> |
554 | | void testHasValue(const T& value, const ALLOC& allocator) |
555 | 8 | { |
556 | 8 | AnyHolder<ALLOC> any(allocator); |
557 | 8 | ASSERT_FALSE(any.hasValue()); |
558 | | |
559 | 8 | any.set(value); |
560 | 8 | ASSERT_TRUE(any.hasValue()); |
561 | | |
562 | 8 | const int intValue = 0xDEAD; |
563 | 8 | any.set(intValue); |
564 | 8 | ASSERT_TRUE(any.hasValue()); |
565 | | |
566 | 8 | any.reset(); |
567 | 8 | ASSERT_FALSE(any.hasValue()); |
568 | 8 | } |
569 | | }; |
570 | | |
571 | | TEST_F(AnyHolderTest, integerPropagatingAllocator) |
572 | 1 | { |
573 | 1 | const int value = 0xDEAD; |
574 | 1 | const TrackingAllocator<uint8_t> allocator; |
575 | 1 | testAnyHolder(value, allocator); |
576 | 1 | } |
577 | | |
578 | | TEST_F(AnyHolderTest, integerNonPropagatingAllocator) |
579 | 1 | { |
580 | 1 | const int value = 0xDEAD; |
581 | 1 | const TrackingAllocatorNonProp<uint8_t> allocator; |
582 | 1 | testAnyHolder(value, allocator); |
583 | 1 | } |
584 | | |
585 | | TEST_F(AnyHolderTest, vectorPropagatingAllocator) |
586 | 1 | { |
587 | 1 | const std::vector<int> value{1, 2, 3}; |
588 | 1 | const TrackingAllocator<uint8_t> allocator; |
589 | 1 | testAnyHolder(value, allocator); |
590 | 1 | } |
591 | | |
592 | | TEST_F(AnyHolderTest, vectorNonPropagatingAllocator) |
593 | 1 | { |
594 | 1 | const std::vector<int> value{1, 2, 3}; |
595 | 1 | const TrackingAllocatorNonProp<uint8_t> allocator; |
596 | 1 | testAnyHolder(value, allocator); |
597 | 1 | } |
598 | | |
599 | | TEST_F(AnyHolderTest, smallObjectPropagatingAllocator) |
600 | 1 | { |
601 | 1 | const SmallObject value; |
602 | 1 | const TrackingAllocator<uint8_t> allocator; |
603 | 1 | testAnyHolder(value, allocator); |
604 | 1 | } |
605 | | |
606 | | TEST_F(AnyHolderTest, smallObjectNonPropagatingAllocator) |
607 | 1 | { |
608 | 1 | const SmallObject value; |
609 | 1 | const TrackingAllocatorNonProp<uint8_t> allocator; |
610 | 1 | testAnyHolder(value, allocator); |
611 | 1 | } |
612 | | |
613 | | TEST_F(AnyHolderTest, bigObjectPropagatingAllocator) |
614 | 1 | { |
615 | 1 | const BigObject value; |
616 | 1 | const TrackingAllocator<uint8_t> allocator; |
617 | 1 | testAnyHolder(value, allocator); |
618 | 1 | } |
619 | | |
620 | | TEST_F(AnyHolderTest, bigObjectNonPropagatingAllocator) |
621 | 1 | { |
622 | 1 | const BigObject value; |
623 | 1 | const TrackingAllocatorNonProp<uint8_t> allocator; |
624 | 1 | testAnyHolder(value, allocator); |
625 | 1 | } |
626 | | |
627 | | TEST_F(AnyHolderTest, unexceptedCallsHeapHolder) |
628 | 1 | { |
629 | 1 | const TrackingAllocator<uint8_t> allocator; |
630 | 1 | detail::HeapHolder<BigObject, TrackingAllocator<uint8_t>>* holder = |
631 | 1 | detail::HeapHolder<BigObject, TrackingAllocator<uint8_t>>::create(allocator); |
632 | 1 | ASSERT_THROW(holder->clone(nullptr), CppRuntimeException); |
633 | 1 | ASSERT_THROW(holder->clone(NoInit, nullptr), CppRuntimeException); |
634 | 1 | ASSERT_THROW(holder->move(nullptr), CppRuntimeException); |
635 | 1 | ASSERT_THROW(holder->move(NoInit, nullptr), CppRuntimeException); |
636 | 1 | holder->destroy(allocator); |
637 | 1 | } |
638 | | |
639 | | TEST_F(AnyHolderTest, unexceptedCallsNonHeapHolder) |
640 | 1 | { |
641 | 1 | const TrackingAllocator<uint8_t> allocator; |
642 | 1 | using MaxInPlaceType = std::aligned_storage<3 * sizeof(void*), alignof(void*)>::type; |
643 | 1 | MaxInPlaceType inPlace = MaxInPlaceType(); |
644 | 1 | detail::NonHeapHolder<uint8_t, TrackingAllocator<uint8_t>>* holder = |
645 | 1 | detail::NonHeapHolder<uint8_t, TrackingAllocator<uint8_t>>::create(&inPlace); |
646 | 1 | ASSERT_THROW(holder->clone(allocator), CppRuntimeException); |
647 | 1 | ASSERT_THROW(holder->clone(NoInit, allocator), CppRuntimeException); |
648 | 1 | ASSERT_THROW(holder->move(allocator), CppRuntimeException); |
649 | 1 | ASSERT_THROW(holder->move(NoInit, allocator), CppRuntimeException); |
650 | 1 | holder->destroy(allocator); |
651 | 1 | } |
652 | | |
653 | | } // namespace zserio |