1 /*
2 * Copyright 2019 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "api/scoped_refptr.h"
12
13 #include <utility>
14 #include <vector>
15
16 #include "test/gtest.h"
17
18 namespace rtc {
19 namespace {
20
21 struct FunctionsCalled {
22 int addref = 0;
23 int release = 0;
24 };
25
26 class ScopedRefCounted {
27 public:
ScopedRefCounted(FunctionsCalled * called)28 explicit ScopedRefCounted(FunctionsCalled* called) : called_(*called) {}
29 ScopedRefCounted(const ScopedRefCounted&) = delete;
30 ScopedRefCounted& operator=(const ScopedRefCounted&) = delete;
31
AddRef()32 void AddRef() {
33 ++called_.addref;
34 ++ref_count_;
35 }
Release()36 void Release() {
37 ++called_.release;
38 if (0 == --ref_count_)
39 delete this;
40 }
41
42 private:
43 ~ScopedRefCounted() = default;
44
45 FunctionsCalled& called_;
46 int ref_count_ = 0;
47 };
48
TEST(ScopedRefptrTest,IsCopyConstructable)49 TEST(ScopedRefptrTest, IsCopyConstructable) {
50 FunctionsCalled called;
51 scoped_refptr<ScopedRefCounted> ptr(new ScopedRefCounted(&called));
52 scoped_refptr<ScopedRefCounted> another_ptr = ptr;
53
54 EXPECT_TRUE(ptr);
55 EXPECT_TRUE(another_ptr);
56 EXPECT_EQ(called.addref, 2);
57 }
58
TEST(ScopedRefptrTest,IsCopyAssignable)59 TEST(ScopedRefptrTest, IsCopyAssignable) {
60 FunctionsCalled called;
61 scoped_refptr<ScopedRefCounted> another_ptr;
62 scoped_refptr<ScopedRefCounted> ptr(new ScopedRefCounted(&called));
63 another_ptr = ptr;
64
65 EXPECT_TRUE(ptr);
66 EXPECT_TRUE(another_ptr);
67 EXPECT_EQ(called.addref, 2);
68 }
69
TEST(ScopedRefptrTest,IsMoveConstructableWithoutExtraAddRefRelease)70 TEST(ScopedRefptrTest, IsMoveConstructableWithoutExtraAddRefRelease) {
71 FunctionsCalled called;
72 scoped_refptr<ScopedRefCounted> ptr(new ScopedRefCounted(&called));
73 scoped_refptr<ScopedRefCounted> another_ptr = std::move(ptr);
74
75 EXPECT_FALSE(ptr);
76 EXPECT_TRUE(another_ptr);
77 EXPECT_EQ(called.addref, 1);
78 EXPECT_EQ(called.release, 0);
79 }
80
TEST(ScopedRefptrTest,IsMoveAssignableWithoutExtraAddRefRelease)81 TEST(ScopedRefptrTest, IsMoveAssignableWithoutExtraAddRefRelease) {
82 FunctionsCalled called;
83 scoped_refptr<ScopedRefCounted> another_ptr;
84 scoped_refptr<ScopedRefCounted> ptr(new ScopedRefCounted(&called));
85 another_ptr = std::move(ptr);
86
87 EXPECT_FALSE(ptr);
88 EXPECT_TRUE(another_ptr);
89 EXPECT_EQ(called.addref, 1);
90 EXPECT_EQ(called.release, 0);
91 }
92
TEST(ScopedRefptrTest,MovableDuringVectorReallocation)93 TEST(ScopedRefptrTest, MovableDuringVectorReallocation) {
94 static_assert(
95 std::is_nothrow_move_constructible<scoped_refptr<ScopedRefCounted>>(),
96 "");
97 // Test below describes a scenario where it is helpful for move constructor
98 // to be noexcept.
99 FunctionsCalled called;
100 std::vector<scoped_refptr<ScopedRefCounted>> ptrs;
101 ptrs.reserve(1);
102 // Insert more elements than reserved to provoke reallocation.
103 ptrs.emplace_back(new ScopedRefCounted(&called));
104 ptrs.emplace_back(new ScopedRefCounted(&called));
105
106 EXPECT_EQ(called.addref, 2);
107 EXPECT_EQ(called.release, 0);
108 }
109
110 } // namespace
111 } // namespace rtc
112