/* vim:set ts=2 sw=2 sts=2 et: */
/**
* \author Marcus Holland-Moritz (github@mhxnet.de)
* \copyright Copyright (c) Marcus Holland-Moritz
*
* This file is part of dwarfs.
*
* dwarfs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dwarfs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dwarfs. If not, see .
*/
#include
#include
#include
#include "dwarfs/file_access_generic.h"
#include "test_helpers.h"
namespace dwarfs::test {
namespace {
class test_input_stream : public input_stream {
public:
test_input_stream(std::string content) { is_.str(std::move(content)); }
std::istream& is() override { return is_; }
void close(std::error_code& /*ec*/) override {}
void close() override {}
private:
std::istringstream is_;
};
class test_output_stream : public output_stream {
public:
test_output_stream(std::filesystem::path const& path, std::error_code& ec,
test_file_access const* tfa)
: path_{path}
, tfa_{tfa} {
if (path_.empty()) {
ec = std::make_error_code(std::errc::invalid_argument);
}
if (auto error = tfa_->get_open_error(path_)) {
ec = error.value();
}
}
std::ostream& os() override { return os_; }
void close(std::error_code& ec) override {
if (auto error = tfa_->get_close_error(path_)) {
ec = error.value();
} else {
tfa_->set_file(path_, os_.str());
}
}
void close() override {
std::error_code ec;
close(ec);
if (ec) {
throw std::system_error(ec, fmt::format("close('{}')", path_.string()));
}
}
private:
std::ostringstream os_;
std::filesystem::path path_;
test_file_access const* tfa_;
};
} // namespace
bool test_file_access::exists(std::filesystem::path const& path) const {
return files_.find(path) != files_.end();
}
std::unique_ptr
test_file_access::open_input(std::filesystem::path const& path,
std::error_code& ec) const {
auto it = files_.find(path);
if (it != files_.end()) {
return std::make_unique(it->second);
}
ec = std::make_error_code(std::errc::no_such_file_or_directory);
return nullptr;
}
std::unique_ptr
test_file_access::open_input(std::filesystem::path const& path) const {
std::error_code ec;
auto rv = open_input(path, ec);
if (ec) {
throw std::system_error(ec, fmt::format("open_input('{}')", path.string()));
}
return rv;
}
std::unique_ptr
test_file_access::open_input_binary(std::filesystem::path const& path,
std::error_code& ec) const {
return open_input(path, ec);
}
std::unique_ptr
test_file_access::open_input_binary(std::filesystem::path const& path) const {
std::error_code ec;
auto rv = open_input_binary(path, ec);
if (ec) {
throw std::system_error(
ec, fmt::format("open_input_binary('{}')", path.string()));
}
return rv;
}
std::unique_ptr
test_file_access::open_output(std::filesystem::path const& path,
std::error_code& ec) const {
auto rv = std::make_unique(path, ec, this);
if (ec) {
rv.reset();
}
return rv;
}
std::unique_ptr
test_file_access::open_output(std::filesystem::path const& path) const {
std::error_code ec;
auto rv = open_output(path, ec);
if (ec) {
throw std::system_error(ec,
fmt::format("open_output('{}')", path.string()));
}
return rv;
}
std::unique_ptr
test_file_access::open_output_binary(std::filesystem::path const& path,
std::error_code& ec) const {
auto rv = std::make_unique(path, ec, this);
if (ec) {
rv.reset();
}
return rv;
}
std::unique_ptr
test_file_access::open_output_binary(std::filesystem::path const& path) const {
std::error_code ec;
auto rv = open_output_binary(path, ec);
if (ec) {
throw std::system_error(
ec, fmt::format("open_output_binary('{}')", path.string()));
}
return rv;
}
void test_file_access::set_file(std::filesystem::path const& path,
std::string content) const {
files_[path] = std::move(content);
}
void test_file_access::set_open_error(std::filesystem::path const& path,
std::error_code ec) const {
open_errors_[path] = ec;
}
void test_file_access::set_close_error(std::filesystem::path const& path,
std::error_code ec) const {
close_errors_[path] = ec;
}
std::optional
test_file_access::get_open_error(std::filesystem::path const& path) const {
if (auto it = open_errors_.find(path); it != open_errors_.end()) {
return it->second;
}
return std::nullopt;
}
std::optional
test_file_access::get_close_error(std::filesystem::path const& path) const {
if (auto it = close_errors_.find(path); it != close_errors_.end()) {
return it->second;
}
return std::nullopt;
}
std::optional
test_file_access::get_file(std::filesystem::path const& path) const {
auto it = files_.find(path);
if (it != files_.end()) {
return it->second;
}
return std::nullopt;
}
test_terminal::test_terminal(std::ostream& out, std::ostream& err)
: out_{&out}
, err_{&err} {}
size_t test_terminal::width() const { return width_; }
bool test_terminal::is_tty(std::ostream& /*os*/) const { return is_tty_; }
bool test_terminal::is_fancy() const { return fancy_; }
std::string_view test_terminal::carriage_return() const { return ""; }
std::string_view test_terminal::rewind_line() const { return ""; }
std::string_view test_terminal::clear_line() const { return ""; }
std::string_view test_terminal::color(termcolor color, termstyle style) const {
static constexpr std::array(termcolor::NUM_COLORS)>
// clang-format off
colors = {{
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}}; // clang-format on
static constexpr size_t const kBoldOffset{
static_cast(termcolor::BOLD_RED) -
static_cast(termcolor::RED)};
static constexpr size_t const kDimOffset{
static_cast(termcolor::DIM_RED) -
static_cast(termcolor::RED)};
switch (style) {
case termstyle::BOLD:
case termstyle::DIM: {
auto ix = static_cast(color);
if (ix < static_cast(termcolor::BOLD_RED)) {
color = static_cast(
ix + (style == termstyle::BOLD ? kBoldOffset : kDimOffset));
}
} break;
default:
break;
}
return colors.at(static_cast(color));
}
std::string test_terminal::colored(std::string text, termcolor color,
bool enable, termstyle style) const {
std::string result;
if (enable) {
auto preamble = this->color(color, style);
auto postamble = this->color(termcolor::NORMAL, termstyle::NORMAL);
result.reserve(preamble.size() + text.size() + postamble.size());
result.append(preamble);
result.append(text);
result.append(postamble);
} else {
result.append(text);
}
return result;
}
test_iolayer::test_iolayer()
: test_iolayer{os_access_mock::create_test_instance()} {}
test_iolayer::test_iolayer(std::shared_ptr os)
: test_iolayer{std::move(os), create_file_access_generic()} {}
test_iolayer::test_iolayer(std::shared_ptr os,
std::shared_ptr fa)
: os_{std::move(os)}
, term_{std::make_shared(out_, err_)}
, fa_{std::move(fa)} {}
test_iolayer::~test_iolayer() = default;
iolayer const& test_iolayer::get() {
if (!iol_) {
if (real_term_) {
iol_ = std::make_unique(iolayer{
.os = os_,
.term = real_term_,
.file = fa_,
.in = std::cin,
.out = std::cout,
.err = std::cerr,
});
} else {
iol_ = std::make_unique(iolayer{
.os = os_,
.term = term_,
.file = fa_,
.in = in_,
.out = out_,
.err = err_,
});
}
}
return *iol_;
}
void test_iolayer::use_real_terminal(bool use) {
real_term_ = terminal::create();
}
void test_iolayer::set_terminal_is_tty(bool is_tty) {
term_->set_is_tty(is_tty);
}
void test_iolayer::set_terminal_fancy(bool fancy) { term_->set_fancy(fancy); }
void test_iolayer::set_terminal_width(size_t width) { term_->set_width(width); }
void test_iolayer::set_in(std::string in) { in_.str(std::move(in)); }
std::string test_iolayer::out() const { return out_.str(); }
std::string test_iolayer::err() const { return err_.str(); }
void test_iolayer::set_os_access(std::shared_ptr os) {
if (iol_) {
throw std::runtime_error("iolayer already created");
}
os_ = std::move(os);
}
void test_iolayer::set_file_access(std::shared_ptr fa) {
if (iol_) {
throw std::runtime_error("iolayer already created");
}
fa_ = std::move(fa);
}
} // namespace dwarfs::test