123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- // 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 <memory>
- #include <unordered_map>
- #include <unordered_set>
- #include <utility>
- #include <vector>
- #include "base/containers/contains.h"
- #include "build/build_config.h"
- #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;
- };
- using ScopedInt = ScopedGeneric<int, IntTraits>;
- } // 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();
- // 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());
- }
- }
- TEST(ScopedGenericTest, Receive) {
- std::vector<int> values_freed;
- IntTraits traits(&values_freed);
- auto a = std::make_unique<ScopedInt>(123, traits);
- EXPECT_EQ(123, a->get());
- {
- ScopedInt::Receiver r(*a);
- EXPECT_EQ(123, a->get());
- *r.get() = 456;
- EXPECT_EQ(123, a->get());
- }
- EXPECT_EQ(456, a->get());
- {
- ScopedInt::Receiver r(*a);
- EXPECT_DEATH_IF_SUPPORTED(a.reset(), "");
- EXPECT_DEATH_IF_SUPPORTED(ScopedInt::Receiver(*a).get(), "");
- }
- }
- namespace {
- struct TrackedIntTraits : public ScopedGenericOwnershipTracking {
- using OwnerMap =
- std::unordered_map<int, const ScopedGeneric<int, TrackedIntTraits>*>;
- TrackedIntTraits(std::unordered_set<int>* freed, OwnerMap* owners)
- : freed(freed), owners(owners) {}
- static int InvalidValue() { return -1; }
- void Free(int value) {
- auto it = owners->find(value);
- ASSERT_EQ(owners->end(), it);
- ASSERT_EQ(0U, freed->count(value));
- freed->insert(value);
- }
- void Acquire(const ScopedGeneric<int, TrackedIntTraits>& owner, int value) {
- auto it = owners->find(value);
- ASSERT_EQ(owners->end(), it);
- (*owners)[value] = &owner;
- }
- void Release(const ScopedGeneric<int, TrackedIntTraits>& owner, int value) {
- auto it = owners->find(value);
- ASSERT_NE(owners->end(), it);
- owners->erase(it);
- }
- std::unordered_set<int>* freed;
- OwnerMap* owners;
- };
- using ScopedTrackedInt = ScopedGeneric<int, TrackedIntTraits>;
- } // namespace
- TEST(ScopedGenericTest, OwnershipTracking) {
- TrackedIntTraits::OwnerMap owners;
- std::unordered_set<int> freed;
- TrackedIntTraits traits(&freed, &owners);
- #define ASSERT_OWNED(value, owner) \
- ASSERT_TRUE(base::Contains(owners, value)); \
- ASSERT_EQ(&owner, owners[value]); \
- ASSERT_FALSE(base::Contains(freed, value))
- #define ASSERT_UNOWNED(value) \
- ASSERT_FALSE(base::Contains(owners, value)); \
- ASSERT_FALSE(base::Contains(freed, value))
- #define ASSERT_FREED(value) \
- ASSERT_FALSE(base::Contains(owners, value)); \
- ASSERT_TRUE(base::Contains(freed, value))
- // Constructor.
- {
- {
- ScopedTrackedInt a(0, traits);
- ASSERT_OWNED(0, a);
- }
- ASSERT_FREED(0);
- }
- owners.clear();
- freed.clear();
- // Reset.
- {
- ScopedTrackedInt a(0, traits);
- ASSERT_OWNED(0, a);
- a.reset(1);
- ASSERT_FREED(0);
- ASSERT_OWNED(1, a);
- a.reset();
- ASSERT_FREED(0);
- ASSERT_FREED(1);
- }
- owners.clear();
- freed.clear();
- // Release.
- {
- {
- ScopedTrackedInt a(0, traits);
- ASSERT_OWNED(0, a);
- int released = a.release();
- ASSERT_EQ(0, released);
- ASSERT_UNOWNED(0);
- }
- ASSERT_UNOWNED(0);
- }
- owners.clear();
- freed.clear();
- // Move constructor.
- {
- ScopedTrackedInt a(0, traits);
- ASSERT_OWNED(0, a);
- {
- ScopedTrackedInt b(std::move(a));
- ASSERT_OWNED(0, b);
- }
- ASSERT_FREED(0);
- }
- owners.clear();
- freed.clear();
- // Move assignment.
- {
- {
- ScopedTrackedInt a(0, traits);
- ScopedTrackedInt b(1, traits);
- ASSERT_OWNED(0, a);
- ASSERT_OWNED(1, b);
- a = std::move(b);
- ASSERT_OWNED(1, a);
- ASSERT_FREED(0);
- }
- ASSERT_FREED(1);
- }
- owners.clear();
- freed.clear();
- #undef ASSERT_OWNED
- #undef ASSERT_UNOWNED
- #undef ASSERT_FREED
- }
- // 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
|