[tests] Use traits to specify test parameters

To deal with variety in target attributes and their expected outputs,
the test parameters are categorized into traits, thus the test program
could define test parameters in a more structured way, without having
to pass multiple tightly-coupled parameters to test functions.
This commit is contained in:
Ming-Hung Tsai 2021-07-06 09:51:27 +08:00
parent 12ef69c31b
commit f395bab7be
13 changed files with 677 additions and 198 deletions

View File

@ -22,18 +22,64 @@ const USAGE: &str = "Usage: cache_check [options] {device|file}\n\
//------------------------------------------
test_accepts_help!(CACHE_CHECK, USAGE);
test_accepts_version!(CACHE_CHECK);
test_rejects_bad_option!(CACHE_CHECK);
struct CacheCheck;
test_missing_input_arg!(CACHE_CHECK);
test_input_file_not_found!(CACHE_CHECK, ARG);
test_input_cannot_be_a_directory!(CACHE_CHECK, ARG);
test_unreadable_input_file!(CACHE_CHECK, ARG);
impl<'a> Program<'a> for CacheCheck {
fn name() -> &'a str {
"cache_check"
}
test_help_message_for_tiny_input_file!(CACHE_CHECK, ARG);
test_spot_xml_data!(CACHE_CHECK, "cache_check", ARG);
test_corrupted_input_data!(CACHE_CHECK, ARG);
fn path() -> &'a str {
CACHE_CHECK
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::InputArg
}
fn bad_option_hint(option: &str) -> String {
msg::bad_option_hint(option)
}
}
impl<'a> InputProgram<'a> for CacheCheck {
fn mk_valid_input(td: &mut TestDir) -> Result<std::path::PathBuf> {
mk_valid_md(td)
}
fn file_not_found() -> &'a str {
msg::FILE_NOT_FOUND
}
fn missing_input_arg() -> &'a str {
msg::MISSING_INPUT_ARG
}
fn corrupted_input() -> &'a str {
msg::BAD_SUPERBLOCK
}
}
impl<'a> BinaryInputProgram<'_> for CacheCheck {}
//------------------------------------------
test_accepts_help!(CacheCheck);
test_accepts_version!(CacheCheck);
test_rejects_bad_option!(CacheCheck);
test_missing_input_arg!(CacheCheck);
test_input_file_not_found!(CacheCheck);
test_input_cannot_be_a_directory!(CacheCheck);
test_unreadable_input_file!(CacheCheck);
test_help_message_for_tiny_input_file!(CacheCheck);
test_spot_xml_data!(CacheCheck);
test_corrupted_input_data!(CacheCheck);
//------------------------------------------

View File

