xref: /aosp_15_r20/external/cronet/base/scoped_generic_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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::__anon9485d7d80111::IntTraits23   IntTraits(std::vector<int>* freed) : freed_ints(freed) {}
24 
InvalidValuebase::__anon9485d7d80111::IntTraits25   static int InvalidValue() {
26     return -1;
27   }
Freebase::__anon9485d7d80111::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 =
165       std::unordered_map<int, const ScopedGeneric<int, TrackedIntTraits>*>;
TrackedIntTraitsbase::__anon9485d7d80211::TrackedIntTraits166   TrackedIntTraits(std::unordered_set<int>* freed, OwnerMap* owners)
167       : freed(freed), owners(owners) {}
168 
InvalidValuebase::__anon9485d7d80211::TrackedIntTraits169   static int InvalidValue() { return -1; }
170 
Freebase::__anon9485d7d80211::TrackedIntTraits171   void Free(int value) {
172     auto it = owners->find(value);
173     ASSERT_EQ(owners->end(), it);
174 
175     ASSERT_EQ(0U, freed->count(value));
176     freed->insert(value);
177   }
178 
Acquirebase::__anon9485d7d80211::TrackedIntTraits179   void Acquire(const ScopedGeneric<int, TrackedIntTraits>& owner, int value) {
180     auto it = owners->find(value);
181     ASSERT_EQ(owners->end(), it);
182     (*owners)[value] = &owner;
183   }
184 
Releasebase::__anon9485d7d80211::TrackedIntTraits185   void Release(const ScopedGeneric<int, TrackedIntTraits>& owner, int value) {
186     auto it = owners->find(value);
187     ASSERT_NE(owners->end(), it);
188     owners->erase(it);
189   }
190 
191   raw_ptr<std::unordered_set<int>> freed;
192   raw_ptr<OwnerMap> owners;
193 };
194 
195 using ScopedTrackedInt = ScopedGeneric<int, TrackedIntTraits>;
196 
197 }  // namespace
198 
TEST(ScopedGenericTest,OwnershipTracking)199 TEST(ScopedGenericTest, OwnershipTracking) {
200   TrackedIntTraits::OwnerMap owners;
201   std::unordered_set<int> freed;
202   TrackedIntTraits traits(&freed, &owners);
203 
204 #define ASSERT_OWNED(value, owner)            \
205   ASSERT_TRUE(base::Contains(owners, value)); \
206   ASSERT_EQ(&owner, owners[value]);           \
207   ASSERT_FALSE(base::Contains(freed, value))
208 
209 #define ASSERT_UNOWNED(value)                  \
210   ASSERT_FALSE(base::Contains(owners, value)); \
211   ASSERT_FALSE(base::Contains(freed, value))
212 
213 #define ASSERT_FREED(value)                    \
214   ASSERT_FALSE(base::Contains(owners, value)); \
215   ASSERT_TRUE(base::Contains(freed, value))
216 
217   // Constructor.
218   {
219     {
220       ScopedTrackedInt a(0, traits);
221       ASSERT_OWNED(0, a);
222     }
223     ASSERT_FREED(0);
224   }
225 
226   owners.clear();
227   freed.clear();
228 
229   // Reset.
230   {
231     ScopedTrackedInt a(0, traits);
232     ASSERT_OWNED(0, a);
233     a.reset(1);
234     ASSERT_FREED(0);
235     ASSERT_OWNED(1, a);
236     a.reset();
237     ASSERT_FREED(0);
238     ASSERT_FREED(1);
239   }
240 
241   owners.clear();
242   freed.clear();
243 
244   // Release.
245   {
246     {
247       ScopedTrackedInt a(0, traits);
248       ASSERT_OWNED(0, a);
249       int released = a.release();
250       ASSERT_EQ(0, released);
251       ASSERT_UNOWNED(0);
252     }
253     ASSERT_UNOWNED(0);
254   }
255 
256   owners.clear();
257   freed.clear();
258 
259   // Move constructor.
260   {
261     ScopedTrackedInt a(0, traits);
262     ASSERT_OWNED(0, a);
263     {
264       ScopedTrackedInt b(std::move(a));
265       ASSERT_OWNED(0, b);
266     }
267     ASSERT_FREED(0);
268   }
269 
270   owners.clear();
271   freed.clear();
272 
273   // Move assignment.
274   {
275     {
276       ScopedTrackedInt a(0, traits);
277       ScopedTrackedInt b(1, traits);
278       ASSERT_OWNED(0, a);
279       ASSERT_OWNED(1, b);
280       a = std::move(b);
281       ASSERT_OWNED(1, a);
282       ASSERT_FREED(0);
283     }
284     ASSERT_FREED(1);
285   }
286 
287   owners.clear();
288   freed.clear();
289 
290 #undef ASSERT_OWNED
291 #undef ASSERT_UNOWNED
292 #undef ASSERT_FREED
293 }
294 
295 // Cheesy manual "no compile" test for manually validating changes.
296 #if 0
297 TEST(ScopedGenericTest, NoCompile) {
298   // Assignment shouldn't work.
299   /*{
300     ScopedInt a(kFirst, traits);
301     ScopedInt b(a);
302   }*/
303 
304   // Comparison shouldn't work.
305   /*{
306     ScopedInt a(kFirst, traits);
307     ScopedInt b(kFirst, traits);
308     if (a == b) {
309     }
310   }*/
311 
312   // Implicit conversion to bool shouldn't work.
313   /*{
314     ScopedInt a(kFirst, traits);
315     bool result = a;
316   }*/
317 }
318 #endif
319 
320 }  // namespace base
321