Coverage Report

Created: 2024-04-30 09:35

test/zserio/HeapOptionalHolderTest.cpp
Line
Count
Source
1
#include "gtest/gtest.h"
2
#include "zserio/OptionalHolder.h"
3
#include "zserio/pmr/PolymorphicAllocator.h"
4
5
#include "TrackingAllocator.h"
6
7
namespace zserio
8
{
9
10
namespace
11
{
12
13
class DummyObject
14
{
15
public:
16
    DummyObject() :
17
            m_value(0),
18
            m_isNoInit(false)
19
2
    {}
20
    explicit DummyObject(int value) :
21
            m_value(value),
22
            m_isNoInit(false)
23
7
    {}
24
    explicit DummyObject(NoInitT, const DummyObject& other) :
25
            m_value(other.m_value),
26
            m_isNoInit(true)
27
4
    {}
28
    int getValue() const
29
10
    {
30
10
        return m_value;
31
10
    }
32
    void setValue(int value)
33
2
    {
34
2
        m_value = value;
35
2
    }
36
37
    bool isNoInit() const
38
11
    {
39
11
        return m_isNoInit;
40
11
    }
41
42
    bool operator==(const DummyObject& other) const
43
3
    {
44
3
        return m_value == other.m_value;
45
3
    }
46
47
private:
48
    int m_value;
49
    bool m_isNoInit;
50
};
51
52
} // namespace
53
54
class HeapOptionalHolderTest : public ::testing::Test
55
{
56
protected:
57
};
58
59
TEST_F(HeapOptionalHolderTest, emptyConstructor)
60
1
{
61
1
    TrackingAllocator<int> alloc;
62
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optional{alloc};
63
1
    ASSERT_EQ(alloc, optional.get_allocator());
64
1
}
65
66
TEST_F(HeapOptionalHolderTest, nullOptConstructor)
67
1
{
68
1
    {
69
1
        NullOptType nullOpt{int()};
70
1
        TrackingAllocator<int> alloc;
71
1
        HeapOptionalHolder<int, TrackingAllocator<int>> optional{nullOpt, alloc};
72
1
        ASSERT_EQ(alloc, optional.get_allocator());
73
1
    }
74
75
1
    {
76
1
        TrackingAllocator<int> alloc;
77
1
        HeapOptionalHolder<int, TrackingAllocator<int>> optional{NullOpt, alloc};
78
1
        ASSERT_EQ(alloc, optional.get_allocator());
79
1
    }
80
1
}
81
82
TEST_F(HeapOptionalHolderTest, lvalueConstructor)
83
1
{
84
1
    TrackingAllocator<std::vector<int>> alloc;
85
86
1
    std::vector<int> values{1, 2, 3};
87
1
    void* origAddress = values.data();
88
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optional{values, alloc};
89
1
    ASSERT_NE(origAddress, (*optional).data());
90
1
    ASSERT_EQ(values, *optional);
91
92
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalFromList{
93
1
            {1, 2, 3}, alloc};
94
1
    std::vector<int> listValues{1, 2, 3};
95
1
    ASSERT_EQ(listValues, *optionalFromList);
96
97
1
    ASSERT_GE(alloc.numAllocs(), 2U);
98
1
}
99
100
TEST_F(HeapOptionalHolderTest, rvalueConstructor)
101
1
{
102
1
    TrackingAllocator<std::vector<int>> alloc;
103
104
1
    std::vector<int> values{1, 2, 3};
105
1
    std::vector<int> origValues{values};
106
1
    void* origAddress = values.data();
107
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optional{
108
1
            std::move(values), alloc};
109
1
    ASSERT_EQ(origAddress, (*optional).data());
110
1
    ASSERT_EQ(origValues, *optional);
111
112
1
    ASSERT_GE(alloc.numAllocs(), 1U);
113
1
}
114
115
TEST_F(HeapOptionalHolderTest, forwardingConstructor)
116
1
{
117
1
    TrackingAllocator<std::vector<int>> alloc;
118
119
1
    std::vector<int> src = {0, 13, 42};
120
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optional{
121
1
            alloc, src.begin(), src.end()};
122
1
    ASSERT_EQ(src, *optional);
123
124
1
    ASSERT_GE(alloc.numAllocs(), 1U);
125
1
}
126
127
TEST_F(HeapOptionalHolderTest, copyConstructor)
128
1
{
129
1
    TrackingAllocator<int> alloc;
130
1
    TrackingAllocator<std::vector<int>> allocVec = alloc;
131
132
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optional(alloc);
133
1
    ASSERT_THROW(*optional, CppRuntimeException);
134
1
    const int intValue = 0xDEAD;
135
1
    optional = intValue;
136
137
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optionalCopy(optional);
138
1
    ASSERT_EQ(intValue, *optionalCopy);
139
1
    ASSERT_EQ(optional.get_allocator(), optionalCopy.get_allocator());
140
141
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObject(DummyObject{10});
142
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObjectCopy = optionalObject;
143
1
    ASSERT_EQ(optionalObject, optionalObjectCopy);
144
1
    ASSERT_EQ(optionalObject.get_allocator(), optionalObjectCopy.get_allocator());
145
146
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalVector{
147
1
            std::vector<int>{1, 2, 3}, allocVec};
148
1
    void* origAddress = (*optionalVector).data();
149
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalVectorCopy{
150
1
            optionalVector};
151
1
    ASSERT_NE(origAddress, (*optionalVectorCopy).data());
152
1
    ASSERT_EQ(*optionalVector, *optionalVectorCopy);
153
1
    ASSERT_EQ(optionalVector.get_allocator(), optionalVectorCopy.get_allocator());
154
155
1
    ASSERT_GE(alloc.numAllocs(), 2U);
156
157
1
    TrackingAllocatorNonProp<int> allocNp;
158
1
    HeapOptionalHolder<int, TrackingAllocatorNonProp<int>> optionalNp(allocNp);
159
1
    HeapOptionalHolder<int, TrackingAllocatorNonProp<int>> optionalNpCopy = optionalNp;
160
1
    ASSERT_NE(optionalNp.get_allocator(), optionalNpCopy.get_allocator());
161
1
}
162
163
TEST_F(HeapOptionalHolderTest, copyConstructorNoInit)
164
1
{
165
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalEmptyObject;
166
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalEmptyObjectCopy{
167
1
            NoInit, optionalEmptyObject};
168
1
    ASSERT_EQ(optionalEmptyObject, optionalEmptyObjectCopy);
169
170
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObject(DummyObject{10});
171
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObjectCopy{NoInit, optionalObject};
172
1
    ASSERT_EQ(optionalObject, optionalObjectCopy);
173
1
    ASSERT_FALSE(optionalObject->isNoInit());
174
1
    ASSERT_TRUE(optionalObjectCopy->isNoInit());
175
1
}
176
177
TEST_F(HeapOptionalHolderTest, copyConstructorAllocator)
178
1
{
179
1
    TrackingAllocator<int> alloc1;
180
1
    TrackingAllocator<std::vector<int>> allocVec1 = alloc1;
181
1
    TrackingAllocator<int> alloc2;
182
1
    TrackingAllocator<std::vector<int>> allocVec2 = alloc2;
183
184
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optional(alloc1);
185
1
    ASSERT_THROW(*optional, CppRuntimeException);
186
187
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optionalCopy(optional, alloc2);
188
1
    ASSERT_NE(optional.get_allocator(), optionalCopy.get_allocator());
189
1
    ASSERT_EQ(optional.get_allocator(), alloc1);
190
1
    ASSERT_EQ(optionalCopy.get_allocator(), alloc2);
191
192
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalVector{
193
1
            std::vector<int>{1, 2, 3}, allocVec1};
194
1
    void* origAddress = (*optionalVector).data();
195
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalVectorCopy{
196
1
            optionalVector, allocVec2};
197
1
    ASSERT_NE(origAddress, (*optionalVectorCopy).data());
198
1
    ASSERT_EQ(*optionalVector, *optionalVectorCopy);
199
1
    ASSERT_NE(optionalVector.get_allocator(), optionalVectorCopy.get_allocator());
200
1
    ASSERT_EQ(optionalVector.get_allocator(), allocVec1);
201
1
    ASSERT_EQ(optionalVectorCopy.get_allocator(), allocVec2);
202
203
1
    ASSERT_GE(alloc1.numAllocs(), 1U);
204
1
    ASSERT_GE(alloc2.numAllocs(), 1U);
205
1
}
206
207
TEST_F(HeapOptionalHolderTest, moveConstructor)
208
1
{
209
1
    TrackingAllocator<int> alloc;
210
211
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optional(13, alloc);
212
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optionalMoved(std::move(optional));
213
214
1
    ASSERT_EQ(*optionalMoved, 13);
215
1
    ASSERT_EQ(optionalMoved.get_allocator(), alloc);
216
1
    ASSERT_FALSE(optional.hasValue());
217
1
    ASSERT_EQ(alloc.numAllocs(), 1U);
218
1
}
219
220
TEST_F(HeapOptionalHolderTest, moveConstructorNoInit)
221
1
{
222
1
    TrackingAllocator<DummyObject> allocEmpty;
223
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalEmptyObject(allocEmpty);
224
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalEmptyObjectMoved{
225
1
            NoInit, std::move(optionalEmptyObject)};
226
1
    ASSERT_FALSE(optionalEmptyObjectMoved.hasValue());
227
228
1
    TrackingAllocator<DummyObject> alloc;
229
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObject(DummyObject{10}, alloc);
230
1
    ASSERT_EQ(10, optionalObject->getValue());
231
1
    ASSERT_FALSE(optionalObject->isNoInit());
232
233
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObjectMoved{
234
1
            NoInit, std::move(optionalObject)};
235
1
    ASSERT_EQ(10, optionalObjectMoved->getValue());
236
    // memory with object has been moved in optional holder, object move constructor has not been called
237
1
    ASSERT_FALSE(optionalObjectMoved->isNoInit());
238
1
}
239
240
TEST_F(HeapOptionalHolderTest, moveConstructorAllocator)
241
1
{
242
1
    TrackingAllocator<int> alloc;
243
1
    TrackingAllocator<int> alloc2;
244
245
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optionalDiff(13, alloc);
246
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optionalDiffMoved(std::move(optionalDiff), alloc2);
247
1
    ASSERT_EQ(*optionalDiffMoved, 13);
248
1
    ASSERT_EQ(optionalDiffMoved.get_allocator(), alloc2);
249
250
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optionalSame(13, alloc);
251
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optionalSameMoved(std::move(optionalSame), alloc);
252
1
    ASSERT_EQ(*optionalSameMoved, 13);
253
1
    ASSERT_EQ(optionalSameMoved.get_allocator(), alloc);
254
255
1
    HeapOptionalHolder<int, TrackingAllocator<int>> emptyOptional(alloc);
256
1
    HeapOptionalHolder<int, TrackingAllocator<int>> emptyMoved(std::move(emptyOptional), alloc2);
257
1
    ASSERT_FALSE(emptyOptional.hasValue());
258
1
    ASSERT_FALSE(emptyMoved.hasValue());
259
1
    ASSERT_EQ(emptyOptional.get_allocator(), alloc);
260
1
    ASSERT_EQ(emptyMoved.get_allocator(), alloc2);
261
262
1
    ASSERT_EQ(alloc.numAllocs(), 2U);
263
1
    ASSERT_EQ(alloc2.numAllocs(), 1U);
264
1
}
265
266
TEST_F(HeapOptionalHolderTest, moveValueConstructorAllocatorNoInit)
267
1
{
268
1
    TrackingAllocator<DummyObject> alloc;
269
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObjectMoved{
270
1
            NoInit, DummyObject{10}, alloc};
271
1
    ASSERT_EQ(10, optionalObjectMoved->getValue());
272
1
    ASSERT_TRUE(optionalObjectMoved->isNoInit());
273
1
    ASSERT_EQ(optionalObjectMoved.get_allocator(), alloc);
274
1
    ASSERT_GE(alloc.numAllocs(), 1U);
275
1
}
276
277
TEST_F(HeapOptionalHolderTest, copyAssignmentOperator)
278
1
{
279
1
    TrackingAllocator<int> alloc;
280
1
    TrackingAllocator<std::vector<int>> allocVec = alloc;
281
282
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optional(alloc);
283
1
    ASSERT_THROW(*optional, CppRuntimeException);
284
1
    const int intValue = 0xDEAD;
285
1
    optional = intValue;
286
287
1
    HeapOptionalHolder<int, TrackingAllocator<int>>& optionalRef(optional);
288
1
    optionalRef = optional;
289
1
    ASSERT_EQ(intValue, *optionalRef);
290
291
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optionalCopy;
292
1
    optionalCopy = optional;
293
1
    ASSERT_EQ(intValue, *optionalCopy);
294
1
    ASSERT_EQ(optional.get_allocator(), optionalCopy.get_allocator());
295
1
    ASSERT_EQ(optional.get_allocator(), alloc);
296
297
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalVector{
298
1
            std::vector<int>{1, 2, 3}, allocVec};
299
1
    void* origAddress = (*optionalVector).data();
300
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalVectorCopy;
301
1
    optionalVectorCopy = optionalVector;
302
1
    ASSERT_NE(origAddress, (*optionalVectorCopy).data());
303
1
    ASSERT_EQ(*optionalVector, *optionalVectorCopy);
304
1
    ASSERT_EQ(optionalVector.get_allocator(), optionalVectorCopy.get_allocator());
305
1
    ASSERT_EQ(optionalVector.get_allocator(), allocVec);
306
307
1
    ASSERT_GE(alloc.numAllocs(), 4U);
308
309
1
    TrackingAllocatorNonProp<int> allocNp;
310
1
    HeapOptionalHolder<int, TrackingAllocatorNonProp<int>> optionalNp(13, allocNp);
311
1
    HeapOptionalHolder<int, TrackingAllocatorNonProp<int>> optionalNpCopy;
312
1
    optionalNpCopy = optionalNp;
313
1
    ASSERT_NE(optionalNp.get_allocator(), optionalNpCopy.get_allocator());
314
315
1
    HeapOptionalHolder<int> optionalInt(123);
316
1
    const HeapOptionalHolder<int>& optionalIntRef = optionalInt;
317
1
    const HeapOptionalHolder<int>& optionalIntRef2 = (optionalInt = optionalIntRef);
318
1
    ASSERT_EQ(123, *optionalInt);
319
1
    ASSERT_EQ(optionalInt, optionalIntRef2);
320
1
}
321
322
TEST_F(HeapOptionalHolderTest, copyAssignmentOperatorNoInit)
323
1
{
324
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalEmptyObject;
325
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalEmptyObjectCopy;
326
1
    optionalEmptyObjectCopy.assign(NoInit, optionalEmptyObject);
327
1
    ASSERT_EQ(optionalEmptyObject, optionalEmptyObjectCopy);
328
329
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObject(DummyObject{10});
330
1
    optionalObject.assign(NoInit, optionalObject);
331
332
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObjectCopy;
333
1
    optionalObjectCopy.assign(NoInit, optionalObject);
334
1
    ASSERT_EQ(optionalObject, optionalObjectCopy);
335
1
    ASSERT_FALSE(optionalObject->isNoInit());
336
1
    ASSERT_TRUE(optionalObjectCopy->isNoInit());
337
1
}
338
339
TEST_F(HeapOptionalHolderTest, moveAssignmentOperator)
340
1
{
341
1
    TrackingAllocator<std::vector<int>> allocVec;
342
343
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalVector{
344
1
            std::vector<int>{1, 2, 3}, allocVec};
345
1
    std::vector<int> origValues{*optionalVector};
346
1
    void* origAddress = (*optionalVector).data();
347
348
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalVectorCopy =
349
1
            optionalVector;
350
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>>& optionalVectorRef =
351
1
            optionalVectorCopy;
352
1
    optionalVectorRef = std::move(optionalVectorCopy);
353
1
    ASSERT_TRUE(optionalVectorRef.hasValue());
354
355
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optionalVectorMoved;
356
1
    optionalVectorMoved = std::move(optionalVector);
357
1
    ASSERT_EQ(origAddress, (*optionalVectorMoved).data());
358
1
    ASSERT_EQ(origValues, *optionalVectorMoved);
359
1
    ASSERT_EQ(optionalVector.get_allocator(), optionalVectorMoved.get_allocator());
360
1
    ASSERT_EQ(optionalVector.get_allocator(), allocVec);
361
362
1
    ASSERT_GE(allocVec.numAllocs(), 1U);
363
364
1
    TrackingAllocatorNonProp<int> allocNp;
365
1
    HeapOptionalHolder<int, TrackingAllocatorNonProp<int>> optionalNp(13, allocNp);
366
1
    HeapOptionalHolder<int, TrackingAllocatorNonProp<int>> optionalNpMoved;
367
1
    optionalNpMoved = std::move(optionalNp);
368
1
    ASSERT_TRUE(optionalNp.hasValue());
369
1
    ASSERT_TRUE(optionalNpMoved.hasValue());
370
1
    ASSERT_NE(optionalNp.get_allocator(), optionalNpMoved.get_allocator());
371
372
1
    HeapOptionalHolder<int> optionalInt(123);
373
1
    HeapOptionalHolder<int>& optionalIntRef = optionalInt;
374
1
    const HeapOptionalHolder<int>& optionalIntRef2 = (optionalInt = std::move(optionalIntRef));
375
1
    ASSERT_EQ(123, *optionalInt);
376
1
    ASSERT_EQ(optionalInt, optionalIntRef2);
377
1
}
378
379
TEST_F(HeapOptionalHolderTest, moveAssignmentOperatorNoInit)
380
1
{
381
1
    TrackingAllocator<DummyObject> allocEmpty;
382
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalEmptyObject(allocEmpty);
383
384
1
    HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalEmptyObjectMoved;
385
1
    optionalEmptyObjectMoved.assign(NoInit, std::move(optionalEmptyObject));
386
1
    ASSERT_FALSE(optionalEmptyObjectMoved.hasValue());
387
388
1
    {
389
1
        TrackingAllocator<DummyObject> alloc;
390
1
        HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObject(DummyObject{10}, alloc);
391
1
        ASSERT_EQ(10, optionalObject->getValue());
392
1
        ASSERT_FALSE(optionalObject->isNoInit());
393
1
        optionalObject.assign(NoInit, std::move(optionalObject));
394
395
1
        HeapOptionalHolder<DummyObject, TrackingAllocator<DummyObject>> optionalObjectMoved;
396
1
        optionalObjectMoved.assign(NoInit, std::move(optionalObject));
397
1
        ASSERT_EQ(10, optionalObjectMoved->getValue());
398
        // memory with object has been moved in optional holder, object move constructor has not been called
399
1
        ASSERT_FALSE(optionalObjectMoved->isNoInit());
400
1
    }
401
402
1
    {
403
1
        TrackingAllocatorNonProp<DummyObject> alloc;
404
1
        HeapOptionalHolder<DummyObject, TrackingAllocatorNonProp<DummyObject>> optionalObject(
405
1
                DummyObject{10}, alloc);
406
1
        ASSERT_EQ(10, optionalObject->getValue());
407
1
        ASSERT_FALSE(optionalObject->isNoInit());
408
1
        optionalObject.assign(NoInit, std::move(optionalObject));
409
410
1
        HeapOptionalHolder<DummyObject, TrackingAllocatorNonProp<DummyObject>> optionalObjectMoved;
411
1
        optionalObjectMoved.assign(NoInit, std::move(optionalObject));
412
1
        ASSERT_EQ(10, optionalObjectMoved->getValue());
413
1
        ASSERT_TRUE(optionalObjectMoved->isNoInit());
414
1
    }
415
1
}
416
417
TEST_F(HeapOptionalHolderTest, lvalueAssignmentOperator)
418
1
{
419
1
    TrackingAllocator<std::vector<int>> allocVec;
420
421
1
    std::vector<int> values{1, 2, 3};
422
1
    void* origAddress = values.data();
423
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optional(allocVec);
424
1
    optional = values;
425
1
    ASSERT_NE(origAddress, (*optional).data());
426
1
    ASSERT_EQ(values, *optional);
427
1
    ASSERT_EQ(optional.get_allocator(), allocVec);
428
429
1
    ASSERT_GE(allocVec.numAllocs(), 1U);
430
431
1
    TrackingAllocatorNonProp<std::vector<int>> allocVecNp;
432
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocatorNonProp<std::vector<int>>> optionalNp(allocVecNp);
433
1
    optionalNp = values;
434
1
    ASSERT_NE(origAddress, (*optionalNp).data());
435
1
    ASSERT_EQ(values, *optionalNp);
436
1
    ASSERT_EQ(optionalNp.get_allocator(), allocVecNp);
437
438
1
    ASSERT_GE(allocVecNp.numAllocs(), 1U);
439
1
}
440
441
TEST_F(HeapOptionalHolderTest, rvalueAssignmentOperator)
442
1
{
443
1
    TrackingAllocator<std::vector<int>> allocVec;
444
445
1
    std::vector<int> values{1, 2, 3};
446
1
    std::vector<int> origValues{values};
447
1
    void* origAddress = values.data();
448
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optional(allocVec);
449
1
    optional = std::move(values);
450
1
    ASSERT_EQ(origAddress, (*optional).data());
451
1
    ASSERT_EQ(origValues, *optional);
452
1
    ASSERT_EQ(optional.get_allocator(), allocVec);
453
454
1
    ASSERT_GE(allocVec.numAllocs(), 1U);
455
456
1
    TrackingAllocatorNonProp<std::vector<int>> allocVecNp;
457
1
    values = origValues;
458
1
    origAddress = values.data();
459
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocatorNonProp<std::vector<int>>> optionalNp(allocVecNp);
460
1
    optionalNp = std::move(values);
461
1
    ASSERT_EQ(origAddress, (*optionalNp).data());
462
1
    ASSERT_EQ(origValues, *optionalNp);
463
1
    ASSERT_EQ(optionalNp.get_allocator(), allocVecNp);
464
465
1
    ASSERT_GE(allocVecNp.numAllocs(), 1U);
466
1
}
467
468
TEST_F(HeapOptionalHolderTest, reset)
469
1
{
470
1
    TrackingAllocator<std::vector<int>> allocVec;
471
472
1
    HeapOptionalHolder<std::vector<int>, TrackingAllocator<std::vector<int>>> optional{
473
1
            std::vector<int>{1, 2, 3}, allocVec};
474
1
    ASSERT_TRUE(optional.hasValue());
475
1
    ASSERT_EQ(1, (*optional)[0]);
476
1
    ASSERT_EQ(allocVec.numAllocs(), 1U);
477
478
1
    optional.reset();
479
1
    ASSERT_EQ(allocVec.numAllocs(), 0);
480
1
    ASSERT_FALSE(optional.hasValue());
481
482
1
    optional = std::vector<int>{3, 2, 1};
483
1
    ASSERT_EQ(allocVec.numAllocs(), 1U);
484
1
    ASSERT_TRUE(optional.hasValue());
485
1
    ASSERT_EQ(3, (*optional)[0]);
486
487
1
    optional.reset();
488
1
    ASSERT_EQ(allocVec.numAllocs(), 0);
489
1
    ASSERT_FALSE(optional.hasValue());
490
1
}
491
492
TEST_F(HeapOptionalHolderTest, hasValue)
493
1
{
494
1
    HeapOptionalHolder<int> optionalInt;
495
1
    ASSERT_THROW(*optionalInt, CppRuntimeException);
496
1
    ASSERT_EQ(false, optionalInt.hasValue());
497
498
1
    optionalInt = 0xDEAD;
499
1
    ASSERT_EQ(true, optionalInt.hasValue());
500
1
}
501
502
TEST_F(HeapOptionalHolderTest, setGet)
503
1
{
504
1
    HeapOptionalHolder<int> optionalInt;
505
1
    ASSERT_THROW(*optionalInt, CppRuntimeException);
506
1
    const int intValue = 0xDEAD;
507
1
    optionalInt = intValue;
508
1
    ASSERT_EQ(intValue, *optionalInt);
509
510
1
    HeapOptionalHolder<float> optionalFloat;
511
1
    ASSERT_THROW(*optionalFloat, CppRuntimeException);
512
1
    const float floatValue = 3.14F;
513
1
    optionalFloat = floatValue;
514
1
    ASSERT_EQ(floatValue, optionalFloat.value());
515
516
1
    HeapOptionalHolder<DummyObject> optionalObject;
517
1
    ASSERT_THROW(*optionalObject, CppRuntimeException);
518
1
    DummyObject objectValue;
519
1
    objectValue.setValue(intValue);
520
1
    optionalObject = objectValue;
521
1
    const DummyObject& readObjectValue = *optionalObject;
522
1
    ASSERT_EQ(intValue, readObjectValue.getValue());
523
1
    ASSERT_EQ(intValue, optionalObject->getValue());
524
525
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optionalAlloc;
526
1
    ASSERT_THROW(*optionalAlloc, CppRuntimeException);
527
1
}
528
529
TEST_F(HeapOptionalHolderTest, operatorEquality)
530
1
{
531
1
    HeapOptionalHolder<int> optional1;
532
1
    optional1 = 0xDEAD;
533
1
    HeapOptionalHolder<int> optional2;
534
1
    optional2 = 0xDEAD;
535
1
    HeapOptionalHolder<int> optional3;
536
1
    optional3 = 0xBEEF;
537
1
    HeapOptionalHolder<int> optional4;
538
1
    HeapOptionalHolder<int> optional5;
539
1
    HeapOptionalHolder<int> optional6;
540
541
1
    ASSERT_TRUE(optional1 == optional1);
542
1
    ASSERT_TRUE(optional1 == optional2);
543
1
    ASSERT_FALSE(optional1 == optional3);
544
1
    ASSERT_FALSE(optional1 == optional4);
545
1
    ASSERT_TRUE(optional5 == optional6);
546
1
    ASSERT_FALSE(optional5 == optional1);
547
548
1
    TrackingAllocator<int> alloc1;
549
1
    TrackingAllocator<int> alloc2;
550
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optional7(12345, alloc1);
551
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optional8(12345, alloc2);
552
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optional9(alloc2);
553
1
    HeapOptionalHolder<int, TrackingAllocator<int>> optional10(alloc2);
554
1
    ASSERT_EQ(alloc1.numAllocs(), 1);
555
1
    ASSERT_EQ(alloc2.numAllocs(), 1);
556
1
    ASSERT_TRUE(optional7 == optional8);
557
1
    ASSERT_TRUE(optional9 == optional9);
558
1
    ASSERT_TRUE(optional9 == optional10);
559
1
    ASSERT_FALSE(optional7 == optional10);
560
1
}
561
562
TEST_F(HeapOptionalHolderTest, operatorLessThan)
563
1
{
564
1
    HeapOptionalHolder<int> optionalEmpty1;
565
1
    HeapOptionalHolder<int> optionalEmpty2;
566
1
    HeapOptionalHolder<int> optional1(1);
567
1
    HeapOptionalHolder<int> optional2(2);
568
569
1
    ASSERT_FALSE(optionalEmpty1 < optionalEmpty2);
570
1
    ASSERT_TRUE(optionalEmpty1 < optional1);
571
1
    ASSERT_FALSE(optional1 < optionalEmpty1);
572
1
    ASSERT_TRUE(optional1 < optional2);
573
1
    ASSERT_FALSE(optional2 < optional1);
574
1
}
575
576
TEST_F(HeapOptionalHolderTest, constGet)
577
1
{
578
1
    const int intValue = 0xDEAD;
579
1
    HeapOptionalHolder<int> optional;
580
1
    optional = intValue;
581
1
    const HeapOptionalHolder<int> constOptional(optional);
582
1
    ASSERT_EQ(intValue, *constOptional);
583
1
    ASSERT_EQ(intValue, constOptional.value());
584
585
1
    DummyObject objectValue;
586
1
    objectValue.setValue(intValue);
587
1
    HeapOptionalHolder<DummyObject> optionalObject{objectValue};
588
1
    ASSERT_EQ(intValue, optionalObject->getValue());
589
1
}
590
591
} // namespace zserio