/* * * Copyright 2017 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "src/core/lib/gprpp/ref_counted_ptr.h" #include #include #include "src/core/lib/gprpp/dual_ref_counted.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/gprpp/ref_counted.h" #include "test/core/util/test_config.h" namespace grpc_core { namespace testing { namespace { // // RefCountedPtr<> tests // class Foo : public RefCounted { public: Foo() : value_(0) {} explicit Foo(int value) : value_(value) {} int value() const { return value_; } private: int value_; }; TEST(RefCountedPtr, DefaultConstructor) { RefCountedPtr foo; } TEST(RefCountedPtr, ExplicitConstructorEmpty) { RefCountedPtr foo(nullptr); } TEST(RefCountedPtr, ExplicitConstructor) { RefCountedPtr foo(new Foo()); } TEST(RefCountedPtr, MoveConstructor) { RefCountedPtr foo(new Foo()); RefCountedPtr foo2(std::move(foo)); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(nullptr, foo.get()); EXPECT_NE(nullptr, foo2.get()); } TEST(RefCountedPtr, MoveAssignment) { RefCountedPtr foo(new Foo()); RefCountedPtr foo2 = std::move(foo); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(nullptr, foo.get()); EXPECT_NE(nullptr, foo2.get()); } TEST(RefCountedPtr, CopyConstructor) { RefCountedPtr foo(new Foo()); RefCountedPtr foo2(foo); EXPECT_NE(nullptr, foo.get()); EXPECT_EQ(foo.get(), foo2.get()); } TEST(RefCountedPtr, CopyAssignment) { RefCountedPtr foo(new Foo()); RefCountedPtr foo2 = foo; EXPECT_NE(nullptr, foo.get()); EXPECT_EQ(foo.get(), foo2.get()); } TEST(RefCountedPtr, CopyAssignmentWhenEmpty) { RefCountedPtr foo; RefCountedPtr foo2; foo2 = foo; EXPECT_EQ(nullptr, foo.get()); EXPECT_EQ(nullptr, foo2.get()); } TEST(RefCountedPtr, CopyAssignmentToSelf) { RefCountedPtr foo(new Foo()); foo = *&foo; // The "*&" avoids warnings from LLVM -Wself-assign. } TEST(RefCountedPtr, EnclosedScope) { RefCountedPtr foo(new Foo()); { RefCountedPtr foo2(std::move(foo)); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(nullptr, foo.get()); EXPECT_NE(nullptr, foo2.get()); } EXPECT_EQ(nullptr, foo.get()); } TEST(RefCountedPtr, ResetFromNullToNonNull) { RefCountedPtr foo; EXPECT_EQ(nullptr, foo.get()); foo.reset(new Foo()); EXPECT_NE(nullptr, foo.get()); } TEST(RefCountedPtr, ResetFromNonNullToNonNull) { RefCountedPtr foo(new Foo()); EXPECT_NE(nullptr, foo.get()); Foo* original = foo.get(); foo.reset(new Foo()); EXPECT_NE(nullptr, foo.get()); EXPECT_NE(original, foo.get()); } TEST(RefCountedPtr, ResetFromNonNullToNull) { RefCountedPtr foo(new Foo()); EXPECT_NE(nullptr, foo.get()); foo.reset(); EXPECT_EQ(nullptr, foo.get()); } TEST(RefCountedPtr, ResetFromNullToNull) { RefCountedPtr foo; EXPECT_EQ(nullptr, foo.get()); foo.reset(); EXPECT_EQ(nullptr, foo.get()); } TEST(RefCountedPtr, DerefernceOperators) { RefCountedPtr foo(new Foo()); foo->value(); Foo& foo_ref = *foo; foo_ref.value(); } TEST(RefCountedPtr, EqualityOperators) { RefCountedPtr foo(new Foo()); RefCountedPtr bar = foo; RefCountedPtr empty; // Test equality between RefCountedPtrs. EXPECT_EQ(foo, bar); EXPECT_NE(foo, empty); // Test equality with bare pointers. EXPECT_EQ(foo, foo.get()); EXPECT_EQ(empty, nullptr); EXPECT_NE(foo, nullptr); } TEST(RefCountedPtr, Swap) { Foo* foo = new Foo(); Foo* bar = new Foo(); RefCountedPtr ptr1(foo); RefCountedPtr ptr2(bar); ptr1.swap(ptr2); EXPECT_EQ(foo, ptr2.get()); EXPECT_EQ(bar, ptr1.get()); RefCountedPtr ptr3; ptr3.swap(ptr2); EXPECT_EQ(nullptr, ptr2.get()); EXPECT_EQ(foo, ptr3.get()); } TEST(MakeRefCounted, NoArgs) { RefCountedPtr foo = MakeRefCounted(); EXPECT_EQ(0, foo->value()); } TEST(MakeRefCounted, Args) { RefCountedPtr foo = MakeRefCounted(3); EXPECT_EQ(3, foo->value()); } class FooWithTracing : public RefCounted { public: FooWithTracing() : RefCounted("FooWithTracing") {} }; TEST(RefCountedPtr, RefCountedWithTracing) { RefCountedPtr foo(new FooWithTracing()); RefCountedPtr foo2 = foo->Ref(DEBUG_LOCATION, "foo"); foo2.release(); foo->Unref(DEBUG_LOCATION, "foo"); } class BaseClass : public RefCounted { public: BaseClass() {} }; class Subclass : public BaseClass { public: Subclass() {} }; TEST(RefCountedPtr, ConstructFromSubclass) { RefCountedPtr p(new Subclass()); } TEST(RefCountedPtr, CopyAssignFromSubclass) { RefCountedPtr b; EXPECT_EQ(nullptr, b.get()); RefCountedPtr s = MakeRefCounted(); b = s; EXPECT_NE(nullptr, b.get()); } TEST(RefCountedPtr, MoveAssignFromSubclass) { RefCountedPtr b; EXPECT_EQ(nullptr, b.get()); RefCountedPtr s = MakeRefCounted(); b = std::move(s); EXPECT_NE(nullptr, b.get()); } TEST(RefCountedPtr, ResetFromSubclass) { RefCountedPtr b; EXPECT_EQ(nullptr, b.get()); b.reset(new Subclass()); EXPECT_NE(nullptr, b.get()); } TEST(RefCountedPtr, EqualityWithSubclass) { Subclass* s = new Subclass(); RefCountedPtr b(s); EXPECT_EQ(b, s); } void FunctionTakingBaseClass(RefCountedPtr p) { p.reset(); // To appease clang-tidy. } TEST(RefCountedPtr, CanPassSubclassToFunctionExpectingBaseClass) { RefCountedPtr p = MakeRefCounted(); FunctionTakingBaseClass(p); } void FunctionTakingSubclass(RefCountedPtr p) { p.reset(); // To appease clang-tidy. } TEST(RefCountedPtr, CanPassSubclassToFunctionExpectingSubclass) { RefCountedPtr p = MakeRefCounted(); FunctionTakingSubclass(p); } // // WeakRefCountedPtr<> tests // class Bar : public DualRefCounted { public: Bar() : value_(0) {} explicit Bar(int value) : value_(value) {} ~Bar() override { GPR_ASSERT(shutting_down_); } void Orphan() override { shutting_down_ = true; } int value() const { return value_; } private: int value_; bool shutting_down_ = false; }; TEST(WeakRefCountedPtr, DefaultConstructor) { WeakRefCountedPtr bar; } TEST(WeakRefCountedPtr, ExplicitConstructorEmpty) { WeakRefCountedPtr bar(nullptr); } TEST(WeakRefCountedPtr, ExplicitConstructor) { RefCountedPtr bar_strong(new Bar()); bar_strong->WeakRef().release(); WeakRefCountedPtr bar(bar_strong.get()); } TEST(WeakRefCountedPtr, MoveConstructor) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); WeakRefCountedPtr bar2(std::move(bar)); EXPECT_EQ(nullptr, bar.get()); // NOLINT EXPECT_NE(nullptr, bar2.get()); } TEST(WeakRefCountedPtr, MoveAssignment) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); WeakRefCountedPtr bar2 = std::move(bar); EXPECT_EQ(nullptr, bar.get()); // NOLINT EXPECT_NE(nullptr, bar2.get()); } TEST(WeakRefCountedPtr, CopyConstructor) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); WeakRefCountedPtr bar2(bar); EXPECT_NE(nullptr, bar.get()); EXPECT_EQ(bar.get(), bar2.get()); } TEST(WeakRefCountedPtr, CopyAssignment) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); WeakRefCountedPtr bar2 = bar; EXPECT_NE(nullptr, bar.get()); EXPECT_EQ(bar.get(), bar2.get()); } TEST(WeakRefCountedPtr, CopyAssignmentWhenEmpty) { WeakRefCountedPtr bar; WeakRefCountedPtr bar2; bar2 = bar; EXPECT_EQ(nullptr, bar.get()); EXPECT_EQ(nullptr, bar2.get()); } TEST(WeakRefCountedPtr, CopyAssignmentToSelf) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); bar = *&bar; // The "*&" avoids warnings from LLVM -Wself-assign. } TEST(WeakRefCountedPtr, EnclosedScope) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); { WeakRefCountedPtr bar2(std::move(bar)); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(nullptr, bar.get()); EXPECT_NE(nullptr, bar2.get()); } EXPECT_EQ(nullptr, bar.get()); } TEST(WeakRefCountedPtr, ResetFromNullToNonNull) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar; EXPECT_EQ(nullptr, bar.get()); bar_strong->WeakRef().release(); bar.reset(bar_strong.get()); EXPECT_NE(nullptr, bar.get()); } TEST(WeakRefCountedPtr, ResetFromNonNullToNonNull) { RefCountedPtr bar_strong(new Bar()); RefCountedPtr bar2_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); EXPECT_NE(nullptr, bar.get()); bar2_strong->WeakRef().release(); bar.reset(bar2_strong.get()); EXPECT_NE(nullptr, bar.get()); EXPECT_NE(bar_strong.get(), bar.get()); } TEST(WeakRefCountedPtr, ResetFromNonNullToNull) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); EXPECT_NE(nullptr, bar.get()); bar.reset(); EXPECT_EQ(nullptr, bar.get()); } TEST(WeakRefCountedPtr, ResetFromNullToNull) { WeakRefCountedPtr bar; EXPECT_EQ(nullptr, bar.get()); bar.reset(); EXPECT_EQ(nullptr, bar.get()); } TEST(WeakRefCountedPtr, DerefernceOperators) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); bar->value(); Bar& bar_ref = *bar; bar_ref.value(); } TEST(WeakRefCountedPtr, EqualityOperators) { RefCountedPtr bar_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); WeakRefCountedPtr bar2 = bar; WeakRefCountedPtr empty; // Test equality between RefCountedPtrs. EXPECT_EQ(bar, bar2); EXPECT_NE(bar, empty); // Test equality with bare pointers. EXPECT_EQ(bar, bar.get()); EXPECT_EQ(empty, nullptr); EXPECT_NE(bar, nullptr); } TEST(WeakRefCountedPtr, Swap) { RefCountedPtr bar_strong(new Bar()); RefCountedPtr bar2_strong(new Bar()); WeakRefCountedPtr bar = bar_strong->WeakRef(); WeakRefCountedPtr bar2 = bar2_strong->WeakRef(); bar.swap(bar2); EXPECT_EQ(bar_strong.get(), bar2.get()); EXPECT_EQ(bar2_strong.get(), bar.get()); WeakRefCountedPtr bar3; bar3.swap(bar2); EXPECT_EQ(nullptr, bar2.get()); EXPECT_EQ(bar_strong.get(), bar3.get()); } class BarWithTracing : public DualRefCounted { public: BarWithTracing() : DualRefCounted("BarWithTracing") {} ~BarWithTracing() override { GPR_ASSERT(shutting_down_); } void Orphan() override { shutting_down_ = true; } private: bool shutting_down_ = false; }; TEST(WeakRefCountedPtr, RefCountedWithTracing) { RefCountedPtr bar_strong(new BarWithTracing()); WeakRefCountedPtr bar = bar_strong->WeakRef(); WeakRefCountedPtr bar2 = bar->WeakRef(DEBUG_LOCATION, "bar"); bar2.release(); bar->WeakUnref(DEBUG_LOCATION, "bar"); } class WeakBaseClass : public DualRefCounted { public: WeakBaseClass() {} ~WeakBaseClass() override { GPR_ASSERT(shutting_down_); } void Orphan() override { shutting_down_ = true; } private: bool shutting_down_ = false; }; class WeakSubclass : public WeakBaseClass { public: WeakSubclass() {} }; TEST(WeakRefCountedPtr, ConstructFromWeakSubclass) { RefCountedPtr strong(new WeakSubclass()); WeakRefCountedPtr p(strong->WeakRef().release()); } TEST(WeakRefCountedPtr, CopyAssignFromWeakSubclass) { RefCountedPtr strong(new WeakSubclass()); WeakRefCountedPtr b; EXPECT_EQ(nullptr, b.get()); WeakRefCountedPtr s = strong->WeakRef(); b = s; EXPECT_NE(nullptr, b.get()); } TEST(WeakRefCountedPtr, MoveAssignFromWeakSubclass) { RefCountedPtr strong(new WeakSubclass()); WeakRefCountedPtr b; EXPECT_EQ(nullptr, b.get()); WeakRefCountedPtr s = strong->WeakRef(); b = std::move(s); EXPECT_NE(nullptr, b.get()); } TEST(WeakRefCountedPtr, ResetFromWeakSubclass) { RefCountedPtr strong(new WeakSubclass()); WeakRefCountedPtr b; EXPECT_EQ(nullptr, b.get()); b.reset(strong->WeakRef().release()); EXPECT_NE(nullptr, b.get()); } TEST(WeakRefCountedPtr, EqualityWithWeakSubclass) { RefCountedPtr strong(new WeakSubclass()); WeakRefCountedPtr b = strong->WeakRef(); EXPECT_EQ(b, strong.get()); } void FunctionTakingWeakBaseClass(WeakRefCountedPtr p) { p.reset(); // To appease clang-tidy. } TEST(WeakRefCountedPtr, CanPassWeakSubclassToFunctionExpectingWeakBaseClass) { RefCountedPtr strong(new WeakSubclass()); WeakRefCountedPtr p = strong->WeakRef(); FunctionTakingWeakBaseClass(p); } void FunctionTakingWeakSubclass(WeakRefCountedPtr p) { p.reset(); // To appease clang-tidy. } TEST(WeakRefCountedPtr, CanPassWeakSubclassToFunctionExpectingWeakSubclass) { RefCountedPtr strong(new WeakSubclass()); WeakRefCountedPtr p = strong->WeakRef(); FunctionTakingWeakSubclass(p); } } // namespace } // namespace testing } // namespace grpc_core int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }