test/zserio/InplaceOptionalHolderTest.cpp
Line | Count | Source |
1 | | #include <vector> |
2 | | |
3 | | #include "zserio/OptionalHolder.h" |
4 | | |
5 | | #include "gtest/gtest.h" |
6 | | |
7 | | namespace zserio |
8 | | { |
9 | | |
10 | | namespace |
11 | | { |
12 | | |
13 | | class DummyObject |
14 | | { |
15 | | public: |
16 | 2 | DummyObject() : m_value(0), m_isNoInit(false) {} |
17 | 6 | explicit DummyObject(int value) : m_value(value), m_isNoInit(false) {} |
18 | 5 | explicit DummyObject(NoInitT, const DummyObject& other) : m_value(other.m_value), m_isNoInit(true) {} |
19 | 8 | int getValue() const { return m_value; } |
20 | 2 | void setValue(int value) { m_value = value; } |
21 | | |
22 | 9 | bool isNoInit() const { return m_isNoInit; } |
23 | | |
24 | 3 | bool operator==(const DummyObject& other) const { return m_value == other.m_value; } |
25 | | |
26 | | private: |
27 | | int m_value; |
28 | | bool m_isNoInit; |
29 | | }; |
30 | | |
31 | | } // namespace |
32 | | |
33 | | class InplaceOptionalHolderTest : public ::testing::Test |
34 | | { |
35 | | protected: |
36 | | }; |
37 | | |
38 | | TEST_F(InplaceOptionalHolderTest, emptyConstructor) |
39 | 1 | { |
40 | 1 | InplaceOptionalHolder<int> optional; |
41 | 1 | ASSERT_FALSE(optional.hasValue()); |
42 | 1 | } |
43 | | |
44 | | TEST_F(InplaceOptionalHolderTest, nullOptConstructor) |
45 | 1 | { |
46 | 1 | { |
47 | 1 | NullOptType nullOpt{int()}; |
48 | 1 | InplaceOptionalHolder<int> optional{nullOpt}; |
49 | 1 | ASSERT_FALSE(optional.hasValue()); |
50 | 1 | } |
51 | | |
52 | 1 | { |
53 | 1 | InplaceOptionalHolder<int> optional{NullOpt}; |
54 | 1 | ASSERT_FALSE(optional.hasValue()); |
55 | 1 | } |
56 | 1 | } |
57 | | |
58 | | TEST_F(InplaceOptionalHolderTest, lvalueConstructor) |
59 | 1 | { |
60 | 1 | std::vector<int> values{1, 2, 3}; |
61 | 1 | void* origAddress = values.data(); |
62 | 1 | InplaceOptionalHolder<std::vector<int>> optional{values}; |
63 | 1 | ASSERT_NE(origAddress, (*optional).data()); |
64 | 1 | ASSERT_EQ(values, *optional); |
65 | | |
66 | | // check initializer list |
67 | 1 | InplaceOptionalHolder<std::vector<int>> optionalFromList{{1, 2, 3}}; |
68 | 1 | std::vector<int> listValues{1, 2, 3}; |
69 | 1 | ASSERT_EQ(listValues, *optionalFromList); |
70 | 1 | } |
71 | | |
72 | | TEST_F(InplaceOptionalHolderTest, rvalueConstructor) |
73 | 1 | { |
74 | 1 | std::vector<int> values{1, 2, 3}; |
75 | 1 | std::vector<int> origValues{values}; |
76 | 1 | void* origAddress = values.data(); |
77 | 1 | InplaceOptionalHolder<std::vector<int>> optional{std::move(values)}; |
78 | 1 | ASSERT_EQ(origAddress, (*optional).data()); |
79 | 1 | ASSERT_EQ(origValues, *optional); |
80 | 1 | } |
81 | | |
82 | | TEST_F(InplaceOptionalHolderTest, copyConstructor) |
83 | 1 | { |
84 | 1 | InplaceOptionalHolder<int> optional; |
85 | 1 | ASSERT_THROW(*optional, CppRuntimeException); |
86 | 1 | const int intValue = 0xDEAD; |
87 | 1 | optional = intValue; |
88 | | |
89 | 1 | InplaceOptionalHolder<int> optionalCopy(optional); |
90 | 1 | ASSERT_EQ(intValue, *optionalCopy); |
91 | | |
92 | 1 | InplaceOptionalHolder<std::vector<int>> optionalVector{std::vector<int>{1, 2, 3}}; |
93 | 1 | void* origAddress = (*optionalVector).data(); |
94 | 1 | InplaceOptionalHolder<std::vector<int>> optionalVectorCopy{optionalVector}; |
95 | 1 | ASSERT_NE(origAddress, (*optionalVectorCopy).data()); |
96 | 1 | ASSERT_EQ(*optionalVector, *optionalVectorCopy); |
97 | | |
98 | 1 | InplaceOptionalHolder<DummyObject> optionalObject(DummyObject{10}); |
99 | 1 | InplaceOptionalHolder<DummyObject> optionalObjectCopy = optionalObject; |
100 | 1 | ASSERT_EQ(optionalObject, optionalObjectCopy); |
101 | 1 | } |
102 | | |
103 | | TEST_F(InplaceOptionalHolderTest, copyConstructorNoInit) |
104 | 1 | { |
105 | 1 | InplaceOptionalHolder<DummyObject> optionalEmptyObject; |
106 | 1 | InplaceOptionalHolder<DummyObject> optionalEmptyObjectCopy{NoInit, optionalEmptyObject}; |
107 | 1 | ASSERT_EQ(optionalEmptyObject, optionalEmptyObjectCopy); |
108 | | |
109 | 1 | InplaceOptionalHolder<DummyObject> optionalObject(DummyObject{10}); |
110 | 1 | InplaceOptionalHolder<DummyObject> optionalObjectCopy{NoInit, optionalObject}; |
111 | 1 | ASSERT_EQ(optionalObject, optionalObjectCopy); |
112 | 1 | ASSERT_FALSE(optionalObject->isNoInit()); |
113 | 1 | ASSERT_TRUE(optionalObjectCopy->isNoInit()); |
114 | 1 | } |
115 | | |
116 | | TEST_F(InplaceOptionalHolderTest, copyAssignmentOperator) |
117 | 1 | { |
118 | 1 | InplaceOptionalHolder<int> optional; |
119 | 1 | ASSERT_THROW(*optional, CppRuntimeException); |
120 | 1 | const int intValue = 0xDEAD; |
121 | 1 | optional = intValue; |
122 | | |
123 | 1 | InplaceOptionalHolder<int>& optionalRef(optional); |
124 | 1 | optionalRef = optional; |
125 | 1 | ASSERT_EQ(intValue, *optionalRef); |
126 | | |
127 | 1 | InplaceOptionalHolder<int> optionalCopy; |
128 | 1 | optionalCopy = optional; |
129 | 1 | ASSERT_EQ(intValue, *optionalCopy); |
130 | | |
131 | 1 | InplaceOptionalHolder<std::vector<int>> optionalVector{std::vector<int>{1, 2, 3}}; |
132 | 1 | void* origAddress = (*optionalVector).data(); |
133 | 1 | InplaceOptionalHolder<std::vector<int>> optionalVectorCopy; |
134 | 1 | optionalVectorCopy = optionalVector; |
135 | 1 | ASSERT_NE(origAddress, ((*optionalVectorCopy).data())); |
136 | 1 | ASSERT_EQ(*optionalVector, *optionalVectorCopy); |
137 | | |
138 | 1 | InplaceOptionalHolder<std::vector<int>> emptyOptionalVector; |
139 | 1 | InplaceOptionalHolder<std::vector<int>> emptyOptionalVectorCopy; |
140 | 1 | emptyOptionalVectorCopy = emptyOptionalVector; |
141 | 1 | ASSERT_EQ(false, emptyOptionalVectorCopy.hasValue()); |
142 | 1 | } |
143 | | |
144 | | TEST_F(InplaceOptionalHolderTest, copyAssignmentOperatorNoInit) |
145 | 1 | { |
146 | 1 | InplaceOptionalHolder<DummyObject> optionalEmptyObject; |
147 | 1 | InplaceOptionalHolder<DummyObject> optionalEmptyObjectCopy; |
148 | 1 | optionalEmptyObjectCopy.assign(NoInit, optionalEmptyObject); |
149 | 1 | ASSERT_EQ(optionalEmptyObject, optionalEmptyObjectCopy); |
150 | | |
151 | 1 | InplaceOptionalHolder<DummyObject> optionalObject(DummyObject{10}); |
152 | 1 | optionalObject.assign(NoInit, optionalObject); |
153 | | |
154 | 1 | InplaceOptionalHolder<DummyObject> optionalObjectCopy; |
155 | 1 | optionalObjectCopy.assign(NoInit, optionalObject); |
156 | 1 | ASSERT_EQ(optionalObject, optionalObjectCopy); |
157 | 1 | ASSERT_FALSE(optionalObject->isNoInit()); |
158 | 1 | ASSERT_TRUE(optionalObjectCopy->isNoInit()); |
159 | 1 | } |
160 | | |
161 | | TEST_F(InplaceOptionalHolderTest, moveConstructor) |
162 | 1 | { |
163 | 1 | InplaceOptionalHolder<std::vector<int>> optionalVector{std::vector<int>{1, 2, 3}}; |
164 | 1 | std::vector<int> origValues{*optionalVector}; |
165 | 1 | void* origAddress = (*optionalVector).data(); |
166 | 1 | InplaceOptionalHolder<std::vector<int>> optionalVectorMoved{std::move(optionalVector)}; |
167 | 1 | ASSERT_EQ(origAddress, ((*optionalVectorMoved).data())); |
168 | 1 | ASSERT_EQ(origValues, *optionalVectorMoved); |
169 | | |
170 | 1 | InplaceOptionalHolder<std::vector<int>> emptyOptionalVector; |
171 | 1 | InplaceOptionalHolder<std::vector<int>> emptyOptionalVectorMoved{std::move(emptyOptionalVector)}; |
172 | 1 | ASSERT_EQ(false, emptyOptionalVectorMoved.hasValue()); |
173 | | |
174 | 1 | InplaceOptionalHolder<int> optionalInt{1}; |
175 | 1 | InplaceOptionalHolder<int> optionalIntMoved{std::move(optionalInt)}; |
176 | 1 | ASSERT_EQ(1, *optionalIntMoved); |
177 | | |
178 | 1 | InplaceOptionalHolder<int> emptyOptionalInt; |
179 | 1 | InplaceOptionalHolder<int> emptyOptionalIntMoved{std::move(emptyOptionalInt)}; |
180 | 1 | ASSERT_EQ(false, emptyOptionalIntMoved.hasValue()); |
181 | 1 | } |
182 | | |
183 | | TEST_F(InplaceOptionalHolderTest, moveConstructorNoInit) |
184 | 1 | { |
185 | 1 | InplaceOptionalHolder<DummyObject> optionalEmptyObject; |
186 | 1 | InplaceOptionalHolder<DummyObject> optionalEmptyObjectMoved{NoInit, std::move(optionalEmptyObject)}; |
187 | 1 | ASSERT_FALSE(optionalEmptyObjectMoved.hasValue()); |
188 | | |
189 | 1 | InplaceOptionalHolder<DummyObject> optionalObject(DummyObject{10}); |
190 | 1 | ASSERT_EQ(10, optionalObject->getValue()); |
191 | 1 | ASSERT_FALSE(optionalObject->isNoInit()); |
192 | | |
193 | 1 | InplaceOptionalHolder<DummyObject> optionalObjectMoved{NoInit, std::move(optionalObject)}; |
194 | 1 | ASSERT_EQ(10, optionalObjectMoved->getValue()); |
195 | 1 | ASSERT_TRUE(optionalObjectMoved->isNoInit()); |
196 | 1 | } |
197 | | |
198 | | TEST_F(InplaceOptionalHolderTest, moveValueConstructorNoInit) |
199 | 1 | { |
200 | 1 | InplaceOptionalHolder<DummyObject> optionalObjectMoved{NoInit, DummyObject{10}}; |
201 | 1 | ASSERT_EQ(10, optionalObjectMoved->getValue()); |
202 | 1 | ASSERT_TRUE(optionalObjectMoved->isNoInit()); |
203 | 1 | } |
204 | | |
205 | | TEST_F(InplaceOptionalHolderTest, forwardingConstructor) |
206 | 1 | { |
207 | 1 | { |
208 | 1 | InPlaceT inPlace{}; |
209 | 1 | std::vector<int> src = {0, 13, 42}; |
210 | 1 | InplaceOptionalHolder<std::vector<int>> optional{inPlace, src.begin(), src.end()}; |
211 | 1 | ASSERT_EQ(src, *optional); |
212 | 1 | } |
213 | | |
214 | 1 | { |
215 | 1 | std::vector<int> src = {0, 13, 42}; |
216 | 1 | InplaceOptionalHolder<std::vector<int>> optional{InPlace, src.begin(), src.end()}; |
217 | 1 | ASSERT_EQ(src, *optional); |
218 | 1 | } |
219 | 1 | } |
220 | | |
221 | | TEST_F(InplaceOptionalHolderTest, moveAssignmentOperator) |
222 | 1 | { |
223 | 1 | InplaceOptionalHolder<std::vector<int>> optionalVector{std::vector<int>{1, 2, 3}}; |
224 | 1 | std::vector<int> origValues{*optionalVector}; |
225 | 1 | void* origAddress = (*optionalVector).data(); |
226 | | |
227 | 1 | InplaceOptionalHolder<std::vector<int>>& optionalVectorRef(optionalVector); |
228 | 1 | optionalVectorRef = std::move(optionalVector); |
229 | 1 | ASSERT_EQ(origAddress, (*optionalVectorRef).data()); |
230 | 1 | ASSERT_EQ(origValues, *optionalVectorRef); |
231 | | |
232 | 1 | InplaceOptionalHolder<std::vector<int>> optionalVectorMoved; |
233 | 1 | optionalVectorMoved = std::move(optionalVectorRef); |
234 | 1 | ASSERT_EQ(origAddress, (*optionalVectorMoved).data()); |
235 | 1 | ASSERT_EQ(origValues, *optionalVectorMoved); |
236 | | |
237 | 1 | InplaceOptionalHolder<std::vector<int>> emptyOptionalVector; |
238 | 1 | InplaceOptionalHolder<std::vector<int>> emptyOptionalVectorMoved; |
239 | 1 | emptyOptionalVectorMoved = std::move(emptyOptionalVector); |
240 | 1 | ASSERT_EQ(false, emptyOptionalVectorMoved.hasValue()); |
241 | 1 | } |
242 | | |
243 | | TEST_F(InplaceOptionalHolderTest, moveAssignmentOperatorNoInit) |
244 | 1 | { |
245 | 1 | InplaceOptionalHolder<DummyObject> optionalEmptyObject; |
246 | 1 | InplaceOptionalHolder<DummyObject> optionalEmptyObjectMoved; |
247 | 1 | optionalEmptyObjectMoved.assign(NoInit, std::move(optionalEmptyObject)); |
248 | 1 | ASSERT_FALSE(optionalEmptyObjectMoved.hasValue()); |
249 | | |
250 | 1 | InplaceOptionalHolder<DummyObject> optionalObject(DummyObject{10}); |
251 | 1 | ASSERT_EQ(10, optionalObject->getValue()); |
252 | 1 | ASSERT_FALSE(optionalObject->isNoInit()); |
253 | 1 | optionalObject.assign(NoInit, std::move(optionalObject)); |
254 | | |
255 | 1 | InplaceOptionalHolder<DummyObject> optionalObjectMoved; |
256 | 1 | optionalObjectMoved.assign(NoInit, std::move(optionalObject)); |
257 | 1 | ASSERT_EQ(10, optionalObjectMoved->getValue()); |
258 | | // memory with object has been moved in optional holder, object move constructor has not been called |
259 | 1 | ASSERT_TRUE(optionalObjectMoved->isNoInit()); |
260 | 1 | } |
261 | | |
262 | | TEST_F(InplaceOptionalHolderTest, lvalueAssignmentOperator) |
263 | 1 | { |
264 | 1 | std::vector<int> values{1, 2, 3}; |
265 | 1 | void* origAddress = values.data(); |
266 | 1 | InplaceOptionalHolder<std::vector<int>> optional; |
267 | 1 | optional = values; |
268 | 1 | ASSERT_NE(origAddress, (*optional).data()); |
269 | 1 | ASSERT_EQ(values, *optional); |
270 | 1 | } |
271 | | |
272 | | TEST_F(InplaceOptionalHolderTest, rvalueAssignmentOperator) |
273 | 1 | { |
274 | 1 | std::vector<int> values{1, 2, 3}; |
275 | 1 | std::vector<int> origValues{values}; |
276 | 1 | void* origAddress = values.data(); |
277 | 1 | InplaceOptionalHolder<std::vector<int>> optional; |
278 | 1 | optional = std::move(values); |
279 | 1 | ASSERT_EQ(origAddress, (*optional).data()); |
280 | 1 | ASSERT_EQ(origValues, *optional); |
281 | 1 | } |
282 | | |
283 | | TEST_F(InplaceOptionalHolderTest, reset) |
284 | 1 | { |
285 | 1 | InplaceOptionalHolder<std::vector<int>> optional{std::vector<int>{1, 2, 3}}; |
286 | 1 | ASSERT_TRUE(optional.hasValue()); |
287 | 1 | ASSERT_EQ(1, (*optional)[0]); |
288 | | |
289 | 1 | optional.reset(); |
290 | 1 | ASSERT_FALSE(optional.hasValue()); |
291 | | |
292 | 1 | optional = std::vector<int>{3, 2, 1}; |
293 | 1 | ASSERT_TRUE(optional.hasValue()); |
294 | 1 | ASSERT_EQ(3, (*optional)[0]); |
295 | | |
296 | 1 | optional.reset(); |
297 | 1 | ASSERT_FALSE(optional.hasValue()); |
298 | 1 | } |
299 | | |
300 | | TEST_F(InplaceOptionalHolderTest, operatorEquality) |
301 | 1 | { |
302 | 1 | InplaceOptionalHolder<int> optional1; |
303 | 1 | optional1 = 0xDEAD; |
304 | 1 | InplaceOptionalHolder<int> optional2; |
305 | 1 | optional2 = 0xDEAD; |
306 | 1 | InplaceOptionalHolder<int> optional3; |
307 | 1 | optional3 = 0xBEEF; |
308 | 1 | InplaceOptionalHolder<int> optional4; |
309 | 1 | InplaceOptionalHolder<int> optional5; |
310 | 1 | InplaceOptionalHolder<int> optional6; |
311 | | |
312 | 1 | ASSERT_TRUE(optional1 == optional1); |
313 | 1 | ASSERT_TRUE(optional1 == optional2); |
314 | 1 | ASSERT_FALSE(optional1 == optional3); |
315 | 1 | ASSERT_FALSE(optional1 == optional4); |
316 | 1 | ASSERT_TRUE(optional5 == optional6); |
317 | 1 | ASSERT_FALSE(optional5 == optional1); |
318 | 1 | } |
319 | | |
320 | | TEST_F(InplaceOptionalHolderTest, operatorLessThan) |
321 | 1 | { |
322 | 1 | InplaceOptionalHolder<int> optionalEmpty1; |
323 | 1 | InplaceOptionalHolder<int> optionalEmpty2; |
324 | 1 | InplaceOptionalHolder<int> optional1(1); |
325 | 1 | InplaceOptionalHolder<int> optional2(2); |
326 | | |
327 | 1 | ASSERT_FALSE(optionalEmpty1 < optionalEmpty2); |
328 | 1 | ASSERT_TRUE(optionalEmpty1 < optional1); |
329 | 1 | ASSERT_FALSE(optional1 < optionalEmpty1); |
330 | 1 | ASSERT_TRUE(optional1 < optional2); |
331 | 1 | ASSERT_FALSE(optional2 < optional1); |
332 | 1 | } |
333 | | |
334 | | TEST_F(InplaceOptionalHolderTest, setGet) |
335 | 1 | { |
336 | 1 | InplaceOptionalHolder<int> optionalInt; |
337 | 1 | ASSERT_THROW(*optionalInt, CppRuntimeException); |
338 | 1 | const int intValue = 0xDEAD; |
339 | 1 | optionalInt = intValue; |
340 | 1 | ASSERT_EQ(intValue, *optionalInt); |
341 | | |
342 | 1 | InplaceOptionalHolder<float> optionalFloat; |
343 | 1 | ASSERT_THROW(*optionalFloat, CppRuntimeException); |
344 | 1 | const float floatValue = 3.14F; |
345 | 1 | optionalFloat = floatValue; |
346 | 1 | ASSERT_EQ(floatValue, optionalFloat.value()); |
347 | | |
348 | 1 | InplaceOptionalHolder<DummyObject> optionalObject; |
349 | 1 | ASSERT_THROW(*optionalObject, CppRuntimeException); |
350 | 1 | DummyObject objectValue; |
351 | 1 | objectValue.setValue(intValue); |
352 | 1 | optionalObject = objectValue; |
353 | 1 | const DummyObject& readObjectValue = *optionalObject; |
354 | 1 | ASSERT_EQ(intValue, readObjectValue.getValue()); |
355 | 1 | ASSERT_EQ(intValue, optionalObject->getValue()); |
356 | 1 | } |
357 | | |
358 | | TEST_F(InplaceOptionalHolderTest, hasValue) |
359 | 1 | { |
360 | 1 | InplaceOptionalHolder<int> optionalInt; |
361 | 1 | ASSERT_THROW(*optionalInt, CppRuntimeException); |
362 | 1 | ASSERT_EQ(false, optionalInt.hasValue()); |
363 | | |
364 | 1 | optionalInt = 0xDEAD; |
365 | 1 | ASSERT_EQ(true, optionalInt.hasValue()); |
366 | 1 | } |
367 | | |
368 | | TEST_F(InplaceOptionalHolderTest, constGet) |
369 | 1 | { |
370 | 1 | const int intValue = 0xDEAD; |
371 | 1 | InplaceOptionalHolder<int> optional; |
372 | 1 | optional = intValue; |
373 | 1 | const InplaceOptionalHolder<int> constOptional(optional); |
374 | 1 | ASSERT_EQ(intValue, *constOptional); |
375 | 1 | ASSERT_EQ(intValue, constOptional.value()); |
376 | | |
377 | 1 | DummyObject objectValue; |
378 | 1 | objectValue.setValue(intValue); |
379 | 1 | InplaceOptionalHolder<DummyObject> optionalObject{objectValue}; |
380 | 1 | ASSERT_EQ(intValue, optionalObject->getValue()); |
381 | 1 | } |
382 | | |
383 | | } // namespace zserio |