1// 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_ptr.h"
6
7#include "base/basictypes.h"
8#include "base/bind.h"
9#include "base/callback.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12namespace {
13
14// Used to test depth subtyping.
15class ConDecLoggerParent {
16 public:
17  virtual ~ConDecLoggerParent() {}
18
19  virtual void SetPtr(int* ptr) = 0;
20
21  virtual int SomeMeth(int x) const = 0;
22};
23
24class ConDecLogger : public ConDecLoggerParent {
25 public:
26  ConDecLogger() : ptr_(NULL) { }
27  explicit ConDecLogger(int* ptr) { SetPtr(ptr); }
28  virtual ~ConDecLogger() { --*ptr_; }
29
30  virtual void SetPtr(int* ptr) OVERRIDE { ptr_ = ptr; ++*ptr_; }
31
32  virtual int SomeMeth(int x) const OVERRIDE { return x; }
33
34 private:
35  int* ptr_;
36
37  DISALLOW_COPY_AND_ASSIGN(ConDecLogger);
38};
39
40struct CountingDeleter {
41  explicit CountingDeleter(int* count) : count_(count) {}
42  inline void operator()(double* ptr) const {
43    (*count_)++;
44  }
45  int* count_;
46};
47
48// Used to test assignment of convertible deleters.
49struct CountingDeleterChild : public CountingDeleter {
50  explicit CountingDeleterChild(int* count) : CountingDeleter(count) {}
51};
52
53class OverloadedNewAndDelete {
54 public:
55  void* operator new(size_t size) {
56    g_new_count++;
57    return malloc(size);
58  }
59
60  void operator delete(void* ptr) {
61    g_delete_count++;
62    free(ptr);
63  }
64
65  static void ResetCounters() {
66    g_new_count = 0;
67    g_delete_count = 0;
68  }
69
70  static int new_count() { return g_new_count; }
71  static int delete_count() { return g_delete_count; }
72
73 private:
74  static int g_new_count;
75  static int g_delete_count;
76};
77
78int OverloadedNewAndDelete::g_new_count = 0;
79int OverloadedNewAndDelete::g_delete_count = 0;
80
81scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
82  return logger.Pass();
83}
84
85void GrabAndDrop(scoped_ptr<ConDecLogger> logger) {
86}
87
88// Do not delete this function!  It's existence is to test that you can
89// return a temporarily constructed version of the scoper.
90scoped_ptr<ConDecLogger> TestReturnOfType(int* constructed) {
91  return scoped_ptr<ConDecLogger>(new ConDecLogger(constructed));
92}
93
94scoped_ptr<ConDecLoggerParent> UpcastUsingPassAs(
95    scoped_ptr<ConDecLogger> object) {
96  return object.PassAs<ConDecLoggerParent>();
97}
98
99}  // namespace
100
101TEST(ScopedPtrTest, ScopedPtr) {
102  int constructed = 0;
103
104  // Ensure size of scoped_ptr<> doesn't increase unexpectedly.
105  COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr<int>),
106                 scoped_ptr_larger_than_raw_ptr);
107
108  {
109    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
110    EXPECT_EQ(1, constructed);
111    EXPECT_TRUE(scoper.get());
112
113    EXPECT_EQ(10, scoper->SomeMeth(10));
114    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
115    EXPECT_EQ(10, (*scoper).SomeMeth(10));
116  }
117  EXPECT_EQ(0, constructed);
118
119  // Test reset() and release()
120  {
121    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
122    EXPECT_EQ(1, constructed);
123    EXPECT_TRUE(scoper.get());
124
125    scoper.reset(new ConDecLogger(&constructed));
126    EXPECT_EQ(1, constructed);
127    EXPECT_TRUE(scoper.get());
128
129    scoper.reset();
130    EXPECT_EQ(0, constructed);
131    EXPECT_FALSE(scoper.get());
132
133    scoper.reset(new ConDecLogger(&constructed));
134    EXPECT_EQ(1, constructed);
135    EXPECT_TRUE(scoper.get());
136
137    ConDecLogger* take = scoper.release();
138    EXPECT_EQ(1, constructed);
139    EXPECT_FALSE(scoper.get());
140    delete take;
141    EXPECT_EQ(0, constructed);
142
143    scoper.reset(new ConDecLogger(&constructed));
144    EXPECT_EQ(1, constructed);
145    EXPECT_TRUE(scoper.get());
146  }
147  EXPECT_EQ(0, constructed);
148
149  // Test swap(), == and !=
150  {
151    scoped_ptr<ConDecLogger> scoper1;
152    scoped_ptr<ConDecLogger> scoper2;
153    EXPECT_TRUE(scoper1 == scoper2.get());
154    EXPECT_FALSE(scoper1 != scoper2.get());
155
156    ConDecLogger* logger = new ConDecLogger(&constructed);
157    scoper1.reset(logger);
158    EXPECT_EQ(logger, scoper1.get());
159    EXPECT_FALSE(scoper2.get());
160    EXPECT_FALSE(scoper1 == scoper2.get());
161    EXPECT_TRUE(scoper1 != scoper2.get());
162
163    scoper2.swap(scoper1);
164    EXPECT_EQ(logger, scoper2.get());
165    EXPECT_FALSE(scoper1.get());
166    EXPECT_FALSE(scoper1 == scoper2.get());
167    EXPECT_TRUE(scoper1 != scoper2.get());
168  }
169  EXPECT_EQ(0, constructed);
170}
171
172TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
173  int constructed = 0;
174
175  // Test construction from a scoped_ptr to a derived class.
176  {
177    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
178    EXPECT_EQ(1, constructed);
179    EXPECT_TRUE(scoper.get());
180
181    scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass());
182    EXPECT_EQ(1, constructed);
183    EXPECT_TRUE(scoper_parent.get());
184    EXPECT_FALSE(scoper.get());
185
186    EXPECT_EQ(10, scoper_parent->SomeMeth(10));
187    EXPECT_EQ(10, scoper_parent.get()->SomeMeth(10));
188    EXPECT_EQ(10, (*scoper_parent).SomeMeth(10));
189  }
190  EXPECT_EQ(0, constructed);
191
192  // Test assignment from a scoped_ptr to a derived class.
193  {
194    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
195    EXPECT_EQ(1, constructed);
196    EXPECT_TRUE(scoper.get());
197
198    scoped_ptr<ConDecLoggerParent> scoper_parent;
199    scoper_parent = scoper.Pass();
200    EXPECT_EQ(1, constructed);
201    EXPECT_TRUE(scoper_parent.get());
202    EXPECT_FALSE(scoper.get());
203  }
204  EXPECT_EQ(0, constructed);
205
206  // Test construction of a scoped_ptr with an additional const annotation.
207  {
208    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
209    EXPECT_EQ(1, constructed);
210    EXPECT_TRUE(scoper.get());
211
212    scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass());
213    EXPECT_EQ(1, constructed);
214    EXPECT_TRUE(scoper_const.get());
215    EXPECT_FALSE(scoper.get());
216
217    EXPECT_EQ(10, scoper_const->SomeMeth(10));
218    EXPECT_EQ(10, scoper_const.get()->SomeMeth(10));
219    EXPECT_EQ(10, (*scoper_const).SomeMeth(10));
220  }
221  EXPECT_EQ(0, constructed);
222
223  // Test assignment to a scoped_ptr with an additional const annotation.
224  {
225    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
226    EXPECT_EQ(1, constructed);
227    EXPECT_TRUE(scoper.get());
228
229    scoped_ptr<const ConDecLogger> scoper_const;
230    scoper_const = scoper.Pass();
231    EXPECT_EQ(1, constructed);
232    EXPECT_TRUE(scoper_const.get());
233    EXPECT_FALSE(scoper.get());
234  }
235  EXPECT_EQ(0, constructed);
236
237  // Test assignment to a scoped_ptr deleter of parent type.
238  {
239    // Custom deleters never touch these value.
240    double dummy_value, dummy_value2;
241    int deletes = 0;
242    int alternate_deletes = 0;
243    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
244                                               CountingDeleter(&deletes));
245    scoped_ptr<double, CountingDeleterChild> scoper_child(
246        &dummy_value2, CountingDeleterChild(&alternate_deletes));
247
248    EXPECT_TRUE(scoper);
249    EXPECT_TRUE(scoper_child);
250    EXPECT_EQ(0, deletes);
251    EXPECT_EQ(0, alternate_deletes);
252
253    // Test this compiles and correctly overwrites the deleter state.
254    scoper = scoper_child.Pass();
255    EXPECT_TRUE(scoper);
256    EXPECT_FALSE(scoper_child);
257    EXPECT_EQ(1, deletes);
258    EXPECT_EQ(0, alternate_deletes);
259
260    scoper.reset();
261    EXPECT_FALSE(scoper);
262    EXPECT_FALSE(scoper_child);
263    EXPECT_EQ(1, deletes);
264    EXPECT_EQ(1, alternate_deletes);
265
266    scoper_child.reset(&dummy_value);
267    EXPECT_TRUE(scoper_child);
268    EXPECT_EQ(1, deletes);
269    EXPECT_EQ(1, alternate_deletes);
270    scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass());
271    EXPECT_TRUE(scoper_construct);
272    EXPECT_FALSE(scoper_child);
273    EXPECT_EQ(1, deletes);
274    EXPECT_EQ(1, alternate_deletes);
275
276    scoper_construct.reset();
277    EXPECT_EQ(1, deletes);
278    EXPECT_EQ(2, alternate_deletes);
279  }
280}
281
282TEST(ScopedPtrTest, ScopedPtrWithArray) {
283  static const int kNumLoggers = 12;
284
285  int constructed = 0;
286
287  {
288    scoped_ptr<ConDecLogger[]> scoper(new ConDecLogger[kNumLoggers]);
289    EXPECT_TRUE(scoper);
290    EXPECT_EQ(&scoper[0], scoper.get());
291    for (int i = 0; i < kNumLoggers; ++i) {
292      scoper[i].SetPtr(&constructed);
293    }
294    EXPECT_EQ(12, constructed);
295
296    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
297    EXPECT_EQ(10, scoper[2].SomeMeth(10));
298  }
299  EXPECT_EQ(0, constructed);
300
301  // Test reset() and release()
302  {
303    scoped_ptr<ConDecLogger[]> scoper;
304    EXPECT_FALSE(scoper.get());
305    EXPECT_FALSE(scoper.release());
306    EXPECT_FALSE(scoper.get());
307    scoper.reset();
308    EXPECT_FALSE(scoper.get());
309
310    scoper.reset(new ConDecLogger[kNumLoggers]);
311    for (int i = 0; i < kNumLoggers; ++i) {
312      scoper[i].SetPtr(&constructed);
313    }
314    EXPECT_EQ(12, constructed);
315    scoper.reset();
316    EXPECT_EQ(0, constructed);
317
318    scoper.reset(new ConDecLogger[kNumLoggers]);
319    for (int i = 0; i < kNumLoggers; ++i) {
320      scoper[i].SetPtr(&constructed);
321    }
322    EXPECT_EQ(12, constructed);
323    ConDecLogger* ptr = scoper.release();
324    EXPECT_EQ(12, constructed);
325    delete[] ptr;
326    EXPECT_EQ(0, constructed);
327  }
328  EXPECT_EQ(0, constructed);
329
330  // Test swap(), ==, !=, and type-safe Boolean.
331  {
332    scoped_ptr<ConDecLogger[]> scoper1;
333    scoped_ptr<ConDecLogger[]> scoper2;
334    EXPECT_TRUE(scoper1 == scoper2.get());
335    EXPECT_FALSE(scoper1 != scoper2.get());
336
337    ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
338    for (int i = 0; i < kNumLoggers; ++i) {
339      loggers[i].SetPtr(&constructed);
340    }
341    scoper1.reset(loggers);
342    EXPECT_TRUE(scoper1);
343    EXPECT_EQ(loggers, scoper1.get());
344    EXPECT_FALSE(scoper2);
345    EXPECT_FALSE(scoper2.get());
346    EXPECT_FALSE(scoper1 == scoper2.get());
347    EXPECT_TRUE(scoper1 != scoper2.get());
348
349    scoper2.swap(scoper1);
350    EXPECT_EQ(loggers, scoper2.get());
351    EXPECT_FALSE(scoper1.get());
352    EXPECT_FALSE(scoper1 == scoper2.get());
353    EXPECT_TRUE(scoper1 != scoper2.get());
354  }
355  EXPECT_EQ(0, constructed);
356
357  {
358    ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
359    scoped_ptr<ConDecLogger[]> scoper(loggers);
360    EXPECT_TRUE(scoper);
361    for (int i = 0; i < kNumLoggers; ++i) {
362      scoper[i].SetPtr(&constructed);
363    }
364    EXPECT_EQ(kNumLoggers, constructed);
365
366    // Test Pass() with constructor;
367    scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass());
368    EXPECT_EQ(kNumLoggers, constructed);
369
370    // Test Pass() with assignment;
371    scoped_ptr<ConDecLogger[]> scoper3;
372    scoper3 = scoper2.Pass();
373    EXPECT_EQ(kNumLoggers, constructed);
374    EXPECT_FALSE(scoper);
375    EXPECT_FALSE(scoper2);
376    EXPECT_TRUE(scoper3);
377  }
378  EXPECT_EQ(0, constructed);
379}
380
381TEST(ScopedPtrTest, PassBehavior) {
382  int constructed = 0;
383  {
384    ConDecLogger* logger = new ConDecLogger(&constructed);
385    scoped_ptr<ConDecLogger> scoper(logger);
386    EXPECT_EQ(1, constructed);
387
388    // Test Pass() with constructor;
389    scoped_ptr<ConDecLogger> scoper2(scoper.Pass());
390    EXPECT_EQ(1, constructed);
391
392    // Test Pass() with assignment;
393    scoped_ptr<ConDecLogger> scoper3;
394    scoper3 = scoper2.Pass();
395    EXPECT_EQ(1, constructed);
396    EXPECT_FALSE(scoper.get());
397    EXPECT_FALSE(scoper2.get());
398    EXPECT_TRUE(scoper3.get());
399  }
400
401  // Test uncaught Pass() does not leak.
402  {
403    ConDecLogger* logger = new ConDecLogger(&constructed);
404    scoped_ptr<ConDecLogger> scoper(logger);
405    EXPECT_EQ(1, constructed);
406
407    // Should auto-destruct logger by end of scope.
408    scoper.Pass();
409    EXPECT_FALSE(scoper.get());
410  }
411  EXPECT_EQ(0, constructed);
412
413  // Test that passing to function which does nothing does not leak.
414  {
415    ConDecLogger* logger = new ConDecLogger(&constructed);
416    scoped_ptr<ConDecLogger> scoper(logger);
417    EXPECT_EQ(1, constructed);
418
419    // Should auto-destruct logger by end of scope.
420    GrabAndDrop(scoper.Pass());
421    EXPECT_FALSE(scoper.get());
422  }
423  EXPECT_EQ(0, constructed);
424}
425
426TEST(ScopedPtrTest, ReturnTypeBehavior) {
427  int constructed = 0;
428
429  // Test that we can return a scoped_ptr.
430  {
431    ConDecLogger* logger = new ConDecLogger(&constructed);
432    scoped_ptr<ConDecLogger> scoper(logger);
433    EXPECT_EQ(1, constructed);
434
435    PassThru(scoper.Pass());
436    EXPECT_FALSE(scoper.get());
437  }
438  EXPECT_EQ(0, constructed);
439
440  // Test uncaught return type not leak.
441  {
442    ConDecLogger* logger = new ConDecLogger(&constructed);
443    scoped_ptr<ConDecLogger> scoper(logger);
444    EXPECT_EQ(1, constructed);
445
446    // Should auto-destruct logger by end of scope.
447    PassThru(scoper.Pass());
448    EXPECT_FALSE(scoper.get());
449  }
450  EXPECT_EQ(0, constructed);
451
452  // Call TestReturnOfType() so the compiler doesn't warn for an unused
453  // function.
454  {
455    TestReturnOfType(&constructed);
456  }
457  EXPECT_EQ(0, constructed);
458}
459
460TEST(ScopedPtrTest, PassAs) {
461  int constructed = 0;
462  {
463    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
464    EXPECT_EQ(1, constructed);
465    EXPECT_TRUE(scoper.get());
466
467    scoped_ptr<ConDecLoggerParent> scoper_parent;
468    scoper_parent = UpcastUsingPassAs(scoper.Pass());
469    EXPECT_EQ(1, constructed);
470    EXPECT_TRUE(scoper_parent.get());
471    EXPECT_FALSE(scoper.get());
472  }
473  EXPECT_EQ(0, constructed);
474}
475
476TEST(ScopedPtrTest, CustomDeleter) {
477  double dummy_value;  // Custom deleter never touches this value.
478  int deletes = 0;
479  int alternate_deletes = 0;
480
481  // Normal delete support.
482  {
483    deletes = 0;
484    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
485                                               CountingDeleter(&deletes));
486    EXPECT_EQ(0, deletes);
487    EXPECT_TRUE(scoper.get());
488  }
489  EXPECT_EQ(1, deletes);
490
491  // Test reset() and release().
492  deletes = 0;
493  {
494    scoped_ptr<double, CountingDeleter> scoper(NULL,
495                                               CountingDeleter(&deletes));
496    EXPECT_FALSE(scoper.get());
497    EXPECT_FALSE(scoper.release());
498    EXPECT_FALSE(scoper.get());
499    scoper.reset();
500    EXPECT_FALSE(scoper.get());
501    EXPECT_EQ(0, deletes);
502
503    scoper.reset(&dummy_value);
504    scoper.reset();
505    EXPECT_EQ(1, deletes);
506
507    scoper.reset(&dummy_value);
508    EXPECT_EQ(&dummy_value, scoper.release());
509  }
510  EXPECT_EQ(1, deletes);
511
512  // Test get_deleter().
513  deletes = 0;
514  alternate_deletes = 0;
515  {
516    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
517                                               CountingDeleter(&deletes));
518    // Call deleter manually.
519    EXPECT_EQ(0, deletes);
520    scoper.get_deleter()(&dummy_value);
521    EXPECT_EQ(1, deletes);
522
523    // Deleter is still there after reset.
524    scoper.reset();
525    EXPECT_EQ(2, deletes);
526    scoper.get_deleter()(&dummy_value);
527    EXPECT_EQ(3, deletes);
528
529    // Deleter can be assigned into (matches C++11 unique_ptr<> spec).
530    scoper.get_deleter() = CountingDeleter(&alternate_deletes);
531    scoper.reset(&dummy_value);
532    EXPECT_EQ(0, alternate_deletes);
533
534  }
535  EXPECT_EQ(3, deletes);
536  EXPECT_EQ(1, alternate_deletes);
537
538  // Test operator= deleter support.
539  deletes = 0;
540  alternate_deletes = 0;
541  {
542    double dummy_value2;
543    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
544                                               CountingDeleter(&deletes));
545    scoped_ptr<double, CountingDeleter> scoper2(
546        &dummy_value2,
547        CountingDeleter(&alternate_deletes));
548    EXPECT_EQ(0, deletes);
549    EXPECT_EQ(0, alternate_deletes);
550
551    // Pass the second deleter through a constructor and an operator=. Then
552    // reinitialize the empty scopers to ensure that each one is deleting
553    // properly.
554    scoped_ptr<double, CountingDeleter> scoper3(scoper2.Pass());
555    scoper = scoper3.Pass();
556    EXPECT_EQ(1, deletes);
557
558    scoper2.reset(&dummy_value2);
559    scoper3.reset(&dummy_value2);
560    EXPECT_EQ(0, alternate_deletes);
561
562  }
563  EXPECT_EQ(1, deletes);
564  EXPECT_EQ(3, alternate_deletes);
565
566  // Test swap(), ==, !=, and type-safe Boolean.
567  {
568    scoped_ptr<double, CountingDeleter> scoper1(NULL,
569                                                CountingDeleter(&deletes));
570    scoped_ptr<double, CountingDeleter> scoper2(NULL,
571                                                CountingDeleter(&deletes));
572    EXPECT_TRUE(scoper1 == scoper2.get());
573    EXPECT_FALSE(scoper1 != scoper2.get());
574
575    scoper1.reset(&dummy_value);
576    EXPECT_TRUE(scoper1);
577    EXPECT_EQ(&dummy_value, scoper1.get());
578    EXPECT_FALSE(scoper2);
579    EXPECT_FALSE(scoper2.get());
580    EXPECT_FALSE(scoper1 == scoper2.get());
581    EXPECT_TRUE(scoper1 != scoper2.get());
582
583    scoper2.swap(scoper1);
584    EXPECT_EQ(&dummy_value, scoper2.get());
585    EXPECT_FALSE(scoper1.get());
586    EXPECT_FALSE(scoper1 == scoper2.get());
587    EXPECT_TRUE(scoper1 != scoper2.get());
588  }
589}
590
591// Sanity check test for overloaded new and delete operators. Does not do full
592// coverage of reset/release/Pass() operations as that is redundant with the
593// above.
594TEST(ScopedPtrTest, OverloadedNewAndDelete) {
595  {
596    OverloadedNewAndDelete::ResetCounters();
597    scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete());
598    EXPECT_TRUE(scoper.get());
599
600    scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass());
601  }
602  EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
603  EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
604}
605