diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-09-22 22:47:33 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-09-22 22:47:33 +0200 |
| commit | d05b9343f69a0841043963088e0003368e205bd9 (patch) | |
| tree | 8cde07ff86d27cbc808a0a149b89d0024b4a586c /ttwhy/routers/echo.tests.cpp | |
| parent | 22f6534081acfabdab4956d337604a21e7da5b64 (diff) | |
| download | ttwhy-master.tar.xz ttwhy-master.zip | |
Diffstat (limited to 'ttwhy/routers/echo.tests.cpp')
| -rw-r--r-- | ttwhy/routers/echo.tests.cpp | 257 |
1 files changed, 0 insertions, 257 deletions
diff --git a/ttwhy/routers/echo.tests.cpp b/ttwhy/routers/echo.tests.cpp deleted file mode 100644 index da2db40..0000000 --- a/ttwhy/routers/echo.tests.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include <asio.hpp> - -#include <catch2/catch_test_macros.hpp> - -#include <string> -#include <string_view> -#include <utility> - -import ttwhy.routers; -import ttwhy.scanners; - -using namespace std::string_view_literals; - -namespace -{ - struct mock_stream - { - using executor_type = asio::any_io_executor; - - asio::any_io_executor executor; - std::string written{}; - - explicit mock_stream(asio::any_io_executor exec) - : executor{std::move(exec)} - {} - - auto get_executor() const noexcept -> executor_type - { - return executor; - } - - template<typename ConstBufferSequence, typename Token> - auto async_write_some(ConstBufferSequence const & buffers, Token && token) - { - return asio::async_initiate<Token, void(asio::error_code, std::size_t)>( - [this](auto handler, ConstBufferSequence bufs) { - auto const total = asio::buffer_size(bufs); - auto const offset = written.size(); - written.resize(offset + total); - asio::buffer_copy(asio::buffer(written.data() + offset, total), bufs); - asio::post(executor, [handler = std::move(handler), total]() mutable { - std::move(handler)(asio::error_code{}, total); - }); - }, - token, buffers); - } - }; - - struct incomplete_router_no_process - { - }; - - struct incomplete_router_wrong_return - { - auto process(ttwhy::scanners::input_event) -> void; - }; - - struct incomplete_router_wrong_event - { - auto process(int) -> asio::awaitable<void>; - }; -} // namespace - -TEST_CASE("The router concept validates router candidate interfaces", "[router][concept]") -{ - STATIC_REQUIRE(ttwhy::router<ttwhy::routers::echo<mock_stream>, ttwhy::scanners::input_event>); - STATIC_REQUIRE_FALSE(ttwhy::router<incomplete_router_no_process, ttwhy::scanners::input_event>); - STATIC_REQUIRE_FALSE(ttwhy::router<incomplete_router_wrong_return, ttwhy::scanners::input_event>); - STATIC_REQUIRE_FALSE(ttwhy::router<incomplete_router_wrong_event, ttwhy::scanners::input_event>); -} - -SCENARIO("The echo router handles terminal navigation within the valid printed area", "[router][echo]") -{ - GIVEN("An initialized echo router with a mock stream") - { - auto context = asio::io_context{}; - auto stream = mock_stream{context.get_executor()}; - auto router = ttwhy::routers::echo{stream}; - - auto run_coro = [&](asio::awaitable<void> coro) { - asio::co_spawn(context, std::move(coro), asio::detached); - context.restart(); - context.run(); - }; - - WHEN("Typing characters") - { - run_coro(router.process(ttwhy::scanners::character_event{'A'})); - run_coro(router.process(ttwhy::scanners::character_event{'B'})); - - THEN("Characters are echoed and positions advance") - { - CHECK(stream.written == "AB"); - CHECK(router.cursor_position() == 2); - CHECK(router.max_position() == 2); - } - - AND_WHEN("Navigating left") - { - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::left})); - - THEN("The cursor moves left") - { - CHECK(stream.written == "\x1b[D"); - CHECK(router.cursor_position() == 1); - CHECK(router.max_position() == 2); - } - - AND_WHEN("Navigating left again to position 0") - { - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::left})); - - THEN("The cursor reaches 0") - { - CHECK(stream.written == "\x1b[D"); - CHECK(router.cursor_position() == 0); - CHECK(router.max_position() == 2); - } - - AND_WHEN("Attempting to navigate left beyond 0") - { - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::left})); - - THEN("Navigation is prevented and nothing is emitted") - { - CHECK(stream.written.empty()); - CHECK(router.cursor_position() == 0); - CHECK(router.max_position() == 2); - } - } - } - } - - AND_WHEN("Attempting to navigate right beyond what was printed") - { - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::right})); - - THEN("Navigation is prevented and nothing is emitted") - { - CHECK(stream.written.empty()); - CHECK(router.cursor_position() == 2); - CHECK(router.max_position() == 2); - } - } - - AND_WHEN("Navigating left and then overwriting with new character") - { - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::left})); - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::character_event{'X'})); - - THEN("The new character is written and max position is preserved") - { - CHECK(stream.written == "X"); - CHECK(router.cursor_position() == 2); - CHECK(router.max_position() == 2); - } - } - - AND_WHEN("Using Home and End keys") - { - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::home})); - - THEN("Home navigates to 0") - { - CHECK(stream.written == "\x1b[2D"); - CHECK(router.cursor_position() == 0); - CHECK(router.max_position() == 2); - } - - AND_WHEN("Pressing Home when already at 0") - { - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::home})); - - THEN("Nothing is emitted") - { - CHECK(stream.written.empty()); - CHECK(router.cursor_position() == 0); - } - } - - AND_WHEN("Pressing End from 0") - { - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::end})); - - THEN("End moves to max position") - { - CHECK(stream.written == "\x1b[2C"); - CHECK(router.cursor_position() == 2); - CHECK(router.max_position() == 2); - } - } - } - - AND_WHEN("Pressing Enter") - { - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::control_event{ttwhy::scanners::control_key::enter})); - - THEN("Newline is emitted and positions reset") - { - CHECK(stream.written == "\r\n"); - CHECK(router.cursor_position() == 0); - CHECK(router.max_position() == 0); - } - } - - AND_WHEN("Pressing Backspace at position 0 after reset") - { - run_coro(router.process(ttwhy::scanners::control_event{ttwhy::scanners::control_key::enter})); - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::control_event{ttwhy::scanners::control_key::backspace})); - - THEN("Backspace does nothing at position 0") - { - CHECK(stream.written.empty()); - CHECK(router.cursor_position() == 0); - CHECK(router.max_position() == 0); - } - } - - AND_WHEN("Using Delete key") - { - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::left})); - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::delete_key})); - - THEN("Delete character sequence is emitted and max position shrinks") - { - CHECK(stream.written == "\x1b[P"); - CHECK(router.cursor_position() == 1); - CHECK(router.max_position() == 1); - } - - AND_WHEN("Pressing Delete when cursor is at max position") - { - stream.written.clear(); - run_coro(router.process(ttwhy::scanners::navigation_event{ttwhy::scanners::navigation_key::delete_key})); - - THEN("Nothing is emitted") - { - CHECK(stream.written.empty()); - CHECK(router.cursor_position() == 1); - CHECK(router.max_position() == 1); - } - } - } - } - } -} |
