#include "helpers.hpp" #include #include #include #include #include #include #include #include "catch.hpp" using iter::chain; using itertest::SolidInt; using itertest::BasicIterable; using Vec = const std::vector; TEST_CASE("chain: three strings", "[chain]") { std::string s1{"abc"}; std::string s2{"mno"}; std::string s3{"xyz"}; auto ch = chain(s1, s2, s3); Vec v(std::begin(ch), std::end(ch)); Vec vc{'a','b','c','m','n','o','x','y','z'}; REQUIRE( v == vc ); } TEST_CASE("chain: with different container types", "[chain]") { std::string s1{"abc"}; std::list li{'m', 'n', 'o'}; std::vector vec{'x', 'y', 'z'}; auto ch = chain(s1, li, vec); Vec v(std::begin(ch), std::end(ch)); Vec vc{'a','b','c','m','n','o','x','y','z'}; REQUIRE( v == vc ); } TEST_CASE("chain: handles empty containers", "[chain]") { std::string emp; std::string a{"a"}; std::string b{"b"}; std::string c{"c"}; Vec vc{'a', 'b', 'c'}; SECTION("Empty container at front") { auto ch = chain(emp, a, b, c); Vec v(std::begin(ch), std::end(ch)); REQUIRE( v == vc ); } SECTION("Empty container at back") { auto ch = chain(a, b, c, emp); Vec v(std::begin(ch), std::end(ch)); REQUIRE( v == vc ); } SECTION("Empty container in middle") { auto ch = chain(a, emp, b, emp, c); Vec v(std::begin(ch), std::end(ch)); REQUIRE( v == vc ); } SECTION("Consecutive empty containers at front") { auto ch = chain(emp, emp, a, b, c); Vec v(std::begin(ch), std::end(ch)); REQUIRE( v == vc ); } SECTION("Consecutive empty containers at back") { auto ch = chain(a, b, c, emp, emp); Vec v(std::begin(ch), std::end(ch)); REQUIRE( v == vc ); } SECTION("Consecutive empty containers in middle") { auto ch = chain(a, emp, emp, b, emp, emp, c); Vec v(std::begin(ch), std::end(ch)); REQUIRE( v == vc ); } } TEST_CASE("chain: with only empty containers", "[chain]") { std::string emp{}; SECTION("one empty container") { auto ch = chain(emp); REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); } SECTION("two empty containers") { auto ch = chain(emp, emp); REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); } SECTION("three empty containers") { auto ch = chain(emp, emp, emp); REQUIRE_FALSE( std::begin(ch) != std::end(ch) ); } } TEST_CASE("chain: doesn't move or copy elements of iterable", "[chain]") { constexpr SolidInt arr[] = {{6}, {7}, {8}}; for (auto&& i : chain(arr, arr)) { (void)i; } } TEST_CASE("chain: binds reference to lvalue and moves rvalue", "[chain]") { BasicIterable bi{'x', 'y', 'z'}; BasicIterable bi2{'a', 'j', 'm'}; SECTION("First moved, second ref'd") { chain(std::move(bi), bi2); REQUIRE( bi.was_moved_from() ); REQUIRE_FALSE( bi2.was_moved_from() ); } SECTION("First ref'd, second moved") { chain(bi, std::move(bi2)); REQUIRE_FALSE( bi.was_moved_from() ); REQUIRE( bi2.was_moved_from() ); } } TEST_CASE("chain: operator==", "[chain]") { std::string emp{}; auto ch = chain(emp); REQUIRE( std::begin(ch) == std::end(ch) ); } TEST_CASE("chain: postfix ++", "[chain]") { std::string s1{"a"}, s2{"b"}; auto ch = chain(s1, s2); auto it = std::begin(ch); it++; REQUIRE( *it == 'b'); } TEST_CASE("chain: iterator meets requirements", "[chain]") { Vec ns{}; auto c = chain(ns, ns); REQUIRE( itertest::IsIterator::value ); } TEST_CASE("chain.from_iterable: basic test", "[chain.from_iterable]") { std::vector sv{"abc", "xyz"}; auto ch = chain.from_iterable(sv); std::vector v(std::begin(ch), std::end(ch)); std::vector vc{'a', 'b', 'c', 'x', 'y', 'z'}; REQUIRE( v == vc ); } TEST_CASE("chain.from_iterable: iterators cant be copy constructed " "and assigned", "[chain.from_iterable]") { std::vector sv{"abc", "xyz"}; auto ch = chain.from_iterable(sv); auto it = std::begin(ch); SECTION("Copy constructed") { auto it2 = it; ++it; REQUIRE( it != it2 ); } SECTION("Copy assigned") { auto it2 = std::end(ch); it2 = it; REQUIRE( it == it2 ); } } TEST_CASE("chain.from_iterable: postfix ++", "[chain.from_iterable]") { std::vector sv{"a", "n"}; auto ch = chain.from_iterable(sv); auto it = std::begin(ch); it++; REQUIRE( *it == 'n' ); } TEST_CASE("chain.from_iterable: moves rvalues and binds ref to lvalues", "[chain.from_iterable]") { BasicIterable bi{"abc", "xyz"}; SECTION("Moves rvalue") { chain.from_iterable(std::move(bi)); REQUIRE( bi.was_moved_from() ); } SECTION("Binds ref to lvalue") { chain.from_iterable(bi); REQUIRE_FALSE( bi.was_moved_from() ); } } TEST_CASE("chain.from_iterable: empty", "[chain.from_iterable]") { const std::vector v{}; auto ch = chain.from_iterable(v); REQUIRE( std::begin(ch) == std::end(ch) ); } TEST_CASE("chain.from_iterable: iterator meets requirements", "[chain.from_iterable]") { const std::vector v{}; auto c = chain.from_iterable(v); REQUIRE( itertest::IsIterator::value ); }