blob: 0cbcbd2141ae6faba7d82ef6565152c4b8285fe7 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2014 The Chromium Authors
[email protected]821261bc2014-03-12 19:19:242// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakj0c8d4aa2015-11-25 05:29:585#include "base/scoped_generic.h"
6
Marek Haranczyk96d09bd2018-11-15 10:54:347#include <memory>
Josh Gao00ce8452018-10-31 00:05:428#include <unordered_map>
9#include <unordered_set>
danakj0c8d4aa2015-11-25 05:29:5810#include <utility>
[email protected]821261bc2014-03-12 19:19:2411#include <vector>
12
Jan Wilken Dörrieb5a41c32020-12-09 18:55:4713#include "base/containers/contains.h"
Keishi Hattoric1b00232022-11-22 09:04:2614#include "base/memory/raw_ptr.h"
Josh Gao00ce8452018-10-31 00:05:4215#include "build/build_config.h"
[email protected]821261bc2014-03-12 19:19:2416#include "testing/gtest/include/gtest/gtest.h"
17
18namespace base {
19
20namespace {
21
22struct IntTraits {
23 IntTraits(std::vector<int>* freed) : freed_ints(freed) {}
24
25 static int InvalidValue() {
26 return -1;
27 }
28 void Free(int value) {
29 freed_ints->push_back(value);
30 }
31
Keishi Hattoric1b00232022-11-22 09:04:2632 raw_ptr<std::vector<int>> freed_ints;
[email protected]821261bc2014-03-12 19:19:2433};
34
Josh Gao00ce8452018-10-31 00:05:4235using ScopedInt = ScopedGeneric<int, IntTraits>;
[email protected]821261bc2014-03-12 19:19:2436
37} // namespace
38
39TEST(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
danakj0c8d4aa2015-11-25 05:29:5881 // Move constructor.
[email protected]821261bc2014-03-12 19:19:2482 {
83 ScopedInt a(kFirst, traits);
danakj0c8d4aa2015-11-25 05:29:5884 ScopedInt b(std::move(a));
[email protected]821261bc2014-03-12 19:19:2485 EXPECT_TRUE(values_freed.empty()); // Nothing should be freed.
86 ASSERT_EQ(IntTraits::InvalidValue(), a.get());
87 ASSERT_EQ(kFirst, b.get());
88 }
rsesek9470f6b2015-03-10 22:28:5889
[email protected]821261bc2014-03-12 19:19:2490 ASSERT_EQ(1u, values_freed.size());
91 ASSERT_EQ(kFirst, values_freed[0]);
rsesek9470f6b2015-03-10 22:28:5892 values_freed.clear();
93
danakj0c8d4aa2015-11-25 05:29:5894 // Move assign.
rsesek9470f6b2015-03-10 22:28:5895 {
96 ScopedInt a(kFirst, traits);
97 ScopedInt b(kSecond, traits);
danakj0c8d4aa2015-11-25 05:29:5898 b = std::move(a);
rsesek9470f6b2015-03-10 22:28:5899 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();
[email protected]821261bc2014-03-12 19:19:24108}
109
110TEST(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
Josh Gao00ce8452018-10-31 00:05:42138TEST(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
Josh Gao00ce8452018-10-31 00:05:42154 {
155 ScopedInt::Receiver r(*a);
Josh Gaob3ad105d2018-11-01 01:01:57156 EXPECT_DEATH_IF_SUPPORTED(a.reset(), "");
157 EXPECT_DEATH_IF_SUPPORTED(ScopedInt::Receiver(*a).get(), "");
Josh Gao00ce8452018-10-31 00:05:42158 }
Josh Gao00ce8452018-10-31 00:05:42159}
160
161namespace {
162
163struct TrackedIntTraits : public ScopedGenericOwnershipTracking {
164 using OwnerMap =
165 std::unordered_map<int, const ScopedGeneric<int, TrackedIntTraits>*>;
166 TrackedIntTraits(std::unordered_set<int>* freed, OwnerMap* owners)
167 : freed(freed), owners(owners) {}
168
169 static int InvalidValue() { return -1; }
170
171 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
179 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
185 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
Keishi Hattoric1b00232022-11-22 09:04:26191 raw_ptr<std::unordered_set<int>> freed;
192 raw_ptr<OwnerMap> owners;
Josh Gao00ce8452018-10-31 00:05:42193};
194
195using ScopedTrackedInt = ScopedGeneric<int, TrackedIntTraits>;
196
197} // namespace
198
199TEST(ScopedGenericTest, OwnershipTracking) {
200 TrackedIntTraits::OwnerMap owners;
201 std::unordered_set<int> freed;
202 TrackedIntTraits traits(&freed, &owners);
203
Jan Wilken Dörrief61e74c2019-06-07 08:20:02204#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))
Josh Gao00ce8452018-10-31 00:05:42208
Jan Wilken Dörrief61e74c2019-06-07 08:20:02209#define ASSERT_UNOWNED(value) \
210 ASSERT_FALSE(base::Contains(owners, value)); \
211 ASSERT_FALSE(base::Contains(freed, value))
Josh Gao00ce8452018-10-31 00:05:42212
Jan Wilken Dörrief61e74c2019-06-07 08:20:02213#define ASSERT_FREED(value) \
214 ASSERT_FALSE(base::Contains(owners, value)); \
215 ASSERT_TRUE(base::Contains(freed, value))
Josh Gao00ce8452018-10-31 00:05:42216
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
Josh Gao00ce8452018-10-31 00:05:42290#undef ASSERT_OWNED
291#undef ASSERT_UNOWNED
292#undef ASSERT_FREED
293}
294
[email protected]821261bc2014-03-12 19:19:24295// Cheesy manual "no compile" test for manually validating changes.
296#if 0
297TEST(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