blob: ab7bb09191de271ebefe77d22e475a8cc1703c42 [file] [log] [blame]
perkj0489e492016-10-20 00:24:01 -07001/*
2 * Copyright 2016 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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "rtc_base/ref_counted_object.h"
12
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <memory>
perkj0489e492016-10-20 00:24:01 -070014#include <string>
Danil Chapovalov8df643b2021-01-22 16:11:10 +010015#include <type_traits>
Yves Gerey3e707812018-11-28 16:47:49 +010016#include <utility>
perkj0489e492016-10-20 00:24:01 -070017
Mirko Bonadeid9708072019-01-25 20:26:48 +010018#include "api/scoped_refptr.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/ref_count.h"
Yves Gerey3e707812018-11-28 16:47:49 +010020#include "test/gtest.h"
perkj0489e492016-10-20 00:24:01 -070021
22namespace rtc {
23
24namespace {
25
26class A {
27 public:
28 A() {}
29
30 private:
31 RTC_DISALLOW_COPY_AND_ASSIGN(A);
32};
33
34class RefClass : public RefCountInterface {
35 public:
36 RefClass() {}
37
38 protected:
ehmaldonadoda8dcfb2017-01-04 07:11:23 -080039 ~RefClass() override {}
perkj0489e492016-10-20 00:24:01 -070040};
41
42class RefClassWithRvalue : public RefCountInterface {
43 public:
44 explicit RefClassWithRvalue(std::unique_ptr<A> a) : a_(std::move(a)) {}
45
46 protected:
ehmaldonadoda8dcfb2017-01-04 07:11:23 -080047 ~RefClassWithRvalue() override {}
perkj0489e492016-10-20 00:24:01 -070048
49 public:
50 std::unique_ptr<A> a_;
51};
52
53class RefClassWithMixedValues : public RefCountInterface {
54 public:
55 RefClassWithMixedValues(std::unique_ptr<A> a, int b, const std::string& c)
56 : a_(std::move(a)), b_(b), c_(c) {}
57
58 protected:
ehmaldonadoda8dcfb2017-01-04 07:11:23 -080059 ~RefClassWithMixedValues() override {}
perkj0489e492016-10-20 00:24:01 -070060
61 public:
62 std::unique_ptr<A> a_;
63 int b_;
64 std::string c_;
65};
66
Tomas Gunnarssond7842002021-04-22 17:41:33 +020067class Foo {
68 public:
69 Foo() {}
70 Foo(int i, int j) : foo_(i + j) {}
71 int foo_ = 0;
72};
73
74class FooItf : public RefCountInterface {
75 public:
76 FooItf() {}
77 FooItf(int i, int j) : foo_(i + j) {}
78 int foo_ = 0;
79};
80
perkj0489e492016-10-20 00:24:01 -070081} // namespace
82
Niels Möller6f72f562017-10-19 13:15:17 +020083TEST(RefCountedObject, HasOneRef) {
perkj0489e492016-10-20 00:24:01 -070084 scoped_refptr<RefCountedObject<RefClass>> aref(
85 new RefCountedObject<RefClass>());
86 EXPECT_TRUE(aref->HasOneRef());
Niels Möller6f72f562017-10-19 13:15:17 +020087 aref->AddRef();
88 EXPECT_FALSE(aref->HasOneRef());
89 EXPECT_EQ(aref->Release(), RefCountReleaseStatus::kOtherRefsRemained);
90 EXPECT_TRUE(aref->HasOneRef());
perkj0489e492016-10-20 00:24:01 -070091}
92
93TEST(RefCountedObject, SupportRValuesInCtor) {
94 std::unique_ptr<A> a(new A());
95 scoped_refptr<RefClassWithRvalue> ref(
96 new RefCountedObject<RefClassWithRvalue>(std::move(a)));
97 EXPECT_TRUE(ref->a_.get() != nullptr);
98 EXPECT_TRUE(a.get() == nullptr);
99}
100
101TEST(RefCountedObject, SupportMixedTypesInCtor) {
102 std::unique_ptr<A> a(new A());
103 int b = 9;
104 std::string c = "hello";
105 scoped_refptr<RefClassWithMixedValues> ref(
106 new RefCountedObject<RefClassWithMixedValues>(std::move(a), b, c));
107 EXPECT_TRUE(ref->a_.get() != nullptr);
108 EXPECT_TRUE(a.get() == nullptr);
109 EXPECT_EQ(b, ref->b_);
110 EXPECT_EQ(c, ref->c_);
111}
112
Danil Chapovalov8df643b2021-01-22 16:11:10 +0100113TEST(FinalRefCountedObject, CanWrapIntoScopedRefptr) {
114 using WrappedTyped = FinalRefCountedObject<A>;
115 static_assert(!std::is_polymorphic<WrappedTyped>::value, "");
116 scoped_refptr<WrappedTyped> ref(new WrappedTyped());
117 EXPECT_TRUE(ref.get());
118 EXPECT_TRUE(ref->HasOneRef());
119 // Test reference counter is updated on some simple operations.
120 scoped_refptr<WrappedTyped> ref2 = ref;
121 EXPECT_FALSE(ref->HasOneRef());
122 EXPECT_FALSE(ref2->HasOneRef());
123
124 ref = nullptr;
125 EXPECT_TRUE(ref2->HasOneRef());
126}
127
Danil Chapovalov80b76282021-04-26 16:32:27 +0200128TEST(FinalRefCountedObject, CanCreateFromMovedType) {
129 class MoveOnly {
130 public:
131 MoveOnly(int a) : a_(a) {}
132 MoveOnly(MoveOnly&&) = default;
133
134 int a() { return a_; }
135
136 private:
137 int a_;
138 };
139 MoveOnly foo(5);
140 auto ref = make_ref_counted<MoveOnly>(std::move(foo));
141 EXPECT_EQ(ref->a(), 5);
142}
143
Tomas Gunnarssond7842002021-04-22 17:41:33 +0200144// This test is mostly a compile-time test for scoped_refptr compatibility.
145TEST(RefCounted, SmartPointers) {
146 // Sanity compile-time tests. FooItf is virtual, Foo is not, FooItf inherits
147 // from RefCountInterface, Foo does not.
148 static_assert(std::is_base_of<RefCountInterface, FooItf>::value, "");
149 static_assert(!std::is_base_of<RefCountInterface, Foo>::value, "");
150 static_assert(std::is_polymorphic<FooItf>::value, "");
151 static_assert(!std::is_polymorphic<Foo>::value, "");
152
153 // Check if Ref generates the expected types for Foo and FooItf.
154 static_assert(std::is_base_of<Foo, Ref<Foo>::Type>::value &&
155 !std::is_same<Foo, Ref<Foo>::Type>::value,
156 "");
157 static_assert(std::is_same<FooItf, Ref<FooItf>::Type>::value, "");
158
159 {
160 // Test with FooItf, a class that inherits from RefCountInterface.
161 // Check that we get a valid FooItf reference counted object.
162 auto p = make_ref_counted<FooItf>(2, 3);
163 EXPECT_NE(p.get(), nullptr);
164 EXPECT_EQ(p->foo_, 5); // the FooItf ctor just stores 2+3 in foo_.
165
166 // Use a couple of different ways of declaring what should result in the
167 // same type as `p` is of.
168 scoped_refptr<Ref<FooItf>::Type> p2 = p;
169 Ref<FooItf>::Ptr p3 = p;
170 }
171
172 {
173 // Same for `Foo`
174 auto p = make_ref_counted<Foo>(2, 3);
175 EXPECT_NE(p.get(), nullptr);
176 EXPECT_EQ(p->foo_, 5);
177 scoped_refptr<Ref<Foo>::Type> p2 = p;
178 Ref<Foo>::Ptr p3 = p;
179 }
180}
181
perkj0489e492016-10-20 00:24:01 -0700182} // namespace rtc