/* * * 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/memory.h" #include "src/core/lib/gprpp/ref_counted.h" #include "test/core/util/test_config.h" namespace grpc_core { namespace testing { namespace { 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()); } TEST(RefCountedPtr, MoveConstructor) { RefCountedPtr foo(New()); RefCountedPtr foo2(std::move(foo)); EXPECT_EQ(nullptr, foo.get()); EXPECT_NE(nullptr, foo2.get()); } TEST(RefCountedPtr, MoveAssignment) { RefCountedPtr foo(New()); RefCountedPtr foo2 = std::move(foo); EXPECT_EQ(nullptr, foo.get()); EXPECT_NE(nullptr, foo2.get()); } TEST(RefCountedPtr, CopyConstructor) { RefCountedPtr foo(New()); const RefCountedPtr& foo2(foo); EXPECT_NE(nullptr, foo.get()); EXPECT_EQ(foo.get(), foo2.get()); } TEST(RefCountedPtr, CopyAssignment) { RefCountedPtr foo(New()); const 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; // The "*&" avoids warnings from LLVM -Wself-assign. } TEST(RefCountedPtr, EnclosedScope) { RefCountedPtr foo(New()); { RefCountedPtr foo2(std::move(foo)); 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()); EXPECT_NE(nullptr, foo.get()); } TEST(RefCountedPtr, ResetFromNonNullToNonNull) { RefCountedPtr foo(New()); EXPECT_NE(nullptr, foo.get()); Foo* original = foo.get(); foo.reset(New()); EXPECT_NE(nullptr, foo.get()); EXPECT_NE(original, foo.get()); } TEST(RefCountedPtr, ResetFromNonNullToNull) { RefCountedPtr foo(New()); 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->value(); Foo& foo_ref = *foo; foo_ref.value(); } TEST(RefCountedPtr, EqualityOperators) { RefCountedPtr foo(New()); 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(MakeRefCounted, NoArgs) { RefCountedPtr foo = MakeRefCounted(); EXPECT_EQ(0, foo->value()); } TEST(MakeRefCounted, Args) { RefCountedPtr foo = MakeRefCounted(3); EXPECT_EQ(3, foo->value()); } TraceFlag foo_tracer(true, "foo"); class FooWithTracing : public RefCounted { public: FooWithTracing() : RefCounted(&foo_tracer) {} }; TEST(RefCountedPtr, RefCountedWithTracing) { RefCountedPtr foo(New()); 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()); } 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()); EXPECT_NE(nullptr, b.get()); } TEST(RefCountedPtr, EqualityWithSubclass) { Subclass* s = New(); 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); } } // 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(); }