1 //
2 // Copyright 2020 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "src/core/lib/gprpp/dual_ref_counted.h"
18
19 #include <memory>
20
21 #include "gtest/gtest.h"
22
23 #include "test/core/util/test_config.h"
24
25 namespace grpc_core {
26 namespace testing {
27 namespace {
28
29 class Foo : public DualRefCounted<Foo> {
30 public:
31 Foo() = default;
~Foo()32 ~Foo() override { GPR_ASSERT(shutting_down_); }
33
Orphaned()34 void Orphaned() override { shutting_down_ = true; }
35
36 private:
37 bool shutting_down_ = false;
38 };
39
TEST(DualRefCounted,Basic)40 TEST(DualRefCounted, Basic) {
41 Foo* foo = new Foo();
42 foo->Unref();
43 }
44
TEST(DualRefCounted,ExtraRef)45 TEST(DualRefCounted, ExtraRef) {
46 Foo* foo = new Foo();
47 foo->Ref().release();
48 foo->Unref();
49 foo->Unref();
50 }
51
TEST(DualRefCounted,ExtraWeakRef)52 TEST(DualRefCounted, ExtraWeakRef) {
53 Foo* foo = new Foo();
54 foo->WeakRef().release();
55 foo->Unref();
56 foo->WeakUnref();
57 }
58
TEST(DualRefCounted,RefIfNonZero)59 TEST(DualRefCounted, RefIfNonZero) {
60 Foo* foo = new Foo();
61 foo->WeakRef().release();
62 {
63 RefCountedPtr<Foo> foop = foo->RefIfNonZero();
64 EXPECT_NE(foop.get(), nullptr);
65 }
66 foo->Unref();
67 {
68 RefCountedPtr<Foo> foop = foo->RefIfNonZero();
69 EXPECT_EQ(foop.get(), nullptr);
70 }
71 foo->WeakUnref();
72 }
73
TEST(DualRefCounted,RefAndWeakRefAsSubclass)74 TEST(DualRefCounted, RefAndWeakRefAsSubclass) {
75 class Bar : public Foo {};
76 Foo* foo = new Bar();
77 RefCountedPtr<Bar> barp = foo->RefAsSubclass<Bar>();
78 barp.release();
79 barp = foo->RefAsSubclass<Bar>(DEBUG_LOCATION, "test");
80 barp.release();
81 WeakRefCountedPtr<Bar> weak_barp = foo->WeakRefAsSubclass<Bar>();
82 weak_barp.release();
83 weak_barp = foo->WeakRefAsSubclass<Bar>(DEBUG_LOCATION, "test");
84 weak_barp.release();
85 foo->WeakUnref();
86 foo->WeakUnref();
87 foo->Unref();
88 foo->Unref();
89 foo->Unref();
90 }
91
92 class FooWithTracing : public DualRefCounted<FooWithTracing> {
93 public:
FooWithTracing()94 FooWithTracing() : DualRefCounted("FooWithTracing") {}
~FooWithTracing()95 ~FooWithTracing() override { GPR_ASSERT(shutting_down_); }
96
Orphaned()97 void Orphaned() override { shutting_down_ = true; }
98
99 private:
100 bool shutting_down_ = false;
101 };
102
TEST(DualRefCountedWithTracing,Basic)103 TEST(DualRefCountedWithTracing, Basic) {
104 FooWithTracing* foo = new FooWithTracing();
105 foo->Ref(DEBUG_LOCATION, "extra_ref").release();
106 foo->Unref(DEBUG_LOCATION, "extra_ref");
107 foo->WeakRef(DEBUG_LOCATION, "extra_ref").release();
108 foo->WeakUnref(DEBUG_LOCATION, "extra_ref");
109 // Can use the no-argument methods, too.
110 foo->Ref().release();
111 foo->Unref();
112 foo->WeakRef().release();
113 foo->WeakUnref();
114 foo->Unref(DEBUG_LOCATION, "original_ref");
115 }
116
117 } // namespace
118 } // namespace testing
119 } // namespace grpc_core
120
main(int argc,char ** argv)121 int main(int argc, char** argv) {
122 grpc::testing::TestEnvironment env(&argc, argv);
123 ::testing::InitGoogleTest(&argc, argv);
124 return RUN_ALL_TESTS();
125 }
126