diff --git a/tests/cache_check.rs b/tests/cache_check.rs index 9a629d1..f89c182 100644 --- a/tests/cache_check.rs +++ b/tests/cache_check.rs @@ -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 { + 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); //------------------------------------------ diff --git a/tests/common/common_args.rs b/tests/common/common_args.rs index f4b0a5d..41387df 100644 --- a/tests/common/common_args.rs +++ b/tests/common/common_args.rs @@ -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>() } }; } diff --git a/tests/common/input_arg.rs b/tests/common/input_arg.rs index 30f4400..4e096db 100644 --- a/tests/common/input_arg.rs +++ b/tests/common/input_arg.rs @@ -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 { + 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(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(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(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(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(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(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>() } }; } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 71503b2..a4801aa 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -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 "; - pub const MISSING_OUTPUT_ARG: &str = - "The following required arguments were not provided\n -o "; + 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; + + // 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 { let command = duct::cmd(program, args).stdout_capture().stderr_capture(); @@ -291,4 +338,13 @@ where Ok(()) } +pub fn ensure_superblock_zeroed(p: &PathBuf, thunk: F) -> Result<()> +where + F: Fn() -> Result<()>, +{ + thunk()?; + assert!(superblock_all_zeroes(p)?); + Ok(()) +} + //------------------------------------------ diff --git a/tests/common/output_option.rs b/tests/common/output_option.rs index 3ec3a97..a5e5e7b 100644 --- a/tests/common/output_option.rs +++ b/tests/common/output_option.rs @@ -3,85 +3,85 @@ use crate::common::*; //----------------------------------------- // test invalid arguments -pub fn test_missing_output_option(program: &str, mk_input: F) -> Result<()> +pub fn test_missing_output_option<'a, P>() -> Result<()> where - F: Fn(&mut TestDir) -> Result, + 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(program: &str, mk_input: F) -> Result<()> +pub fn test_output_file_not_found<'a, P>() -> Result<()> where - F: Fn(&mut TestDir) -> Result, + 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(

::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(program: &str, mk_input: F) -> Result<()> +pub fn test_output_cannot_be_a_directory<'a, P>() -> Result<()> where - F: Fn(&mut TestDir) -> Result, + 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(program: &str, mk_input: F) -> Result<()> +pub fn test_unwritable_output_file<'a, P>() -> Result<()> where - F: Fn(&mut TestDir) -> Result, + 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(program: &str, mk_input: F) -> Result<()> +pub fn test_tiny_output_file<'a, P>() -> Result<()> where - F: Fn(&mut TestDir) -> Result, + 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>() } }; } diff --git a/tests/thin_check.rs b/tests/thin_check.rs index 159b447..577a34d 100644 --- a/tests/thin_check.rs +++ b/tests/thin_check.rs @@ -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 { + 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 diff --git a/tests/thin_delta.rs b/tests/thin_delta.rs index cdd203d..c9256a8 100644 --- a/tests/thin_delta.rs +++ b/tests/thin_delta.rs @@ -19,9 +19,35 @@ const USAGE: &str = "Usage: thin_delta [options] \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); //------------------------------------------ diff --git a/tests/thin_dump.rs b/tests/thin_dump.rs index 1cb6819..6d6eb11 100644 --- a/tests/thin_dump.rs +++ b/tests/thin_dump.rs @@ -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 { + 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 diff --git a/tests/thin_metadata_pack.rs b/tests/thin_metadata_pack.rs index 92917df..616bc83 100644 --- a/tests/thin_metadata_pack.rs +++ b/tests/thin_metadata_pack.rs @@ -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 { + 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); + +//----------------------------------------- diff --git a/tests/thin_metadata_unpack.rs b/tests/thin_metadata_unpack.rs index c2fc068..9a66d58 100644 --- a/tests/thin_metadata_unpack.rs +++ b/tests/thin_metadata_unpack.rs @@ -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 { + 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); //------------------------------------------ diff --git a/tests/thin_repair.rs b/tests/thin_repair.rs index 1884e6f..31ecaa8 100644 --- a/tests/thin_repair.rs +++ b/tests/thin_repair.rs @@ -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 { + 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 diff --git a/tests/thin_restore.rs b/tests/thin_restore.rs index 79336e4..5208d71 100644 --- a/tests/thin_restore.rs +++ b/tests/thin_restore.rs @@ -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 { + 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); //----------------------------------------- diff --git a/tests/thin_rmap.rs b/tests/thin_rmap.rs index eab535d..1acae99 100644 --- a/tests/thin_rmap.rs +++ b/tests/thin_rmap.rs @@ -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); //------------------------------------------