@ -4,29 +4,35 @@ use thinp::version::tools_version;
//------------------------------------------
// help
pub fn test_help_short(program: &str, usage: &str) -> Result<()> {
let stdout = run_ok(program, &["-h"])?;
assert_eq!(stdout, usage);
pub fn test_help_short<'a, P>() -> Result<()>
where
P: Program<'a>,
{
let stdout = run_ok(P::path(), &["-h"])?;
assert_eq!(stdout, P::usage());
Ok(())
}
pub fn test_help_long(program: &str, usage: &str) -> Result<()> {
let stdout = run_ok(program, &["--help"])?;
assert_eq!(stdout, usage);
pub fn test_help_long<'a, P>() -> Result<()>
where
P: Program<'a>,
{
let stdout = run_ok(P::path(), &["--help"])?;
assert_eq!(stdout, P::usage());
Ok(())
}
#[macro_export]
macro_rules! test_accepts_help {
($program: ident, $usage: expr) => {
($program: ident) => {
#[test]
fn accepts_h() -> Result<()> {
test_help_short($program, $usage)
test_help_short::<$program>()
}
#[test]
fn accepts_help() -> Result<()> {
test_help_long($program, $usage)
test_help_long::<$program>()
}
};
}
@ -34,14 +40,20 @@ macro_rules! test_accepts_help {
//------------------------------------------
// version
pub fn test_version_short(program: &str) -> Result<()> {
let stdout = run_ok(program, &["-V"])?;
pub fn test_version_short<'a, P>() -> Result<()>
where
P: Program<'a>,
{
let stdout = run_ok(P::path(), &["-V"])?;
assert!(stdout.contains(tools_version()));
Ok(())
}
pub fn test_version_long(program: &str) -> Result<()> {
let stdout = run_ok(program, &["--version"])?;
pub fn test_version_long<'a, P>() -> Result<()>
where
P: Program<'a>,
{
let stdout = run_ok(P::path(), &["--version"])?;
assert!(stdout.contains(tools_version()));
Ok(())
}
@ -51,21 +63,25 @@ macro_rules! test_accepts_version {
($program: ident) => {
#[test]
fn accepts_v() -> Result<()> {
test_version_short($program)
test_version_short::<$program>()
}
#[test]
fn accepts_version() -> Result<()> {
test_version_long($program)
test_version_long::<$program>()
}
};
}
//------------------------------------------
pub fn test_rejects_bad_option(program: &str) -> Result<()> {
let stderr = run_fail(program, &["--hedgehogs-only"])?;
assert!(stderr.contains("unrecognized option \'--hedgehogs-only\'"));
pub fn test_rejects_bad_option<'a, P>() -> Result<()>
where
P: Program<'a>,
{
let option = "--hedgehogs-only";
let stderr = run_fail(P::path(), &[option])?;
assert!(stderr.contains(&P::bad_option_hint(option)));
Ok(())
}
@ -74,7 +90,7 @@ macro_rules! test_rejects_bad_option {
($program: ident) => {
#[test]
fn rejects_bad_option() -> Result<()> {
test_rejects_bad_option($program)
test_rejects_bad_option::<$program>()
}
};
}

View File

@ -4,7 +4,9 @@ use crate::common::*;
//------------------------------------------
// wrappers
pub fn with_output_md_untouched(
type ArgsBuilder = fn(&mut TestDir, &str, &dyn Fn(&[&str]) -> Result<()>) -> Result<()>;
fn with_output_md_untouched(
td: &mut TestDir,
input: &str,
thunk: &dyn Fn(&[&str]) -> Result<()>,
@ -16,7 +18,19 @@ pub fn with_output_md_untouched(
})
}
pub fn input_arg_only(
fn with_output_superblock_zeroed(
td: &mut TestDir,
input: &str,
thunk: &dyn Fn(&[&str]) -> Result<()>,
) -> Result<()> {
let output = mk_zeroed_md(td)?;
ensure_superblock_zeroed(&output, || {
let args = ["-i", input, "-o", output.to_str().unwrap()];
thunk(&args)
})
}
fn input_arg_only(
_td: &mut TestDir,
input: &str,
thunk: &dyn Fn(&[&str]) -> Result<()>,
@ -25,12 +39,22 @@ pub fn input_arg_only(
thunk(&args)
}
fn build_args_fn(t: ArgType) -> Result<ArgsBuilder> {
match t {
ArgType::InputArg => Ok(input_arg_only),
ArgType::IoOptions => Ok(with_output_md_untouched),
}
}
//------------------------------------------
// test invalid arguments
pub fn test_missing_input_arg(program: &str) -> Result<()> {
let stderr = run_fail(program, &[])?;
assert!(stderr.contains(msg::MISSING_INPUT_ARG));
pub fn test_missing_input_arg<'a, P>() -> Result<()>
where
P: InputProgram<'a>,
{
let stderr = run_fail(P::path(), &[])?;
assert!(stderr.contains(P::missing_input_arg()));
Ok(())
}
@ -39,18 +63,21 @@ macro_rules! test_missing_input_arg {
($program: ident) => {
#[test]
fn missing_input_arg() -> Result<()> {
test_missing_input_arg($program)
test_missing_input_arg::<$program>()
}
};
}
pub fn test_missing_input_option(program: &str) -> Result<()> {
pub fn test_missing_input_option<'a, P>() -> Result<()>
where
P: InputProgram<'a>,
{
let mut td = TestDir::new()?;
let output = mk_zeroed_md(&mut td)?;
ensure_untouched(&output, || {
let args = ["-o", output.to_str().unwrap()];
let stderr = run_fail(program, &args)?;
assert!(stderr.contains(msg::MISSING_INPUT_ARG));
let stderr = run_fail(P::path(), &args)?;
assert!(stderr.contains(P::missing_input_arg()));
Ok(())
})
}
@ -60,48 +87,44 @@ macro_rules! test_missing_input_option {
($program: ident) => {
#[test]
fn missing_input_option() -> Result<()> {
test_missing_input_option($program)
test_missing_input_option::<$program>()
}
};
}
pub fn test_input_file_not_found<F>(program: &str, wrapper: F) -> Result<()>
pub fn test_input_file_not_found<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir, &str, &dyn Fn(&[&str]) -> Result<()>) -> Result<()>,
P: InputProgram<'a>,
{
let mut td = TestDir::new()?;
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, "no-such-file", &|args: &[&str]| {
let stderr = run_fail(program, args)?;
assert!(stderr.contains(msg::FILE_NOT_FOUND));
let stderr = run_fail(P::path(), args)?;
assert!(stderr.contains(P::file_not_found()));
Ok(())
})
}
#[macro_export]
macro_rules! test_input_file_not_found {
($program: ident, ARG) => {
($program: ident) => {
#[test]
fn input_file_not_found() -> Result<()> {
test_input_file_not_found($program, input_arg_only)
}
};
($program: ident, OPTION) => {
#[test]
fn input_file_not_found() -> Result<()> {
test_input_file_not_found($program, with_output_md_untouched)
test_input_file_not_found::<$program>()
}
};
}
pub fn test_input_cannot_be_a_directory<F>(program: &str, wrapper: F) -> Result<()>
pub fn test_input_cannot_be_a_directory<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir, &str, &dyn Fn(&[&str]) -> Result<()>) -> Result<()>,
P: InputProgram<'a>,
{
let mut td = TestDir::new()?;
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, "/tmp", &|args: &[&str]| {
let stderr = run_fail(program, args)?;
let stderr = run_fail(P::path(), args)?;
assert!(stderr.contains("Not a block device or regular file"));
Ok(())
})
@ -109,23 +132,17 @@ where
#[macro_export]
macro_rules! test_input_cannot_be_a_directory {
($program: ident, ARG) => {
($program: ident) => {
#[test]
fn input_cannot_be_a_directory() -> Result<()> {
test_input_cannot_be_a_directory($program, input_arg_only)
}
};
($program: ident, OPTION) => {
#[test]
fn input_cannot_be_a_directory() -> Result<()> {
test_input_cannot_be_a_directory($program, with_output_md_untouched)
test_input_cannot_be_a_directory::<$program>()
}
};
}
pub fn test_unreadable_input_file<F>(program: &str, wrapper: F) -> Result<()>
pub fn test_unreadable_input_file<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir, &str, &dyn Fn(&[&str]) -> Result<()>) -> Result<()>,
P: InputProgram<'a>,
{
let mut td = TestDir::new()?;
@ -133,8 +150,9 @@ where
let input = mk_valid_md(&mut td)?;
duct::cmd!("chmod", "-r", &input).run()?;
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, input.to_str().unwrap(), &|args: &[&str]| {
let stderr = run_fail(program, args)?;
let stderr = run_fail(P::path(), args)?;
assert!(stderr.contains("Permission denied"));
Ok(())
})
@ -142,16 +160,10 @@ where
#[macro_export]
macro_rules! test_unreadable_input_file {
($program: ident, ARG) => {
($program: ident) => {
#[test]
fn unreadable_input_file() -> Result<()> {
test_unreadable_input_file($program, input_arg_only)
}
};
($program: ident, OPTION) => {
#[test]
fn unreadable_input_file() -> Result<()> {
test_unreadable_input_file($program, with_output_md_untouched)
test_unreadable_input_file::<$program>()
}
};
}
@ -159,17 +171,18 @@ macro_rules! test_unreadable_input_file {
//------------------------------------------
// test invalid content
pub fn test_help_message_for_tiny_input_file<F>(program: &str, wrapper: F) -> Result<()>
pub fn test_help_message_for_tiny_input_file<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir, &str, &dyn Fn(&[&str]) -> Result<()>) -> Result<()>,
P: BinaryInputProgram<'a>,
{
let mut td = TestDir::new()?;
let input = td.mk_path("meta.bin");
file_utils::create_sized_file(&input, 1024)?;
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, input.to_str().unwrap(), &|args: &[&str]| {
let stderr = run_fail(program, args)?;
let stderr = run_fail(P::path(), args)?;
assert!(stderr.contains("Metadata device/file too small. Is this binary metadata?"));
Ok(())
})
@ -177,23 +190,17 @@ where
#[macro_export]
macro_rules! test_help_message_for_tiny_input_file {
($program: ident, ARG) => {
($program: ident) => {
#[test]
fn prints_help_message_for_tiny_input_file() -> Result<()> {
test_help_message_for_tiny_input_file($program, input_arg_only)
}
};
($program: ident, OPTION) => {
#[test]
fn prints_help_message_for_tiny_input_file() -> Result<()> {
test_help_message_for_tiny_input_file($program, with_output_md_untouched)
test_help_message_for_tiny_input_file::<$program>()
}
};
}
pub fn test_spot_xml_data<F>(program: &str, name: &str, wrapper: F) -> Result<()>
pub fn test_spot_xml_data<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir, &str, &dyn Fn(&[&str]) -> Result<()>) -> Result<()>,
P: BinaryInputProgram<'a>,
{
let mut td = TestDir::new()?;
@ -202,12 +209,13 @@ where
let mut gen = FragmentedS::new(4, 10240);
write_xml(&input, &mut gen)?;
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, input.to_str().unwrap(), &|args: &[&str]| {
let stderr = run_fail(program, args)?;
let stderr = run_fail(P::path(), args)?;
eprintln!("{}", stderr);
let msg = format!(
"This looks like XML. {} only checks the binary metadata format.",
name
P::name()
);
assert!(stderr.contains(&msg));
Ok(())
@ -216,46 +224,38 @@ where
#[macro_export]
macro_rules! test_spot_xml_data {
($program: ident, $name: expr, ARG) => {
($program: ident) => {
#[test]
fn spot_xml_data() -> Result<()> {
test_spot_xml_data($program, $name, input_arg_only)
}
};
($program: ident, $name: expr, OPTION) => {
#[test]
fn spot_xml_data() -> Result<()> {
test_spot_xml_data($program, $name, with_output_md_untouched)
test_spot_xml_data::<$program>()
}
};
}
pub fn test_corrupted_input_data<F>(program: &str, wrapper: F) -> Result<()>
pub fn test_corrupted_input_data<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir, &str, &dyn Fn(&[&str]) -> Result<()>) -> Result<()>,
P: InputProgram<'a>,
{
let mut td = TestDir::new()?;
let input = mk_zeroed_md(&mut td)?;
let wrapper = match P::arg_type() {
ArgType::InputArg => input_arg_only,
ArgType::IoOptions => with_output_superblock_zeroed,
};
wrapper(&mut td, input.to_str().unwrap(), &|args: &[&str]| {
let stderr = run_fail(program, args)?;
assert!(stderr.contains("bad checksum in superblock"));
let stderr = run_fail(P::path(), args)?;
assert!(stderr.contains(P::corrupted_input()));
Ok(())
})
}
#[macro_export]
macro_rules! test_corrupted_input_data {
($program: ident, ARG) => {
($program: ident) => {
#[test]
fn corrupted_input_data() -> Result<()> {
test_corrupted_input_data($program, input_arg_only)
}
};
($program: ident, OPTION) => {
#[test]
fn corrupted_input_data() -> Result<()> {
test_corrupted_input_data($program, with_output_md_untouched)
test_corrupted_input_data::<$program>()
}
};
}

View File

@ -19,22 +19,33 @@ use test_dir::TestDir;
//------------------------------------------
#[cfg(not(feature = "rust_tests"))]
pub mod msg {
pub mod cpp_msg {
pub const FILE_NOT_FOUND: &str = "No such file or directory";
pub const MISSING_INPUT_ARG: &str = "No input file provided";
pub const MISSING_OUTPUT_ARG: &str = "No output file provided";
pub const BAD_SUPERBLOCK: &str = "bad checksum in superblock";
pub fn bad_option_hint(option: &str) -> String {
format!("unrecognized option '{}'", option)
}
}
#[cfg(feature = "rust_tests")]
pub mod msg {
pub mod rust_msg {
pub const FILE_NOT_FOUND: &str = "Couldn't find input file";
pub const MISSING_INPUT_ARG: &str =
"The following required arguments were not provided\n -i <FILE>";
pub const MISSING_OUTPUT_ARG: &str =
"The following required arguments were not provided\n -o <FILE>";
pub const MISSING_INPUT_ARG: &str = "The following required arguments were not provided"; // TODO: be specific
pub const MISSING_OUTPUT_ARG: &str = "The following required arguments were not provided"; // TODO: be specific
pub const BAD_SUPERBLOCK: &str = "bad checksum in superblock";
pub fn bad_option_hint(option: &str) -> String {
format!("Found argument '{}' which wasn't expected", option)
}
}
#[cfg(not(feature = "rust_tests"))]
pub use cpp_msg as msg;
#[cfg(feature = "rust_tests")]
pub use rust_msg as msg;
//------------------------------------------
#[macro_export]
@ -86,6 +97,42 @@ pub const THIN_GENERATE_DAMAGE: &str = path_to_cpp!("thin_generate_damage"); //
//------------------------------------------
pub enum ArgType {
InputArg,
IoOptions,
}
pub trait Program<'a> {
fn name() -> &'a str;
fn path() -> &'a str;
fn usage() -> &'a str;
fn arg_type() -> ArgType;
// error messages
fn bad_option_hint(option: &str) -> String;
}
pub trait InputProgram<'a>: Program<'a> {
fn mk_valid_input(td: &mut TestDir) -> Result<PathBuf>;
// error messages
fn missing_input_arg() -> &'a str;
fn file_not_found() -> &'a str;
fn corrupted_input() -> &'a str;
}
pub trait BinaryInputProgram<'a>: InputProgram<'a> {}
pub trait OutputProgram<'a>: InputProgram<'a> {
// error messages
fn missing_output_arg() -> &'a str;
fn file_not_found() -> &'a str;
}
pub trait BinaryOutputProgram<'a>: OutputProgram<'a> {}
//------------------------------------------
// Returns stdout. The command must return zero.
pub fn run_ok(program: &str, args: &[&str]) -> Result<String> {
let command = duct::cmd(program, args).stdout_capture().stderr_capture();
@ -291,4 +338,13 @@ where
Ok(())
}
pub fn ensure_superblock_zeroed<F>(p: &PathBuf, thunk: F) -> Result<()>
where
F: Fn() -> Result<()>,
{
thunk()?;
assert!(superblock_all_zeroes(p)?);
Ok(())
}
//------------------------------------------

View File

@ -3,85 +3,85 @@ use crate::common::*;
//-----------------------------------------
// test invalid arguments
pub fn test_missing_output_option<F>(program: &str, mk_input: F) -> Result<()>
pub fn test_missing_output_option<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir) -> Result<PathBuf>,
P: OutputProgram<'a>,
{
let mut td = TestDir::new()?;
let input = mk_input(&mut td)?;
let stderr = run_fail(program, &["-i", input.to_str().unwrap()])?;
assert!(stderr.contains(msg::MISSING_OUTPUT_ARG));
let input = P::mk_valid_input(&mut td)?;
let stderr = run_fail(P::path(), &["-i", input.to_str().unwrap()])?;
assert!(stderr.contains(P::missing_output_arg()));
Ok(())
}
#[macro_export]
macro_rules! test_missing_output_option {
($program: ident, $mk_input: ident) => {
($program: ident) => {
#[test]
fn missing_output_option() -> Result<()> {
test_missing_output_option($program, $mk_input)
test_missing_output_option::<$program>()
}
};
}
pub fn test_output_file_not_found<F>(program: &str, mk_input: F) -> Result<()>
pub fn test_output_file_not_found<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir) -> Result<PathBuf>,
P: OutputProgram<'a>,
{
let mut td = TestDir::new()?;
let input = mk_input(&mut td)?;
let input = P::mk_valid_input(&mut td)?;
let stderr = run_fail(
program,
P::path(),
&["-i", input.to_str().unwrap(), "-o", "no-such-file"],
)?;
assert!(stderr.contains(msg::FILE_NOT_FOUND));
assert!(stderr.contains(<P as OutputProgram>::file_not_found()));
Ok(())
}
#[macro_export]
macro_rules! test_output_file_not_found {
($program: ident, $mk_input: ident) => {
($program: ident) => {
#[test]
fn output_file_not_found() -> Result<()> {
test_output_file_not_found($program, $mk_input)
test_output_file_not_found::<$program>()
}
};
}
pub fn test_output_cannot_be_a_directory<F>(program: &str, mk_input: F) -> Result<()>
pub fn test_output_cannot_be_a_directory<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir) -> Result<PathBuf>,
P: OutputProgram<'a>,
{
let mut td = TestDir::new()?;
let input = mk_input(&mut td)?;
let stderr = run_fail(program, &["-i", input.to_str().unwrap(), "-o", "/tmp"])?;
assert!(stderr.contains(msg::FILE_NOT_FOUND));
let input = P::mk_valid_input(&mut td)?;
let stderr = run_fail(P::path(), &["-i", input.to_str().unwrap(), "-o", "/tmp"])?;
assert!(stderr.contains("Not a block device or regular file"));
Ok(())
}
#[macro_export]
macro_rules! test_output_cannot_be_a_directory {
($program: ident, $mk_input: ident) => {
($program: ident) => {
#[test]
fn output_cannot_be_a_directory() -> Result<()> {
test_output_cannot_be_a_directory($program, $mk_input)
test_output_cannot_be_a_directory::<$program>()
}
};
}
pub fn test_unwritable_output_file<F>(program: &str, mk_input: F) -> Result<()>
pub fn test_unwritable_output_file<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir) -> Result<PathBuf>,
P: OutputProgram<'a>,
{
let mut td = TestDir::new()?;
let input = mk_input(&mut td)?;
let input = P::mk_valid_input(&mut td)?;
let output = td.mk_path("meta.bin");
let _file = file_utils::create_sized_file(&output, 4096);
duct::cmd!("chmod", "-w", &output).run()?;
let stderr = run_fail(
program,
P::path(),
&[
"-i",
input.to_str().unwrap(),
@ -95,10 +95,10 @@ where
#[macro_export]
macro_rules! test_unwritable_output_file {
($program: ident, $mk_input: ident) => {
($program: ident) => {
#[test]
fn unwritable_output_file() -> Result<()> {
test_unwritable_output_file($program, $mk_input)
test_unwritable_output_file::<$program>()
}
};
}
@ -107,18 +107,18 @@ macro_rules! test_unwritable_output_file {
// test invalid content
// currently thin/cache_restore only
pub fn test_tiny_output_file<F>(program: &str, mk_input: F) -> Result<()>
pub fn test_tiny_output_file<'a, P>() -> Result<()>
where
F: Fn(&mut TestDir) -> Result<PathBuf>,
P: BinaryOutputProgram<'a>,
{
let mut td = TestDir::new()?;
let input = mk_input(&mut td)?;
let input = P::mk_valid_input(&mut td)?;
let output = td.mk_path("meta.bin");
let _file = file_utils::create_sized_file(&output, 4096);
let stderr = run_fail(
program,
P::path(),
&[
"-i",
input.to_str().unwrap(),
@ -132,10 +132,10 @@ where
#[macro_export]
macro_rules! test_tiny_output_file {
($program: ident, $mk_input: ident) => {
($program: ident) => {
#[test]
fn tiny_output_file() -> Result<()> {
test_tiny_output_file($program, $mk_input)
test_tiny_output_file::<$program>()
}
};
}

View File

@ -22,20 +22,66 @@ const USAGE: &str = "Usage: thin_check [options] {device|file}\n\
{--skip-mappings}\n \
{--super-block-only}";
//-----------------------------------------
struct ThinCheck;
impl<'a> Program<'a> for ThinCheck {
fn name() -> &'a str {
"thin_check"
}
fn path() -> &'a str {
THIN_CHECK
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::InputArg
}
fn bad_option_hint(option: &str) -> String {
msg::bad_option_hint(option)
}
}
impl<'a> InputProgram<'a> for ThinCheck {
fn mk_valid_input(td: &mut TestDir) -> Result<std::path::PathBuf> {
mk_valid_md(td)
}
fn file_not_found() -> &'a str {
msg::FILE_NOT_FOUND
}
fn missing_input_arg() -> &'a str {
msg::MISSING_INPUT_ARG
}
fn corrupted_input() -> &'a str {
msg::BAD_SUPERBLOCK
}
}
impl<'a> BinaryInputProgram<'_> for ThinCheck {}
//------------------------------------------
test_accepts_help!(THIN_CHECK, USAGE);
test_accepts_version!(THIN_CHECK);
test_rejects_bad_option!(THIN_CHECK);
test_accepts_help!(ThinCheck);
test_accepts_version!(ThinCheck);
test_rejects_bad_option!(ThinCheck);
test_missing_input_arg!(THIN_CHECK);
test_input_file_not_found!(THIN_CHECK, ARG);
test_input_cannot_be_a_directory!(THIN_CHECK, ARG);
test_unreadable_input_file!(THIN_CHECK, ARG);
test_missing_input_arg!(ThinCheck);
test_input_file_not_found!(ThinCheck);
test_input_cannot_be_a_directory!(ThinCheck);
test_unreadable_input_file!(ThinCheck);
test_help_message_for_tiny_input_file!(THIN_CHECK, ARG);
test_spot_xml_data!(THIN_CHECK, "thin_check", ARG);
test_corrupted_input_data!(THIN_CHECK, ARG);
test_help_message_for_tiny_input_file!(ThinCheck);
test_spot_xml_data!(ThinCheck);
test_corrupted_input_data!(ThinCheck);
//------------------------------------------
// test exclusive flags

View File

@ -19,9 +19,35 @@ const USAGE: &str = "Usage: thin_delta [options] <device or file>\n\
//------------------------------------------
test_accepts_help!(THIN_DELTA, USAGE);
test_accepts_version!(THIN_DELTA);
test_rejects_bad_option!(THIN_DELTA);
struct ThinDelta;
impl<'a> Program<'a> for ThinDelta {
fn name() -> &'a str {
"thin_delta"
}
fn path() -> &'a str {
THIN_DELTA
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::InputArg
}
fn bad_option_hint(option: &str) -> String {
cpp_msg::bad_option_hint(option)
}
}
//------------------------------------------
test_accepts_help!(ThinDelta);
test_accepts_version!(ThinDelta);
test_rejects_bad_option!(ThinDelta);
//------------------------------------------

View File

@ -23,16 +23,60 @@ const USAGE: &str = "Usage: thin_dump [options] {device|file}\n\
{--skip-mappings}\n \
{-V|--version}";
//-----------------------------------------
struct ThinDump;
impl<'a> Program<'a> for ThinDump {
fn name() -> &'a str {
"thin_dump"
}
fn path() -> &'a str {
THIN_DUMP
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::InputArg
}
fn bad_option_hint(option: &str) -> String {
msg::bad_option_hint(option)
}
}
impl<'a> InputProgram<'a> for ThinDump {
fn mk_valid_input(td: &mut TestDir) -> Result<std::path::PathBuf> {
mk_valid_md(td)
}
fn file_not_found() -> &'a str {
msg::FILE_NOT_FOUND
}
fn missing_input_arg() -> &'a str {
msg::MISSING_INPUT_ARG
}
fn corrupted_input() -> &'a str {
msg::BAD_SUPERBLOCK
}
}
//------------------------------------------
test_accepts_help!(THIN_DUMP, USAGE);
test_accepts_version!(THIN_DUMP);
test_rejects_bad_option!(THIN_DUMP);
test_accepts_help!(ThinDump);
test_accepts_version!(ThinDump);
test_rejects_bad_option!(ThinDump);
test_missing_input_arg!(THIN_DUMP);
test_input_file_not_found!(THIN_DUMP, ARG);
test_input_cannot_be_a_directory!(THIN_DUMP, ARG);
test_unreadable_input_file!(THIN_DUMP, ARG);
test_missing_input_arg!(ThinDump);
test_input_file_not_found!(ThinDump);
test_input_cannot_be_a_directory!(ThinDump);
test_unreadable_input_file!(ThinDump);
//------------------------------------------
// test dump & restore cycle

View File

@ -5,6 +5,7 @@ mod common;
use common::common_args::*;
use common::input_arg::*;
use common::output_option::*;
use common::test_dir::*;
use common::*;
//------------------------------------------
@ -28,12 +29,66 @@ const USAGE: &str = concat!(
//------------------------------------------
test_accepts_help!(THIN_METADATA_PACK, USAGE);
test_accepts_version!(THIN_METADATA_PACK);
test_rejects_bad_option!(THIN_METADATA_PACK);
struct ThinMetadataPack;
test_missing_input_option!(THIN_METADATA_PACK);
test_missing_output_option!(THIN_METADATA_PACK, mk_valid_md);
test_input_file_not_found!(THIN_METADATA_PACK, OPTION);
impl<'a> Program<'a> for ThinMetadataPack {
fn name() -> &'a str {
"thin_metadata_pack"
}
fn path() -> &'a str {
THIN_METADATA_PACK
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::IoOptions
}
fn bad_option_hint(option: &str) -> String {
rust_msg::bad_option_hint(option)
}
}
impl<'a> InputProgram<'a> for ThinMetadataPack {
fn mk_valid_input(td: &mut TestDir) -> Result<std::path::PathBuf> {
mk_valid_md(td)
}
fn file_not_found() -> &'a str {
rust_msg::FILE_NOT_FOUND
}
fn missing_input_arg() -> &'a str {
rust_msg::MISSING_INPUT_ARG
}
fn corrupted_input() -> &'a str {
rust_msg::BAD_SUPERBLOCK
}
}
impl<'a> OutputProgram<'a> for ThinMetadataPack {
fn file_not_found() -> &'a str {
rust_msg::FILE_NOT_FOUND
}
fn missing_output_arg() -> &'a str {
rust_msg::MISSING_OUTPUT_ARG
}
}
//------------------------------------------
test_accepts_help!(ThinMetadataPack);
test_accepts_version!(ThinMetadataPack);
test_rejects_bad_option!(ThinMetadataPack);
test_missing_input_option!(ThinMetadataPack);
test_missing_output_option!(ThinMetadataPack);
test_input_file_not_found!(ThinMetadataPack);
//-----------------------------------------

View File

@ -29,15 +29,69 @@ const USAGE: &str = concat!(
//------------------------------------------
test_accepts_help!(THIN_METADATA_UNPACK, USAGE);
test_accepts_version!(THIN_METADATA_UNPACK);
test_rejects_bad_option!(THIN_METADATA_UNPACK);
struct ThinMetadataUnpack;
test_missing_input_option!(THIN_METADATA_PACK);
test_input_file_not_found!(THIN_METADATA_UNPACK, OPTION);
test_corrupted_input_data!(THIN_METADATA_UNPACK, OPTION);
impl<'a> Program<'a> for ThinMetadataUnpack {
fn name() -> &'a str {
"thin_metadata_pack"
}
test_missing_output_option!(THIN_METADATA_UNPACK, mk_valid_md);
fn path() -> &'a str {
THIN_METADATA_UNPACK
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::IoOptions
}
fn bad_option_hint(option: &str) -> String {
rust_msg::bad_option_hint(option)
}
}
impl<'a> InputProgram<'a> for ThinMetadataUnpack {
fn mk_valid_input(td: &mut TestDir) -> Result<std::path::PathBuf> {
mk_zeroed_md(td) // FIXME: make a real pack file
}
fn file_not_found() -> &'a str {
rust_msg::FILE_NOT_FOUND
}
fn missing_input_arg() -> &'a str {
rust_msg::MISSING_INPUT_ARG
}
fn corrupted_input() -> &'a str {
"Not a pack file"
}
}
impl<'a> OutputProgram<'a> for ThinMetadataUnpack {
fn file_not_found() -> &'a str {
rust_msg::FILE_NOT_FOUND
}
fn missing_output_arg() -> &'a str {
rust_msg::MISSING_OUTPUT_ARG
}
}
//------------------------------------------
test_accepts_help!(ThinMetadataUnpack);
test_accepts_version!(ThinMetadataUnpack);
test_rejects_bad_option!(ThinMetadataUnpack);
test_missing_input_option!(ThinMetadataUnpack);
test_input_file_not_found!(ThinMetadataUnpack);
test_corrupted_input_data!(ThinMetadataUnpack);
test_missing_output_option!(ThinMetadataUnpack);
//------------------------------------------

