Skip to content

Commit

Permalink
test: test command line tool usage / help
Browse files Browse the repository at this point in the history
  • Loading branch information
mhx committed Dec 28, 2023
1 parent 85be65e commit c5340cf
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 10 deletions.
17 changes: 10 additions & 7 deletions src/dwarfs_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ struct dwarfs_userdata {
dwarfs_userdata(dwarfs_userdata const&) = delete;
dwarfs_userdata& operator=(dwarfs_userdata const&) = delete;

bool is_help{false};
options opts;
stream_logger lgr;
filesystem_v2 fs;
Expand Down Expand Up @@ -962,7 +963,7 @@ void usage(std::ostream& os, std::filesystem::path const& progname) {
#if !DWARFS_FUSE_LOWLEVEL
<< "USING HIGH-LEVEL FUSE API\n\n"
#endif
<< "usage: " << progname.filename().string()
<< "Usage: " << progname.filename().string()
<< " <image> <mountpoint> [options]\n\n"
<< "DWARFS options:\n"
<< " -o cachesize=SIZE set size of block cache (512M)\n"
Expand Down Expand Up @@ -995,8 +996,6 @@ void usage(std::ostream& os, std::filesystem::path const& progname) {
fuse_main(args.argc, args.argv, &fsops, nullptr);
fuse_opt_free_args(&args);
#endif

::exit(1);
}

int option_hdl(void* data, char const* arg, int key,
Expand All @@ -1022,7 +1021,8 @@ int option_hdl(void* data, char const* arg, int key,

case FUSE_OPT_KEY_OPT:
if (::strncmp(arg, "-h", 2) == 0 || ::strncmp(arg, "--help", 6) == 0) {
usage(userdata.iol.err, opts.progname);
userdata.is_help = true;
return -1;
}
break;

Expand Down Expand Up @@ -1265,7 +1265,8 @@ int dwarfs_main(int argc, sys_char** argv, iolayer const& iol) {
struct fuse_cmdline_opts fuse_opts;

if (fuse_parse_cmdline(&args, &fuse_opts) == -1 || !fuse_opts.mountpoint) {
usage(iol.err, opts.progname);
usage(iol.out, opts.progname);
return userdata.is_help ? 0 : 1;
}

if (fuse_opts.foreground) {
Expand All @@ -1278,7 +1279,8 @@ int dwarfs_main(int argc, sys_char** argv, iolayer const& iol) {
int mt, fg;

if (fuse_parse_cmdline(&args, &mountpoint, &mt, &fg) == -1 || !mountpoint) {
usage(iol.err, opts.progname);
usage(iol.out, opts.progname);
return userdata.is_help ? 0 : 1;
}

if (fg) {
Expand Down Expand Up @@ -1349,7 +1351,8 @@ int dwarfs_main(int argc, sys_char** argv, iolayer const& iol) {
}

if (!opts.seen_mountpoint) {
usage(iol.err, opts.progname);
usage(iol.out, opts.progname);
return 1;
}

LOG_PROXY(debug_logger_policy, userdata.lgr);
Expand Down
4 changes: 3 additions & 1 deletion src/dwarfsck_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,10 @@ int dwarfsck_main(int argc, sys_char** argv, iolayer const& iol) {
return 1;
}

auto constexpr usage = "Usage: dwarfsck [OPTIONS...]\n";

if (vm.count("help") or !vm.count("input")) {
iol.out << tool_header("dwarfsck") << opts << "\n";
iol.out << tool_header("dwarfsck") << usage << "\n" << opts << "\n";
return 0;
}

Expand Down
5 changes: 4 additions & 1 deletion src/dwarfsextract_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,12 @@ int dwarfsextract_main(int argc, sys_char** argv, iolayer const& iol) {
return 1;
}

auto constexpr usage = "Usage: dwarfsextract [OPTIONS...]\n";

if (vm.count("help") or !vm.count("input")) {
iol.err << tool_header("dwarfsextract") << "using "
iol.out << tool_header("dwarfsextract") << "using "
<< ::archive_version_string() << "\n\n"
<< usage << "\n"
<< opts << "\n";
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion src/mkdwarfs_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ int mkdwarfs_main(int argc, sys_char** argv, iolayer const& iol) {
return 1;
}

auto const usage = "Usage: mkdwarfs [OPTIONS...]\n";
auto constexpr usage = "Usage: mkdwarfs [OPTIONS...]\n";

if (vm.count("long-help")) {
std::string_view constexpr block_data_hdr{"Block Data"};
Expand Down
1 change: 1 addition & 0 deletions test/test_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class test_file_access : public file_access {

class test_iolayer {
public:
test_iolayer();
test_iolayer(std::shared_ptr<os_access_mock> os);
test_iolayer(std::shared_ptr<os_access_mock> os,
std::shared_ptr<file_access const> fa);
Expand Down
3 changes: 3 additions & 0 deletions test/test_iolayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ std::string test_terminal::colored(std::string text, termcolor color,
return result;
}

test_iolayer::test_iolayer()
: test_iolayer{os_access_mock::create_test_instance()} {}

test_iolayer::test_iolayer(std::shared_ptr<os_access_mock> os)
: test_iolayer{std::move(os), create_file_access_generic()} {}

Expand Down
159 changes: 159 additions & 0 deletions test/tool_main_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <filesystem>

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <fmt/format.h>
Expand All @@ -42,8 +43,166 @@ namespace {
auto test_dir = fs::path(TEST_DATA_DIR).make_preferred();
auto audio_data_dir = test_dir / "pcmaudio";

class tool_main_test : public testing::Test {
public:
void SetUp() override { iol = std::make_unique<test::test_iolayer>(); }

void TearDown() override { iol.reset(); }

std::string out() const { return iol->out(); }
std::string err() const { return iol->err(); }

std::unique_ptr<test::test_iolayer> iol;
};

} // namespace

class mkdwarfs_main_test : public tool_main_test {
public:
int run(std::vector<std::string> args) {
args.insert(args.begin(), "mkdwarfs");
return mkdwarfs_main(args, iol->get());
}
};

class dwarfsck_main_test : public tool_main_test {
public:
int run(std::vector<std::string> args) {
args.insert(args.begin(), "dwarfsck");
return dwarfsck_main(args, iol->get());
}
};

class dwarfsextract_main_test : public tool_main_test {
public:
int run(std::vector<std::string> args) {
args.insert(args.begin(), "dwarfsextract");
return dwarfsextract_main(args, iol->get());
}
};

class dwarfs_main_test : public tool_main_test {
public:
int run(std::vector<std::string> args) {
args.insert(args.begin(), "dwarfs");
return dwarfs_main(args, iol->get());
}
};

TEST_F(mkdwarfs_main_test, no_cmdline_args) {
auto exit_code = run({});
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(err().empty());
EXPECT_FALSE(out().empty());
EXPECT_THAT(out(), ::testing::HasSubstr("Usage: mkdwarfs"));
EXPECT_THAT(out(), ::testing::HasSubstr("--help"));
}

TEST_F(dwarfsck_main_test, no_cmdline_args) {
auto exit_code = run({});
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(err().empty());
EXPECT_FALSE(out().empty());
EXPECT_THAT(out(), ::testing::HasSubstr("Usage: dwarfsck"));
EXPECT_THAT(out(), ::testing::HasSubstr("--help"));
}

TEST_F(dwarfsextract_main_test, no_cmdline_args) {
auto exit_code = run({});
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(err().empty());
EXPECT_FALSE(out().empty());
EXPECT_THAT(out(), ::testing::HasSubstr("Usage: dwarfsextract"));
EXPECT_THAT(out(), ::testing::HasSubstr("--help"));
}

TEST_F(dwarfs_main_test, no_cmdline_args) {
auto exit_code = run({});
EXPECT_EQ(exit_code, 1); // FUSE will exit with 1
EXPECT_FALSE(out().empty());
EXPECT_TRUE(err().empty());
EXPECT_THAT(out(), ::testing::HasSubstr("Usage: dwarfs"));
// Cannot check for --help here because FUSE will print to stdout
// EXPECT_THAT(err(), ::testing::HasSubstr("--help"));
}

TEST_F(mkdwarfs_main_test, invalid_cmdline_args) {
auto exit_code = run({"--some-invalid-option"});
EXPECT_EQ(exit_code, 1);
EXPECT_FALSE(err().empty());
EXPECT_TRUE(out().empty());
EXPECT_THAT(err(), ::testing::HasSubstr(
"unrecognised option '--some-invalid-option'"));
}

TEST_F(dwarfsck_main_test, invalid_cmdline_args) {
auto exit_code = run({"--some-invalid-option"});
EXPECT_EQ(exit_code, 1);
EXPECT_FALSE(err().empty());
EXPECT_TRUE(out().empty());
EXPECT_THAT(err(), ::testing::HasSubstr(
"unrecognised option '--some-invalid-option'"));
}

TEST_F(dwarfsextract_main_test, invalid_cmdline_args) {
auto exit_code = run({"--some-invalid-option"});
EXPECT_EQ(exit_code, 1);
EXPECT_FALSE(err().empty());
EXPECT_TRUE(out().empty());
EXPECT_THAT(err(), ::testing::HasSubstr(
"unrecognised option '--some-invalid-option'"));
}

TEST_F(mkdwarfs_main_test, cmdline_help_arg) {
auto exit_code = run({"--help"});
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(err().empty());
EXPECT_FALSE(out().empty());
EXPECT_THAT(out(), ::testing::HasSubstr("Usage: mkdwarfs"));
EXPECT_THAT(out(), ::testing::HasSubstr("--help"));
EXPECT_THAT(out(), ::testing::HasSubstr("--long-help"));
// check that the detailed help is not shown
EXPECT_THAT(out(), ::testing::Not(::testing::HasSubstr("Advanced options:")));
EXPECT_THAT(out(),
::testing::Not(::testing::HasSubstr("Compression algorithms:")));
}

TEST_F(mkdwarfs_main_test, cmdline_long_help_arg) {
auto exit_code = run({"--long-help"});
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(err().empty());
EXPECT_FALSE(out().empty());
EXPECT_THAT(out(), ::testing::HasSubstr("Usage: mkdwarfs"));
EXPECT_THAT(out(), ::testing::HasSubstr("Advanced options:"));
EXPECT_THAT(out(), ::testing::HasSubstr("Compression level defaults:"));
EXPECT_THAT(out(), ::testing::HasSubstr("Compression algorithms:"));
EXPECT_THAT(out(), ::testing::HasSubstr("Categories:"));
}

TEST_F(dwarfsck_main_test, cmdline_help_arg) {
auto exit_code = run({"--help"});
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(err().empty());
EXPECT_FALSE(out().empty());
EXPECT_THAT(out(), ::testing::HasSubstr("Usage: dwarfs"));
}

TEST_F(dwarfsextract_main_test, cmdline_help_arg) {
auto exit_code = run({"--help"});
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(err().empty());
EXPECT_FALSE(out().empty());
EXPECT_THAT(out(), ::testing::HasSubstr("Usage: dwarfs"));
}

TEST_F(dwarfs_main_test, cmdline_help_arg) {
auto exit_code = run({"--help"});
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(err().empty());
EXPECT_FALSE(out().empty());
EXPECT_THAT(out(), ::testing::HasSubstr("Usage: dwarfs"));
}

class categorizer_test : public testing::TestWithParam<std::string> {};

TEST_P(categorizer_test, end_to_end) {
Expand Down

0 comments on commit c5340cf

Please sign in to comment.