blob: 73291a8e433609636953ff4f195af842bb0b16bb [file] [log] [blame]
[email protected]821261bc2014-03-12 19:19:241// Copyright 2014 The Chromium Authors. All rights reserved.
2// 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
Josh Gao00ce8452018-10-31 00:05:4213#include "base/stl_util.h"
14#include "build/build_config.h"
[email protected]821261bc2014-03-12 19:19:2415#include "testing/gtest/include/gtest/gtest.h"
16
17namespace base {
18
19namespace {
20
21struct IntTraits {
22 IntTraits(std::vector<int>* freed) : freed_ints(freed) {}
23
24 static int InvalidValue() {
25 return -1;
26 }
27 void Free(int value) {
28 freed_ints->push_back(value);
29 }
30
31 std::vector<int>* freed_ints;
32};
33
Josh Gao00ce8452018-10-31 00:05:4234using ScopedInt = ScopedGeneric<int, IntTraits>;
[email protected]821261bc2014-03-12 19:19:2435
36} // namespace
37
38TEST(ScopedGenericTest, ScopedGeneric) {
39 std::vector<int> values_freed;
40 IntTraits traits(&values_freed);
41
42 // Invalid case, delete should not be called.
43 {
44 ScopedInt a(IntTraits::InvalidValue(), traits);
45 }
46 EXPECT_TRUE(values_freed.empty());
47
48 // Simple deleting case.
49 static const int kFirst = 0;
50 {
51 ScopedInt a(kFirst, traits);
52 }
53 ASSERT_EQ(1u, values_freed.size());
54 ASSERT_EQ(kFirst, values_freed[0]);
55 values_freed.clear();
56
57 // Release should return the right value and leave the object empty.
58 {
59 ScopedInt a(kFirst, traits);
60 EXPECT_EQ(kFirst, a.release());
61
62 ScopedInt b(IntTraits::InvalidValue(), traits);
63 EXPECT_EQ(IntTraits::InvalidValue(), b.release());
64 }
65 ASSERT_TRUE(values_freed.empty());
66
67 // Reset should free the old value, then the new one should go away when
68 // it goes out of scope.
69 static const int kSecond = 1;
70 {
71 ScopedInt b(kFirst, traits);
72 b.reset(kSecond);
73 ASSERT_EQ(1u, values_freed.size());
74 ASSERT_EQ(kFirst, values_freed[0]);
75 }
76 ASSERT_EQ(2u, values_freed.size());
77 ASSERT_EQ(kSecond, values_freed[1]);
78 values_freed.clear();
79
80 // Swap.
81 {
82 ScopedInt a(kFirst, traits);
83 ScopedInt b(kSecond, traits);
84 a.swap(b);
85 EXPECT_TRUE(values_freed.empty()); // Nothing should be freed.
86 EXPECT_EQ(kSecond, a.get());
87 EXPECT_EQ(kFirst, b.get());
88 }
89 // Values should be deleted in the opposite order.
90 ASSERT_EQ(2u, values_freed.size());
91 EXPECT_EQ(kFirst, values_freed[0]);
92 EXPECT_EQ(kSecond, values_freed[1]);
93 values_freed.clear();
94
danakj0c8d4aa2015-11-25 05:29:5895 // Move constructor.
[email protected]821261bc2014-03-12 19:19:2496 {
97 ScopedInt a(kFirst, traits);
danakj0c8d4aa2015-11-25 05:29:5898 ScopedInt b(std::move(a));
[email protected]821261bc2014-03-12 19:19:2499 EXPECT_TRUE(values_freed.empty()); // Nothing should be freed.
100 ASSERT_EQ(IntTraits::InvalidValue(), a.get());
101 ASSERT_EQ(kFirst, b.get());
102 }
rsesek9470f6b2015-03-10 22:28:58103
[email protected]821261bc2014-03-12 19:19:24104 ASSERT_EQ(1u, values_freed.size());
105 ASSERT_EQ(kFirst, values_freed[0]);
rsesek9470f6b2015-03-10 22:28:58106 values_freed.clear();
107
danakj0c8d4aa2015-11-25 05:29:58108 // Move assign.
rsesek9470f6b2015-03-10 22:28:58109 {
110 ScopedInt a(kFirst, traits);
111 ScopedInt b(kSecond, traits);
danakj0c8d4aa2015-11-25 05:29:58112 b = std::move(a);
rsesek9470f6b2015-03-10 22:28:58113 ASSERT_EQ(1u, values_freed.size());
114 EXPECT_EQ(kSecond, values_freed[0]);
115 ASSERT_EQ(IntTraits::InvalidValue(), a.get());
116 ASSERT_EQ(kFirst, b.get());
117 }
118
119 ASSERT_EQ(2u, values_freed.size());
120 EXPECT_EQ(kFirst, values_freed[1]);
121 values_freed.clear();
[email protected]821261bc2014-03-12 19:19:24122}
123
124TEST(ScopedGenericTest, Operators) {
125 std::vector<int> values_freed;
126 IntTraits traits(&values_freed);
127
128 static const int kFirst = 0;
129 static const int kSecond = 1;
130 {
131 ScopedInt a(kFirst, traits);
132 EXPECT_TRUE(a == kFirst);
133 EXPECT_FALSE(a != kFirst);
134 EXPECT_FALSE(a == kSecond);
135 EXPECT_TRUE(a != kSecond);
136
137 EXPECT_TRUE(kFirst == a);
138 EXPECT_FALSE(kFirst != a);
139 EXPECT_FALSE(kSecond == a);
140 EXPECT_TRUE(kSecond != a);
141 }
142
143 // is_valid().
144 {
145 ScopedInt a(kFirst, traits);
146 EXPECT_TRUE(a.is_valid());
147 a.reset();
148 EXPECT_FALSE(a.is_valid());
149 }
150}
151
Josh Gao00ce8452018-10-31 00:05:42152TEST(ScopedGenericTest, Receive) {
153 std::vector<int> values_freed;
154 IntTraits traits(&values_freed);
155 auto a = std::make_unique<ScopedInt>(123, traits);
156
157 EXPECT_EQ(123, a->get());
158
159 {
160 ScopedInt::Receiver r(*a);
161 EXPECT_EQ(123, a->get());
162 *r.get() = 456;
163 EXPECT_EQ(123, a->get());
164 }
165
166 EXPECT_EQ(456, a->get());
167
Josh Gao00ce8452018-10-31 00:05:42168 {
169 ScopedInt::Receiver r(*a);
Josh Gaob3ad105d2018-11-01 01:01:57170 EXPECT_DEATH_IF_SUPPORTED(a.reset(), "");
171 EXPECT_DEATH_IF_SUPPORTED(ScopedInt::Receiver(*a).get(), "");
Josh Gao00ce8452018-10-31 00:05:42172 }
Josh Gao00ce8452018-10-31 00:05:42173}
174
175namespace {
176
177struct TrackedIntTraits : public ScopedGenericOwnershipTracking {
178 using OwnerMap =
179 std::unordered_map<int, const ScopedGeneric<int, TrackedIntTraits>*>;
180 TrackedIntTraits(std::unordered_set<int>* freed, OwnerMap* owners)
181 : freed(freed), owners(owners) {}
182
183 static int InvalidValue() { return -1; }
184
185 void Free(int value) {
186 auto it = owners->find(value);
187 ASSERT_EQ(owners->end(), it);
188
189 ASSERT_EQ(0U, freed->count(value));
190 freed->insert(value);
191 }
192
193 void Acquire(const ScopedGeneric<int, TrackedIntTraits>& owner, int value) {
194 auto it = owners->find(value);
195 ASSERT_EQ(owners->end(), it);
196 (*owners)[value] = &owner;
197 }
198
199 void Release(const ScopedGeneric<int, TrackedIntTraits>& owner, int value) {
200 auto it = owners->find(value);
201 ASSERT_NE(owners->end(), it);
202 owners->erase(it);
203 }
204
205 std::unordered_set<int>* freed;
206 OwnerMap* owners;
207};
208
209using ScopedTrackedInt = ScopedGeneric<int, TrackedIntTraits>;
210
211} // namespace
212
213TEST(ScopedGenericTest, OwnershipTracking) {
214 TrackedIntTraits::OwnerMap owners;
215 std::unordered_set<int> freed;
216 TrackedIntTraits traits(&freed, &owners);
217
Jan Wilken Dörrief61e74c2019-06-07 08:20:02218#define ASSERT_OWNED(value, owner) \
219 ASSERT_TRUE(base::Contains(owners, value)); \
220 ASSERT_EQ(&owner, owners[value]); \
221 ASSERT_FALSE(base::Contains(freed, value))
Josh Gao00ce8452018-10-31 00:05:42222
Jan Wilken Dörrief61e74c2019-06-07 08:20:02223#define ASSERT_UNOWNED(value) \
224 ASSERT_FALSE(base::Contains(owners, value)); \
225 ASSERT_FALSE(base::Contains(freed, value))
Josh Gao00ce8452018-10-31 00:05:42226
Jan Wilken Dörrief61e74c2019-06-07 08:20:02227#define ASSERT_FREED(value) \
228 ASSERT_FALSE(base::Contains(owners, value)); \
229 ASSERT_TRUE(base::Contains(freed, value))
Josh Gao00ce8452018-10-31 00:05:42230
231 // Constructor.
232 {
233 {
234 ScopedTrackedInt a(0, traits);
235 ASSERT_OWNED(0, a);
236 }
237 ASSERT_FREED(0);
238 }
239
240 owners.clear();
241 freed.clear();
242
243 // Reset.
244 {
245 ScopedTrackedInt a(0, traits);
246 ASSERT_OWNED(0, a);
247 a.reset(1);
248 ASSERT_FREED(0);
249 ASSERT_OWNED(1, a);
250 a.reset();
251 ASSERT_FREED(0);
252 ASSERT_FREED(1);
253 }
254
255 owners.clear();
256 freed.clear();
257
258 // Release.
259 {
260 {
261 ScopedTrackedInt a(0, traits);
262 ASSERT_OWNED(0, a);
263 int released = a.release();
264 ASSERT_EQ(0, released);
265 ASSERT_UNOWNED(0);
266 }
267 ASSERT_UNOWNED(0);
268 }
269
270 owners.clear();
271 freed.clear();
272
273 // Move constructor.
274 {
275 ScopedTrackedInt a(0, traits);
276 ASSERT_OWNED(0, a);
277 {
278 ScopedTrackedInt b(std::move(a));
279 ASSERT_OWNED(0, b);
280 }
281 ASSERT_FREED(0);
282 }
283
284 owners.clear();
285 freed.clear();
286
287 // Move assignment.
288 {
289 {
290 ScopedTrackedInt a(0, traits);
291 ScopedTrackedInt b(1, traits);
292 ASSERT_OWNED(0, a);
293 ASSERT_OWNED(1, b);
294 a = std::move(b);
295 ASSERT_OWNED(1, a);
296 ASSERT_FREED(0);
297 }
298 ASSERT_FREED(1);
299 }
300
301 owners.clear();
302 freed.clear();
303
304 // Swap.
305 {
306 {
307 ScopedTrackedInt a(0, traits);
308 ScopedTrackedInt b(1, traits);
309 ASSERT_OWNED(0, a);
310 ASSERT_OWNED(1, b);
311 a.swap(b);
312 ASSERT_OWNED(1, a);
313 ASSERT_OWNED(0, b);
314 }
315 ASSERT_FREED(0);
316 ASSERT_FREED(1);
317 }
318
319 owners.clear();
320 freed.clear();
321
322#undef ASSERT_OWNED
323#undef ASSERT_UNOWNED
324#undef ASSERT_FREED
325}
326
[email protected]821261bc2014-03-12 19:19:24327// Cheesy manual "no compile" test for manually validating changes.
328#if 0
329TEST(ScopedGenericTest, NoCompile) {
330 // Assignment shouldn't work.
331 /*{
332 ScopedInt a(kFirst, traits);
333 ScopedInt b(a);
334 }*/
335
336 // Comparison shouldn't work.
337 /*{
338 ScopedInt a(kFirst, traits);
339 ScopedInt b(kFirst, traits);
340 if (a == b) {
341 }
342 }*/
343
344 // Implicit conversion to bool shouldn't work.
345 /*{
346 ScopedInt a(kFirst, traits);
347 bool result = a;
348 }*/
349}
350#endif
351
352} // namespace base