|  | /* | 
|  | *  Copyright 2019 The WebRTC Project Authors. All rights reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "api/scoped_refptr.h" | 
|  |  | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "test/gtest.h" | 
|  |  | 
|  | namespace rtc { | 
|  | namespace { | 
|  |  | 
|  | struct FunctionsCalled { | 
|  | int addref = 0; | 
|  | int release = 0; | 
|  | }; | 
|  |  | 
|  | class ScopedRefCounted { | 
|  | public: | 
|  | explicit ScopedRefCounted(FunctionsCalled* called) : called_(*called) {} | 
|  | ScopedRefCounted(const ScopedRefCounted&) = delete; | 
|  | ScopedRefCounted& operator=(const ScopedRefCounted&) = delete; | 
|  |  | 
|  | void AddRef() { | 
|  | ++called_.addref; | 
|  | ++ref_count_; | 
|  | } | 
|  | void Release() { | 
|  | ++called_.release; | 
|  | if (0 == --ref_count_) | 
|  | delete this; | 
|  | } | 
|  |  | 
|  | private: | 
|  | ~ScopedRefCounted() = default; | 
|  |  | 
|  | FunctionsCalled& called_; | 
|  | int ref_count_ = 0; | 
|  | }; | 
|  |  | 
|  | TEST(ScopedRefptrTest, IsCopyConstructable) { | 
|  | FunctionsCalled called; | 
|  | scoped_refptr<ScopedRefCounted> ptr(new ScopedRefCounted(&called)); | 
|  | scoped_refptr<ScopedRefCounted> another_ptr = ptr; | 
|  |  | 
|  | EXPECT_TRUE(ptr); | 
|  | EXPECT_TRUE(another_ptr); | 
|  | EXPECT_EQ(called.addref, 2); | 
|  | } | 
|  |  | 
|  | TEST(ScopedRefptrTest, IsCopyAssignable) { | 
|  | FunctionsCalled called; | 
|  | scoped_refptr<ScopedRefCounted> another_ptr; | 
|  | scoped_refptr<ScopedRefCounted> ptr(new ScopedRefCounted(&called)); | 
|  | another_ptr = ptr; | 
|  |  | 
|  | EXPECT_TRUE(ptr); | 
|  | EXPECT_TRUE(another_ptr); | 
|  | EXPECT_EQ(called.addref, 2); | 
|  | } | 
|  |  | 
|  | TEST(ScopedRefptrTest, IsMoveConstructableWithoutExtraAddRefRelease) { | 
|  | FunctionsCalled called; | 
|  | scoped_refptr<ScopedRefCounted> ptr(new ScopedRefCounted(&called)); | 
|  | scoped_refptr<ScopedRefCounted> another_ptr = std::move(ptr); | 
|  |  | 
|  | EXPECT_FALSE(ptr); | 
|  | EXPECT_TRUE(another_ptr); | 
|  | EXPECT_EQ(called.addref, 1); | 
|  | EXPECT_EQ(called.release, 0); | 
|  | } | 
|  |  | 
|  | TEST(ScopedRefptrTest, IsMoveAssignableWithoutExtraAddRefRelease) { | 
|  | FunctionsCalled called; | 
|  | scoped_refptr<ScopedRefCounted> another_ptr; | 
|  | scoped_refptr<ScopedRefCounted> ptr(new ScopedRefCounted(&called)); | 
|  | another_ptr = std::move(ptr); | 
|  |  | 
|  | EXPECT_FALSE(ptr); | 
|  | EXPECT_TRUE(another_ptr); | 
|  | EXPECT_EQ(called.addref, 1); | 
|  | EXPECT_EQ(called.release, 0); | 
|  | } | 
|  |  | 
|  | TEST(ScopedRefptrTest, MovableDuringVectorReallocation) { | 
|  | static_assert( | 
|  | std::is_nothrow_move_constructible<scoped_refptr<ScopedRefCounted>>(), | 
|  | ""); | 
|  | // Test below describes a scenario where it is helpful for move constructor | 
|  | // to be noexcept. | 
|  | FunctionsCalled called; | 
|  | std::vector<scoped_refptr<ScopedRefCounted>> ptrs; | 
|  | ptrs.reserve(1); | 
|  | // Insert more elements than reserved to provoke reallocation. | 
|  | ptrs.emplace_back(new ScopedRefCounted(&called)); | 
|  | ptrs.emplace_back(new ScopedRefCounted(&called)); | 
|  |  | 
|  | EXPECT_EQ(called.addref, 2); | 
|  | EXPECT_EQ(called.release, 0); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace rtc |