View File

@ -22,14 +22,68 @@ const USAGE: &str = "Usage: thin_repair [options] {device|file}\n\
//-----------------------------------------
test_accepts_help!(THIN_REPAIR, USAGE);
test_accepts_version!(THIN_REPAIR);
test_rejects_bad_option!(THIN_REPAIR);
struct ThinRepair;
test_input_file_not_found!(THIN_REPAIR, OPTION);
test_corrupted_input_data!(THIN_REPAIR, OPTION);
impl<'a> Program<'a> for ThinRepair {
fn name() -> &'a str {
"thin_repair"
}
test_missing_output_option!(THIN_REPAIR, mk_valid_md);
fn path() -> &'a str {
THIN_REPAIR
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::IoOptions
}
fn bad_option_hint(option: &str) -> String {
cpp_msg::bad_option_hint(option)
}
}
impl<'a> InputProgram<'a> for ThinRepair {
fn mk_valid_input(td: &mut TestDir) -> Result<std::path::PathBuf> {
mk_valid_md(td)
}
fn file_not_found() -> &'a str {
cpp_msg::FILE_NOT_FOUND
}
fn missing_input_arg() -> &'a str {
cpp_msg::MISSING_INPUT_ARG
}
fn corrupted_input() -> &'a str {
"The following field needs to be provided on the command line due to corruption in the superblock"
}
}
impl<'a> OutputProgram<'a> for ThinRepair {
fn file_not_found() -> &'a str {
cpp_msg::FILE_NOT_FOUND
}
fn missing_output_arg() -> &'a str {
cpp_msg::MISSING_OUTPUT_ARG
}
}
//-----------------------------------------
test_accepts_help!(ThinRepair);
test_accepts_version!(ThinRepair);
test_rejects_bad_option!(ThinRepair);
test_input_file_not_found!(ThinRepair);
test_corrupted_input_data!(ThinRepair);
test_missing_output_option!(ThinRepair);
//-----------------------------------------
// test output to a small file

