blob: 4efc225948bf5ea8e4fa57c7c48e493e4cacd29c [file] [log] [blame]
// Copyright 2014 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/base/containers/PointerSet.h"
#include <gtest/gtest.h>
#include <stdlib.h>
namespace android {
namespace base {
namespace {
class Foo {
public:
Foo() : mValue(0) {}
explicit Foo(int value) : mValue(value) {}
int value() const { return mValue; }
private:
int mValue;
};
class ScopedFooSet : public PointerSet<Foo> {
public:
~ScopedFooSet() {
Iterator iter(this);
while (iter.hasNext()) {
delete iter.next();
}
}
};
} // namespace
TEST(PointerSet, init) {
PointerSet<Foo> set;
EXPECT_TRUE(set.empty());
EXPECT_EQ(0U, set.size());
}
TEST(PointerSet, empty) {
ScopedFooSet set;
EXPECT_TRUE(set.empty());
Foo* foo0 = new Foo(0);
set.add(foo0);
EXPECT_FALSE(set.empty());
set.remove(foo0);
EXPECT_TRUE(set.empty());
delete foo0;
}
TEST(PointerSet, add) {
ScopedFooSet set;
const size_t kCount = 100U;
for (size_t n = 0; n < kCount; ++n) {
set.add(new Foo(n));
EXPECT_EQ(n + 1U, set.size());
}
bool flags[kCount];
for (size_t n = 0; n < kCount; ++n) {
flags[n] = false;
}
Foo** array = set.toArray();
ASSERT_TRUE(array);
for (size_t n = 0; n < kCount; ++n) {
Foo* foo = array[n];
ASSERT_TRUE(foo);
EXPECT_FALSE(flags[foo->value()]);
flags[foo->value()] = true;
}
::free(array);
}
TEST(PointerSet, contains) {
ScopedFooSet set;
const size_t kCount = 100U;
Foo* foos[kCount];
for (size_t n = 0; n < kCount; ++n) {
foos[n] = new Foo(n);
set.add(foos[n]);
}
EXPECT_EQ(kCount, set.size());
for (size_t n = 0; n < kCount; ++n) {
EXPECT_TRUE(set.contains(foos[n])) << "Item #" << n;
}
}
TEST(PointerSet, remove) {
ScopedFooSet set;
const size_t kCount = 100U;
Foo* foos[kCount];
for (size_t n = 0; n < kCount; ++n) {
foos[n] = new Foo(n);
set.add(foos[n]);
}
EXPECT_EQ(kCount, set.size());
// Remove odd items from the set only.
for (size_t n = 0; n < kCount / 2U; ++n) {
Foo* item = foos[n * 2U + 1U];
EXPECT_TRUE(set.remove(item));
EXPECT_EQ(kCount - n - 1, set.size());
}
// Try to remove them again, check that this doesn't change the set.
for (size_t n = 0; n < kCount / 2U; ++n) {
Foo* item = foos[n * 2U + 1U];
EXPECT_FALSE(set.remove(item));
EXPECT_EQ(kCount / 2U, set.size());
}
// Check that even items remain in the set.
for (size_t n = 0; n < kCount / 2U; ++n) {
EXPECT_TRUE(set.contains(foos[n * 2U])) << "Item #" << n;
}
// Delete off items which are no longer in the scoped set.
for (size_t n = 0; n < kCount / 2U; ++n) {
delete foos[n * 2U + 1U];
}
}
TEST(PointerSet, clear) {
ScopedFooSet set;
const size_t kCount = 100U;
Foo* foos[kCount];
for (size_t n = 0; n < kCount; ++n) {
foos[n] = new Foo(n);
set.add(foos[n]);
}
EXPECT_EQ(kCount, set.size());
set.clear();
EXPECT_TRUE(set.empty());
EXPECT_EQ(0U, set.size());
for (size_t n = 0; n < kCount; ++n) {
EXPECT_FALSE(set.contains(foos[n])) << "Item #" << n;
}
for (size_t n = 0; n < kCount; ++n) {
delete foos[n];
}
}
TEST(PointerSet, Iterator) {
ScopedFooSet set;
const size_t kCount = 100U;
Foo* foos[kCount];
for (size_t n = 0; n < kCount; ++n) {
foos[n] = new Foo(n);
set.add(foos[n]);
}
EXPECT_EQ(kCount, set.size());
bool flags[kCount];
for (size_t n = 0; n < kCount; ++n) {
flags[n] = false;
}
PointerSet<Foo>::Iterator iter(&set);
for (size_t n = 0; n < kCount; ++n) {
EXPECT_TRUE(iter.hasNext());
Foo* foo = iter.next();
EXPECT_TRUE(foo);
ASSERT_LT(foo->value(), kCount);
EXPECT_FALSE(flags[foo->value()]) << "Item #" << foo->value();
flags[foo->value()] = true;
}
EXPECT_FALSE(iter.next());
}
} // namespace base
} // namespace android