1 /*
2  *  Copyright 2019 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "api/scoped_refptr.h"
12 
13 #include <utility>
14 #include <vector>
15 
16 #include "test/gtest.h"
17 
18 namespace rtc {
19 namespace {
20 
21 struct FunctionsCalled {
22   int addref = 0;
23   int release = 0;
24 };
25 
26 class ScopedRefCounted {
27  public:
ScopedRefCounted(FunctionsCalled * called)28   explicit ScopedRefCounted(FunctionsCalled* called) : called_(*called) {}
29   ScopedRefCounted(const ScopedRefCounted&) = delete;
30   ScopedRefCounted& operator=(const ScopedRefCounted&) = delete;
31 
AddRef()32   void AddRef() {
33     ++called_.addref;
34     ++ref_count_;
35   }
Release()36   void Release() {
37     ++called_.release;
38     if (0 == --ref_count_)
39       delete this;
40   }
41 
42  private:
43   ~ScopedRefCounted() = default;
44 
45   FunctionsCalled& called_;
46   int ref_count_ = 0;
47 };
48 
TEST(ScopedRefptrTest,IsCopyConstructable)49 TEST(ScopedRefptrTest, IsCopyConstructable) {
50   FunctionsCalled called;
51   scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
52   scoped_refptr<ScopedRefCounted> another_ptr = ptr;
53 
54   EXPECT_TRUE(ptr);
55   EXPECT_TRUE(another_ptr);
56   EXPECT_EQ(called.addref, 2);
57 }
58 
TEST(ScopedRefptrTest,IsCopyAssignable)59 TEST(ScopedRefptrTest, IsCopyAssignable) {
60   FunctionsCalled called;
61   scoped_refptr<ScopedRefCounted> another_ptr;
62   scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
63   another_ptr = ptr;
64 
65   EXPECT_TRUE(ptr);
66   EXPECT_TRUE(another_ptr);
67   EXPECT_EQ(called.addref, 2);
68 }
69 
TEST(ScopedRefptrTest,IsMoveConstructableWithoutExtraAddRefRelease)70 TEST(ScopedRefptrTest, IsMoveConstructableWithoutExtraAddRefRelease) {
71   FunctionsCalled called;
72   scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
73   scoped_refptr<ScopedRefCounted> another_ptr = std::move(ptr);
74 
75   EXPECT_FALSE(ptr);
76   EXPECT_TRUE(another_ptr);
77   EXPECT_EQ(called.addref, 1);
78   EXPECT_EQ(called.release, 0);
79 }
80 
TEST(ScopedRefptrTest,IsMoveAssignableWithoutExtraAddRefRelease)81 TEST(ScopedRefptrTest, IsMoveAssignableWithoutExtraAddRefRelease) {
82   FunctionsCalled called;
83   scoped_refptr<ScopedRefCounted> another_ptr;
84   scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
85   another_ptr = std::move(ptr);
86 
87   EXPECT_FALSE(ptr);
88   EXPECT_TRUE(another_ptr);
89   EXPECT_EQ(called.addref, 1);
90   EXPECT_EQ(called.release, 0);
91 }
92 
TEST(ScopedRefptrTest,MovableDuringVectorReallocation)93 TEST(ScopedRefptrTest, MovableDuringVectorReallocation) {
94   static_assert(
95       std::is_nothrow_move_constructible<scoped_refptr<ScopedRefCounted>>(),
96       "");
97   // Test below describes a scenario where it is helpful for move constructor
98   // to be noexcept.
99   FunctionsCalled called;
100   std::vector<scoped_refptr<ScopedRefCounted>> ptrs;
101   ptrs.reserve(1);
102   // Insert more elements than reserved to provoke reallocation.
103   ptrs.push_back(new ScopedRefCounted(&called));
104   ptrs.push_back(new ScopedRefCounted(&called));
105 
106   EXPECT_EQ(called.addref, 2);
107   EXPECT_EQ(called.release, 0);
108 }
109 
110 }  // namespace
111 }  // namespace rtc
112