diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4eff7bbdfa88c402b238c94acddb1ab8e80002ae..714479919d1c6eed6d8ef3511694f966143d2b54 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -98,6 +98,7 @@ add_executable (unit_tests test_PugsUtils.cpp test_RevisionInfo.cpp test_SmallArray.cpp + test_SmallVector.cpp test_SymbolTable.cpp test_Table.cpp test_Timer.cpp diff --git a/tests/test_SmallVector.cpp b/tests/test_SmallVector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b499c3ab3e984247b7f20f96b626f8ee413763a --- /dev/null +++ b/tests/test_SmallVector.cpp @@ -0,0 +1,472 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <utils/PugsAssert.hpp> + +#include <algebra/SmallVector.hpp> +#include <algebra/TinyVector.hpp> + +// Instantiate to ensure full coverage is performed +template class SmallVector<int>; + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SmallVector", "[algebra]") +{ + SECTION("size") + { + SmallVector<int> x{5}; + REQUIRE(x.size() == 5); + } + + SECTION("write access") + { + SmallVector<int> x{5}; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + x[4] = 4; + + REQUIRE(x[0] == 0); + REQUIRE(x[1] == 1); + REQUIRE(x[2] == 2); + REQUIRE(x[3] == 3); + REQUIRE(x[4] == 4); + } + + SECTION("fill") + { + SmallVector<int> x{5}; + x.fill(2); + + REQUIRE(x[0] == 2); + REQUIRE(x[1] == 2); + REQUIRE(x[2] == 2); + REQUIRE(x[3] == 2); + REQUIRE(x[4] == 2); + } + + SECTION("copy constructor (shallow)") + { + SmallVector<int> x{5}; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + x[4] = 4; + + const SmallVector<int> y = x; + REQUIRE(y[0] == 0); + REQUIRE(y[1] == 1); + REQUIRE(y[2] == 2); + REQUIRE(y[3] == 3); + REQUIRE(y[4] == 4); + } + + SECTION("copy constructor (move)") + { + SmallVector<int> x{5}; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + x[4] = 4; + + const SmallVector<int> y = std::move(x); + REQUIRE(y[0] == 0); + REQUIRE(y[1] == 1); + REQUIRE(y[2] == 2); + REQUIRE(y[3] == 3); + REQUIRE(y[4] == 4); + } + + SECTION("copy (shallow)") + { + SmallVector<int> x{5}; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + x[4] = 4; + + SmallVector<int> y{5}; + y = x; + REQUIRE(y[0] == 0); + REQUIRE(y[1] == 1); + REQUIRE(y[2] == 2); + REQUIRE(y[3] == 3); + REQUIRE(y[4] == 4); + + x[0] = 14; + x[1] = 13; + x[2] = 12; + x[3] = 11; + x[4] = 10; + + REQUIRE(x[0] == 14); + REQUIRE(x[1] == 13); + REQUIRE(x[2] == 12); + REQUIRE(x[3] == 11); + REQUIRE(x[4] == 10); + + REQUIRE(y[0] == 14); + REQUIRE(y[1] == 13); + REQUIRE(y[2] == 12); + REQUIRE(y[3] == 11); + REQUIRE(y[4] == 10); + } + + SECTION("copy (deep)") + { + SmallVector<int> x{5}; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + x[4] = 4; + + SmallVector<int> y{5}; + y = copy(x); + + x[0] = 14; + x[1] = 13; + x[2] = 12; + x[3] = 11; + x[4] = 10; + + REQUIRE(y[0] == 0); + REQUIRE(y[1] == 1); + REQUIRE(y[2] == 2); + REQUIRE(y[3] == 3); + REQUIRE(y[4] == 4); + + REQUIRE(x[0] == 14); + REQUIRE(x[1] == 13); + REQUIRE(x[2] == 12); + REQUIRE(x[3] == 11); + REQUIRE(x[4] == 10); + } + + SECTION("copy to const (shallow)") + { + SmallVector<int> x{5}; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + x[4] = 4; + + SmallVector<const int> y; + y = x; + REQUIRE(y[0] == 0); + REQUIRE(y[1] == 1); + REQUIRE(y[2] == 2); + REQUIRE(y[3] == 3); + REQUIRE(y[4] == 4); + + SmallVector<int> z{5}; + z[0] = 14; + z[1] = 13; + z[2] = 12; + z[3] = 11; + z[4] = 10; + + y = z; + REQUIRE(z[0] == 14); + REQUIRE(z[1] == 13); + REQUIRE(z[2] == 12); + REQUIRE(z[3] == 11); + REQUIRE(z[4] == 10); + + REQUIRE(y[0] == 14); + REQUIRE(y[1] == 13); + REQUIRE(y[2] == 12); + REQUIRE(y[3] == 11); + REQUIRE(y[4] == 10); + } + + SECTION("self scalar multiplication") + { + SmallVector<int> x{5}; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + x[4] = 4; + + x *= 2; + + REQUIRE(x[0] == 0); + REQUIRE(x[1] == 2); + REQUIRE(x[2] == 4); + REQUIRE(x[3] == 6); + REQUIRE(x[4] == 8); + } + + SECTION("left scalar multiplication") + { + SmallVector<int> x{5}; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + x[4] = 4; + + const SmallVector<int> y = 2 * x; + + REQUIRE(y[0] == 0); + REQUIRE(y[1] == 2); + REQUIRE(y[2] == 4); + REQUIRE(y[3] == 6); + REQUIRE(y[4] == 8); + } + + SECTION("dot product") + { + SmallVector<int> x{5}; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + x[4] = 4; + + SmallVector<int> y{5}; + y[0] = 7; + y[1] = 3; + y[2] = 4; + y[3] = 2; + y[4] = 8; + + const int s = dot(x, y); + REQUIRE(s == 49); + } + + SECTION("self scalar division") + { + SmallVector<int> x{5}; + x[0] = 2; + x[1] = 3; + x[2] = 5; + x[3] = 7; + x[4] = 8; + + x /= 2; + + REQUIRE(x[0] == 1); + REQUIRE(x[1] == 1); + REQUIRE(x[2] == 2); + REQUIRE(x[3] == 3); + REQUIRE(x[4] == 4); + } + + SECTION("self minus") + { + SmallVector<int> x{5}; + x[0] = 2; + x[1] = 3; + x[2] = 5; + x[3] = 7; + x[4] = 8; + + SmallVector<int> y{5}; + y[0] = 3; + y[1] = 8; + y[2] = 6; + y[3] = 2; + y[4] = 4; + + x -= y; + + REQUIRE(x[0] == -1); + REQUIRE(x[1] == -5); + REQUIRE(x[2] == -1); + REQUIRE(x[3] == 5); + REQUIRE(x[4] == 4); + } + + SECTION("self sum") + { + SmallVector<int> x{5}; + x[0] = 2; + x[1] = 3; + x[2] = 5; + x[3] = 7; + x[4] = 8; + + SmallVector<int> y{5}; + y[0] = 3; + y[1] = 8; + y[2] = 6; + y[3] = 2; + y[4] = 4; + + x += y; + + REQUIRE(x[0] == 5); + REQUIRE(x[1] == 11); + REQUIRE(x[2] == 11); + REQUIRE(x[3] == 9); + REQUIRE(x[4] == 12); + } + + SECTION("sum") + { + SmallVector<int> x{5}; + x[0] = 2; + x[1] = 3; + x[2] = 5; + x[3] = 7; + x[4] = 8; + + SmallVector<int> y{5}; + y[0] = 3; + y[1] = 8; + y[2] = 6; + y[3] = 2; + y[4] = 4; + + SmallVector z = x + y; + + REQUIRE(z[0] == 5); + REQUIRE(z[1] == 11); + REQUIRE(z[2] == 11); + REQUIRE(z[3] == 9); + REQUIRE(z[4] == 12); + } + + SECTION("difference") + { + SmallVector<int> x{5}; + x[0] = 2; + x[1] = 3; + x[2] = 5; + x[3] = 7; + x[4] = 8; + + SmallVector<int> y{5}; + y[0] = 3; + y[1] = 8; + y[2] = 6; + y[3] = 2; + y[4] = 4; + + SmallVector z = x - y; + + REQUIRE(z[0] == -1); + REQUIRE(z[1] == -5); + REQUIRE(z[2] == -1); + REQUIRE(z[3] == 5); + REQUIRE(z[4] == 4); + } + + SECTION("output") + { + SmallVector<int> x{5}; + x[0] = 3; + x[1] = 7; + x[2] = 2; + x[3] = 1; + x[4] = -4; + + std::ostringstream vector_ost; + vector_ost << x; + std::ostringstream ref_ost; + ref_ost << 0 << ':' << x[0]; + for (size_t i = 1; i < x.size(); ++i) { + ref_ost << ' ' << i << ':' << x[i]; + } + REQUIRE(vector_ost.str() == ref_ost.str()); + } + + SECTION("SmallVector from TinyVector") + { + TinyVector<5> tiny_vector{1, 3, 5, 7, 9}; + + SmallVector vector{tiny_vector}; + + REQUIRE(vector[0] == 1); + REQUIRE(vector[1] == 3); + REQUIRE(vector[2] == 5); + REQUIRE(vector[3] == 7); + REQUIRE(vector[4] == 9); + + SECTION("ensures deep copy") + { + tiny_vector = zero; + + REQUIRE(tiny_vector[0] == 0); + REQUIRE(tiny_vector[1] == 0); + REQUIRE(tiny_vector[2] == 0); + REQUIRE(tiny_vector[3] == 0); + REQUIRE(tiny_vector[4] == 0); + + REQUIRE(vector[0] == 1); + REQUIRE(vector[1] == 3); + REQUIRE(vector[2] == 5); + REQUIRE(vector[3] == 7); + REQUIRE(vector[4] == 9); + } + } + +#ifndef NDEBUG + + SECTION("output with signaling NaN") + { + SmallVector<double> x{5}; + x[0] = 3; + x[2] = 2; + + std::ostringstream vector_ost; + vector_ost << x; + std::ostringstream ref_ost; + ref_ost << 0 << ':' << 3 << ' '; + ref_ost << 1 << ":nan "; + ref_ost << 2 << ':' << 2 << ' '; + ref_ost << 3 << ":nan "; + ref_ost << 4 << ":nan"; + REQUIRE(vector_ost.str() == ref_ost.str()); + } + + SECTION("invalid dot product") + { + SmallVector<int> x{5}; + SmallVector<int> y{4}; + + REQUIRE_THROWS_WITH(dot(x, y), "cannot compute dot product: incompatible vector sizes"); + } + + SECTION("invalid substract") + { + SmallVector<int> x{5}; + SmallVector<int> y{4}; + + REQUIRE_THROWS_WITH(x -= y, "cannot substract vector: incompatible sizes"); + } + + SECTION("invalid add") + { + SmallVector<int> x{5}; + SmallVector<int> y{4}; + + REQUIRE_THROWS_WITH(x += y, "cannot add vector: incompatible sizes"); + } + + SECTION("invalid difference") + { + SmallVector<int> x{5}; + SmallVector<int> y{4}; + + REQUIRE_THROWS_WITH(x - y, "cannot compute vector difference: incompatible sizes"); + } + + SECTION("invalid sum") + { + SmallVector<int> x{5}; + SmallVector<int> y{4}; + + REQUIRE_THROWS_WITH(x + y, "cannot compute vector sum: incompatible sizes"); + } + +#endif // NDEBUG +}