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.
5 #include "base/scoped_generic.h"
8 #include <unordered_map>
9 #include <unordered_set>
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"
23 IntTraits(std::vector<int>* freed) : freed_ints(freed) {}
25 static int InvalidValue() {
28 void Free(int value) {
29 freed_ints->push_back(value);
32 raw_ptr<std::vector<int>> freed_ints;
35 using ScopedInt = ScopedGeneric<int, IntTraits>;
39 TEST(ScopedGenericTest, ScopedGeneric) {
40 std::vector<int> values_freed;
41 IntTraits traits(&values_freed);
43 // Invalid case, delete should not be called.
45 ScopedInt a(IntTraits::InvalidValue(), traits);
47 EXPECT_TRUE(values_freed.empty());
49 // Simple deleting case.
50 static const int kFirst = 0;
52 ScopedInt a(kFirst, traits);
54 ASSERT_EQ(1u, values_freed.size());
55 ASSERT_EQ(kFirst, values_freed[0]);
58 // Release should return the right value and leave the object empty.
60 ScopedInt a(kFirst, traits);
61 EXPECT_EQ(kFirst, a.release());
63 ScopedInt b(IntTraits::InvalidValue(), traits);
64 EXPECT_EQ(IntTraits::InvalidValue(), b.release());
66 ASSERT_TRUE(values_freed.empty());
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;
72 ScopedInt b(kFirst, traits);
74 ASSERT_EQ(1u, values_freed.size());
75 ASSERT_EQ(kFirst, values_freed[0]);
77 ASSERT_EQ(2u, values_freed.size());
78 ASSERT_EQ(kSecond, values_freed[1]);
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());
90 ASSERT_EQ(1u, values_freed.size());
91 ASSERT_EQ(kFirst, values_freed[0]);
96 ScopedInt a(kFirst, traits);
97 ScopedInt b(kSecond, traits);
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());
105 ASSERT_EQ(2u, values_freed.size());
106 EXPECT_EQ(kFirst, values_freed[1]);
107 values_freed.clear();
110 TEST(ScopedGenericTest, Operators) {
111 std::vector<int> values_freed;
112 IntTraits traits(&values_freed);
114 static const int kFirst = 0;
115 static const int kSecond = 1;
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);
123 EXPECT_TRUE(kFirst == a);
124 EXPECT_FALSE(kFirst != a);
125 EXPECT_FALSE(kSecond == a);
126 EXPECT_TRUE(kSecond != a);
131 ScopedInt a(kFirst, traits);
132 EXPECT_TRUE(a.is_valid());
134 EXPECT_FALSE(a.is_valid());
138 TEST(ScopedGenericTest, Receive) {
139 std::vector<int> values_freed;
140 IntTraits traits(&values_freed);
141 auto a = std::make_unique<ScopedInt>(123, traits);
143 EXPECT_EQ(123, a->get());
146 ScopedInt::Receiver r(*a);
147 EXPECT_EQ(123, a->get());
149 EXPECT_EQ(123, a->get());
152 EXPECT_EQ(456, a->get());
155 ScopedInt::Receiver r(*a);
156 EXPECT_DEATH_IF_SUPPORTED(a.reset(), "");
157 EXPECT_DEATH_IF_SUPPORTED(ScopedInt::Receiver(*a).get(), "");
163 struct TrackedIntTraits : public ScopedGenericOwnershipTracking {
165 std::unordered_map<int, const ScopedGeneric<int, TrackedIntTraits>*>;
166 TrackedIntTraits(std::unordered_set<int>* freed, OwnerMap* owners)
167 : freed(freed), owners(owners) {}
169 static int InvalidValue() { return -1; }
171 void Free(int value) {
172 auto it = owners->find(value);
173 ASSERT_EQ(owners->end(), it);
175 ASSERT_EQ(0U, freed->count(value));
176 freed->insert(value);
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;
185 void Release(const ScopedGeneric<int, TrackedIntTraits>& owner, int value) {
186 auto it = owners->find(value);
187 ASSERT_NE(owners->end(), it);
191 raw_ptr<std::unordered_set<int>> freed;
192 raw_ptr<OwnerMap> owners;
195 using ScopedTrackedInt = ScopedGeneric<int, TrackedIntTraits>;
199 TEST(ScopedGenericTest, OwnershipTracking) {
200 TrackedIntTraits::OwnerMap owners;
201 std::unordered_set<int> freed;
202 TrackedIntTraits traits(&freed, &owners);
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))
209 #define ASSERT_UNOWNED(value) \
210 ASSERT_FALSE(base::Contains(owners, value)); \
211 ASSERT_FALSE(base::Contains(freed, value))
213 #define ASSERT_FREED(value) \
214 ASSERT_FALSE(base::Contains(owners, value)); \
215 ASSERT_TRUE(base::Contains(freed, value))
220 ScopedTrackedInt a(0, traits);
231 ScopedTrackedInt a(0, traits);
247 ScopedTrackedInt a(0, traits);
249 int released = a.release();
250 ASSERT_EQ(0, released);
261 ScopedTrackedInt a(0, traits);
264 ScopedTrackedInt b(std::move(a));
276 ScopedTrackedInt a(0, traits);
277 ScopedTrackedInt b(1, traits);
291 #undef ASSERT_UNOWNED
295 // Cheesy manual "no compile" test for manually validating changes.
297 TEST(ScopedGenericTest, NoCompile) {
298 // Assignment shouldn't work.
300 ScopedInt a(kFirst, traits);
304 // Comparison shouldn't work.
306 ScopedInt a(kFirst, traits);
307 ScopedInt b(kFirst, traits);
312 // Implicit conversion to bool shouldn't work.
314 ScopedInt a(kFirst, traits);