| // 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 |