• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/scoped_generic.h"
6 
7 #include <memory>
8 #include <unordered_map>
9 #include <unordered_set>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/containers/contains.h"
14 #include "base/memory/raw_ptr.h"
15 #include "build/build_config.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace base {
19 
20 namespace {
21 
22 struct IntTraits {
IntTraitsbase::__anon535b855e0111::IntTraits23   IntTraits(std::vector<int>* freed) : freed_ints(freed) {}
24 
InvalidValuebase::__anon535b855e0111::IntTraits25   static int InvalidValue() {
26     return -1;
27   }
Freebase::__anon535b855e0111::IntTraits28   void Free(int value) {
29     freed_ints->push_back(value);
30   }
31 
32   raw_ptr<std::vector<int>> freed_ints;
33 };
34 
35 using ScopedInt = ScopedGeneric<int, IntTraits>;
36 
37 }  // namespace
38 
TEST(ScopedGenericTest,ScopedGeneric)39 TEST(ScopedGenericTest, ScopedGeneric) {
40   std::vector<int> values_freed;
41   IntTraits traits(&values_freed);
42 
43   // Invalid case, delete should not be called.
44   {
45     ScopedInt a(IntTraits::InvalidValue(), traits);
46   }
47   EXPECT_TRUE(values_freed.empty());
48 
49   // Simple deleting case.
50   static const int kFirst = 0;
51   {
52     ScopedInt a(kFirst, traits);
53   }
54   ASSERT_EQ(1u, values_freed.size());
55   ASSERT_EQ(kFirst, values_freed[0]);
56   values_freed.clear();
57 
58   // Release should return the right value and leave the object empty.
59   {
60     ScopedInt a(kFirst, traits);
61     EXPECT_EQ(kFirst, a.release());
62 
63     ScopedInt b(IntTraits::InvalidValue(), traits);
64     EXPECT_EQ(IntTraits::InvalidValue(), b.release());
65   }
66   ASSERT_TRUE(values_freed.empty());
67 
68   // Reset should free the old value, then the new one should go away when
69   // it goes out of scope.
70   static const int kSecond = 1;
71   {
72     ScopedInt b(kFirst, traits);
73     b.reset(kSecond);
74     ASSERT_EQ(1u, values_freed.size());
75     ASSERT_EQ(kFirst, values_freed[0]);
76   }
77   ASSERT_EQ(2u, values_freed.size());
78   ASSERT_EQ(kSecond, values_freed[1]);
79   values_freed.clear();
80 
81   // Move constructor.
82   {
83     ScopedInt a(kFirst, traits);
84     ScopedInt b(std::move(a));
85     EXPECT_TRUE(values_freed.empty());  // Nothing should be freed.
86     ASSERT_EQ(IntTraits::InvalidValue(), a.get());
87     ASSERT_EQ(kFirst, b.get());
88   }
89 
90   ASSERT_EQ(1u, values_freed.size());
91   ASSERT_EQ(kFirst, values_freed[0]);
92   values_freed.clear();
93 
94   // Move assign.
95   {
96     ScopedInt a(kFirst, traits);
97     ScopedInt b(kSecond, traits);
98     b = std::move(a);
99     ASSERT_EQ(1u, values_freed.size());
100     EXPECT_EQ(kSecond, values_freed[0]);
101     ASSERT_EQ(IntTraits::InvalidValue(), a.get());
102     ASSERT_EQ(kFirst, b.get());
103   }
104 
105   ASSERT_EQ(2u, values_freed.size());
106   EXPECT_EQ(kFirst, values_freed[1]);
107   values_freed.clear();
108 }
109 
TEST(ScopedGenericTest,Operators)110 TEST(ScopedGenericTest, Operators) {
111   std::vector<int> values_freed;
112   IntTraits traits(&values_freed);
113 
114   static const int kFirst = 0;
115   static const int kSecond = 1;
116   {
117     ScopedInt a(kFirst, traits);
118     EXPECT_TRUE(a == kFirst);
119     EXPECT_FALSE(a != kFirst);
120     EXPECT_FALSE(a == kSecond);
121     EXPECT_TRUE(a != kSecond);
122 
123     EXPECT_TRUE(kFirst == a);
124     EXPECT_FALSE(kFirst != a);
125     EXPECT_FALSE(kSecond == a);
126     EXPECT_TRUE(kSecond != a);
127   }
128 
129   // is_valid().
130   {
131     ScopedInt a(kFirst, traits);
132     EXPECT_TRUE(a.is_valid());
133     a.reset();
134     EXPECT_FALSE(a.is_valid());
135   }
136 }
137 
TEST(ScopedGenericTest,Receive)138 TEST(ScopedGenericTest, Receive) {
139   std::vector<int> values_freed;
140   IntTraits traits(&values_freed);
141   auto a = std::make_unique<ScopedInt>(123, traits);
142 
143   EXPECT_EQ(123, a->get());
144 
145   {
146     ScopedInt::Receiver r(*a);
147     EXPECT_EQ(123, a->get());
148     *r.get() = 456;
149     EXPECT_EQ(123, a->get());
150   }
151 
152   EXPECT_EQ(456, a->get());
153 
154   {
155     ScopedInt::Receiver r(*a);
156     EXPECT_DEATH_IF_SUPPORTED(a.reset(), "");
157     EXPECT_DEATH_IF_SUPPORTED(ScopedInt::Receiver(*a).get(), "");
158   }
159 }
160 
161 namespace {
162 
163 struct TrackedIntTraits : public ScopedGenericOwnershipTracking {
164   using OwnerMap = std::unordered_map<
165       int,
166       raw_ptr<const ScopedGeneric<int, TrackedIntTraits>, CtnExperimental>>;
TrackedIntTraitsbase::__anon535b855e0211::TrackedIntTraits167   TrackedIntTraits(std::unordered_set<int>* freed, OwnerMap* owners)
168       : freed(freed), owners(owners) {}
169 
InvalidValuebase::__anon535b855e0211::TrackedIntTraits170   static int InvalidValue() { return -1; }
171 
Freebase::__anon535b855e0211::TrackedIntTraits172   void Free(int value) {
173     auto it = owners->find(value);
174     ASSERT_EQ(owners->end(), it);
175 
176     ASSERT_EQ(0U, freed->count(value));
177     freed->insert(value);
178   }
179 
Acquirebase::__anon535b855e0211::TrackedIntTraits180   void Acquire(const ScopedGeneric<int, TrackedIntTraits>& owner, int value) {
181     auto it = owners->find(value);
182     ASSERT_EQ(owners->end(), it);
183     (*owners)[value] = &owner;
184   }
185 
Releasebase::__anon535b855e0211::TrackedIntTraits186   void Release(const ScopedGeneric<int, TrackedIntTraits>& owner, int value) {
187     auto it = owners->find(value);
188     ASSERT_NE(owners->end(), it);
189     owners->erase(it);
190   }
191 
192   raw_ptr<std::unordered_set<int>> freed;
193   raw_ptr<OwnerMap> owners;
194 };
195 
196 using ScopedTrackedInt = ScopedGeneric<int, TrackedIntTraits>;
197 
198 }  // namespace
199 
TEST(ScopedGenericTest,OwnershipTracking)200 TEST(ScopedGenericTest, OwnershipTracking) {
201   TrackedIntTraits::OwnerMap owners;
202   std::unordered_set<int> freed;
203   TrackedIntTraits traits(&freed, &owners);
204 
205 #define ASSERT_OWNED(value, owner)            \
206   ASSERT_TRUE(base::Contains(owners, value)); \
207   ASSERT_EQ(&owner, owners[value]);           \
208   ASSERT_FALSE(base::Contains(freed, value))
209 
210 #define ASSERT_UNOWNED(value)                  \
211   ASSERT_FALSE(base::Contains(owners, value)); \
212   ASSERT_FALSE(base::Contains(freed, value))
213 
214 #define ASSERT_FREED(value)                    \
215   ASSERT_FALSE(base::Contains(owners, value)); \
216   ASSERT_TRUE(base::Contains(freed, value))
217 
218   // Constructor.
219   {
220     {
221       ScopedTrackedInt a(0, traits);
222       ASSERT_OWNED(0, a);
223     }
224     ASSERT_FREED(0);
225   }
226 
227   owners.clear();
228   freed.clear();
229 
230   // Reset.
231   {
232     ScopedTrackedInt a(0, traits);
233     ASSERT_OWNED(0, a);
234     a.reset(1);
235     ASSERT_FREED(0);
236     ASSERT_OWNED(1, a);
237     a.reset();
238     ASSERT_FREED(0);
239     ASSERT_FREED(1);
240   }
241 
242   owners.clear();
243   freed.clear();
244 
245   // Release.
246   {
247     {
248       ScopedTrackedInt a(0, traits);
249       ASSERT_OWNED(0, a);
250       int released = a.release();
251       ASSERT_EQ(0, released);
252       ASSERT_UNOWNED(0);
253     }
254     ASSERT_UNOWNED(0);
255   }
256 
257   owners.clear();
258   freed.clear();
259 
260   // Move constructor.
261   {
262     ScopedTrackedInt a(0, traits);
263     ASSERT_OWNED(0, a);
264     {
265       ScopedTrackedInt b(std::move(a));
266       ASSERT_OWNED(0, b);
267     }
268     ASSERT_FREED(0);
269   }
270 
271   owners.clear();
272   freed.clear();
273 
274   // Move assignment.
275   {
276     {
277       ScopedTrackedInt a(0, traits);
278       ScopedTrackedInt b(1, traits);
279       ASSERT_OWNED(0, a);
280       ASSERT_OWNED(1, b);
281       a = std::move(b);
282       ASSERT_OWNED(1, a);
283       ASSERT_FREED(0);
284     }
285     ASSERT_FREED(1);
286   }
287 
288   owners.clear();
289   freed.clear();
290 
291 #undef ASSERT_OWNED
292 #undef ASSERT_UNOWNED
293 #undef ASSERT_FREED
294 }
295 
296 // Cheesy manual "no compile" test for manually validating changes.
297 #if 0
298 TEST(ScopedGenericTest, NoCompile) {
299   // Assignment shouldn't work.
300   /*{
301     ScopedInt a(kFirst, traits);
302     ScopedInt b(a);
303   }*/
304 
305   // Comparison shouldn't work.
306   /*{
307     ScopedInt a(kFirst, traits);
308     ScopedInt b(kFirst, traits);
309     if (a == b) {
310     }
311   }*/
312 
313   // Implicit conversion to bool shouldn't work.
314   /*{
315     ScopedInt a(kFirst, traits);
316     bool result = a;
317   }*/
318 }
319 #endif
320 
321 }  // namespace base
322