See More

#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); }