/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "catch.hpp" #include #include using namespace rpl; class OnDestructor { public: OnDestructor(std::function callback) : _callback(std::move(callback)) { } ~OnDestructor() { if (_callback) { _callback(); } } private: std::function _callback; }; TEST_CASE("basic producer tests", "[rpl::producer]") { SECTION("producer next, done and lifetime end test") { auto lifetimeEnded = std::make_shared(false); auto sum = std::make_shared(0); auto doneGenerated = std::make_shared(false); auto destroyed = std::make_shared(false); { auto destroyCaller = std::make_shared([=] { *destroyed = true; }); { auto alive = make_producer([=](auto &&consumer) { (void)destroyCaller; consumer.put_next(1); consumer.put_next(2); consumer.put_next(3); consumer.put_done(); return [=] { (void)destroyCaller; *lifetimeEnded = true; }; }).start([=](int value) { (void)destroyCaller; *sum += value; }, [=](no_error) { (void)destroyCaller; }, [=]() { (void)destroyCaller; *doneGenerated = true; }); } } REQUIRE(*sum == 1 + 2 + 3); REQUIRE(*doneGenerated); REQUIRE(*lifetimeEnded); REQUIRE(*destroyed); } SECTION("producer error test") { auto errorGenerated = std::make_shared(false); { auto alive = make_producer([=](auto &&consumer) { consumer.put_error(true); return lifetime(); }).start([=](no_value) { }, [=](bool error) { *errorGenerated = error; }, [=]() { }); } REQUIRE(*errorGenerated); } SECTION("nested lifetimes test") { auto lifetimeEndCount = std::make_shared(0); { auto lifetimes = lifetime(); { auto testProducer = make_producer([=](auto &&consumer) { return [=] { ++*lifetimeEndCount; }; }); testProducer.start_copy([=](no_value) { }, [=](no_error) { }, [=] { }, lifetimes); std::move(testProducer).start([=](no_value) { }, [=](no_error) { }, [=] { }, lifetimes); } REQUIRE(*lifetimeEndCount == 0); } REQUIRE(*lifetimeEndCount == 2); } SECTION("nested producers test") { auto sum = std::make_shared(0); auto lifetimeEndCount = std::make_shared(0); auto saved = lifetime(); { make_producer([=](auto &&consumer) { auto inner = make_producer([=](auto &&consumer) { consumer.put_next(1); consumer.put_next(2); consumer.put_next(3); return [=] { ++*lifetimeEndCount; }; }); auto result = lifetime([=] { ++*lifetimeEndCount; }); inner.start_copy([=](int value) { consumer.put_next_copy(value); }, [=](no_error) { }, [=] { }, result); std::move(inner).start([=](int value) { consumer.put_next_copy(value); }, [=](no_error) { }, [=] { }, result); return result; }).start([=](int value) { *sum += value; }, [=](no_error) { }, [=] { }, saved); } REQUIRE(*sum == 1 + 2 + 3 + 1 + 2 + 3); REQUIRE(*lifetimeEndCount == 0); saved.destroy(); REQUIRE(*lifetimeEndCount == 3); } SECTION("tuple producer test") { auto result = std::make_shared(0); { auto alive = make_producer>([=]( auto &&consumer) { consumer.put_next(std::make_tuple(1, 2.)); return lifetime(); }).start([=](int a, double b) { *result = a + int(b); }, [=](no_error error) { }, [=]() { }); } REQUIRE(*result == 3); } } TEST_CASE("basic event_streams tests", "[rpl::event_stream]") { SECTION("event_stream basic test") { auto sum = std::make_shared(0); event_stream stream; stream.fire(1); stream.fire(2); stream.fire(3); { auto saved = lifetime(); stream.events().start([=](int value) { *sum += value; }, [=](no_error) { }, [=] { }, saved); stream.fire(11); stream.fire(12); stream.fire(13); } stream.fire(21); stream.fire(22); stream.fire(23); REQUIRE(11 + 12 + 13); } SECTION("event_stream add in handler test") { auto sum = std::make_shared(0); event_stream stream; { auto composite = lifetime(); stream.events().start([=, &stream, &composite](int value) { *sum += value; stream.events().start([=](int value) { *sum += value; }, [=](no_error) { }, [=] { }, composite); }, [=](no_error) { }, [=] { }, composite); { auto inner = lifetime(); stream.events().start([=, &stream, &inner](int value) { *sum += value; stream.events().start([=](int value) { *sum += value; }, [=](no_error) { }, [=] { }, inner); }, [=](no_error) { }, [=] { }, inner); stream.fire(1); stream.fire(2); stream.fire(3); } stream.fire(11); stream.fire(12); stream.fire(13); } stream.fire(21); stream.fire(22); stream.fire(23); REQUIRE(*sum == (1 + 1) + ((2 + 2) + (2 + 2)) + ((3 + 3 + 3) + (3 + 3 + 3)) + (11 + 11 + 11 + 11) + (12 + 12 + 12 + 12 + 12) + (13 + 13 + 13 + 13 + 13 + 13)); } SECTION("event_stream add and remove in handler test") { auto sum = std::make_shared(0); event_stream stream; { auto composite = lifetime(); stream.events().start([=, &stream, &composite](int value) { *sum += value; composite.destroy(); stream.events().start([=](int value) { *sum += value; }, [=](no_error) { }, [=] { }, composite); }, [=](no_error) { }, [=] { }, composite); { auto inner = lifetime(); stream.events().start([=, &stream, &inner](int value) { *sum += value; inner.destroy(); stream.events().start([=](int value) { *sum += value; }, [=](no_error) { }, [=] { }, inner); }, [=](no_error) { }, [=] { }, inner); stream.fire(1); stream.fire(2); stream.fire(3); } stream.fire(11); stream.fire(12); stream.fire(13); } stream.fire(21); stream.fire(22); stream.fire(23); REQUIRE(*sum == (1 + 1) + (2 + 2) + (3 + 3) + (11) + (12) + (13)); } SECTION("event_stream ends before handler lifetime") { auto sum = std::make_shared(0); lifetime extended; { event_stream stream; stream.events().start([=](int value) { *sum += value; }, [=](no_error) { }, [=] { }, extended); stream.fire(1); stream.fire(2); stream.fire(3); } REQUIRE(*sum == 1 + 2 + 3); } SECTION("event_stream move test") { auto sum = std::make_shared(0); lifetime extended; { event_stream stream; stream.events() | start_with_next([=](int value) { *sum += value; }, extended); stream.fire(1); stream.fire(2); auto movedStream = std::move(stream); movedStream.fire(3); movedStream.fire(4); } REQUIRE(*sum == 1 + 2 + 3 + 4); } } TEST_CASE("basic piping tests", "[rpl::producer]") { SECTION("start_with_*") { auto sum = std::make_shared(0); auto dones = std::make_shared(0); { auto alive = lifetime(); make_producer([=](auto &&consumer) { consumer.put_next(1); consumer.put_done(); return lifetime(); }) | start_with_next([=](int value) { *sum += value; }, alive); make_producer([=](auto &&consumer) { consumer.put_next(11); consumer.put_error(111); return lifetime(); }) | start_with_error([=](int value) { *sum += value; }, alive); make_producer([=](auto &&consumer) { consumer.put_next(1111); consumer.put_done(); return lifetime(); }) | start_with_done([=]() { *dones += 1; }, alive); make_producer([=](auto &&consumer) { consumer.put_next(11111); consumer.put_next(11112); consumer.put_next(11113); consumer.put_error(11114); return lifetime(); }) | start_with_next_error([=](int value) { *sum += value; }, [=](int value) { *sum += value; }, alive); } auto alive = lifetime(); make_producer([=](auto &&consumer) { consumer.put_next(111111); consumer.put_next(111112); consumer.put_next(111113); consumer.put_done(); return lifetime(); }) | start_with_next_done([=](int value) { *sum += value; }, [=]() { *dones += 11; }, alive); make_producer([=](auto &&consumer) { consumer.put_error(1111111); return lifetime(); }) | start_with_error_done([=](int value) { *sum += value; }, [=]() { *dones = 0; }, alive); make_producer([=](auto &&consumer) { consumer.put_next(11111111); consumer.put_next(11111112); consumer.put_next(11111113); consumer.put_error(11111114); return lifetime(); }) | start_with_next_error_done([=](int value) { *sum += value; }, [=](int value) { *sum += value; }, [=]() { *dones = 0; }, alive); REQUIRE(*sum == 1 + 111 + 11111 + 11112 + 11113 + 11114 + 111111 + 111112 + 111113 + 1111111 + 11111111 + 11111112 + 11111113 + 11111114); REQUIRE(*dones == 1 + 11); } SECTION("start_with_next should copy its callback") { auto sum = std::make_shared(0); { auto next = [=](int value) { REQUIRE(sum != nullptr); *sum += value; }; for (int i = 0; i != 3; ++i) { auto alive = lifetime(); make_producer([=](auto &&consumer) { consumer.put_next(1); consumer.put_done(); return lifetime(); }) | start_with_next(next, alive); } } REQUIRE(*sum == 3); } }