From a864099ba77157090c4cd12817245122c163ec24 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sat, 24 Oct 2020 21:33:44 +0300 Subject: rework Process API & tests * Add separate classes ProcessParameters & ShellParameters for Process::create() and Process::shell() methods. * Add a separate "worker" executable. It's used in tests via a fairly complicated scheme, receiving orders to execute via a shared memory region. * Add tests that utilize the Console API, reading console window's screen buffer directly, making for more reliable tests & broader coverage. --- test/unit_tests/worker/worker.cpp | 118 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 test/unit_tests/worker/worker.cpp (limited to 'test/unit_tests/worker') diff --git a/test/unit_tests/worker/worker.cpp b/test/unit_tests/worker/worker.cpp new file mode 100644 index 0000000..9e48deb --- /dev/null +++ b/test/unit_tests/worker/worker.cpp @@ -0,0 +1,118 @@ +// Copyright (c) 2020 Egor Tensin +// This file is part of the "winapi-common" project. +// For details, see https://github.com/egor-tensin/winapi-common. +// Distributed under the MIT License. + +#include "../shared/command.hpp" +#include "../shared/console.hpp" +#include "../shared/test_data.hpp" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +using worker::Command; + +namespace { + +bool is_window_visible() { + HWND window = ::GetConsoleWindow(); + + if (window == NULL) { + return false; + } + + const auto mask = ::GetWindowLongW(window, GWL_STYLE); + + if (!mask) { + throw winapi::error::windows(GetLastError(), "GetWindowLongW"); + } + + return mask & WS_VISIBLE; +} + +winapi::Handle write_to(winapi::Handle dest, const std::string& msg) { + try { + dest.write(msg + "\r\n"); + } catch (const std::exception& e) { + return winapi::Handle{}; + } + return dest; +} + +std::vector get_console_buffer(std::size_t numof_lines) { + return console::Buffer{}.read_last_lines(numof_lines); +} + +void process_action(Command::Action action, const Command::Args& args, Command::Result& result) { + switch (action) { + case Command::EXIT: + break; + + case Command::GET_CONSOLE_WINDOW: + result.console_window = ::GetConsoleWindow(); + break; + + case Command::IS_WINDOW_VISIBLE: + result.is_window_visible = is_window_visible(); + break; + + case Command::GET_STD_HANDLES: + result.std_handles.in = ::GetStdHandle(STD_INPUT_HANDLE); + result.std_handles.out = ::GetStdHandle(STD_OUTPUT_HANDLE); + result.std_handles.err = ::GetStdHandle(STD_ERROR_HANDLE); + break; + + case Command::TEST_WRITE: + result.std_handles.in = winapi::Handle::std_in().get(); + result.std_handles.out = + write_to(winapi::Handle::std_out(), worker::test_data::out()).get(); + result.std_handles.err = + write_to(winapi::Handle::std_err(), worker::test_data::err()).get(); + break; + + case Command::GET_CONSOLE_BUFFER: + result.console_buffer = + result.console_buffer.convert(get_console_buffer(args.numof_lines)); + break; + + default: + throw std::runtime_error{"invalid worker command"}; + } +} + +int loop() { + auto exit_loop = false; + + const auto cmd = Command::open(); + + while (!exit_loop) { + cmd->process_action([&exit_loop](Command::Action action, + const Command::Args& args, + Command::Result& result) { + if (action == Command::EXIT) { + exit_loop = true; + } else { + process_action(action, args, result); + } + }); + } + return 0; +} + +} // namespace + +int main(int argc, char* argv[]) { + int ec = loop(); + std::this_thread::sleep_for(std::chrono::milliseconds{1000}); + return ec; +} -- cgit v1.2.3