#include #include #include #include #include #include #include #include "helpers.hpp" #include "catch.hpp" using iter::sorted; using Vec = const std::vector; TEST_CASE("sorted: iterates through a vector in sorted order", "[sorted]" ){ Vec ns = {4, 0, 5, 1, 6, 7, 9, 3, 2, 8}; auto s = sorted(ns); Vec v(std::begin(s), std::end(s)); Vec vc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; REQUIRE( v == vc ); } TEST_CASE("sorted: can modify elements through sorted", "[sorted]") { std::vector ns(3, 9); for (auto&& n : sorted(ns)) { n = -1; } Vec vc(3, -1); REQUIRE( ns == vc ); } TEST_CASE("sorted: can iterate over unordered container", "[sorted]") { std::unordered_set ns = {1, 3, 2, 0, 4}; auto s = sorted(ns); Vec v(std::begin(s), std::end(s)); Vec vc = {0, 1, 2, 3, 4}; REQUIRE( v == vc ); } TEST_CASE("sorted: empty when iterable is empty", "[sorted]") { Vec ns{}; auto s = sorted(ns); REQUIRE( std::begin(s) == std::end(s) ); } namespace { bool int_greater_than(int lhs, int rhs) { return lhs > rhs; } struct IntGreaterThan { bool operator() (int lhs, int rhs) const { return lhs > rhs; } }; } TEST_CASE("sorted: works with different functor types", "[sorted]") { Vec ns = {4, 1, 3, 2, 0}; std::vector v; SECTION("with function pointer") { auto s = sorted(ns, int_greater_than); v.insert(v.begin(), std::begin(s), std::end(s)); } SECTION("with callable object") { auto s = sorted(ns, IntGreaterThan{}); v.insert(v.begin(), std::begin(s), std::end(s)); } SECTION("with lambda") { auto s = sorted(ns, [](int lhs, int rhs){return lhs > rhs;}); v.insert(v.begin(), std::begin(s), std::end(s)); } Vec vc = {4, 3, 2, 1, 0}; REQUIRE( v == vc ); } namespace { template class BasicIterableWithConstDeref { private: T *data; std::size_t size; bool was_moved_from_ = false; public: BasicIterableWithConstDeref(std::initializer_list il) : data{new T[il.size()]}, size{il.size()} { // would like to use enumerate, can't because it's for unit // testing enumerate std::size_t i = 0; for (auto&& e : il) { data[i] = e; ++i; } } BasicIterableWithConstDeref& operator=(BasicIterableWithConstDeref&&) = delete; BasicIterableWithConstDeref& operator=(const BasicIterableWithConstDeref&) = delete; BasicIterableWithConstDeref(const BasicIterableWithConstDeref&) = delete; BasicIterableWithConstDeref(BasicIterableWithConstDeref&& other) : data{other.data}, size{other.size} { other.data = nullptr; other.was_moved_from_ = true; } bool was_moved_from() const { return this->was_moved_from_; } ~BasicIterableWithConstDeref() { delete [] this->data; } class Iterator { private: T *p; public: Iterator(T *b) : p{b} { } bool operator!=(const Iterator& other) const { return this->p != other.p; } Iterator& operator++() { ++this->p; return *this; } T& operator*() { return *this->p; } const T& operator*() const { return *this->p; } }; Iterator begin() { return {this->data}; } Iterator end() { return {this->data + this->size}; } }; } TEST_CASE("sorted: moves rvalues and binds to lvalues", "[sorted]") { BasicIterableWithConstDeref bi{1, 2}; sorted(bi); REQUIRE_FALSE( bi.was_moved_from() ); sorted(std::move(bi)); REQUIRE( bi.was_moved_from() ); } TEST_CASE("sorted: doesn't move or copy elements of iterable", "[sorted]") { using itertest::SolidInt; constexpr SolidInt arr[] = {{6}, {7}, {8}}; for (auto&& i : sorted(arr, [](const SolidInt& lhs, const SolidInt& rhs){ return lhs.getint() < rhs.getint();})) { (void)i; } } TEST_CASE("sorted: iterator meets requirements", "[sorted]") { Vec v; auto r = sorted(v); REQUIRE( itertest::IsIterator::value ); }