#include
#include
#include
#include
#include "pele/array.hpp"
using pele::Array;
// to silence "unused variable" warnings from the compiler
#define UNUSED(var) ((void)var)
TEST(ArrayTest, DefaultConstructor_IsOK) {
pele::Array v;
EXPECT_EQ(0u, v.size());
EXPECT_FALSE(v.data());
EXPECT_TRUE(v.empty());
}
TEST(ArrayTest, Constructor_HandlesPositiveInput) {
pele::Array v(6);
EXPECT_EQ(6u, v.size());
EXPECT_TRUE(v.data());
}
TEST(ArrayTest, Constructor_HandlesZero) {
pele::Array v(0);
EXPECT_EQ(0u, v.size());
EXPECT_TRUE(v.empty());
}
TEST(ArrayTest, Constructor_SetsValue) {
pele::Array v(6u, 10.);
EXPECT_EQ(6u, v.size());
for (int i = 0; i < 6; ++i) {
EXPECT_NEAR(v[i], 10., 1e-10);
}
}
TEST(ArrayTest, InitializerListConstructor_Works) {
const std::initializer_list l = {1, 2, 3, 4, 5, 6, 7, 8, 9};
const pele::Array x(l);
EXPECT_EQ(9u, x.size());
for (const unsigned int &i : l) {
EXPECT_EQ(i, x[i - 1]);
}
}
TEST(ArrayTest, CopyConstructor_WrapsCorrectly) {
// should wrap v
pele::Array v(6);
pele::Array v2(v);
EXPECT_EQ(v.data(), v2.data());
EXPECT_EQ(v.size(), v2.size());
}
TEST(ArrayTest, FreeWrappedArray_Works) {
// I discovered an error with this test
pele::Array v(6);
pele::Array v2(v);
pele::Array v3(v);
EXPECT_EQ(3, v.reference_count());
EXPECT_EQ(3, v2.reference_count());
v.free();
EXPECT_EQ(1, v.reference_count());
EXPECT_EQ(2, v2.reference_count());
EXPECT_EQ(2, v3.reference_count());
// ASSERT_THROW(pele::Array v3(v), std::runtime_error);
}
// TEST(ArrayTest, CopyConstructorEmptyArray_Fails){
// // should wrap v
// pele::Array v;
// ASSERT_THROW(pele::Array v2(v), std::runtime_error);
// }
TEST(ArrayTest, AssignmentOperator_WrapsCorrectly) {
// should wrap v
pele::Array v(6);
pele::Array v2;
v2 = v;
EXPECT_EQ(v.data(), v2.data());
EXPECT_EQ(v.size(), v2.size());
}
// TEST(ArrayTest, AssignmentOperatorEmptyArray_Fails){
// // This throwing an error is consistent with the logic, but I wish it
// didn't fail
// // Maybe someday we can change the logic so this won't have to fail
// pele::Array v;
// ASSERT_THROW(v = Array(), std::runtime_error);
// pele::Array v2;
// ASSERT_THROW(v = v2, std::runtime_error);
// }
TEST(ArrayTest, Wrap_Works) {
pele::Array v(6);
EXPECT_EQ(v.reference_count(), 1);
pele::Array v2;
v2.wrap(v);
EXPECT_EQ(v.data(), v2.data());
EXPECT_EQ(v.reference_count(), 2);
EXPECT_EQ(v2.reference_count(), v.reference_count());
}
// TEST(ArrayTest, WrapEmptyArray_Fails){
// // can't wrap an array with no data
// pele::Array v;
// pele::Array v2;
// ASSERT_THROW(v2.wrap(v), std::runtime_error);
// }
TEST(ArrayTest, WrapSelf_DoesNothing) {
pele::Array v(6);
EXPECT_EQ(v.reference_count(), 1u);
v.wrap(v);
EXPECT_EQ(v.reference_count(), 1u);
}
TEST(ArrayTest, Free_Works) {
pele::Array v(6);
v.free();
EXPECT_EQ(0u, v.size());
// EXPECT_FALSE(v.data());
EXPECT_TRUE(v.empty());
v.free();
}
TEST(ArrayTest, Free_Unwraps) {
pele::Array v1(6);
pele::Array v2(v1);
EXPECT_EQ(2, v1.reference_count());
EXPECT_TRUE(v1 == v2);
v2.free();
EXPECT_EQ(1u, v1.reference_count());
EXPECT_EQ(1u, v2.reference_count());
EXPECT_TRUE(v1 != v2);
EXPECT_EQ(0u, v2.size());
EXPECT_EQ(6u, v1.size());
}
TEST(ArrayTest, Copy_WorksNotWrap) {
pele::Array v(6);
for (size_t i = 0; i < v.size(); ++i) v[i] = i;
pele::Array v2(6);
v2 = v.copy();
EXPECT_NE(v.data(), v2.data());
for (int i = 0; i < 6; ++i) {
EXPECT_NEAR(v[i], v2[i], 1e-10);
}
}
TEST(ArrayTest, Assign_CopiesNoWrap) {
pele::Array v(6);
for (size_t i = 0; i < v.size(); ++i) v[i] = i;
pele::Array v2(6);
v2.assign(v);
EXPECT_NE(v.data(), v2.data());
for (int i = 0; i < 6; ++i) {
EXPECT_NEAR(v[i], v2[i], 1e-10);
}
}
TEST(ArrayTest, AssignWrongSize_Fails) {
pele::Array v(6);
pele::Array v2;
EXPECT_THROW(v2.assign(v), std::runtime_error);
v2 = Array(1);
EXPECT_THROW(v2.assign(v), std::runtime_error);
v2 = Array(8);
EXPECT_THROW(v2.assign(v), std::runtime_error);
v2.free();
v.free();
v2.assign(v); // this is pointless, but it shouldn't fail
}
TEST(ArrayTest, ConstructFromVector_Wraps) {
std::vector vec(6);
pele::Array v(vec);
EXPECT_FALSE(v.empty());
EXPECT_EQ(v.reference_count(), 1);
EXPECT_EQ(v.data(), vec.data());
EXPECT_EQ(v.size(), vec.size());
pele::Array v2(v);
EXPECT_EQ(v.data(), v2.data());
v2.free();
v2 = v;
EXPECT_EQ(v.data(), v2.data());
v2.free();
v2.wrap(v);
EXPECT_EQ(v.data(), v2.data());
v.free();
v2.free();
vec[0] = 0; // the data in vec should not have been deallocated
}
TEST(ArrayTest, RangeBasedFor_Works) {
Array v(3, 0);
for (double &val : v) {
val += 1;
}
for (size_t i = 0; i < v.size(); ++i) {
EXPECT_EQ(1, v[i]);
}
}
TEST(ArrayTest, EqualityOperator_Works) {
Array v1(3);
Array v2(3);
EXPECT_FALSE(v1 == v2);
v1.wrap(v2);
EXPECT_TRUE(v1 == v2);
}
TEST(ArrayTest, InEqualityOperator_Works) {
Array v1(3);
Array v2(3);
EXPECT_TRUE(v1 != v2);
v1.wrap(v2);
EXPECT_FALSE(v1 != v2);
}
TEST(ArrayTest, SumOperator_Array) {
pele::Array v(6, -1);
pele::Array v2(6, 1);
for (size_t i = 0; i < v2.size(); ++i) v2[i] = 1;
v += v2;
EXPECT_NE(v.data(), v2.data());
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 0);
EXPECT_EQ(v2[i], 1);
}
}
TEST(ArrayTest, SumOperator_ArraySelf) {
pele::Array v(6, 1);
double *old_v_data = v.data();
v += v;
EXPECT_EQ(v.data(), old_v_data); // check that memory has not moved
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 2);
}
}
TEST(ArrayTest, SumOperator_Const) {
double c = 1;
pele::Array v(6, -1);
v += c;
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 0);
}
EXPECT_EQ(c, 1);
}
TEST(ArrayTest, SumOperator_Throws) {
const pele::Array rhs({1, 2, 3});
const pele::Array rhs2({1, 2});
pele::Array lhs({4, 5});
EXPECT_NO_THROW(lhs += rhs2);
EXPECT_THROW(lhs += rhs, std::runtime_error);
}
TEST(ArrayTest, DiffOperator_Throws) {
const pele::Array rhs({1, 2, 3});
const pele::Array rhs2({1, 2});
pele::Array lhs({4, 5});
EXPECT_NO_THROW(lhs -= rhs2);
EXPECT_THROW(lhs -= rhs, std::runtime_error);
}
TEST(ArrayTest, ProdOperator_Throws) {
const pele::Array rhs({1, 2, 3});
const pele::Array rhs2({1, 2});
pele::Array lhs({4, 5});
EXPECT_NO_THROW(lhs *= rhs2);
EXPECT_THROW(lhs *= rhs, std::runtime_error);
}
TEST(ArrayTest, DivOperator_Throws) {
const pele::Array rhs({1, 2, 3});
const pele::Array rhs2({1, 2});
pele::Array lhs({4, 5});
EXPECT_NO_THROW(lhs /= rhs2);
EXPECT_THROW(lhs /= rhs, std::runtime_error);
}
///////////
TEST(ArrayTest, DifOperator_Array) {
pele::Array v(6, 1);
pele::Array v2(6, 1);
v -= v2;
EXPECT_NE(v.data(), v2.data());
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 0);
EXPECT_EQ(v2[i], 1);
}
}
TEST(ArrayTest, DifOperator_ArraySelf) {
pele::Array v(6, 1);
double *old_v_data = v.data();
v -= v;
EXPECT_EQ(v.data(), old_v_data); // check that memory has not moved
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 0);
}
}
TEST(ArrayTest, DifOperator_Const) {
double c = 1;
pele::Array v(6, 1);
v -= c;
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 0);
}
EXPECT_EQ(c, 1);
}
///////////
TEST(ArrayTest, ProdOperator_Array) {
pele::Array v(6, 2);
pele::Array v2(6, 10);
v *= v2;
EXPECT_NE(v.data(), v2.data());
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 20);
EXPECT_EQ(v2[i], 10);
}
}
TEST(ArrayTest, ProdOperator_ArraySelf) {
pele::Array v(6, 2);
double *old_v_data = v.data();
v *= v;
EXPECT_EQ(v.data(), old_v_data); // check that memory has not moved
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 4);
}
}
TEST(ArrayTest, ProdOperator_Const) {
double c = 10;
pele::Array v(6, 2);
v *= c;
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 20);
}
EXPECT_EQ(c, 10);
}
///////////
TEST(ArrayTest, AddOperator) {
pele::Array v(6, 2);
pele::Array vr(6, 10);
pele::Array vl;
vl = v + vr;
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(vl[i], 12);
EXPECT_EQ(v[i], 2);
EXPECT_EQ(vr[i], 10);
}
}
TEST(ArrayTest, SubtractOperator) {
pele::Array vr(6, 2);
pele::Array v(6, 10);
pele::Array vl;
vl = v - vr;
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(vl[i], 8);
EXPECT_EQ(vr[i], 2);
EXPECT_EQ(v[i], 10);
}
}
TEST(ArrayTest, NegationOperator) {
pele::Array v{1, 2, 3};
pele::Array vl;
vl = -v;
EXPECT_EQ(vl[0], -1);
EXPECT_EQ(vl[1], -2);
EXPECT_EQ(vl[2], -3);
EXPECT_EQ(v[0], 1);
EXPECT_EQ(v[1], 2);
EXPECT_EQ(v[2], 3);
}
///////////
TEST(ArrayTest, DivOperator_Array) {
pele::Array v(6, 2);
pele::Array v2(6, 2);
v /= v2;
EXPECT_NE(v.data(), v2.data());
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 1);
EXPECT_EQ(v2[i], 2);
}
}
TEST(ArrayTest, DivOperator_ArraySelf) {
pele::Array v(6, 2);
double *old_v_data = v.data();
v /= v;
EXPECT_EQ(v.data(), old_v_data); // check that memory has not moved
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 1);
}
}
TEST(ArrayTest, DivOperator_Const) {
double c = 2;
pele::Array v(6, 2);
v /= c;
for (int i = 0; i < 6; ++i) {
EXPECT_EQ(v[i], 1);
}
EXPECT_EQ(c, 2);
}
TEST(ArrayTest, SumFunction) {
pele::Array v(6, 2);
EXPECT_EQ(v.sum(), 12);
}
TEST(ArrayTest, SumFunction_Throws) {
EXPECT_THROW(pele::Array().sum(), std::runtime_error);
EXPECT_NO_THROW(pele::Array({42}).sum());
}
TEST(ArrayTest, ProdFunction) {
pele::Array v(6, 2);
EXPECT_EQ(v.prod(), 64);
EXPECT_THROW(pele::Array().prod(), std::runtime_error);
EXPECT_NO_THROW(pele::Array({42}).prod());
}
TEST(ArrayTest, Iterator_Works) {
pele::Array v(6, -1);
size_t count = 0;
for (Array::iterator iter = v.begin(); iter != v.end(); ++iter) {
*iter = count;
count++;
}
for (count = 0; count < v.size(); ++count) {
EXPECT_EQ(v[count], count);
}
}
TEST(ArrayTest, ConstArray_NotModifiable) {
pele::Array const v(6, 0);
double x = v[0];
v.empty();
double const *d = v.data();
v.data();
size_t count = 0;
for (Array::const_iterator iter = v.begin(); iter != v.end();
++iter) {
x = *iter;
count++;
}
EXPECT_EQ(count, v.size());
UNUSED(d);
UNUSED(x);
}
TEST(ArrayTest, View_Works) {
pele::Array v(6);
for (size_t i = 0; i < v.size(); ++i) {
v[i] = i;
}
pele::Array v2 = v.view(1, 3);
EXPECT_EQ(v[0], 0u);
EXPECT_EQ(v2[0], 1u);
EXPECT_EQ(v2[1], 2u);
EXPECT_EQ(v2.size(), 2u);
EXPECT_FALSE(v == v2);
pele::Array v3 = v2.view(1, 2);
EXPECT_EQ(v3[0], 2u);
EXPECT_EQ(v3.size(), 1u);
EXPECT_EQ(v.size(), 6u);
EXPECT_EQ(v[0], 0u);
}
TEST(ArrayTest, FullView_IsSame) {
pele::Array v(6);
pele::Array v2 = v.view(0, 6);
EXPECT_TRUE(v == v2);
}
TEST(ArrayTest, BadInput_Fails) {
pele::Array v(6);
pele::Array v2;
ASSERT_THROW(v2 = v.view(-1, 2), std::invalid_argument);
ASSERT_THROW(v2 = v.view(3, 2), std::invalid_argument);
ASSERT_THROW(v2 = v.view(0, 7), std::invalid_argument);
}
TEST(ArrayTest, MinMax_Works) {
pele::Array x(42, 0);
x[7] = 12;
x[9] = -1.1;
EXPECT_DOUBLE_EQ(x.get_min(), -1.1);
EXPECT_DOUBLE_EQ(x.get_max(), 12);
}
TEST(ArrayDotTest, Dot_Works) {
pele::Array v1(6, 3);
pele::Array v2(6, 2);
double d = pele::dot(v1, v2);
EXPECT_EQ(3 * 2 * 6, d);
}
TEST(ArrayNormTest, Norm_Works) {
pele::Array v1(6, 3);
double d = pele::norm(v1);
EXPECT_NEAR(sqrt(3 * 3 * 6), d, 1e-10);
}