• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/util/dual_ref_counted.h"
18 
19 #include <memory>
20 
21 #include "absl/log/check.h"
22 #include "gtest/gtest.h"
23 #include "src/core/util/manual_constructor.h"
24 #include "src/core/util/ref_counted.h"
25 #include "test/core/test_util/test_config.h"
26 
27 namespace grpc_core {
28 namespace testing {
29 namespace {
30 
31 class Foo : public DualRefCounted<Foo> {
32  public:
33   Foo() = default;
~Foo()34   ~Foo() override { CHECK(shutting_down_); }
35 
Orphaned()36   void Orphaned() override { shutting_down_ = true; }
37 
38  private:
39   bool shutting_down_ = false;
40 };
41 
TEST(DualRefCounted,Basic)42 TEST(DualRefCounted, Basic) {
43   Foo* foo = new Foo();
44   foo->Unref();
45 }
46 
TEST(DualRefCounted,ExtraRef)47 TEST(DualRefCounted, ExtraRef) {
48   Foo* foo = new Foo();
49   foo->Ref().release();
50   foo->Unref();
51   foo->Unref();
52 }
53 
TEST(DualRefCounted,ExtraWeakRef)54 TEST(DualRefCounted, ExtraWeakRef) {
55   Foo* foo = new Foo();
56   foo->WeakRef().release();
57   foo->Unref();
58   foo->WeakUnref();
59 }
60 
TEST(DualRefCounted,RefIfNonZero)61 TEST(DualRefCounted, RefIfNonZero) {
62   Foo* foo = new Foo();
63   foo->WeakRef().release();
64   {
65     RefCountedPtr<Foo> foop = foo->RefIfNonZero();
66     EXPECT_NE(foop.get(), nullptr);
67   }
68   foo->Unref();
69   {
70     RefCountedPtr<Foo> foop = foo->RefIfNonZero();
71     EXPECT_EQ(foop.get(), nullptr);
72   }
73   foo->WeakUnref();
74 }
75 
TEST(DualRefCounted,RefAndWeakRefAsSubclass)76 TEST(DualRefCounted, RefAndWeakRefAsSubclass) {
77   class Bar : public Foo {};
78   Foo* foo = new Bar();
79   RefCountedPtr<Bar> barp = foo->RefAsSubclass<Bar>();
80   barp.release();
81   barp = foo->RefAsSubclass<Bar>(DEBUG_LOCATION, "test");
82   barp.release();
83   WeakRefCountedPtr<Bar> weak_barp = foo->WeakRefAsSubclass<Bar>();
84   weak_barp.release();
85   weak_barp = foo->WeakRefAsSubclass<Bar>(DEBUG_LOCATION, "test");
86   weak_barp.release();
87   foo->WeakUnref();
88   foo->WeakUnref();
89   foo->Unref();
90   foo->Unref();
91   foo->Unref();
92 }
93 
94 class FooWithTracing : public DualRefCounted<FooWithTracing> {
95  public:
FooWithTracing()96   FooWithTracing() : DualRefCounted("FooWithTracing") {}
~FooWithTracing()97   ~FooWithTracing() override { CHECK(shutting_down_); }
98 
Orphaned()99   void Orphaned() override { shutting_down_ = true; }
100 
101  private:
102   bool shutting_down_ = false;
103 };
104 
TEST(DualRefCountedWithTracing,Basic)105 TEST(DualRefCountedWithTracing, Basic) {
106   FooWithTracing* foo = new FooWithTracing();
107   foo->Ref(DEBUG_LOCATION, "extra_ref").release();
108   foo->Unref(DEBUG_LOCATION, "extra_ref");
109   foo->WeakRef(DEBUG_LOCATION, "extra_ref").release();
110   foo->WeakUnref(DEBUG_LOCATION, "extra_ref");
111   // Can use the no-argument methods, too.
112   foo->Ref().release();
113   foo->Unref();
114   foo->WeakRef().release();
115   foo->WeakUnref();
116   foo->Unref(DEBUG_LOCATION, "original_ref");
117 }
118 
119 class FooWithNoDelete final
120     : public DualRefCounted<FooWithNoDelete, NonPolymorphicRefCount,
121                             UnrefCallDtor> {
122  public:
FooWithNoDelete(bool * orphaned_called,bool * destructor_called)123   FooWithNoDelete(bool* orphaned_called, bool* destructor_called)
124       : DualRefCounted<FooWithNoDelete, NonPolymorphicRefCount, UnrefCallDtor>(
125             "FooWithNoDelete"),
126         orphaned_called_(orphaned_called),
127         destructor_called_(destructor_called) {}
~FooWithNoDelete()128   ~FooWithNoDelete() { *destructor_called_ = true; }
129 
Orphaned()130   void Orphaned() override { *orphaned_called_ = true; }
131 
132  private:
133   bool* const orphaned_called_;
134   bool* const destructor_called_;
135 };
136 
TEST(DualRefCountedWithNoDelete,Basic)137 TEST(DualRefCountedWithNoDelete, Basic) {
138   ManualConstructor<FooWithNoDelete> foo;
139   bool destructor_called = false;
140   bool orphaned_called = false;
141   foo.Init(&orphaned_called, &destructor_called);
142   EXPECT_FALSE(orphaned_called);
143   EXPECT_FALSE(destructor_called);
144   foo->WeakRef().release();
145   EXPECT_FALSE(orphaned_called);
146   EXPECT_FALSE(destructor_called);
147   foo->Unref();
148   EXPECT_TRUE(orphaned_called);
149   EXPECT_FALSE(destructor_called);
150   foo->WeakUnref();
151   EXPECT_TRUE(orphaned_called);
152   EXPECT_TRUE(destructor_called);
153 }
154 
155 }  // namespace
156 }  // namespace testing
157 }  // namespace grpc_core
158 
main(int argc,char ** argv)159 int main(int argc, char** argv) {
160   grpc::testing::TestEnvironment env(&argc, argv);
161   ::testing::InitGoogleTest(&argc, argv);
162   return RUN_ALL_TESTS();
163 }
164