#include "generator.hh" #include #include #include namespace nix { TEST(Generator, yields) { auto g = []() -> Generator { co_yield 1; co_yield 2; }(); ASSERT_EQ(g.next(), 1); ASSERT_EQ(g.next(), 2); ASSERT_FALSE(g.next().has_value()); } TEST(Generator, returns) { { auto g = []() -> Generator { co_return; }(); ASSERT_FALSE(g.next().has_value()); } { auto g = []() -> Generator { co_yield 1; co_yield []() -> Generator { co_return; }(); co_yield 2; co_yield []() -> Generator { co_yield 10; }(); co_yield 3; (void) "dummy statement to force some more execution"; }(); ASSERT_EQ(g.next(), 1); ASSERT_EQ(g.next(), 2); ASSERT_EQ(g.next(), 10); ASSERT_EQ(g.next(), 3); ASSERT_FALSE(g.next().has_value()); } } TEST(Generator, nests) { auto g = []() -> Generator { co_yield 1; co_yield []() -> Generator { co_yield 9; co_yield []() -> Generator { co_yield 99; co_yield 100; }(); }(); auto g2 = []() -> Generator { co_yield []() -> Generator { co_yield 2000; co_yield 2001; }(); co_yield 1001; }(); co_yield g2.next().value(); co_yield std::move(g2); co_yield 2; }(); ASSERT_EQ(g.next(), 1); ASSERT_EQ(g.next(), 9); ASSERT_EQ(g.next(), 99); ASSERT_EQ(g.next(), 100); ASSERT_EQ(g.next(), 2000); ASSERT_EQ(g.next(), 2001); ASSERT_EQ(g.next(), 1001); ASSERT_EQ(g.next(), 2); ASSERT_FALSE(g.next().has_value()); } TEST(Generator, nestsExceptions) { auto g = []() -> Generator { co_yield 1; co_yield []() -> Generator { co_yield 9; throw 1; co_yield 10; }(); co_yield 2; }(); ASSERT_EQ(g.next(), 1); ASSERT_EQ(g.next(), 9); ASSERT_THROW(g.next(), int); } TEST(Generator, exception) { { auto g = []() -> Generator { co_yield 1; throw 1; }(); ASSERT_EQ(g.next(), 1); ASSERT_THROW(g.next(), int); ASSERT_FALSE(g.next().has_value()); } { auto g = []() -> Generator { throw 1; co_return; }(); ASSERT_THROW(g.next(), int); ASSERT_FALSE(g.next().has_value()); } } namespace { struct Transform { int state = 0; std::pair operator()(std::integral auto x) { return {x, state++}; } Generator, Transform> operator()(const char *) { co_yield 9; co_yield 19; } Generator, Transform> operator()(Generator && inner) { return [](auto g) mutable -> Generator, Transform> { while (auto i = g.next()) { co_yield *i; } }(std::move(inner)); } }; } TEST(Generator, transform) { auto g = []() -> Generator, Transform> { co_yield int32_t(-1); co_yield ""; co_yield []() -> Generator { co_yield 7; }(); co_yield 20; }(); ASSERT_EQ(g.next(), (std::pair{4294967295, 0})); ASSERT_EQ(g.next(), (std::pair{9, 0})); ASSERT_EQ(g.next(), (std::pair{19, 1})); ASSERT_EQ(g.next(), (std::pair{7, 0})); ASSERT_EQ(g.next(), (std::pair{20, 1})); ASSERT_FALSE(g.next().has_value()); } namespace { struct ThrowTransform { int operator()(int x) { return x; } int operator()(bool) { throw 2; } Generator operator()(Generator && inner) { throw false; } }; } TEST(Generator, transformThrows) { { auto g = []() -> Generator { co_yield 1; co_yield false; co_yield 2; }(); ASSERT_EQ(g.next(), 1); ASSERT_THROW(g.next(), int); ASSERT_FALSE(g.next().has_value()); } { auto g = []() -> Generator { co_yield 1; co_yield []() -> Generator { co_yield 2; }(); co_yield 3; }(); ASSERT_EQ(g.next(), 1); ASSERT_THROW(g.next(), bool); ASSERT_FALSE(g.next().has_value()); } } }