779 lines
20 KiB
C++
779 lines
20 KiB
C++
|
/*
|
||
|
* Copyright (C) 2016 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#include "gtest/gtest.h"
|
||
|
|
||
|
#ifdef GTEST
|
||
|
#include "chre/platform/linux/expect_assert.h"
|
||
|
#endif
|
||
|
|
||
|
#include "chre/platform/assert.h"
|
||
|
#include "chre/util/dynamic_vector.h"
|
||
|
#include "chre/util/macros.h"
|
||
|
|
||
|
#include <stdint.h>
|
||
|
|
||
|
using chre::DynamicVector;
|
||
|
|
||
|
namespace {
|
||
|
constexpr int kMaxTestCapacity = 10;
|
||
|
int gDestructorCount[kMaxTestCapacity];
|
||
|
|
||
|
class DestructorCounter {
|
||
|
public:
|
||
|
~DestructorCounter() {
|
||
|
if (mValue >= 0) {
|
||
|
gDestructorCount[mValue]++;
|
||
|
}
|
||
|
};
|
||
|
void setValue(int value) {
|
||
|
mValue = value;
|
||
|
}
|
||
|
int getValue() {
|
||
|
return mValue;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
int mValue = -1;
|
||
|
};
|
||
|
|
||
|
void resetDestructorCounts() {
|
||
|
for (size_t i = 0; i < ARRAY_SIZE(gDestructorCount); i++) {
|
||
|
gDestructorCount[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
} // namespace
|
||
|
|
||
|
TEST(DynamicVector, EmptyByDefault) {
|
||
|
DynamicVector<int> vector;
|
||
|
EXPECT_EQ(vector.data(), nullptr);
|
||
|
EXPECT_TRUE(vector.empty());
|
||
|
EXPECT_EQ(vector.size(), 0);
|
||
|
EXPECT_EQ(vector.capacity(), 0);
|
||
|
vector.clear();
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, PushBackAndRead) {
|
||
|
DynamicVector<int> vector;
|
||
|
ASSERT_TRUE(vector.push_back(0x1337));
|
||
|
EXPECT_EQ(vector.size(), 1);
|
||
|
EXPECT_EQ(vector.capacity(), 1);
|
||
|
EXPECT_EQ(vector.data(), &vector[0]);
|
||
|
EXPECT_FALSE(vector.empty());
|
||
|
EXPECT_EQ(vector[0], 0x1337);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, PushBackReserveAndReadTrivialType) {
|
||
|
DynamicVector<int> vector;
|
||
|
ASSERT_TRUE(vector.emplace_back(0x1337));
|
||
|
ASSERT_TRUE(vector.push_back(0xface));
|
||
|
int x = 0xcafe;
|
||
|
ASSERT_TRUE(vector.push_back(std::move(x)));
|
||
|
ASSERT_TRUE(vector.insert(vector.size(), 0xd00d));
|
||
|
EXPECT_EQ(vector.size(), 4);
|
||
|
EXPECT_EQ(vector.capacity(), 4);
|
||
|
EXPECT_EQ(vector[0], 0x1337);
|
||
|
EXPECT_EQ(vector[1], 0xface);
|
||
|
EXPECT_EQ(vector[2], 0xcafe);
|
||
|
EXPECT_EQ(vector[3], 0xd00d);
|
||
|
|
||
|
ASSERT_TRUE(vector.reserve(8));
|
||
|
EXPECT_EQ(vector.size(), 4);
|
||
|
EXPECT_EQ(vector.capacity(), 8);
|
||
|
EXPECT_EQ(vector[0], 0x1337);
|
||
|
EXPECT_EQ(vector[1], 0xface);
|
||
|
EXPECT_EQ(vector[2], 0xcafe);
|
||
|
EXPECT_EQ(vector[3], 0xd00d);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, CompareEqual) {
|
||
|
DynamicVector<int> lhs;
|
||
|
ASSERT_TRUE(lhs.push_back(0x1337));
|
||
|
ASSERT_TRUE(lhs.push_back(0xface));
|
||
|
DynamicVector<int> rhs;
|
||
|
ASSERT_TRUE(rhs.push_back(0x1337));
|
||
|
ASSERT_TRUE(rhs.push_back(0xface));
|
||
|
|
||
|
ASSERT_EQ(lhs, rhs); // equal vectors
|
||
|
|
||
|
ASSERT_TRUE(lhs.push_back(0xb00c));
|
||
|
ASSERT_FALSE(lhs == rhs); // different size
|
||
|
|
||
|
ASSERT_TRUE(rhs.push_back(0xc00b));
|
||
|
ASSERT_FALSE(lhs == rhs); // equal size different elements
|
||
|
}
|
||
|
|
||
|
constexpr int kConstructedMagic = 0xdeadbeef;
|
||
|
|
||
|
class MovableButNonCopyable : public chre::NonCopyable {
|
||
|
public:
|
||
|
MovableButNonCopyable(int value) : mValue(value) {}
|
||
|
|
||
|
MovableButNonCopyable(MovableButNonCopyable &&other) {
|
||
|
mValue = other.mValue;
|
||
|
other.mValue = -1;
|
||
|
}
|
||
|
|
||
|
MovableButNonCopyable &operator=(MovableButNonCopyable &&other) {
|
||
|
CHRE_ASSERT(mMagic == kConstructedMagic);
|
||
|
mValue = other.mValue;
|
||
|
other.mValue = -1;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
int getValue() const {
|
||
|
return mValue;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
int mMagic = kConstructedMagic;
|
||
|
int mValue;
|
||
|
};
|
||
|
|
||
|
TEST(DynamicVector, PushBackReserveAndReadMovableButNonCopyable) {
|
||
|
DynamicVector<MovableButNonCopyable> vector;
|
||
|
ASSERT_TRUE(vector.emplace_back(0x1337));
|
||
|
ASSERT_TRUE(vector.emplace_back(0xface));
|
||
|
MovableButNonCopyable mbnc(0xcafe);
|
||
|
ASSERT_TRUE(vector.push_back(std::move(mbnc)));
|
||
|
EXPECT_EQ(mbnc.getValue(), -1);
|
||
|
MovableButNonCopyable mbnc2(0xd00d);
|
||
|
ASSERT_TRUE(vector.insert(vector.size(), std::move(mbnc2)));
|
||
|
EXPECT_EQ(mbnc2.getValue(), -1);
|
||
|
|
||
|
ASSERT_TRUE(vector.reserve(8));
|
||
|
EXPECT_EQ(vector[0].getValue(), 0x1337);
|
||
|
EXPECT_EQ(vector[1].getValue(), 0xface);
|
||
|
EXPECT_EQ(vector[2].getValue(), 0xcafe);
|
||
|
EXPECT_EQ(vector[3].getValue(), 0xd00d);
|
||
|
EXPECT_EQ(vector.size(), 4);
|
||
|
EXPECT_EQ(vector.capacity(), 8);
|
||
|
}
|
||
|
|
||
|
class CopyableButNonMovable {
|
||
|
public:
|
||
|
CopyableButNonMovable(int value) : mValue(value) {}
|
||
|
|
||
|
CopyableButNonMovable(const CopyableButNonMovable &other) {
|
||
|
mValue = other.mValue;
|
||
|
}
|
||
|
|
||
|
CopyableButNonMovable &operator=(const CopyableButNonMovable &other) {
|
||
|
CHRE_ASSERT(mMagic == kConstructedMagic);
|
||
|
mValue = other.mValue;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
CopyableButNonMovable(CopyableButNonMovable &&other) = delete;
|
||
|
CopyableButNonMovable &operator=(CopyableButNonMovable &&other) = delete;
|
||
|
|
||
|
int getValue() const {
|
||
|
return mValue;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
int mMagic = kConstructedMagic;
|
||
|
int mValue;
|
||
|
};
|
||
|
|
||
|
TEST(DynamicVector, PushBackReserveAndReadCopyableButNonMovable) {
|
||
|
DynamicVector<CopyableButNonMovable> vector;
|
||
|
ASSERT_TRUE(vector.emplace_back(0x1337));
|
||
|
ASSERT_TRUE(vector.emplace_back(0xface));
|
||
|
CopyableButNonMovable cbnm(0xcafe);
|
||
|
ASSERT_TRUE(vector.push_back(cbnm));
|
||
|
CopyableButNonMovable cbnm2(0xd00d);
|
||
|
ASSERT_TRUE(vector.insert(vector.size(), cbnm2));
|
||
|
|
||
|
ASSERT_TRUE(vector.reserve(8));
|
||
|
EXPECT_EQ(vector[0].getValue(), 0x1337);
|
||
|
EXPECT_EQ(vector[1].getValue(), 0xface);
|
||
|
EXPECT_EQ(vector[2].getValue(), 0xcafe);
|
||
|
EXPECT_EQ(vector[3].getValue(), 0xd00d);
|
||
|
EXPECT_EQ(vector.size(), 4);
|
||
|
EXPECT_EQ(vector.capacity(), 8);
|
||
|
}
|
||
|
|
||
|
class MovableAndCopyable {
|
||
|
public:
|
||
|
MovableAndCopyable(int value) : mValue(value) {}
|
||
|
|
||
|
MovableAndCopyable(const MovableAndCopyable &other) {
|
||
|
mValue = other.mValue;
|
||
|
}
|
||
|
|
||
|
MovableAndCopyable(MovableAndCopyable &&other) {
|
||
|
// The move constructor multiplies the value by 2 so that we can see that it
|
||
|
// was used
|
||
|
mValue = other.mValue * 2;
|
||
|
}
|
||
|
|
||
|
MovableAndCopyable &operator=(const MovableAndCopyable &other) {
|
||
|
CHRE_ASSERT(mMagic == kConstructedMagic);
|
||
|
mValue = other.mValue;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
MovableAndCopyable &operator=(MovableAndCopyable &&other) {
|
||
|
assert(mMagic == kConstructedMagic);
|
||
|
mValue = other.mValue * 2;
|
||
|
other.mValue = -1;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
int getValue() const {
|
||
|
return mValue;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
int mMagic = kConstructedMagic;
|
||
|
int mValue;
|
||
|
};
|
||
|
|
||
|
TEST(DynamicVector, ReservePrefersMove) {
|
||
|
// Ensure that preference is given to std::move in reserve()
|
||
|
DynamicVector<MovableAndCopyable> vector;
|
||
|
|
||
|
// Reserve enough space for the first two elements.
|
||
|
ASSERT_TRUE(vector.reserve(2));
|
||
|
ASSERT_TRUE(vector.emplace_back(1000));
|
||
|
ASSERT_TRUE(vector.emplace_back(2000));
|
||
|
|
||
|
// Reserve more than enough space causing a move to be required.
|
||
|
ASSERT_TRUE(vector.reserve(4));
|
||
|
|
||
|
// Move on this type results in a multiplication by 2. Verify that all
|
||
|
// elements have been multiplied by 2.
|
||
|
EXPECT_EQ(vector[0].getValue(), 2000);
|
||
|
EXPECT_EQ(vector[1].getValue(), 4000);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A simple test helper object to count number of construction and destructions.
|
||
|
*/
|
||
|
class Foo {
|
||
|
public:
|
||
|
/**
|
||
|
* Construct an object storing a simple integer. Increment the number of
|
||
|
* objects that have been constructed of this type.
|
||
|
*/
|
||
|
Foo(int value) : value(value) {
|
||
|
sConstructedCounter++;
|
||
|
}
|
||
|
|
||
|
Foo(const Foo &other) {
|
||
|
value = other.value;
|
||
|
sConstructedCounter++;
|
||
|
}
|
||
|
|
||
|
Foo(Foo &&other) = delete;
|
||
|
|
||
|
/**
|
||
|
* Tear down the object, decrementing the number of objects that have been
|
||
|
* constructed of this type.
|
||
|
*/
|
||
|
~Foo() {
|
||
|
sConstructedCounter--;
|
||
|
}
|
||
|
|
||
|
//! The number of objects of this type that have been constructed.
|
||
|
static ssize_t sConstructedCounter;
|
||
|
|
||
|
//! The value stored in the object to verify the contents of this object after
|
||
|
//! construction.
|
||
|
int value;
|
||
|
};
|
||
|
|
||
|
//! Storage for the Foo reference counter.
|
||
|
ssize_t Foo::sConstructedCounter = 0;
|
||
|
|
||
|
TEST(DynamicVector, EmplaceBackAndDestruct) {
|
||
|
Foo::sConstructedCounter = 0;
|
||
|
{
|
||
|
DynamicVector<Foo> vector;
|
||
|
ASSERT_TRUE(vector.emplace_back(1000));
|
||
|
ASSERT_TRUE(vector.emplace_back(2000));
|
||
|
ASSERT_TRUE(vector.emplace_back(3000));
|
||
|
ASSERT_TRUE(vector.emplace_back(4000));
|
||
|
|
||
|
ASSERT_EQ(vector[0].value, 1000);
|
||
|
ASSERT_EQ(vector[1].value, 2000);
|
||
|
ASSERT_EQ(vector[2].value, 3000);
|
||
|
ASSERT_EQ(vector[3].value, 4000);
|
||
|
|
||
|
EXPECT_EQ(Foo::sConstructedCounter, 4);
|
||
|
}
|
||
|
|
||
|
EXPECT_EQ(Foo::sConstructedCounter, 0);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, InsertEmpty) {
|
||
|
DynamicVector<int> vector;
|
||
|
EXPECT_CHRE_ASSERT(EXPECT_FALSE(vector.insert(1, 0x1337)));
|
||
|
|
||
|
// Insert to empty vector
|
||
|
ASSERT_TRUE(vector.insert(0, 0x1337));
|
||
|
EXPECT_EQ(vector[0], 0x1337);
|
||
|
|
||
|
// Insert at end triggering grow
|
||
|
ASSERT_EQ(vector.capacity(), 1);
|
||
|
EXPECT_TRUE(vector.insert(1, 0xface));
|
||
|
EXPECT_EQ(vector[0], 0x1337);
|
||
|
EXPECT_EQ(vector[1], 0xface);
|
||
|
|
||
|
// Insert at beginning triggering grow
|
||
|
ASSERT_EQ(vector.capacity(), 2);
|
||
|
EXPECT_TRUE(vector.insert(0, 0xcafe));
|
||
|
EXPECT_EQ(vector[0], 0xcafe);
|
||
|
EXPECT_EQ(vector[1], 0x1337);
|
||
|
EXPECT_EQ(vector[2], 0xface);
|
||
|
|
||
|
// Insert at middle with spare capacity
|
||
|
ASSERT_EQ(vector.capacity(), 4);
|
||
|
EXPECT_TRUE(vector.insert(1, 0xdead));
|
||
|
EXPECT_EQ(vector[0], 0xcafe);
|
||
|
EXPECT_EQ(vector[1], 0xdead);
|
||
|
EXPECT_EQ(vector[2], 0x1337);
|
||
|
EXPECT_EQ(vector[3], 0xface);
|
||
|
|
||
|
// Insert at middle triggering grow
|
||
|
ASSERT_EQ(vector.capacity(), 4);
|
||
|
EXPECT_TRUE(vector.insert(2, 0xbeef));
|
||
|
EXPECT_EQ(vector[0], 0xcafe);
|
||
|
EXPECT_EQ(vector[1], 0xdead);
|
||
|
EXPECT_EQ(vector[2], 0xbeef);
|
||
|
EXPECT_EQ(vector[3], 0x1337);
|
||
|
EXPECT_EQ(vector[4], 0xface);
|
||
|
|
||
|
// Insert at beginning with spare capacity
|
||
|
ASSERT_EQ(vector.capacity(), 8);
|
||
|
ASSERT_EQ(vector.size(), 5);
|
||
|
EXPECT_TRUE(vector.insert(0, 0xabad));
|
||
|
EXPECT_EQ(vector[0], 0xabad);
|
||
|
EXPECT_EQ(vector[1], 0xcafe);
|
||
|
EXPECT_EQ(vector[2], 0xdead);
|
||
|
EXPECT_EQ(vector[3], 0xbeef);
|
||
|
EXPECT_EQ(vector[4], 0x1337);
|
||
|
EXPECT_EQ(vector[5], 0xface);
|
||
|
|
||
|
// Insert at end with spare capacity
|
||
|
ASSERT_EQ(vector.size(), 6);
|
||
|
EXPECT_TRUE(vector.insert(vector.size(), 0xc0de));
|
||
|
EXPECT_EQ(vector[0], 0xabad);
|
||
|
EXPECT_EQ(vector[1], 0xcafe);
|
||
|
EXPECT_EQ(vector[2], 0xdead);
|
||
|
EXPECT_EQ(vector[3], 0xbeef);
|
||
|
EXPECT_EQ(vector[4], 0x1337);
|
||
|
EXPECT_EQ(vector[5], 0xface);
|
||
|
EXPECT_EQ(vector[6], 0xc0de);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, PushBackInsertInMiddleAndRead) {
|
||
|
DynamicVector<int> vector;
|
||
|
ASSERT_TRUE(vector.push_back(0x1337));
|
||
|
ASSERT_TRUE(vector.push_back(0xface));
|
||
|
ASSERT_TRUE(vector.push_back(0xcafe));
|
||
|
ASSERT_TRUE(vector.insert(1, 0xbeef));
|
||
|
|
||
|
ASSERT_EQ(vector[0], 0x1337);
|
||
|
ASSERT_EQ(vector[1], 0xbeef);
|
||
|
ASSERT_EQ(vector[2], 0xface);
|
||
|
ASSERT_EQ(vector[3], 0xcafe);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, PushBackAndErase) {
|
||
|
DynamicVector<int> vector;
|
||
|
ASSERT_TRUE(vector.push_back(0x1337));
|
||
|
ASSERT_TRUE(vector.push_back(0xcafe));
|
||
|
ASSERT_TRUE(vector.push_back(0xbeef));
|
||
|
ASSERT_TRUE(vector.push_back(0xface));
|
||
|
|
||
|
vector.erase(1);
|
||
|
|
||
|
ASSERT_EQ(vector[0], 0x1337);
|
||
|
ASSERT_EQ(vector[1], 0xbeef);
|
||
|
ASSERT_EQ(vector[2], 0xface);
|
||
|
ASSERT_EQ(vector.size(), 3);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, FindEmpty) {
|
||
|
DynamicVector<int> vector;
|
||
|
ASSERT_EQ(vector.find(0), 0);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, FindWithElements) {
|
||
|
DynamicVector<int> vector;
|
||
|
ASSERT_TRUE(vector.push_back(0x1337));
|
||
|
ASSERT_TRUE(vector.push_back(0xcafe));
|
||
|
ASSERT_TRUE(vector.push_back(0xbeef));
|
||
|
|
||
|
ASSERT_EQ(vector.find(0x1337), 0);
|
||
|
ASSERT_EQ(vector.find(0xcafe), 1);
|
||
|
ASSERT_EQ(vector.find(0xbeef), 2);
|
||
|
ASSERT_EQ(vector.find(1000), 3);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, EraseDestructorCalled) {
|
||
|
resetDestructorCounts();
|
||
|
|
||
|
DynamicVector<DestructorCounter> vector;
|
||
|
vector.reserve(4);
|
||
|
for (size_t i = 0; i < 4; ++i) {
|
||
|
vector.emplace_back();
|
||
|
vector[i].setValue(i);
|
||
|
}
|
||
|
|
||
|
// last item before erase is '3'.
|
||
|
vector.erase(1);
|
||
|
EXPECT_EQ(0, gDestructorCount[0]);
|
||
|
EXPECT_EQ(0, gDestructorCount[1]);
|
||
|
EXPECT_EQ(0, gDestructorCount[2]);
|
||
|
EXPECT_EQ(1, gDestructorCount[3]);
|
||
|
|
||
|
// last item before erase is still '3'.
|
||
|
vector.erase(2);
|
||
|
EXPECT_EQ(0, gDestructorCount[0]);
|
||
|
EXPECT_EQ(0, gDestructorCount[1]);
|
||
|
EXPECT_EQ(0, gDestructorCount[2]);
|
||
|
EXPECT_EQ(2, gDestructorCount[3]);
|
||
|
|
||
|
// last item before erase is now '2'.
|
||
|
vector.erase(0);
|
||
|
EXPECT_EQ(0, gDestructorCount[0]);
|
||
|
EXPECT_EQ(0, gDestructorCount[1]);
|
||
|
EXPECT_EQ(1, gDestructorCount[2]);
|
||
|
EXPECT_EQ(2, gDestructorCount[3]);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, Clear) {
|
||
|
resetDestructorCounts();
|
||
|
|
||
|
DynamicVector<DestructorCounter> vector;
|
||
|
vector.reserve(4);
|
||
|
for (size_t i = 0; i < 4; ++i) {
|
||
|
vector.emplace_back();
|
||
|
vector[i].setValue(i);
|
||
|
}
|
||
|
|
||
|
vector.clear();
|
||
|
EXPECT_EQ(vector.size(), 0);
|
||
|
EXPECT_EQ(vector.capacity(), 4);
|
||
|
|
||
|
for (size_t i = 0; i < 4; ++i) {
|
||
|
EXPECT_EQ(gDestructorCount[i], 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVectorDeathTest, SwapWithInvalidIndex) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0x1337);
|
||
|
vector.push_back(0xcafe);
|
||
|
EXPECT_DEATH(vector.swap(0, 2), "");
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVectorDeathTest, SwapWithInvalidIndices) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0x1337);
|
||
|
vector.push_back(0xcafe);
|
||
|
EXPECT_DEATH(vector.swap(2, 3), "");
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, Swap) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0x1337);
|
||
|
vector.push_back(0xcafe);
|
||
|
|
||
|
vector.swap(0, 1);
|
||
|
EXPECT_EQ(vector[0], 0xcafe);
|
||
|
EXPECT_EQ(vector[1], 0x1337);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, BackFront) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0x1337);
|
||
|
EXPECT_EQ(vector.front(), 0x1337);
|
||
|
EXPECT_EQ(vector.back(), 0x1337);
|
||
|
vector.push_back(0xcafe);
|
||
|
EXPECT_EQ(vector.front(), 0x1337);
|
||
|
EXPECT_EQ(vector.back(), 0xcafe);
|
||
|
vector.erase(0);
|
||
|
EXPECT_EQ(vector.front(), 0xcafe);
|
||
|
EXPECT_EQ(vector.back(), 0xcafe);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, Iterator) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0);
|
||
|
vector.push_back(1);
|
||
|
vector.push_back(2);
|
||
|
|
||
|
size_t index = 0;
|
||
|
for (DynamicVector<int>::iterator it = vector.begin(); it != vector.end();
|
||
|
++it) {
|
||
|
EXPECT_EQ(vector[index++], *it);
|
||
|
}
|
||
|
|
||
|
DynamicVector<int>::iterator it = vector.begin() + vector.size() - 1;
|
||
|
EXPECT_EQ(vector[vector.size() - 1], *it);
|
||
|
|
||
|
it = vector.begin() + vector.size();
|
||
|
EXPECT_TRUE(it == vector.end());
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, ConstIterator) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0);
|
||
|
vector.push_back(1);
|
||
|
vector.push_back(2);
|
||
|
|
||
|
size_t index = 0;
|
||
|
for (DynamicVector<int>::const_iterator cit = vector.cbegin();
|
||
|
cit != vector.cend(); ++cit) {
|
||
|
EXPECT_EQ(vector[index++], *cit);
|
||
|
}
|
||
|
|
||
|
DynamicVector<int>::const_iterator cit = vector.cbegin() + vector.size() - 1;
|
||
|
EXPECT_EQ(vector[vector.size() - 1], *cit);
|
||
|
|
||
|
cit = vector.cbegin() + vector.size();
|
||
|
EXPECT_TRUE(cit == vector.cend());
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, IteratorAndPushBack) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0);
|
||
|
vector.push_back(1);
|
||
|
vector.push_back(2);
|
||
|
size_t oldCapacity = vector.capacity();
|
||
|
|
||
|
DynamicVector<int>::iterator it_b = vector.begin();
|
||
|
DynamicVector<int>::iterator it_e = vector.end();
|
||
|
|
||
|
vector.push_back(3);
|
||
|
ASSERT_TRUE(oldCapacity == vector.capacity());
|
||
|
|
||
|
size_t index = 0;
|
||
|
for (; it_b != it_e; ++it_b) {
|
||
|
EXPECT_EQ(vector[index++], *it_b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, IteratorAndEmplaceBack) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0);
|
||
|
vector.push_back(1);
|
||
|
vector.push_back(2);
|
||
|
size_t oldCapacity = vector.capacity();
|
||
|
|
||
|
DynamicVector<int>::iterator it_b = vector.begin();
|
||
|
DynamicVector<int>::iterator it_e = vector.end();
|
||
|
|
||
|
vector.emplace_back(3);
|
||
|
ASSERT_TRUE(oldCapacity == vector.capacity());
|
||
|
|
||
|
size_t index = 0;
|
||
|
for (; it_b != it_e; ++it_b) {
|
||
|
EXPECT_EQ(vector[index++], *it_b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, IteratorAndReserve) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0);
|
||
|
vector.push_back(1);
|
||
|
vector.push_back(2);
|
||
|
size_t oldCapacity = vector.capacity();
|
||
|
|
||
|
DynamicVector<int>::iterator it_b = vector.begin();
|
||
|
DynamicVector<int>::iterator it_e = vector.end();
|
||
|
|
||
|
vector.reserve(oldCapacity);
|
||
|
ASSERT_TRUE(oldCapacity == vector.capacity());
|
||
|
|
||
|
size_t index = 0;
|
||
|
for (; it_b != it_e; ++it_b) {
|
||
|
EXPECT_EQ(vector[index++], *it_b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, IteratorAndInsert) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0);
|
||
|
vector.push_back(1);
|
||
|
vector.push_back(2);
|
||
|
size_t oldCapacity = vector.capacity();
|
||
|
|
||
|
DynamicVector<int>::iterator it_b = vector.begin();
|
||
|
|
||
|
vector.insert(2, 3);
|
||
|
ASSERT_TRUE(oldCapacity == vector.capacity());
|
||
|
|
||
|
size_t index = 0;
|
||
|
while (index < 2) {
|
||
|
EXPECT_EQ(vector[index++], *it_b++);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, IteratorAndErase) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0);
|
||
|
vector.push_back(1);
|
||
|
vector.push_back(2);
|
||
|
|
||
|
DynamicVector<int>::iterator it_b = vector.begin();
|
||
|
|
||
|
vector.erase(2);
|
||
|
|
||
|
size_t index = 0;
|
||
|
while (index < 2) {
|
||
|
EXPECT_EQ(vector[index++], *it_b++);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, IteratorAndSwap) {
|
||
|
DynamicVector<int> vector;
|
||
|
vector.push_back(0);
|
||
|
vector.push_back(1);
|
||
|
vector.push_back(2);
|
||
|
vector.push_back(3);
|
||
|
|
||
|
DynamicVector<int>::iterator it_b = vector.begin();
|
||
|
|
||
|
vector.swap(1, 3);
|
||
|
|
||
|
size_t index = 0;
|
||
|
while (index < 4) {
|
||
|
if (index != 1 && index != 3) {
|
||
|
EXPECT_EQ(vector[index], *it_b);
|
||
|
}
|
||
|
index++;
|
||
|
it_b++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, MoveConstruct) {
|
||
|
DynamicVector<int> vector;
|
||
|
ASSERT_TRUE(vector.push_back(0));
|
||
|
ASSERT_TRUE(vector.push_back(1));
|
||
|
ASSERT_TRUE(vector.push_back(2));
|
||
|
|
||
|
DynamicVector<int> movedVector(std::move(vector));
|
||
|
EXPECT_EQ(vector.data(), nullptr);
|
||
|
EXPECT_NE(movedVector.data(), nullptr);
|
||
|
EXPECT_EQ(vector.size(), 0);
|
||
|
EXPECT_EQ(movedVector.size(), 3);
|
||
|
EXPECT_EQ(vector.capacity(), 0);
|
||
|
EXPECT_EQ(movedVector.capacity(), 4);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, MoveAssignmentConstruct) {
|
||
|
DynamicVector<int> vector;
|
||
|
ASSERT_TRUE(vector.push_back(0));
|
||
|
ASSERT_TRUE(vector.push_back(1));
|
||
|
ASSERT_TRUE(vector.push_back(2));
|
||
|
|
||
|
DynamicVector<int> movedVector;
|
||
|
movedVector = std::move(vector);
|
||
|
EXPECT_EQ(vector.data(), nullptr);
|
||
|
EXPECT_NE(movedVector.data(), nullptr);
|
||
|
EXPECT_EQ(vector.size(), 0);
|
||
|
EXPECT_EQ(movedVector.size(), 3);
|
||
|
EXPECT_EQ(vector.capacity(), 0);
|
||
|
EXPECT_EQ(movedVector.capacity(), 4);
|
||
|
}
|
||
|
|
||
|
TEST(DynamicVector, PrepareForPush) {
|
||
|
DynamicVector<int> vector;
|
||
|
EXPECT_EQ(vector.size(), 0);
|
||
|
EXPECT_EQ(vector.capacity(), 0);
|
||
|
|
||
|
// Perform an initial prepareForPush operation which causes a size of one.
|
||
|
ASSERT_TRUE(vector.prepareForPush());
|
||
|
EXPECT_EQ(vector.size(), 0);
|
||
|
EXPECT_EQ(vector.capacity(), 1);
|
||
|
ASSERT_TRUE(vector.push_back(0xcafe));
|
||
|
EXPECT_EQ(vector.size(), 1);
|
||
|
EXPECT_EQ(vector.capacity(), 1);
|
||
|
|
||
|
// Verify that it becomes larger
|
||
|
ASSERT_TRUE(vector.prepareForPush());
|
||
|
EXPECT_EQ(vector[0], 0xcafe);
|
||
|
EXPECT_EQ(vector.size(), 1);
|
||
|
EXPECT_EQ(vector.capacity(), 2);
|
||
|
|
||
|
// The vector should not become any larger than necessary.
|
||
|
ASSERT_TRUE(vector.prepareForPush());
|
||
|
EXPECT_EQ(vector[0], 0xcafe);
|
||
|
EXPECT_EQ(vector.size(), 1);
|
||
|
EXPECT_EQ(vector.capacity(), 2);
|
||
|
}
|
||
|
|
||
|
// TODO: Add a test for when memory allocation returns nullptr.
|
||
|
|
||
|
TEST(DynamicVector, PopBack) {
|
||
|
DynamicVector<int> vector;
|
||
|
constexpr size_t kSize = 4;
|
||
|
for (int i = 0; i < kSize; i++) {
|
||
|
vector.push_back(i);
|
||
|
}
|
||
|
|
||
|
for (int i = kSize - 1; i >= 0; i--) {
|
||
|
EXPECT_EQ(vector.back(), i);
|
||
|
vector.pop_back();
|
||
|
}
|
||
|
EXPECT_TRUE(vector.empty());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A test class to default construct an integer with an incrementing value.
|
||
|
*/
|
||
|
struct FancyInt {
|
||
|
static int index;
|
||
|
int value;
|
||
|
|
||
|
FancyInt() : value(index++) {}
|
||
|
};
|
||
|
|
||
|
int FancyInt::index = 0;
|
||
|
|
||
|
TEST(DynamicVector, Resize) {
|
||
|
DynamicVector<FancyInt> vector;
|
||
|
ASSERT_TRUE(vector.resize(4));
|
||
|
ASSERT_EQ(vector.size(), 4);
|
||
|
|
||
|
EXPECT_EQ(vector[0].value, 0);
|
||
|
EXPECT_EQ(vector[1].value, 1);
|
||
|
EXPECT_EQ(vector[2].value, 2);
|
||
|
EXPECT_EQ(vector[3].value, 3);
|
||
|
|
||
|
ASSERT_TRUE(vector.resize(2));
|
||
|
ASSERT_EQ(vector.size(), 2);
|
||
|
|
||
|
EXPECT_EQ(vector[0].value, 0);
|
||
|
EXPECT_EQ(vector[1].value, 1);
|
||
|
|
||
|
ASSERT_TRUE(vector.resize(4));
|
||
|
ASSERT_EQ(vector.size(), 4);
|
||
|
|
||
|
EXPECT_EQ(vector[0].value, 0);
|
||
|
EXPECT_EQ(vector[1].value, 1);
|
||
|
EXPECT_EQ(vector[2].value, 4);
|
||
|
EXPECT_EQ(vector[3].value, 5);
|
||
|
|
||
|
// Reset index for future tests
|
||
|
FancyInt::index = 0;
|
||
|
}
|