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