diff --git a/test/test_helpers.h b/test/test_helpers.h index f14b1c7f..a38a447c 100644 --- a/test/test_helpers.h +++ b/test/test_helpers.h @@ -237,6 +237,10 @@ class test_iolayer { void set_os_access(std::shared_ptr os); void set_file_access(std::shared_ptr fa); + std::istream& in_stream() { return in_; } + std::ostream& out_stream() { return out_; } + std::ostream& err_stream() { return err_; } + private: std::shared_ptr os_; std::shared_ptr term_; diff --git a/test/tool_main_test.cpp b/test/tool_main_test.cpp index 87d006b1..dc92615b 100644 --- a/test/tool_main_test.cpp +++ b/test/tool_main_test.cpp @@ -231,9 +231,16 @@ class mkdwarfs_tester : public tester_common { std::unique_ptr lgr; }; -std::string build_test_image() { +std::string +build_test_image(std::vector extra_args = {}, + std::map extra_files = {}) { mkdwarfs_tester t; - if (t.run({"-i", "/", "-o", "-"}) != 0) { + for (auto const& [name, contents] : extra_files) { + t.fa->set_file(name, contents); + } + std::vector args = {"-i", "/", "-o", "-"}; + args.insert(args.end(), extra_args.begin(), extra_args.end()); + if (t.run(args) != 0) { throw std::runtime_error("failed to build test image:\n" + t.err()); } return t.out(); @@ -1579,6 +1586,120 @@ TEST(dwarfsck_test, print_header_and_json) { "--export-metadata and --check-integrity")); } +TEST(dwarfsck_test, print_header) { + std::string const header = "interesting stuff in the header\n"; + auto image = + build_test_image({"--header", "header.txt"}, {{"header.txt", header}}); + + { + auto t = dwarfsck_tester::create_with_image(image); + EXPECT_EQ(0, t.run({"image.dwarfs", "--print-header"})) << t.err(); + EXPECT_EQ(header, t.out()); + } + + { + auto t = dwarfsck_tester::create_with_image(image); + t.iol->out_stream().setstate(std::ios_base::failbit); + EXPECT_EQ(1, t.run({"image.dwarfs", "--print-header"})) << t.err(); + EXPECT_THAT(t.err(), ::testing::HasSubstr("error writing header")); + } +} + +TEST(dwarfsck_test, check_fail) { + static constexpr size_t section_header_size{64}; + auto image = build_test_image(); + + { + auto t = dwarfsck_tester::create_with_image(image); + EXPECT_EQ(0, t.run({"image.dwarfs"})) << t.err(); + } + + { + auto t = dwarfsck_tester::create_with_image(image); + EXPECT_EQ(0, t.run({"image.dwarfs", "--check-integrity"})) << t.err(); + } + + std::map section_offsets; + + { + auto t = dwarfsck_tester::create_with_image(image); + EXPECT_EQ(0, t.run({"image.dwarfs", "--no-check", "-j", "-d3"})) << t.err(); + + auto info = folly::parseJson(t.out()); + ASSERT_TRUE(info.count("sections") > 0) << folly::toPrettyJson(info); + + size_t offset = 0; + + for (auto const& section : info["sections"]) { + auto type = section["type"].asString(); + auto size = section["compressed_size"].asInt(); + section_offsets[type] = offset; + offset += section_header_size + size; + } + + EXPECT_EQ(image.size(), offset); + } + + for (auto const& [type, offset] : section_offsets) { + auto corrupt_image = image; + // flip a bit right after the header + corrupt_image[offset + section_header_size] ^= 0x01; + + { + auto t = dwarfsck_tester::create_with_image(corrupt_image); + + // for blocks, we skip checks with --no-check + if (type == "BLOCK") { + EXPECT_EQ(0, t.run({"image.dwarfs", "--no-check", "-j"})) << t.err(); + EXPECT_GT(t.out().size(), 100) << t.out(); + } else { + EXPECT_EQ(1, t.run({"image.dwarfs", "--no-check", "-j"})) << t.err(); + EXPECT_EQ(0, t.out().size()) << t.out(); + EXPECT_THAT(t.err(), ::testing::HasSubstr(fmt::format( + "checksum error in section: {}", type))); + } + + // std::cout << "[" << type << ", nocheck]\n" << t.out() << std::endl; + } + + { + auto t = dwarfsck_tester::create_with_image(corrupt_image); + + EXPECT_EQ(1, t.run({"image.dwarfs", "-j"})) << t.err(); + + if (type == "BLOCK") { + EXPECT_GT(t.out().size(), 100) << t.out(); + } else { + EXPECT_EQ(0, t.out().size()) << t.out(); + } + + EXPECT_THAT(t.err(), ::testing::HasSubstr(fmt::format( + "checksum error in section: {}", type))); + + // std::cout << "[" << type << "]\n" << t.out() << std::endl; + } + + { + auto t = dwarfsck_tester::create_with_image(corrupt_image); + + EXPECT_EQ(1, t.run({"image.dwarfs", "--check-integrity", "-j"})) + << t.err(); + + if (type == "BLOCK") { + EXPECT_GT(t.out().size(), 100) << t.out(); + EXPECT_THAT(t.err(), ::testing::HasSubstr(fmt::format( + "integrity check error in section: BLOCK"))); + } else { + EXPECT_EQ(0, t.out().size()) << t.out(); + EXPECT_THAT(t.err(), ::testing::HasSubstr(fmt::format( + "checksum error in section: {}", type))); + } + + // std::cout << "[" << type << ", integrity]\n" << t.out() << std::endl; + } + } +} + TEST(dwarfsck_test, print_header_and_export_metadata) { auto t = dwarfsck_tester::create_with_image(); EXPECT_NE(0, t.run({"image.dwarfs", "--print-header",