From 5ba301d316e63e06b06214b3efcc0c3de64e753a Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Wed, 27 Apr 2022 11:11:32 +0200 Subject: [PATCH] Add coverage for terminal_input_parser. --- src/ftxui/component/terminal_input_parser.cpp | 9 +- .../component/terminal_input_parser_test.cpp | 151 +++++++++++++++++- src/ftxui/dom/canvas_test.cpp | 44 +++-- 3 files changed, 184 insertions(+), 20 deletions(-) diff --git a/src/ftxui/component/terminal_input_parser.cpp b/src/ftxui/component/terminal_input_parser.cpp index 38860ad..7d9f74b 100644 --- a/src/ftxui/component/terminal_input_parser.cpp +++ b/src/ftxui/component/terminal_input_parser.cpp @@ -136,12 +136,11 @@ TerminalInputParser::Output TerminalInputParser::ParseUTF8() { unsigned int first_zero = 8; // NOLINT for (unsigned int i = 0; i < 8; ++i) { // NOLINT mask |= selector; - if (head & selector) { - selector >>= 1U; - continue; + if (!(head & selector)) { + first_zero = i; + break; } - first_zero = i; - break; + selector >>= 1U; } // Accumulate the value of the first byte. diff --git a/src/ftxui/component/terminal_input_parser_test.cpp b/src/ftxui/component/terminal_input_parser_test.cpp index 863f974..42d6d8b 100644 --- a/src/ftxui/component/terminal_input_parser_test.cpp +++ b/src/ftxui/component/terminal_input_parser_test.cpp @@ -72,7 +72,7 @@ TEST(Event, EscapeKeyEnoughWait) { EXPECT_FALSE(event_receiver->Receive(&received)); } -TEST(Event, MouseLeftClick) { +TEST(Event, MouseLeftClickPressed) { auto event_receiver = MakeReceiver(); { auto parser = TerminalInputParser(event_receiver->MakeSender()); @@ -95,6 +95,56 @@ TEST(Event, MouseLeftClick) { EXPECT_EQ(Mouse::Left, std::get(received).mouse().button); EXPECT_EQ(12, std::get(received).mouse().x); EXPECT_EQ(42, std::get(received).mouse().y); + EXPECT_EQ(std::get(received).mouse().motion, Mouse::Pressed); + EXPECT_FALSE(event_receiver->Receive(&received)); +} + +TEST(Event, MouseLeftClickReleased) { + auto event_receiver = MakeReceiver(); + { + auto parser = TerminalInputParser(event_receiver->MakeSender()); + parser.Add('\x1B'); + parser.Add('['); + parser.Add('3'); + parser.Add('2'); + parser.Add(';'); + parser.Add('1'); + parser.Add('2'); + parser.Add(';'); + parser.Add('4'); + parser.Add('2'); + parser.Add('m'); + } + + Task received; + EXPECT_TRUE(event_receiver->Receive(&received)); + EXPECT_TRUE(std::get(received).is_mouse()); + EXPECT_EQ(Mouse::Left, std::get(received).mouse().button); + EXPECT_EQ(12, std::get(received).mouse().x); + EXPECT_EQ(42, std::get(received).mouse().y); + EXPECT_EQ(std::get(received).mouse().motion, Mouse::Released); + EXPECT_FALSE(event_receiver->Receive(&received)); +} + +TEST(Event, MouseReporting) { + auto event_receiver = MakeReceiver(); + { + auto parser = TerminalInputParser(event_receiver->MakeSender()); + parser.Add('\x1B'); + parser.Add('['); + parser.Add('1'); + parser.Add('2'); + parser.Add(';'); + parser.Add('4'); + parser.Add('2'); + parser.Add('R'); + } + + Task received; + EXPECT_TRUE(event_receiver->Receive(&received)); + EXPECT_TRUE(std::get(received).is_cursor_reporting()); + EXPECT_EQ(42, std::get(received).cursor_x()); + EXPECT_EQ(12, std::get(received).cursor_y()); EXPECT_FALSE(event_receiver->Receive(&received)); } @@ -232,6 +282,105 @@ TEST(Event, UTF8) { } } +TEST(Event, NewLine) { + for (char newline : {'\r', '\n'}) { + auto event_receiver = MakeReceiver(); + { + auto parser = TerminalInputParser(event_receiver->MakeSender()); + parser.Add(newline); + } + Task received; + EXPECT_TRUE(event_receiver->Receive(&received)); + EXPECT_TRUE(std::get(received) == Event::Return); + } +} + +TEST(Event, Control) { + struct TestCase { + char input; + bool cancel; + }; + std::vector cases; + for (int i = 0; i < 32; ++i) { + if (i == 13 || i == 24 || i == 26 || i == 27) + continue; + cases.push_back({char(i), false}); + } + cases.push_back({char(24), true}); + cases.push_back({char(26), true}); + cases.push_back({char(127), false}); + + for(auto test : cases) { + auto event_receiver = MakeReceiver(); + { + auto parser = TerminalInputParser(event_receiver->MakeSender()); + parser.Add(test.input); + } + Task received; + if (test.cancel) { + EXPECT_FALSE(event_receiver->Receive(&received)); + } else { + EXPECT_TRUE(event_receiver->Receive(&received)); + EXPECT_EQ(std::get(received), Event::Special({test.input})); + } + } +} + +TEST(Event, Special) { + auto str = [](std::string input) { + std::vector output; + for (auto it : input) + output.push_back(it); + return output; + }; + struct { + std::vector input; + Event expected; + } kTestCase[] = { + {str("\x1B[D"), Event::ArrowLeft}, + {str("\x1B[C"), Event::ArrowRight}, + {str("\x1B[A"), Event::ArrowUp}, + {str("\x1B[B"), Event::ArrowDown}, + {{127}, Event::Backspace}, + {str("\x1B[3~"), Event::Delete}, + //{str("\x1B"), Event::Escape}, + {{10}, Event::Return}, + {{9}, Event::Tab}, + {{27, 91, 90}, Event::TabReverse}, + //{str("\x1B[OP"), Event::F1}, + //{str("\x1B[OQ"), Event::F2}, + //{str("\x1B[OR"), Event::F3}, + //{str("\x1B[OS"), Event::F4}, + {str("\x1B[15~"), Event::F5}, + {str("\x1B[17~"), Event::F6}, + {str("\x1B[18~"), Event::F7}, + {str("\x1B[19~"), Event::F8}, + {str("\x1B[20~"), Event::F9}, + {str("\x1B[21~"), Event::F10}, + {str("\x1B[21~"), Event::F11}, + {str("\x1B[24~"), Event::F12}, + {{27, 91, 72}, Event::Home}, + {{27, 91, 70}, Event::End}, + {{27, 91, 53, 126}, Event::PageUp}, + {{27, 91, 54, 126}, Event::PageDown}, + {{0}, Event::Custom}, + }; + + for (auto test : kTestCase) { + auto event_receiver = MakeReceiver(); + { + auto parser = TerminalInputParser(event_receiver->MakeSender()); + for (auto input : test.input) { + parser.Add(input); + } + } + Task received; + EXPECT_TRUE(event_receiver->Receive(&received)); + EXPECT_EQ(std::get(received), test.expected); + EXPECT_FALSE(event_receiver->Receive(&received)); + } +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/dom/canvas_test.cpp b/src/ftxui/dom/canvas_test.cpp index c31c6d8..274bdb9 100644 --- a/src/ftxui/dom/canvas_test.cpp +++ b/src/ftxui/dom/canvas_test.cpp @@ -20,33 +20,49 @@ int Hash(const std::string s) { TEST(BorderTest, GoldPoint) { Terminal::SetColorSupport(Terminal::Color::TrueColor); auto element = canvas([](Canvas& c) { // - c.DrawPoint(3, 3, 1, Color::Red); + c.DrawPoint(3, 3, 1); c.DrawPointToggle(2, 8); - c.DrawPointLine(3, 7, 10, 19, Color::Blue); - c.DrawPointCircle(10, 5, 3, Color::Yellow); - c.DrawPointCircleFilled(20, 5, 3, Color::Green); - c.DrawPointEllipse(10, 10, 5, 2, Color::Blue); - c.DrawPointEllipseFilled(10, 20, 5, 2, Color::DarkGreen); + c.DrawPointToggle(2, 8); + c.DrawPointToggle(2, 8); + c.DrawPointLine(3, 7, 10, 19); + c.DrawPointCircle(10, 5, 3); + c.DrawPointCircleFilled(20, 5, 3); + c.DrawPointEllipse(10, 10, 5, 2); + c.DrawPointEllipseFilled(10, 20, 5, 2); }); Screen screen(30, 10); Render(screen, element); - EXPECT_EQ(Hash(screen.ToString()), 17651); + EXPECT_EQ(Hash(screen.ToString()), 1069); } TEST(BorderTest, GoldBlock) { Terminal::SetColorSupport(Terminal::Color::TrueColor); auto element = canvas([](Canvas& c) { // - c.DrawBlock(3, 3, 1, Color::Red); + c.DrawBlock(3, 3, 1); c.DrawBlockToggle(2, 8); - c.DrawBlockLine(3, 7, 10, 19, Color::Blue); - c.DrawBlockCircle(10, 5, 3, Color::Yellow); - c.DrawBlockCircleFilled(20, 5, 3, Color::Green); - c.DrawBlockEllipse(10, 10, 5, 2, Color::Blue); - c.DrawBlockEllipseFilled(10, 20, 5, 2, Color::DarkGreen); + c.DrawBlockToggle(2, 8); + c.DrawBlockToggle(2, 8); + c.DrawBlockLine(3, 7, 10, 19); + c.DrawBlockCircle(10, 5, 3); + c.DrawBlockCircleFilled(20, 5, 3); + c.DrawBlockEllipse(10, 10, 5, 2); + c.DrawBlockEllipseFilled(10, 20, 5, 2); }); Screen screen(30, 10); Render(screen, element); - EXPECT_EQ(Hash(screen.ToString()), 14383); + EXPECT_EQ(Hash(screen.ToString()), 472); +} + +TEST(BorderTest, GoldText) { + Terminal::SetColorSupport(Terminal::Color::TrueColor); + Canvas c(10, 10); + c.DrawText(0, 0, "test"); + c.DrawText(0, 5, "test"); + c.DrawText(0, 10, "test"); + auto element = canvas(c); + Screen screen(30, 10); + Render(screen, element); + EXPECT_EQ(Hash(screen.ToString()), 10447); } } // namespace ftxui