Flutter Engine
 
Loading...
Searching...
No Matches
ref_counted_unittest.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This file tests both ref_counted.h and ref_ptr.h (which the former includes).
6// TODO(vtl): Possibly we could separate these tests out better, since a lot of
7// it is actually testing |RefPtr|.
8
10
11#include "flutter/fml/macros.h"
12#include "gtest/gtest.h"
13
14// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks)
15
16#if defined(__clang__)
17#define ALLOW_PESSIMIZING_MOVE(code_line) \
18 _Pragma("clang diagnostic push") \
19 _Pragma("clang diagnostic ignored \"-Wpessimizing-move\"") code_line; \
20 _Pragma("clang diagnostic pop")
21#else
22#define ALLOW_PESSIMIZING_MOVE(code_line) code_line;
23#endif
24
25#if defined(__clang__)
26#define ALLOW_SELF_MOVE(code_line) \
27 _Pragma("clang diagnostic push") \
28 _Pragma("clang diagnostic ignored \"-Wself-move\"") code_line; \
29 _Pragma("clang diagnostic pop")
30#else
31#define ALLOW_SELF_MOVE(code_line) code_line;
32#endif
33
34#if defined(__clang__)
35#define ALLOW_SELF_ASSIGN_OVERLOADED(code_line) \
36 _Pragma("clang diagnostic push") \
37 _Pragma("clang diagnostic ignored \"-Wself-assign-overloaded\"") \
38 code_line; \
39 _Pragma("clang diagnostic pop")
40#else
41#define ALLOW_SELF_ASSIGN_OVERLOADED(code_line) code_line;
42#endif
43
44namespace fml {
45namespace {
46
47class MyClass : public RefCountedThreadSafe<MyClass> {
48 protected:
49 MyClass(MyClass** created, bool* was_destroyed)
50 : was_destroyed_(was_destroyed) {
51 if (created) {
52 *created = this;
53 }
54 }
55 virtual ~MyClass() {
56 if (was_destroyed_) {
57 *was_destroyed_ = true;
58 }
59 }
60
61 private:
64
65 bool* was_destroyed_;
66
68};
69
70class MySubclass final : public MyClass {
71 private:
74
75 MySubclass(MySubclass** created, bool* was_destroyed)
76 : MyClass(nullptr, was_destroyed) {
77 if (created) {
78 *created = this;
79 }
80 }
81 ~MySubclass() override {}
82
84};
85
86TEST(RefCountedTest, Constructors) {
87 bool was_destroyed;
88
89 {
90 // Default.
91 RefPtr<MyClass> r;
92 EXPECT_TRUE(r.get() == nullptr);
93 EXPECT_FALSE(r);
94 }
95
96 {
97 // Nullptr.
98 RefPtr<MyClass> r(nullptr);
99 EXPECT_TRUE(r.get() == nullptr);
100 EXPECT_FALSE(r);
101 }
102
103 {
104 MyClass* created = nullptr;
105 was_destroyed = false;
106 // Adopt, then RVO.
107 RefPtr<MyClass> r(MakeRefCounted<MyClass>(&created, &was_destroyed));
108 EXPECT_TRUE(created);
109 EXPECT_EQ(created, r.get());
110 EXPECT_TRUE(r);
111 EXPECT_FALSE(was_destroyed);
112 }
113 EXPECT_TRUE(was_destroyed);
114
115 {
116 MyClass* created = nullptr;
117 was_destroyed = false;
118 // Adopt, then move.
119 ALLOW_PESSIMIZING_MOVE(RefPtr<MyClass> r(
120 std::move(MakeRefCounted<MyClass>(&created, &was_destroyed))))
121 EXPECT_TRUE(created);
122 EXPECT_EQ(created, r.get());
123 EXPECT_TRUE(r);
124 EXPECT_FALSE(was_destroyed);
125 }
126 EXPECT_TRUE(was_destroyed);
127
128 {
129 MyClass* created = nullptr;
130 was_destroyed = false;
131 RefPtr<MyClass> r1(MakeRefCounted<MyClass>(&created, &was_destroyed));
132 // Copy.
133 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
134 RefPtr<MyClass> r2(r1);
135 EXPECT_TRUE(created);
136 EXPECT_EQ(created, r1.get());
137 EXPECT_EQ(created, r2.get());
138 EXPECT_TRUE(r1);
139 EXPECT_TRUE(r2);
140 EXPECT_FALSE(was_destroyed);
141 }
142 EXPECT_TRUE(was_destroyed);
143
144 {
145 MyClass* created = nullptr;
146 was_destroyed = false;
147 RefPtr<MyClass> r1(MakeRefCounted<MyClass>(&created, &was_destroyed));
148 // From raw pointer.
149 RefPtr<MyClass> r2(created);
150 EXPECT_TRUE(created);
151 EXPECT_EQ(created, r1.get());
152 EXPECT_EQ(created, r2.get());
153 EXPECT_TRUE(r1);
154 EXPECT_TRUE(r2);
155 EXPECT_FALSE(was_destroyed);
156 }
157 EXPECT_TRUE(was_destroyed);
158
159 {
160 MySubclass* created = nullptr;
161 was_destroyed = false;
162 // Adopt, then "move".
163 RefPtr<MyClass> r(MakeRefCounted<MySubclass>(&created, &was_destroyed));
164 EXPECT_TRUE(created);
165 EXPECT_EQ(static_cast<MyClass*>(created), r.get());
166 EXPECT_TRUE(r);
167 EXPECT_FALSE(was_destroyed);
168 }
169 EXPECT_TRUE(was_destroyed);
170
171 {
172 MySubclass* created = nullptr;
173 was_destroyed = false;
174 // Adopt, then "move".
175 ALLOW_PESSIMIZING_MOVE(RefPtr<MyClass> r(
176 std::move(MakeRefCounted<MySubclass>(&created, &was_destroyed))))
177 EXPECT_TRUE(created);
178 EXPECT_EQ(static_cast<MyClass*>(created), r.get());
179 EXPECT_TRUE(r);
180 EXPECT_FALSE(was_destroyed);
181 }
182 EXPECT_TRUE(was_destroyed);
183
184 {
185 MySubclass* created = nullptr;
186 was_destroyed = false;
187 RefPtr<MySubclass> r1(MakeRefCounted<MySubclass>(&created, &was_destroyed));
188 // "Copy".
189 RefPtr<MyClass> r2(r1);
190 EXPECT_TRUE(created);
191 EXPECT_EQ(static_cast<MyClass*>(created), r1.get());
192 EXPECT_EQ(static_cast<MyClass*>(created), r2.get());
193 EXPECT_TRUE(r1);
194 EXPECT_TRUE(r2);
195 EXPECT_FALSE(was_destroyed);
196 }
197 EXPECT_TRUE(was_destroyed);
198
199 {
200 MySubclass* created = nullptr;
201 was_destroyed = false;
202 RefPtr<MySubclass> r1(MakeRefCounted<MySubclass>(&created, &was_destroyed));
203 // From raw pointer.
204 RefPtr<MyClass> r2(created);
205 EXPECT_TRUE(created);
206 EXPECT_EQ(static_cast<MyClass*>(created), r1.get());
207 EXPECT_EQ(static_cast<MyClass*>(created), r2.get());
208 EXPECT_TRUE(r1);
209 EXPECT_TRUE(r2);
210 EXPECT_FALSE(was_destroyed);
211 }
212 EXPECT_TRUE(was_destroyed);
213}
214
215TEST(RefCountedTest, NullAssignmentToNull) {
216 RefPtr<MyClass> r1;
217 // No-op null assignment using |nullptr|.
218 r1 = nullptr;
219 EXPECT_TRUE(r1.get() == nullptr);
220 EXPECT_FALSE(r1);
221
222 RefPtr<MyClass> r2;
223 // No-op null assignment using copy constructor.
224 r1 = r2;
225 EXPECT_TRUE(r1.get() == nullptr);
226 EXPECT_TRUE(r2.get() == nullptr);
227 EXPECT_FALSE(r1);
228 EXPECT_FALSE(r2);
229
230 // No-op null assignment using move constructor.
231 r1 = std::move(r2);
232 EXPECT_TRUE(r1.get() == nullptr);
233 // The clang linter flags the method called on the moved-from reference, but
234 // this is testing the move implementation, so it is marked NOLINT.
235 EXPECT_TRUE(r2.get() == nullptr); // NOLINT(clang-analyzer-cplusplus.Move,
236 // bugprone-use-after-move)
237 EXPECT_FALSE(r1);
238 EXPECT_FALSE(r2);
239
240 RefPtr<MySubclass> r3;
241 // No-op null assignment using "copy" constructor.
242 r1 = r3;
243 EXPECT_TRUE(r1.get() == nullptr);
244 EXPECT_TRUE(r3.get() == nullptr);
245 EXPECT_FALSE(r1);
246 EXPECT_FALSE(r3);
247
248 // No-op null assignment using "move" constructor.
249 r1 = std::move(r3);
250 EXPECT_TRUE(r1.get() == nullptr);
251 EXPECT_TRUE(r3.get() == nullptr); // NOLINT(bugprone-use-after-move)
252 EXPECT_FALSE(r1);
253 EXPECT_FALSE(r3);
254}
255
256TEST(RefCountedTest, NonNullAssignmentToNull) {
257 bool was_destroyed;
258
259 {
260 MyClass* created = nullptr;
261 was_destroyed = false;
262 RefPtr<MyClass> r1(MakeRefCounted<MyClass>(&created, &was_destroyed));
263 RefPtr<MyClass> r2;
264 // Copy assignment (to null ref pointer).
265 r2 = r1;
266 EXPECT_EQ(created, r1.get());
267 EXPECT_EQ(created, r2.get());
268 EXPECT_TRUE(r1);
269 EXPECT_TRUE(r2);
270 EXPECT_FALSE(was_destroyed);
271 }
272 EXPECT_TRUE(was_destroyed);
273
274 {
275 MyClass* created = nullptr;
276 was_destroyed = false;
277 RefPtr<MyClass> r1(MakeRefCounted<MyClass>(&created, &was_destroyed));
278 RefPtr<MyClass> r2;
279 // Move assignment (to null ref pointer).
280 r2 = std::move(r1);
281 // The clang linter flags the method called on the moved-from reference, but
282 // this is testing the move implementation, so it is marked NOLINT.
283 EXPECT_TRUE(r1.get() == nullptr); // NOLINT(clang-analyzer-cplusplus.Move,
284 // bugprone-use-after-move)
285 EXPECT_EQ(created, r2.get());
286 EXPECT_FALSE(r1);
287 EXPECT_TRUE(r2);
288 EXPECT_FALSE(was_destroyed);
289 }
290 EXPECT_TRUE(was_destroyed);
291
292 {
293 MySubclass* created = nullptr;
294 was_destroyed = false;
295 RefPtr<MySubclass> r1(MakeRefCounted<MySubclass>(&created, &was_destroyed));
296 RefPtr<MyClass> r2;
297 // "Copy" assignment (to null ref pointer).
298 r2 = r1;
299 EXPECT_EQ(created, r1.get());
300 EXPECT_EQ(static_cast<MyClass*>(created), r2.get());
301 EXPECT_TRUE(r1);
302 EXPECT_TRUE(r2);
303 EXPECT_FALSE(was_destroyed);
304 }
305 EXPECT_TRUE(was_destroyed);
306
307 {
308 MySubclass* created = nullptr;
309 was_destroyed = false;
310 RefPtr<MySubclass> r1(MakeRefCounted<MySubclass>(&created, &was_destroyed));
311 RefPtr<MyClass> r2;
312 // "Move" assignment (to null ref pointer).
313 r2 = std::move(r1);
314 EXPECT_TRUE(r1.get() == nullptr); // NOLINT(bugprone-use-after-move)
315 EXPECT_EQ(static_cast<MyClass*>(created), r2.get());
316 EXPECT_FALSE(r1);
317 EXPECT_TRUE(r2);
318 EXPECT_FALSE(was_destroyed);
319 }
320 EXPECT_TRUE(was_destroyed);
321}
322
323TEST(RefCountedTest, NullAssignmentToNonNull) {
324 bool was_destroyed = false;
325 RefPtr<MyClass> r1(MakeRefCounted<MyClass>(nullptr, &was_destroyed));
326 // Null assignment (to non-null ref pointer) using |nullptr|.
327 r1 = nullptr;
328 EXPECT_TRUE(r1.get() == nullptr);
329 EXPECT_FALSE(r1);
330 EXPECT_TRUE(was_destroyed);
331
332 was_destroyed = false;
333 r1 = MakeRefCounted<MyClass>(nullptr, &was_destroyed);
334 RefPtr<MyClass> r2;
335 // Null assignment (to non-null ref pointer) using copy constructor.
336 r1 = r2;
337 EXPECT_TRUE(r1.get() == nullptr);
338 EXPECT_TRUE(r2.get() == nullptr);
339 EXPECT_FALSE(r1);
340 EXPECT_FALSE(r2);
341 EXPECT_TRUE(was_destroyed);
342
343 was_destroyed = false;
344 r1 = MakeRefCounted<MyClass>(nullptr, &was_destroyed);
345 // Null assignment using move constructor.
346 r1 = std::move(r2);
347 EXPECT_TRUE(r1.get() == nullptr);
348 // The clang linter flags the method called on the moved-from reference, but
349 // this is testing the move implementation, so it is marked NOLINT.
350 EXPECT_TRUE(r2.get() == nullptr); // NOLINT(clang-analyzer-cplusplus.Move,
351 // bugprone-use-after-move)
352 EXPECT_FALSE(r1);
353 EXPECT_FALSE(r2);
354 EXPECT_TRUE(was_destroyed);
355
356 was_destroyed = false;
357 r1 = MakeRefCounted<MyClass>(nullptr, &was_destroyed);
358 RefPtr<MySubclass> r3;
359 // Null assignment (to non-null ref pointer) using "copy" constructor.
360 r1 = r3;
361 EXPECT_TRUE(r1.get() == nullptr);
362 EXPECT_TRUE(r3.get() == nullptr);
363 EXPECT_FALSE(r1);
364 EXPECT_FALSE(r3);
365 EXPECT_TRUE(was_destroyed);
366
367 was_destroyed = false;
368 r1 = MakeRefCounted<MyClass>(nullptr, &was_destroyed);
369 // Null assignment (to non-null ref pointer) using "move" constructor.
370 r1 = std::move(r3);
371 EXPECT_TRUE(r1.get() == nullptr);
372 EXPECT_TRUE(r3.get() == nullptr); // NOLINT(bugprone-use-after-move)
373 EXPECT_FALSE(r1);
374 EXPECT_FALSE(r3);
375 EXPECT_TRUE(was_destroyed);
376}
377
378TEST(RefCountedTest, NonNullAssignmentToNonNull) {
379 bool was_destroyed1;
380 bool was_destroyed2;
381
382 {
383 was_destroyed1 = false;
384 was_destroyed2 = false;
385 RefPtr<MyClass> r1(MakeRefCounted<MyClass>(nullptr, &was_destroyed1));
386 RefPtr<MyClass> r2(MakeRefCounted<MyClass>(nullptr, &was_destroyed2));
387 // Copy assignment (to non-null ref pointer).
388 r2 = r1;
389 EXPECT_EQ(r1.get(), r2.get());
390 EXPECT_TRUE(r1);
391 EXPECT_TRUE(r2);
392 EXPECT_FALSE(was_destroyed1);
393 EXPECT_TRUE(was_destroyed2);
394 }
395 EXPECT_TRUE(was_destroyed1);
396
397 {
398 was_destroyed1 = false;
399 was_destroyed2 = false;
400 RefPtr<MyClass> r1(MakeRefCounted<MyClass>(nullptr, &was_destroyed1));
401 RefPtr<MyClass> r2(MakeRefCounted<MyClass>(nullptr, &was_destroyed2));
402 // Move assignment (to non-null ref pointer).
403 r2 = std::move(r1);
404 // The clang linter flags the method called on the moved-from reference, but
405 // this is testing the move implementation, so it is marked NOLINT.
406 EXPECT_TRUE(r1.get() == nullptr); // NOLINT(clang-analyzer-cplusplus.Move,
407 // bugprone-use-after-move)
408 EXPECT_FALSE(r2.get() == nullptr);
409 EXPECT_FALSE(r1);
410 EXPECT_TRUE(r2);
411 EXPECT_FALSE(was_destroyed1);
412 EXPECT_TRUE(was_destroyed2);
413 }
414 EXPECT_TRUE(was_destroyed1);
415
416 {
417 was_destroyed1 = false;
418 was_destroyed2 = false;
419 RefPtr<MySubclass> r1(MakeRefCounted<MySubclass>(nullptr, &was_destroyed1));
420 RefPtr<MyClass> r2(MakeRefCounted<MyClass>(nullptr, &was_destroyed2));
421 // "Copy" assignment (to non-null ref pointer).
422 r2 = r1;
423 EXPECT_EQ(r1.get(), r2.get());
424 EXPECT_TRUE(r1);
425 EXPECT_TRUE(r2);
426 EXPECT_FALSE(was_destroyed1);
427 EXPECT_TRUE(was_destroyed2);
428 }
429 EXPECT_TRUE(was_destroyed1);
430
431 {
432 was_destroyed1 = false;
433 was_destroyed2 = false;
434 RefPtr<MySubclass> r1(MakeRefCounted<MySubclass>(nullptr, &was_destroyed1));
435 RefPtr<MyClass> r2(MakeRefCounted<MyClass>(nullptr, &was_destroyed2));
436 // Move assignment (to non-null ref pointer).
437 r2 = std::move(r1);
438 EXPECT_TRUE(r1.get() == nullptr); // NOLINT(bugprone-use-after-move)
439 EXPECT_FALSE(r2.get() == nullptr);
440 EXPECT_FALSE(r1);
441 EXPECT_TRUE(r2);
442 EXPECT_FALSE(was_destroyed1);
443 EXPECT_TRUE(was_destroyed2);
444 }
445 EXPECT_TRUE(was_destroyed1);
446}
447
448TEST(RefCountedTest, SelfAssignment) {
449 bool was_destroyed;
450
451 {
452 MyClass* created = nullptr;
453 was_destroyed = false;
454 // This line is marked NOLINT because the clang linter does not reason about
455 // the value of the reference count. In particular, the self-assignment
456 // below is handled in the copy constructor by a refcount increment then
457 // decrement. The linter sees only that the decrement might destroy the
458 // object.
459 RefPtr<MyClass> r(MakeRefCounted<MyClass>( // NOLINT
460 &created, &was_destroyed));
461 // Copy.
463 EXPECT_EQ(created, r.get());
464 EXPECT_FALSE(was_destroyed);
465 }
466 EXPECT_TRUE(was_destroyed);
467
468 {
469 MyClass* created = nullptr;
470 was_destroyed = false;
471 RefPtr<MyClass> r(MakeRefCounted<MyClass>(&created, &was_destroyed));
472 // Move.
473 ALLOW_SELF_MOVE(r = std::move(r))
474 EXPECT_EQ(created, r.get());
475 EXPECT_FALSE(was_destroyed);
476 }
477 EXPECT_TRUE(was_destroyed);
478}
479
480TEST(RefCountedTest, Swap) {
481 MyClass* created1 = nullptr;
482 static bool was_destroyed1;
483 was_destroyed1 = false;
484 RefPtr<MyClass> r1(MakeRefCounted<MyClass>(&created1, &was_destroyed1));
485 EXPECT_TRUE(created1);
486 EXPECT_EQ(created1, r1.get());
487
488 MyClass* created2 = nullptr;
489 static bool was_destroyed2;
490 was_destroyed2 = false;
491 RefPtr<MyClass> r2(MakeRefCounted<MyClass>(&created2, &was_destroyed2));
492 EXPECT_TRUE(created2);
493 EXPECT_EQ(created2, r2.get());
494 EXPECT_NE(created1, created2);
495
496 r1.swap(r2);
497 EXPECT_EQ(created2, r1.get());
498 EXPECT_EQ(created1, r2.get());
499}
500
501TEST(RefCountedTest, GetAndDereferenceOperators) {
502 // Note: We check here that .get(), operator*, and operator-> are const, but
503 // return non-const pointers/refs.
504
505 MyClass* created = nullptr;
506 const RefPtr<MyClass> r(MakeRefCounted<MyClass>(&created, nullptr));
507 MyClass* ptr = r.get(); // Assign to non-const pointer.
508 EXPECT_EQ(created, ptr);
509 ptr = r.operator->(); // Assign to non-const pointer.
510 EXPECT_EQ(created, ptr);
511 MyClass& ref = *r; // "Assign" to non-const reference.
512 EXPECT_EQ(created, &ref);
513}
514
515// You can manually call |AddRef()| and |Release()| if you want.
516TEST(RefCountedTest, AddRefRelease) {
517 MyClass* created = nullptr;
518 bool was_destroyed = false;
519 {
520 RefPtr<MyClass> r(MakeRefCounted<MyClass>(&created, &was_destroyed));
521 EXPECT_EQ(created, r.get());
522 created->AddRef();
523 }
524 EXPECT_FALSE(was_destroyed);
525 created->Release();
526 EXPECT_TRUE(was_destroyed);
527}
528
529TEST(RefCountedTest, Mix) {
530 MySubclass* created = nullptr;
531 bool was_destroyed = false;
532 RefPtr<MySubclass> r1(MakeRefCounted<MySubclass>(&created, &was_destroyed));
533 ASSERT_FALSE(was_destroyed);
534 EXPECT_TRUE(created->HasOneRef());
535 created->AssertHasOneRef();
536
537 RefPtr<MySubclass> r2 = r1;
538 ASSERT_FALSE(was_destroyed);
539 EXPECT_FALSE(created->HasOneRef());
540
541 r1 = nullptr;
542 ASSERT_FALSE(was_destroyed);
543 created->AssertHasOneRef();
544
545 {
546 RefPtr<MyClass> r3 = r2;
547 EXPECT_FALSE(created->HasOneRef());
548 {
549 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
550 RefPtr<MyClass> r4(r3);
551 r2 = nullptr;
552 ASSERT_FALSE(was_destroyed);
553 EXPECT_FALSE(created->HasOneRef());
554 }
555 ASSERT_FALSE(was_destroyed);
556 EXPECT_TRUE(created->HasOneRef());
557 created->AssertHasOneRef();
558
559 r1 = RefPtr<MySubclass>(static_cast<MySubclass*>(r3.get()));
560 ASSERT_FALSE(was_destroyed);
561 EXPECT_FALSE(created->HasOneRef());
562 }
563 ASSERT_FALSE(was_destroyed);
564 EXPECT_TRUE(created->HasOneRef());
565 created->AssertHasOneRef();
566
567 EXPECT_EQ(created, r1.get());
568
569 r1 = nullptr;
570 EXPECT_TRUE(was_destroyed);
571}
572
573class MyPublicClass : public RefCountedThreadSafe<MyPublicClass> {
574 public:
575 // Overloaded constructors work with |MakeRefCounted()|.
576 MyPublicClass() : has_num_(false), num_(0) {}
577 explicit MyPublicClass(int num) : has_num_(true), num_(num) {}
578
579 ~MyPublicClass() {}
580
581 bool has_num() const { return has_num_; }
582 int num() const { return num_; }
583
584 private:
585 bool has_num_;
586 int num_;
587
588 FML_DISALLOW_COPY_AND_ASSIGN(MyPublicClass);
589};
590
591// You can also just keep constructors and destructors public. Make sure that
592// works (mostly that it compiles).
593TEST(RefCountedTest, PublicCtorAndDtor) {
594 RefPtr<MyPublicClass> r1 = MakeRefCounted<MyPublicClass>();
595 ASSERT_TRUE(r1);
596 EXPECT_FALSE(r1->has_num());
597
598 RefPtr<MyPublicClass> r2 = MakeRefCounted<MyPublicClass>(123);
599 ASSERT_TRUE(r2);
600 EXPECT_TRUE(r2->has_num());
601 EXPECT_EQ(123, r2->num());
602 EXPECT_NE(r1.get(), r2.get());
603
604 r1 = r2;
605 EXPECT_TRUE(r1->has_num());
606 EXPECT_EQ(123, r1->num());
607 EXPECT_EQ(r1.get(), r2.get());
608
609 r2 = nullptr;
610 EXPECT_FALSE(r2);
611 EXPECT_TRUE(r1->has_num());
612 EXPECT_EQ(123, r1->num());
613
614 r1 = nullptr;
615 EXPECT_FALSE(r1);
616}
617
618// The danger with having a public constructor or destructor is that certain
619// things will compile. You should get some protection by assertions in Debug
620// builds.
621#ifndef NDEBUG
622TEST(RefCountedTest, DebugChecks) {
623 {
624 MyPublicClass* p = new MyPublicClass();
625 EXPECT_DEATH_IF_SUPPORTED( // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
626 delete p, "!adoption_required_");
627 }
628
629 {
630 MyPublicClass* p = new MyPublicClass();
631 EXPECT_DEATH_IF_SUPPORTED( // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
632 RefPtr<MyPublicClass> r(p), "!adoption_required_");
633 }
634
635 {
636 RefPtr<MyPublicClass> r(MakeRefCounted<MyPublicClass>());
637 EXPECT_DEATH_IF_SUPPORTED(delete r.get(), "destruction_started_");
638 }
639}
640#endif
641
642// TODO(vtl): Add (threaded) stress tests.
643
644} // namespace
645} // namespace fml
646
647// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition macros.h:27
TEST(MallocMapping, EmptyContructor)
#define FML_FRIEND_REF_COUNTED_THREAD_SAFE(T)
#define FML_FRIEND_MAKE_REF_COUNTED(T)
#define ALLOW_PESSIMIZING_MOVE(code_line)
#define ALLOW_SELF_ASSIGN_OVERLOADED(code_line)
#define ALLOW_SELF_MOVE(code_line)