View File

@ -23,15 +23,71 @@ const USAGE: &str = "Usage: thin_restore [options]\n\
//------------------------------------------
test_accepts_help!(THIN_RESTORE, USAGE);
test_accepts_version!(THIN_RESTORE);
struct ThinRestore;
test_missing_input_option!(THIN_RESTORE);
test_input_file_not_found!(THIN_RESTORE, OPTION);
test_corrupted_input_data!(THIN_RESTORE, OPTION);
impl<'a> Program<'a> for ThinRestore {
fn name() -> &'a str {
"thin_restore"
}
test_missing_output_option!(THIN_RESTORE, mk_valid_xml);
test_tiny_output_file!(THIN_RESTORE, mk_valid_xml);
fn path() -> &'a str {
THIN_RESTORE
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::IoOptions
}
fn bad_option_hint(option: &str) -> String {
msg::bad_option_hint(option)
}
}
impl<'a> InputProgram<'a> for ThinRestore {
fn mk_valid_input(td: &mut TestDir) -> Result<std::path::PathBuf> {
mk_valid_md(td)
}
fn file_not_found() -> &'a str {
msg::FILE_NOT_FOUND
}
fn missing_input_arg() -> &'a str {
msg::MISSING_INPUT_ARG
}
fn corrupted_input() -> &'a str {
"" // we don't intent to verify error messages of XML parsing
}
}
impl<'a> OutputProgram<'a> for ThinRestore {
fn file_not_found() -> &'a str {
msg::FILE_NOT_FOUND
}
fn missing_output_arg() -> &'a str {
msg::MISSING_OUTPUT_ARG
}
}
impl<'a> BinaryOutputProgram<'_> for ThinRestore {}
//-----------------------------------------
test_accepts_help!(ThinRestore);
test_accepts_version!(ThinRestore);
test_missing_input_option!(ThinRestore);
test_input_file_not_found!(ThinRestore);
test_corrupted_input_data!(ThinRestore);
test_missing_output_option!(ThinRestore);
test_tiny_output_file!(ThinRestore);
//-----------------------------------------

View File

@ -19,9 +19,35 @@ const USAGE: &str = "Usage: thin_rmap [options] {device|file}\n\
//------------------------------------------
test_accepts_help!(THIN_RMAP, USAGE);
test_accepts_version!(THIN_RMAP);
test_rejects_bad_option!(THIN_RMAP);
struct ThinRmap;
impl<'a> Program<'a> for ThinRmap {
fn name() -> &'a str {
"thin_rmap"
}
fn path() -> &'a str {
THIN_RMAP
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::InputArg
}
fn bad_option_hint(option: &str) -> String {
cpp_msg::bad_option_hint(option)
}
}
//------------------------------------------
test_accepts_help!(ThinRmap);
test_accepts_version!(ThinRmap);
test_rejects_bad_option!(ThinRmap);
//------------------------------------------