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