diff --git a/include/nba/core/enumerate.hh b/include/nba/core/enumerate.hh index 88aea24..f55a315 100644 --- a/include/nba/core/enumerate.hh +++ b/include/nba/core/enumerate.hh @@ -3,6 +3,7 @@ #ifndef __NBA_CORE_ENUM_HH__ #define __NBA_CORE_ENUM_HH__ +#include #include #include #include diff --git a/tests/test_core_enumerate.cc b/tests/test_core_enumerate.cc new file mode 100644 index 0000000..7ea5b43 --- /dev/null +++ b/tests/test_core_enumerate.cc @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +// Test cases are adopted from +// https://github.com/minjang/minjang.github.io/blob/master/assets/2016/python_like_enumerate/python_like.cpp + +using namespace std; +using namespace nba; + +TEST(CoreEnumerateTest, ForwardIterator) { + vector A = {"foo", "bar", "baz"}; + const vector Adup = {"foofoo", "barbar", "bazbaz"}; + vector B = {"foo", "bar", "baz"}; + const vector Borig = {"foo", "bar", "baz"}; + size_t idx = 0; + // Get elements via reference. A is modified. + for (pair p : enumerate(A)) { + EXPECT_EQ(idx, p.first) << "Enumerated index must match with induction-based index."; + p.second += p.second; + idx ++; + } + for (pair p : enumerate(A)) { + EXPECT_EQ(Adup[p.first], p.second) << "A should have been modified."; + } + // Get elements via value (copy). B is not modified. + for (pair p : enumerate(B)) { + p.second += p.second; + } + for (auto p : enumerate(B)) { // type of p: pair + EXPECT_EQ(Borig[p.first], p.second) << "B should not have been modified."; + } +} + +TEST(CoreEnumerateTest, Array) { + string C[] = {"foo", "bar", "baz"}; + const string Cdup[] = {"foofoo", "barbar", "bazbaz"}; + size_t idx = 0; + // Generally, auto&& is efficient since it does not copy pair instances. + // In this case, decltype(p) == pair&& + for (auto&& p : enumerate(C, 100)) { + EXPECT_EQ(idx + 100, p.first) << "Enumerated index must match with induction-based index."; + p.second += p.second; + idx ++; + } + for (auto&& p : enumerate(C, 100)) { + EXPECT_EQ(Cdup[p.first - 100], p.second) << "auto&& should allow modification."; + } +} + +TEST(CoreEnumerateTest, ConstIterator) { + const string E[] = {"foo", "bar", "baz"}; + size_t idx = 0; + // In this case, decltype(p) == pair&& + for (auto&& p : enumerate(E)) { + p.first += 1; + EXPECT_EQ(idx + 1, p.first) << "Index should be modifiable."; + // p.second is const + idx ++; + } +} + +TEST(CoreEnumerateTest, RValueIterator) { + const vector T = {"foo", "bar", "baz"}; + size_t idx = 0; + // Object creation is an rvalue. + for (auto&& p : enumerate(vector{"foo", "bar", "baz"})) { + EXPECT_EQ(idx, p.first); + EXPECT_EQ(T[idx], p.second); + idx ++; + } + // Function return value is also an rvalue. + // decltype(p) == pair&& + auto create = []()->vector { return {"foo", "bar", "baz"}; }; + idx = 0; + for (auto&& p : enumerate(create())) { + EXPECT_EQ(idx, p.first); + EXPECT_EQ(T[idx], p.second); + idx ++; + } +} + +TEST(CoreEnumerateTest, InitializerList) { + const vector T = {"foo", "bar", "baz"}; + size_t idx = 0; + for (auto&& p : enumerate({"foo", "bar", "baz"})) { + EXPECT_EQ(idx, p.first); + EXPECT_EQ(T[idx], p.second); + idx ++; + } +} + +// vim: ts=8 sts=4 sw=4 et