1// 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
5#include "base/scoped_generic.h"
6
7#include <utility>
8#include <vector>
9
10#include "testing/gtest/include/gtest/gtest.h"
11
12namespace base {
13
14namespace {
15
16struct IntTraits {
17  IntTraits(std::vector<int>* freed) : freed_ints(freed) {}
18
19  static int InvalidValue() {
20    return -1;
21  }
22  void Free(int value) {
23    freed_ints->push_back(value);
24  }
25
26  std::vector<int>* freed_ints;
27};
28
29typedef ScopedGeneric<int, IntTraits> ScopedInt;
30
31}  // namespace
32
33TEST(ScopedGenericTest, ScopedGeneric) {
34  std::vector<int> values_freed;
35  IntTraits traits(&values_freed);
36
37  // Invalid case, delete should not be called.
38  {
39    ScopedInt a(IntTraits::InvalidValue(), traits);
40  }
41  EXPECT_TRUE(values_freed.empty());
42
43  // Simple deleting case.
44  static const int kFirst = 0;
45  {
46    ScopedInt a(kFirst, traits);
47  }
48  ASSERT_EQ(1u, values_freed.size());
49  ASSERT_EQ(kFirst, values_freed[0]);
50  values_freed.clear();
51
52  // Release should return the right value and leave the object empty.
53  {
54    ScopedInt a(kFirst, traits);
55    EXPECT_EQ(kFirst, a.release());
56
57    ScopedInt b(IntTraits::InvalidValue(), traits);
58    EXPECT_EQ(IntTraits::InvalidValue(), b.release());
59  }
60  ASSERT_TRUE(values_freed.empty());
61
62  // Reset should free the old value, then the new one should go away when
63  // it goes out of scope.
64  static const int kSecond = 1;
65  {
66    ScopedInt b(kFirst, traits);
67    b.reset(kSecond);
68    ASSERT_EQ(1u, values_freed.size());
69    ASSERT_EQ(kFirst, values_freed[0]);
70  }
71  ASSERT_EQ(2u, values_freed.size());
72  ASSERT_EQ(kSecond, values_freed[1]);
73  values_freed.clear();
74
75  // Swap.
76  {
77    ScopedInt a(kFirst, traits);
78    ScopedInt b(kSecond, traits);
79    a.swap(b);
80    EXPECT_TRUE(values_freed.empty());  // Nothing should be freed.
81    EXPECT_EQ(kSecond, a.get());
82    EXPECT_EQ(kFirst, b.get());
83  }
84  // Values should be deleted in the opposite order.
85  ASSERT_EQ(2u, values_freed.size());
86  EXPECT_EQ(kFirst, values_freed[0]);
87  EXPECT_EQ(kSecond, values_freed[1]);
88  values_freed.clear();
89
90  // Move constructor.
91  {
92    ScopedInt a(kFirst, traits);
93    ScopedInt b(std::move(a));
94    EXPECT_TRUE(values_freed.empty());  // Nothing should be freed.
95    ASSERT_EQ(IntTraits::InvalidValue(), a.get());
96    ASSERT_EQ(kFirst, b.get());
97  }
98
99  ASSERT_EQ(1u, values_freed.size());
100  ASSERT_EQ(kFirst, values_freed[0]);
101  values_freed.clear();
102
103  // Move assign.
104  {
105    ScopedInt a(kFirst, traits);
106    ScopedInt b(kSecond, traits);
107    b = std::move(a);
108    ASSERT_EQ(1u, values_freed.size());
109    EXPECT_EQ(kSecond, values_freed[0]);
110    ASSERT_EQ(IntTraits::InvalidValue(), a.get());
111    ASSERT_EQ(kFirst, b.get());
112  }
113
114  ASSERT_EQ(2u, values_freed.size());
115  EXPECT_EQ(kFirst, values_freed[1]);
116  values_freed.clear();
117}
118
119TEST(ScopedGenericTest, Operators) {
120  std::vector<int> values_freed;
121  IntTraits traits(&values_freed);
122
123  static const int kFirst = 0;
124  static const int kSecond = 1;
125  {
126    ScopedInt a(kFirst, traits);
127    EXPECT_TRUE(a == kFirst);
128    EXPECT_FALSE(a != kFirst);
129    EXPECT_FALSE(a == kSecond);
130    EXPECT_TRUE(a != kSecond);
131
132    EXPECT_TRUE(kFirst == a);
133    EXPECT_FALSE(kFirst != a);
134    EXPECT_FALSE(kSecond == a);
135    EXPECT_TRUE(kSecond != a);
136  }
137
138  // is_valid().
139  {
140    ScopedInt a(kFirst, traits);
141    EXPECT_TRUE(a.is_valid());
142    a.reset();
143    EXPECT_FALSE(a.is_valid());
144  }
145}
146
147// Cheesy manual "no compile" test for manually validating changes.
148#if 0
149TEST(ScopedGenericTest, NoCompile) {
150  // Assignment shouldn't work.
151  /*{
152    ScopedInt a(kFirst, traits);
153    ScopedInt b(a);
154  }*/
155
156  // Comparison shouldn't work.
157  /*{
158    ScopedInt a(kFirst, traits);
159    ScopedInt b(kFirst, traits);
160    if (a == b) {
161    }
162  }*/
163
164  // Implicit conversion to bool shouldn't work.
165  /*{
166    ScopedInt a(kFirst, traits);
167    bool result = a;
168  }*/
169}
170#endif
171
172}  // namespace base
173