1 /*
2 * Copyright (c) 2021, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "test_platform.h"
30
31 #include <string.h>
32
33 #include <openthread/config.h>
34
35 #include "test_util.hpp"
36 #include "common/code_utils.hpp"
37 #include "common/owned_ptr.hpp"
38 #include "common/retain_ptr.hpp"
39
40 namespace ot {
41
42 class TestObject : public RetainCountable
43 {
44 public:
TestObject(void)45 TestObject(void)
46 : mWasFreed(false)
47 {
48 }
49
Free(void)50 void Free(void) { mWasFreed = true; }
ResetTestFlags(void)51 void ResetTestFlags(void) { mWasFreed = false; }
GetRetainCount(void) const52 uint16_t GetRetainCount(void) const { return RetainCountable::GetRetainCount(); }
WasFreed(void) const53 bool WasFreed(void) const { return mWasFreed && (GetRetainCount() == 0); }
54
55 private:
56 bool mWasFreed;
57 };
58
59 static constexpr uint16_t kSkipRetainCountCheck = 0xffff;
60
61 template <typename PointerType>
VerifyPointer(const PointerType & aPointer,const TestObject * aObject,uint16_t aRetainCount=kSkipRetainCountCheck)62 void VerifyPointer(const PointerType &aPointer,
63 const TestObject *aObject,
64 uint16_t aRetainCount = kSkipRetainCountCheck)
65 {
66 if (aObject == nullptr)
67 {
68 VerifyOrQuit(aPointer.IsNull());
69 VerifyOrQuit(aPointer.Get() == nullptr);
70 VerifyOrQuit(aPointer == nullptr);
71 }
72 else
73 {
74 VerifyOrQuit(!aPointer.IsNull());
75 VerifyOrQuit(aPointer.Get() == aObject);
76 VerifyOrQuit(aPointer == aObject);
77 VerifyOrQuit(aPointer != nullptr);
78
79 VerifyOrQuit(!aPointer->WasFreed());
80 VerifyOrQuit(!(*aPointer).WasFreed());
81
82 if (aRetainCount != kSkipRetainCountCheck)
83 {
84 VerifyOrQuit(aObject->GetRetainCount() == aRetainCount);
85 }
86 }
87
88 VerifyOrQuit(aPointer == aPointer);
89 }
90
TestOwnedPtr(void)91 void TestOwnedPtr(void)
92 {
93 TestObject obj1;
94 TestObject obj2;
95 TestObject obj3;
96
97 printf("\n====================================================================================\n");
98 printf("Testing `OwnedPtr`\n");
99
100 printf("\n - Default constructor (null pointer)");
101
102 {
103 OwnedPtr<TestObject> ptr;
104
105 VerifyPointer(ptr, nullptr);
106 }
107
108 printf("\n - Constructor taking ownership of an object");
109 obj1.ResetTestFlags();
110
111 {
112 OwnedPtr<TestObject> ptr(&obj1);
113
114 VerifyPointer(ptr, &obj1);
115 }
116
117 VerifyOrQuit(obj1.WasFreed());
118
119 printf("\n - Move constructor taking over from another");
120 obj1.ResetTestFlags();
121
122 {
123 OwnedPtr<TestObject> ptr1(&obj1);
124 OwnedPtr<TestObject> ptr2(ptr1.PassOwnership());
125
126 VerifyPointer(ptr1, nullptr);
127 VerifyPointer(ptr2, &obj1);
128 }
129
130 VerifyOrQuit(obj1.WasFreed());
131
132 printf("\n - `Free()` method");
133 obj1.ResetTestFlags();
134
135 {
136 OwnedPtr<TestObject> ptr(&obj1);
137
138 VerifyPointer(ptr, &obj1);
139
140 ptr.Free();
141
142 VerifyOrQuit(obj1.WasFreed());
143 VerifyPointer(ptr, nullptr);
144
145 ptr.Free();
146
147 VerifyOrQuit(obj1.WasFreed());
148 VerifyPointer(ptr, nullptr);
149 }
150
151 printf("\n - `Reset()` method");
152 obj1.ResetTestFlags();
153 obj2.ResetTestFlags();
154 obj3.ResetTestFlags();
155
156 {
157 OwnedPtr<TestObject> ptr(&obj1);
158
159 VerifyPointer(ptr, &obj1);
160
161 ptr.Reset(&obj2);
162
163 VerifyOrQuit(obj1.WasFreed());
164 VerifyOrQuit(!obj2.WasFreed());
165 VerifyPointer(ptr, &obj2);
166
167 ptr.Reset();
168 VerifyOrQuit(obj2.WasFreed());
169 VerifyPointer(ptr, nullptr);
170
171 ptr.Reset(&obj3);
172 VerifyPointer(ptr, &obj3);
173 }
174
175 VerifyOrQuit(obj1.WasFreed());
176 VerifyOrQuit(obj2.WasFreed());
177 VerifyOrQuit(obj3.WasFreed());
178
179 printf("\n - Self `Reset()`");
180 obj1.ResetTestFlags();
181
182 {
183 OwnedPtr<TestObject> ptr1(&obj1);
184 OwnedPtr<TestObject> ptr2;
185
186 VerifyPointer(ptr1, &obj1);
187
188 ptr1.Reset(&obj1);
189 VerifyPointer(ptr1, &obj1);
190
191 ptr2.Reset(nullptr);
192 VerifyPointer(ptr2, nullptr);
193 }
194
195 VerifyOrQuit(obj1.WasFreed());
196
197 printf("\n - Move assignment (operator `=`)");
198 obj1.ResetTestFlags();
199 obj2.ResetTestFlags();
200 obj3.ResetTestFlags();
201
202 {
203 OwnedPtr<TestObject> ptr1(&obj1);
204 OwnedPtr<TestObject> ptr2(&obj2);
205 OwnedPtr<TestObject> ptr3(&obj3);
206
207 VerifyPointer(ptr1, &obj1);
208 VerifyPointer(ptr2, &obj2);
209 VerifyPointer(ptr3, &obj3);
210
211 // Move from non-null (ptr1) to non-null (ptr2)
212 ptr2 = ptr1.PassOwnership();
213 VerifyPointer(ptr1, nullptr);
214 VerifyPointer(ptr2, &obj1);
215 VerifyOrQuit(!obj1.WasFreed());
216 VerifyOrQuit(obj2.WasFreed());
217
218 // Move from null (ptr1) to non-null (ptr3)
219 ptr3 = ptr1.PassOwnership();
220 VerifyPointer(ptr1, nullptr);
221 VerifyPointer(ptr3, nullptr);
222 VerifyOrQuit(obj3.WasFreed());
223
224 // Move from non-null (ptr2) to null (ptr1)
225 ptr1 = ptr2.PassOwnership();
226 VerifyPointer(ptr1, &obj1);
227 VerifyPointer(ptr2, nullptr);
228 VerifyOrQuit(!obj1.WasFreed());
229
230 // Move from null (ptr2) to null (ptr3)
231 ptr3 = ptr2.PassOwnership();
232 VerifyPointer(ptr2, nullptr);
233 VerifyPointer(ptr3, nullptr);
234 VerifyOrQuit(!obj1.WasFreed());
235 }
236
237 VerifyOrQuit(obj1.WasFreed());
238
239 printf("\n - Self move assignment (operator `=`)");
240 obj1.ResetTestFlags();
241
242 {
243 OwnedPtr<TestObject> ptr1(&obj1);
244 OwnedPtr<TestObject> ptr2;
245
246 VerifyPointer(ptr1, &obj1);
247 VerifyPointer(ptr2, nullptr);
248
249 // Move from non-null (ptr1) to itself
250 ptr1 = ptr1.PassOwnership();
251 VerifyPointer(ptr1, &obj1);
252
253 // Move from null (ptr2) to itself
254 ptr2 = ptr2.PassOwnership();
255 VerifyPointer(ptr2, nullptr);
256 }
257
258 VerifyOrQuit(obj1.WasFreed());
259
260 printf("\n - `Release()` method");
261 obj1.ResetTestFlags();
262
263 {
264 OwnedPtr<TestObject> ptr(&obj1);
265
266 VerifyPointer(ptr, &obj1);
267
268 VerifyOrQuit(ptr.Release() == &obj1);
269 VerifyOrQuit(!obj1.WasFreed());
270 VerifyPointer(ptr, nullptr);
271
272 VerifyOrQuit(ptr.Release() == nullptr);
273 VerifyOrQuit(!obj1.WasFreed());
274 VerifyPointer(ptr, nullptr);
275 }
276
277 printf("\n\n-- PASS\n");
278 }
279
TestRetainPtr(void)280 void TestRetainPtr(void)
281 {
282 TestObject obj1;
283 TestObject obj2;
284 TestObject obj3;
285
286 printf("\n====================================================================================\n");
287 printf("Testing `RetainPtr`\n");
288
289 VerifyOrQuit(obj1.GetRetainCount() == 0);
290 VerifyOrQuit(obj2.GetRetainCount() == 0);
291 VerifyOrQuit(obj3.GetRetainCount() == 0);
292
293 printf("\n - Default constructor (null pointer)");
294
295 {
296 RetainPtr<TestObject> ptr;
297
298 VerifyPointer(ptr, nullptr);
299 }
300
301 printf("\n - Constructor taking over management of an object");
302 obj1.ResetTestFlags();
303
304 {
305 RetainPtr<TestObject> ptr(&obj1);
306
307 VerifyPointer(ptr, &obj1, 1);
308 }
309
310 VerifyOrQuit(obj1.WasFreed());
311
312 printf("\n - Two constructed `RetainPtr`s of the same object");
313 obj1.ResetTestFlags();
314
315 {
316 RetainPtr<TestObject> ptr1(&obj1);
317 RetainPtr<TestObject> ptr2(&obj1);
318
319 VerifyPointer(ptr1, &obj1, 2);
320 VerifyPointer(ptr2, &obj1, 2);
321 }
322
323 VerifyOrQuit(obj1.WasFreed());
324
325 printf("\n - Copy constructor");
326 obj1.ResetTestFlags();
327
328 {
329 RetainPtr<TestObject> ptr1(&obj1);
330 RetainPtr<TestObject> ptr2(ptr1);
331
332 VerifyPointer(ptr1, &obj1, 2);
333 VerifyPointer(ptr2, &obj1, 2);
334 }
335
336 VerifyOrQuit(obj1.WasFreed());
337
338 printf("\n - `Reset()` method");
339 obj1.ResetTestFlags();
340 obj2.ResetTestFlags();
341 obj3.ResetTestFlags();
342
343 {
344 RetainPtr<TestObject> ptr(&obj1);
345
346 VerifyPointer(ptr, &obj1, 1);
347
348 ptr.Reset(&obj2);
349 VerifyOrQuit(obj1.WasFreed());
350 VerifyOrQuit(!obj2.WasFreed());
351 VerifyPointer(ptr, &obj2, 1);
352
353 ptr.Reset();
354 VerifyOrQuit(obj2.WasFreed());
355 VerifyPointer(ptr, nullptr);
356
357 ptr.Reset(&obj3);
358 VerifyPointer(ptr, &obj3, 1);
359 }
360
361 VerifyOrQuit(obj1.WasFreed());
362 VerifyOrQuit(obj2.WasFreed());
363 VerifyOrQuit(obj3.WasFreed());
364
365 printf("\n - Self `Reset()`");
366 obj1.ResetTestFlags();
367
368 {
369 RetainPtr<TestObject> ptr1(&obj1);
370 RetainPtr<TestObject> ptr2;
371
372 VerifyPointer(ptr1, &obj1, 1);
373
374 ptr1.Reset(&obj1);
375 VerifyPointer(ptr1, &obj1, 1);
376
377 ptr2.Reset(nullptr);
378 VerifyPointer(ptr2, nullptr);
379 }
380
381 VerifyOrQuit(obj1.WasFreed());
382
383 printf("\n - Assignment `=`");
384 obj1.ResetTestFlags();
385 obj2.ResetTestFlags();
386
387 {
388 RetainPtr<TestObject> ptr1(&obj1);
389 RetainPtr<TestObject> ptr2(&obj2);
390 RetainPtr<TestObject> ptr3;
391
392 VerifyPointer(ptr1, &obj1, 1);
393 VerifyPointer(ptr2, &obj2, 1);
394 VerifyPointer(ptr3, nullptr);
395
396 VerifyOrQuit(ptr1 != ptr2);
397 VerifyOrQuit(ptr1 != ptr3);
398 VerifyOrQuit(ptr2 != ptr3);
399
400 // Set from non-null (ptr1) to non-null (ptr2)
401 ptr2 = ptr1;
402 VerifyPointer(ptr1, &obj1, 2);
403 VerifyPointer(ptr2, &obj1, 2);
404 VerifyOrQuit(obj2.WasFreed());
405 VerifyOrQuit(ptr1 == ptr2);
406
407 // Set from null (ptr3) to non-null (ptr1)
408 ptr1 = ptr3;
409 VerifyPointer(ptr1, nullptr);
410 VerifyPointer(ptr3, nullptr);
411 VerifyPointer(ptr2, &obj1, 1);
412 VerifyOrQuit(ptr1 == ptr3);
413
414 // Move from null (ptr1) to null (ptr3)
415 ptr3 = ptr1;
416 VerifyPointer(ptr1, nullptr);
417 VerifyPointer(ptr3, nullptr);
418 VerifyOrQuit(ptr1 == ptr3);
419
420 // Move from non-null (ptr2) to null (ptr3)
421 ptr3 = ptr2;
422 VerifyPointer(ptr2, &obj1, 2);
423 VerifyPointer(ptr3, &obj1, 2);
424 VerifyOrQuit(ptr2 == ptr3);
425 }
426
427 VerifyOrQuit(obj1.WasFreed());
428 VerifyOrQuit(obj2.WasFreed());
429
430 printf("\n - Self assignment `=`");
431 obj1.ResetTestFlags();
432
433 {
434 RetainPtr<TestObject> ptr1(&obj1);
435 RetainPtr<TestObject> ptr2;
436
437 VerifyPointer(ptr1, &obj1, 1);
438 VerifyPointer(ptr2, nullptr);
439
440 // Set from non-null (ptr1) to itself. We use `*(&ptr1) to
441 // silence `clang` error/warning not allowing explicit self
442 // assignment to same variable.
443 ptr1 = *(&ptr1);
444 VerifyPointer(ptr1, &obj1, 1);
445
446 // Set from null (ptr2) to itself
447 ptr2 = *(&ptr2);
448 VerifyPointer(ptr2, nullptr);
449 }
450
451 VerifyOrQuit(obj1.WasFreed());
452
453 printf("\n - `Release()` method");
454 obj1.ResetTestFlags();
455
456 {
457 RetainPtr<TestObject> ptr(&obj1);
458
459 VerifyPointer(ptr, &obj1, 1);
460
461 VerifyOrQuit(ptr.Release() == &obj1);
462 VerifyPointer(ptr, nullptr);
463
464 VerifyOrQuit(ptr.Release() == nullptr);
465 VerifyPointer(ptr, nullptr);
466 }
467
468 VerifyOrQuit(!obj1.WasFreed());
469 VerifyOrQuit(obj1.GetRetainCount() == 1);
470
471 printf("\n\n-- PASS\n");
472 }
473
474 } // namespace ot
475
main(void)476 int main(void)
477 {
478 ot::TestOwnedPtr();
479 ot::TestRetainPtr();
480 printf("\nAll tests passed.\n");
481 return 0;
482 }
483