blob: ea3dcdc4858f225ef1d4fb9ceb0e4a6fc5048ef7 [file] [log] [blame]
Daniel Eratb8cf9492015-07-06 13:18:13 -06001// Copyright (c) 2012 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
5#include "base/memory/scoped_vector.h"
6
Luis Hector Chavez94ffa552016-05-25 15:29:35 -07007#include <memory>
Alex Vakulenko0d205d72016-01-15 13:02:14 -08008#include <utility>
9
Daniel Eratb8cf9492015-07-06 13:18:13 -060010#include "base/bind.h"
11#include "base/callback.h"
Alex Vakulenko0d205d72016-01-15 13:02:14 -080012#include "base/macros.h"
Daniel Eratb8cf9492015-07-06 13:18:13 -060013#include "testing/gtest/include/gtest/gtest.h"
14
15namespace {
16
17// The LifeCycleObject notifies its Observer upon construction & destruction.
18class LifeCycleObject {
19 public:
20 class Observer {
21 public:
22 virtual void OnLifeCycleConstruct(LifeCycleObject* o) = 0;
23 virtual void OnLifeCycleDestroy(LifeCycleObject* o) = 0;
24
25 protected:
26 virtual ~Observer() {}
27 };
28
29 ~LifeCycleObject() {
Alex Vakulenko0d205d72016-01-15 13:02:14 -080030 if (observer_)
31 observer_->OnLifeCycleDestroy(this);
Daniel Eratb8cf9492015-07-06 13:18:13 -060032 }
33
34 private:
35 friend class LifeCycleWatcher;
36
37 explicit LifeCycleObject(Observer* observer)
38 : observer_(observer) {
39 observer_->OnLifeCycleConstruct(this);
40 }
41
Alex Vakulenko0d205d72016-01-15 13:02:14 -080042 void DisconnectObserver() {
43 observer_ = nullptr;
44 }
45
Daniel Eratb8cf9492015-07-06 13:18:13 -060046 Observer* observer_;
47
48 DISALLOW_COPY_AND_ASSIGN(LifeCycleObject);
49};
50
51// The life cycle states we care about for the purposes of testing ScopedVector
52// against objects.
53enum LifeCycleState {
54 LC_INITIAL,
55 LC_CONSTRUCTED,
56 LC_DESTROYED,
57};
58
59// Because we wish to watch the life cycle of an object being constructed and
60// destroyed, and further wish to test expectations against the state of that
61// object, we cannot save state in that object itself. Instead, we use this
62// pairing of the watcher, which observes the object and notifies of
63// construction & destruction. Since we also may be testing assumptions about
64// things not getting freed, this class also acts like a scoping object and
65// deletes the |constructed_life_cycle_object_|, if any when the
66// LifeCycleWatcher is destroyed. To keep this simple, the only expected state
67// changes are:
68// INITIAL -> CONSTRUCTED -> DESTROYED.
69// Anything more complicated than that should start another test.
70class LifeCycleWatcher : public LifeCycleObject::Observer {
71 public:
72 LifeCycleWatcher() : life_cycle_state_(LC_INITIAL) {}
Alex Vakulenko0d205d72016-01-15 13:02:14 -080073 ~LifeCycleWatcher() override {
74 // Stop watching the watched object. Without this, the object's destructor
75 // will call into OnLifeCycleDestroy when destructed, which happens after
76 // this destructor has finished running.
77 if (constructed_life_cycle_object_)
78 constructed_life_cycle_object_->DisconnectObserver();
79 }
Daniel Eratb8cf9492015-07-06 13:18:13 -060080
81 // Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this
82 // LifeCycleWatcher.
83 void OnLifeCycleConstruct(LifeCycleObject* object) override {
84 ASSERT_EQ(LC_INITIAL, life_cycle_state_);
85 ASSERT_EQ(NULL, constructed_life_cycle_object_.get());
86 life_cycle_state_ = LC_CONSTRUCTED;
87 constructed_life_cycle_object_.reset(object);
88 }
89
90 // Assert CONSTRUCTED -> DESTROYED and the |object| being destroyed is the
91 // same one we saw constructed.
92 void OnLifeCycleDestroy(LifeCycleObject* object) override {
93 ASSERT_EQ(LC_CONSTRUCTED, life_cycle_state_);
94 LifeCycleObject* constructed_life_cycle_object =
95 constructed_life_cycle_object_.release();
96 ASSERT_EQ(constructed_life_cycle_object, object);
97 life_cycle_state_ = LC_DESTROYED;
98 }
99
100 LifeCycleState life_cycle_state() const { return life_cycle_state_; }
101
102 // Factory method for creating a new LifeCycleObject tied to this
103 // LifeCycleWatcher.
104 LifeCycleObject* NewLifeCycleObject() {
105 return new LifeCycleObject(this);
106 }
107
108 // Returns true iff |object| is the same object that this watcher is tracking.
109 bool IsWatching(LifeCycleObject* object) const {
110 return object == constructed_life_cycle_object_.get();
111 }
112
113 private:
114 LifeCycleState life_cycle_state_;
Luis Hector Chavez94ffa552016-05-25 15:29:35 -0700115 std::unique_ptr<LifeCycleObject> constructed_life_cycle_object_;
Daniel Eratb8cf9492015-07-06 13:18:13 -0600116
117 DISALLOW_COPY_AND_ASSIGN(LifeCycleWatcher);
118};
119
120TEST(ScopedVectorTest, LifeCycleWatcher) {
121 LifeCycleWatcher watcher;
122 EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
123 LifeCycleObject* object = watcher.NewLifeCycleObject();
124 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
125 delete object;
126 EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
127}
128
129TEST(ScopedVectorTest, PopBack) {
130 LifeCycleWatcher watcher;
131 EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
132 ScopedVector<LifeCycleObject> scoped_vector;
133 scoped_vector.push_back(watcher.NewLifeCycleObject());
134 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
135 EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
136 scoped_vector.pop_back();
137 EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
138 EXPECT_TRUE(scoped_vector.empty());
139}
140
141TEST(ScopedVectorTest, Clear) {
142 LifeCycleWatcher watcher;
143 EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
144 ScopedVector<LifeCycleObject> scoped_vector;
145 scoped_vector.push_back(watcher.NewLifeCycleObject());
146 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
147 EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
148 scoped_vector.clear();
149 EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
150 EXPECT_TRUE(scoped_vector.empty());
151}
152
153TEST(ScopedVectorTest, WeakClear) {
154 LifeCycleWatcher watcher;
155 EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
156 ScopedVector<LifeCycleObject> scoped_vector;
157 scoped_vector.push_back(watcher.NewLifeCycleObject());
158 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
159 EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
160 scoped_vector.weak_clear();
161 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
162 EXPECT_TRUE(scoped_vector.empty());
163}
164
165TEST(ScopedVectorTest, ResizeShrink) {
166 LifeCycleWatcher first_watcher;
167 EXPECT_EQ(LC_INITIAL, first_watcher.life_cycle_state());
168 LifeCycleWatcher second_watcher;
169 EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
170 ScopedVector<LifeCycleObject> scoped_vector;
171
172 scoped_vector.push_back(first_watcher.NewLifeCycleObject());
173 EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
174 EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
175 EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
176 EXPECT_FALSE(second_watcher.IsWatching(scoped_vector[0]));
177
178 scoped_vector.push_back(second_watcher.NewLifeCycleObject());
179 EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
180 EXPECT_EQ(LC_CONSTRUCTED, second_watcher.life_cycle_state());
181 EXPECT_FALSE(first_watcher.IsWatching(scoped_vector[1]));
182 EXPECT_TRUE(second_watcher.IsWatching(scoped_vector[1]));
183
184 // Test that shrinking a vector deletes elements in the disappearing range.
185 scoped_vector.resize(1);
186 EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
187 EXPECT_EQ(LC_DESTROYED, second_watcher.life_cycle_state());
188 EXPECT_EQ(1u, scoped_vector.size());
189 EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
190}
191
192TEST(ScopedVectorTest, ResizeGrow) {
193 LifeCycleWatcher watcher;
194 EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
195 ScopedVector<LifeCycleObject> scoped_vector;
196 scoped_vector.push_back(watcher.NewLifeCycleObject());
197 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
198 EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
199
200 scoped_vector.resize(5);
201 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
202 ASSERT_EQ(5u, scoped_vector.size());
203 EXPECT_TRUE(watcher.IsWatching(scoped_vector[0]));
204 EXPECT_FALSE(watcher.IsWatching(scoped_vector[1]));
205 EXPECT_FALSE(watcher.IsWatching(scoped_vector[2]));
206 EXPECT_FALSE(watcher.IsWatching(scoped_vector[3]));
207 EXPECT_FALSE(watcher.IsWatching(scoped_vector[4]));
208}
209
210TEST(ScopedVectorTest, Scope) {
211 LifeCycleWatcher watcher;
212 EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
213 {
214 ScopedVector<LifeCycleObject> scoped_vector;
215 scoped_vector.push_back(watcher.NewLifeCycleObject());
216 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
217 EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
218 }
219 EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
220}
221
222TEST(ScopedVectorTest, MoveConstruct) {
223 LifeCycleWatcher watcher;
224 EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
225 {
226 ScopedVector<LifeCycleObject> scoped_vector;
227 scoped_vector.push_back(watcher.NewLifeCycleObject());
228 EXPECT_FALSE(scoped_vector.empty());
229 EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
230
Alex Vakulenko0d205d72016-01-15 13:02:14 -0800231 ScopedVector<LifeCycleObject> scoped_vector_copy(std::move(scoped_vector));
Daniel Eratb8cf9492015-07-06 13:18:13 -0600232 EXPECT_TRUE(scoped_vector.empty());
233 EXPECT_FALSE(scoped_vector_copy.empty());
234 EXPECT_TRUE(watcher.IsWatching(scoped_vector_copy.back()));
235
236 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
237 }
238 EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
239}
240
241TEST(ScopedVectorTest, MoveAssign) {
242 LifeCycleWatcher watcher;
243 EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
244 {
245 ScopedVector<LifeCycleObject> scoped_vector;
246 scoped_vector.push_back(watcher.NewLifeCycleObject());
247 ScopedVector<LifeCycleObject> scoped_vector_assign;
248 EXPECT_FALSE(scoped_vector.empty());
249 EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
250
Alex Vakulenko0d205d72016-01-15 13:02:14 -0800251 scoped_vector_assign = std::move(scoped_vector);
Daniel Eratb8cf9492015-07-06 13:18:13 -0600252 EXPECT_TRUE(scoped_vector.empty());
253 EXPECT_FALSE(scoped_vector_assign.empty());
254 EXPECT_TRUE(watcher.IsWatching(scoped_vector_assign.back()));
255
256 EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
257 }
258 EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
259}
260
261class DeleteCounter {
262 public:
263 explicit DeleteCounter(int* deletes)
264 : deletes_(deletes) {
265 }
266
267 ~DeleteCounter() {
268 (*deletes_)++;
269 }
270
271 void VoidMethod0() {}
272
273 private:
274 int* const deletes_;
275
276 DISALLOW_COPY_AND_ASSIGN(DeleteCounter);
277};
278
279template <typename T>
280ScopedVector<T> PassThru(ScopedVector<T> scoper) {
Alex Vakulenko0d205d72016-01-15 13:02:14 -0800281 return scoper;
Daniel Eratb8cf9492015-07-06 13:18:13 -0600282}
283
284TEST(ScopedVectorTest, Passed) {
285 int deletes = 0;
286 ScopedVector<DeleteCounter> deleter_vector;
287 deleter_vector.push_back(new DeleteCounter(&deletes));
288 EXPECT_EQ(0, deletes);
289 base::Callback<ScopedVector<DeleteCounter>(void)> callback =
290 base::Bind(&PassThru<DeleteCounter>, base::Passed(&deleter_vector));
291 EXPECT_EQ(0, deletes);
292 ScopedVector<DeleteCounter> result = callback.Run();
293 EXPECT_EQ(0, deletes);
294 result.clear();
295 EXPECT_EQ(1, deletes);
296};
297
298TEST(ScopedVectorTest, InsertRange) {
299 LifeCycleWatcher watchers[5];
300
301 std::vector<LifeCycleObject*> vec;
302 for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
303 ++it) {
304 EXPECT_EQ(LC_INITIAL, it->life_cycle_state());
305 vec.push_back(it->NewLifeCycleObject());
306 EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
307 }
308 // Start scope for ScopedVector.
309 {
310 ScopedVector<LifeCycleObject> scoped_vector;
311 scoped_vector.insert(scoped_vector.end(), vec.begin() + 1, vec.begin() + 3);
312 for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
313 ++it)
314 EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
315 }
316 for(LifeCycleWatcher* it = watchers; it != watchers + 1; ++it)
317 EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
318 for(LifeCycleWatcher* it = watchers + 1; it != watchers + 3; ++it)
319 EXPECT_EQ(LC_DESTROYED, it->life_cycle_state());
320 for(LifeCycleWatcher* it = watchers + 3; it != watchers + arraysize(watchers);
321 ++it)
322 EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
323}
324
Luis Hector Chaveze5b2c6f2017-07-26 17:33:47 +0000325// Assertions for push_back(scoped_ptr).
Daniel Eratb8cf9492015-07-06 13:18:13 -0600326TEST(ScopedVectorTest, PushBackScopedPtr) {
327 int delete_counter = 0;
Luis Hector Chavez94ffa552016-05-25 15:29:35 -0700328 std::unique_ptr<DeleteCounter> elem(new DeleteCounter(&delete_counter));
Daniel Eratb8cf9492015-07-06 13:18:13 -0600329 EXPECT_EQ(0, delete_counter);
330 {
331 ScopedVector<DeleteCounter> v;
Alex Vakulenko0d205d72016-01-15 13:02:14 -0800332 v.push_back(std::move(elem));
Daniel Eratb8cf9492015-07-06 13:18:13 -0600333 EXPECT_EQ(0, delete_counter);
334 }
335 EXPECT_EQ(1, delete_counter);
336}
337
338} // namespace