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