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