|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/scoped_generic.h" | 
|  |  | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct IntTraits { | 
|  | IntTraits(std::vector<int>* freed) : freed_ints(freed) {} | 
|  |  | 
|  | static int InvalidValue() { | 
|  | return -1; | 
|  | } | 
|  | void Free(int value) { | 
|  | freed_ints->push_back(value); | 
|  | } | 
|  |  | 
|  | std::vector<int>* freed_ints; | 
|  | }; | 
|  |  | 
|  | typedef ScopedGeneric<int, IntTraits> ScopedInt; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | TEST(ScopedGenericTest, ScopedGeneric) { | 
|  | std::vector<int> values_freed; | 
|  | IntTraits traits(&values_freed); | 
|  |  | 
|  | // Invalid case, delete should not be called. | 
|  | { | 
|  | ScopedInt a(IntTraits::InvalidValue(), traits); | 
|  | } | 
|  | EXPECT_TRUE(values_freed.empty()); | 
|  |  | 
|  | // Simple deleting case. | 
|  | static const int kFirst = 0; | 
|  | { | 
|  | ScopedInt a(kFirst, traits); | 
|  | } | 
|  | ASSERT_EQ(1u, values_freed.size()); | 
|  | ASSERT_EQ(kFirst, values_freed[0]); | 
|  | values_freed.clear(); | 
|  |  | 
|  | // Release should return the right value and leave the object empty. | 
|  | { | 
|  | ScopedInt a(kFirst, traits); | 
|  | EXPECT_EQ(kFirst, a.release()); | 
|  |  | 
|  | ScopedInt b(IntTraits::InvalidValue(), traits); | 
|  | EXPECT_EQ(IntTraits::InvalidValue(), b.release()); | 
|  | } | 
|  | ASSERT_TRUE(values_freed.empty()); | 
|  |  | 
|  | // Reset should free the old value, then the new one should go away when | 
|  | // it goes out of scope. | 
|  | static const int kSecond = 1; | 
|  | { | 
|  | ScopedInt b(kFirst, traits); | 
|  | b.reset(kSecond); | 
|  | ASSERT_EQ(1u, values_freed.size()); | 
|  | ASSERT_EQ(kFirst, values_freed[0]); | 
|  | } | 
|  | ASSERT_EQ(2u, values_freed.size()); | 
|  | ASSERT_EQ(kSecond, values_freed[1]); | 
|  | values_freed.clear(); | 
|  |  | 
|  | // Swap. | 
|  | { | 
|  | ScopedInt a(kFirst, traits); | 
|  | ScopedInt b(kSecond, traits); | 
|  | a.swap(b); | 
|  | EXPECT_TRUE(values_freed.empty());  // Nothing should be freed. | 
|  | EXPECT_EQ(kSecond, a.get()); | 
|  | EXPECT_EQ(kFirst, b.get()); | 
|  | } | 
|  | // Values should be deleted in the opposite order. | 
|  | ASSERT_EQ(2u, values_freed.size()); | 
|  | EXPECT_EQ(kFirst, values_freed[0]); | 
|  | EXPECT_EQ(kSecond, values_freed[1]); | 
|  | values_freed.clear(); | 
|  |  | 
|  | // Move constructor. | 
|  | { | 
|  | ScopedInt a(kFirst, traits); | 
|  | ScopedInt b(std::move(a)); | 
|  | EXPECT_TRUE(values_freed.empty());  // Nothing should be freed. | 
|  | ASSERT_EQ(IntTraits::InvalidValue(), a.get()); | 
|  | ASSERT_EQ(kFirst, b.get()); | 
|  | } | 
|  |  | 
|  | ASSERT_EQ(1u, values_freed.size()); | 
|  | ASSERT_EQ(kFirst, values_freed[0]); | 
|  | values_freed.clear(); | 
|  |  | 
|  | // Move assign. | 
|  | { | 
|  | ScopedInt a(kFirst, traits); | 
|  | ScopedInt b(kSecond, traits); | 
|  | b = std::move(a); | 
|  | ASSERT_EQ(1u, values_freed.size()); | 
|  | EXPECT_EQ(kSecond, values_freed[0]); | 
|  | ASSERT_EQ(IntTraits::InvalidValue(), a.get()); | 
|  | ASSERT_EQ(kFirst, b.get()); | 
|  | } | 
|  |  | 
|  | ASSERT_EQ(2u, values_freed.size()); | 
|  | EXPECT_EQ(kFirst, values_freed[1]); | 
|  | values_freed.clear(); | 
|  | } | 
|  |  | 
|  | TEST(ScopedGenericTest, Operators) { | 
|  | std::vector<int> values_freed; | 
|  | IntTraits traits(&values_freed); | 
|  |  | 
|  | static const int kFirst = 0; | 
|  | static const int kSecond = 1; | 
|  | { | 
|  | ScopedInt a(kFirst, traits); | 
|  | EXPECT_TRUE(a == kFirst); | 
|  | EXPECT_FALSE(a != kFirst); | 
|  | EXPECT_FALSE(a == kSecond); | 
|  | EXPECT_TRUE(a != kSecond); | 
|  |  | 
|  | EXPECT_TRUE(kFirst == a); | 
|  | EXPECT_FALSE(kFirst != a); | 
|  | EXPECT_FALSE(kSecond == a); | 
|  | EXPECT_TRUE(kSecond != a); | 
|  | } | 
|  |  | 
|  | // is_valid(). | 
|  | { | 
|  | ScopedInt a(kFirst, traits); | 
|  | EXPECT_TRUE(a.is_valid()); | 
|  | a.reset(); | 
|  | EXPECT_FALSE(a.is_valid()); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Cheesy manual "no compile" test for manually validating changes. | 
|  | #if 0 | 
|  | TEST(ScopedGenericTest, NoCompile) { | 
|  | // Assignment shouldn't work. | 
|  | /*{ | 
|  | ScopedInt a(kFirst, traits); | 
|  | ScopedInt b(a); | 
|  | }*/ | 
|  |  | 
|  | // Comparison shouldn't work. | 
|  | /*{ | 
|  | ScopedInt a(kFirst, traits); | 
|  | ScopedInt b(kFirst, traits); | 
|  | if (a == b) { | 
|  | } | 
|  | }*/ | 
|  |  | 
|  | // Implicit conversion to bool shouldn't work. | 
|  | /*{ | 
|  | ScopedInt a(kFirst, traits); | 
|  | bool result = a; | 
|  | }*/ | 
|  | } | 
|  | #endif | 
|  |  | 
|  | }  // namespace base |