Skip to content

Commit c7d4829

Browse files
committed
add tests for CLI usage
1 parent c0e0531 commit c7d4829

File tree

3 files changed

+156
-4
lines changed

3 files changed

+156
-4
lines changed

src/cli/args.rs

+154-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use clap::{Parser, ValueHint};
88
/// Supported formats: tar, zip, gz, xz/lzma, bz/bz2, lz4, sz, zst.
99
///
1010
/// Repository: https://github.com/ouch-org/ouch
11-
#[derive(Parser, Debug)]
11+
#[derive(Parser, Debug, PartialEq)]
1212
#[command(about, version)]
1313
// Disable rustdoc::bare_urls because rustdoc parses URLs differently than Clap
1414
#[allow(rustdoc::bare_urls)]
@@ -41,7 +41,7 @@ pub struct CliArgs {
4141
#[arg(short, long, global = true)]
4242
pub format: Option<OsString>,
4343

44-
/// Ouch and claps subcommands
44+
// Ouch and claps subcommands
4545
#[command(subcommand)]
4646
pub cmd: Subcommand,
4747
}
@@ -97,3 +97,155 @@ pub enum Subcommand {
9797
tree: bool,
9898
},
9999
}
100+
101+
#[cfg(test)]
102+
mod tests {
103+
use super::*;
104+
105+
fn args_splitter(input: &str) -> impl Iterator<Item = &str> {
106+
input.split_whitespace()
107+
}
108+
109+
fn to_paths(iter: impl IntoIterator<Item = &'static str>) -> Vec<PathBuf> {
110+
iter.into_iter().map(PathBuf::from).collect()
111+
}
112+
113+
macro_rules! test {
114+
($args:expr, $expected:expr) => {
115+
let result = match CliArgs::try_parse_from(args_splitter($args)) {
116+
Ok(result) => result,
117+
Err(err) => panic!(
118+
"CLI result is Err, expected Ok, input: '{}'.\nResult: '{err}'",
119+
$args
120+
),
121+
};
122+
assert_eq!(result, $expected, "CLI result mismatched, input: '{}'.", $args);
123+
};
124+
}
125+
126+
fn mock_cli_args() -> CliArgs {
127+
CliArgs {
128+
yes: false,
129+
no: false,
130+
accessible: false,
131+
hidden: false,
132+
quiet: false,
133+
gitignore: false,
134+
format: None,
135+
// This is usually replaced in assertion tests
136+
cmd: Subcommand::Decompress {
137+
// Put a crazy value here so no test can assert it unintentionally
138+
files: vec!["\x00\x11\x22".into()],
139+
output_dir: None,
140+
},
141+
}
142+
}
143+
144+
#[test]
145+
fn test_clap_cli_ok() {
146+
test!(
147+
"ouch decompress file.tar.gz",
148+
CliArgs {
149+
cmd: Subcommand::Decompress {
150+
files: to_paths(["file.tar.gz"]),
151+
output_dir: None,
152+
},
153+
..mock_cli_args()
154+
}
155+
);
156+
test!(
157+
"ouch d file.tar.gz",
158+
CliArgs {
159+
cmd: Subcommand::Decompress {
160+
files: to_paths(["file.tar.gz"]),
161+
output_dir: None,
162+
},
163+
..mock_cli_args()
164+
}
165+
);
166+
test!(
167+
"ouch d a b c",
168+
CliArgs {
169+
cmd: Subcommand::Decompress {
170+
files: to_paths(["a", "b", "c"]),
171+
output_dir: None,
172+
},
173+
..mock_cli_args()
174+
}
175+
);
176+
177+
test!(
178+
"ouch compress file file.tar.gz",
179+
CliArgs {
180+
cmd: Subcommand::Compress {
181+
files: to_paths(["file"]),
182+
output: PathBuf::from("file.tar.gz"),
183+
level: None,
184+
fast: false,
185+
slow: false,
186+
},
187+
..mock_cli_args()
188+
}
189+
);
190+
test!(
191+
"ouch compress a b c archive.tar.gz",
192+
CliArgs {
193+
cmd: Subcommand::Compress {
194+
files: to_paths(["a", "b", "c"]),
195+
output: PathBuf::from("archive.tar.gz"),
196+
level: None,
197+
fast: false,
198+
slow: false,
199+
},
200+
..mock_cli_args()
201+
}
202+
);
203+
test!(
204+
"ouch compress a b c archive.tar.gz",
205+
CliArgs {
206+
cmd: Subcommand::Compress {
207+
files: to_paths(["a", "b", "c"]),
208+
output: PathBuf::from("archive.tar.gz"),
209+
level: None,
210+
fast: false,
211+
slow: false,
212+
},
213+
..mock_cli_args()
214+
}
215+
);
216+
217+
let inputs = [
218+
"ouch compress a b c output --format tar.gz",
219+
// https://github.com/clap-rs/clap/issues/5115
220+
// "ouch compress a b c --format tar.gz output",
221+
// "ouch compress a b --format tar.gz c output",
222+
// "ouch compress a --format tar.gz b c output",
223+
"ouch compress --format tar.gz a b c output",
224+
"ouch --format tar.gz compress a b c output",
225+
];
226+
for input in inputs {
227+
test!(
228+
input,
229+
CliArgs {
230+
cmd: Subcommand::Compress {
231+
files: to_paths(["a", "b", "c"]),
232+
output: PathBuf::from("output"),
233+
level: None,
234+
fast: false,
235+
slow: false,
236+
},
237+
format: Some("tar.gz".into()),
238+
..mock_cli_args()
239+
}
240+
);
241+
}
242+
}
243+
244+
#[test]
245+
fn test_clap_cli_err() {
246+
assert!(CliArgs::try_parse_from(args_splitter("ouch c")).is_err());
247+
assert!(CliArgs::try_parse_from(args_splitter("ouch c input")).is_err());
248+
assert!(CliArgs::try_parse_from(args_splitter("ouch d")).is_err());
249+
assert!(CliArgs::try_parse_from(args_splitter("ouch l")).is_err());
250+
}
251+
}

src/cli/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl CliArgs {
2020
/// And:
2121
/// 1. Make paths absolute.
2222
/// 2. Checks the QuestionPolicy.
23-
pub fn parse_args() -> crate::Result<(Self, QuestionPolicy, FileVisibilityPolicy)> {
23+
pub fn parse_and_validate_args() -> crate::Result<(Self, QuestionPolicy, FileVisibilityPolicy)> {
2424
let mut args = Self::parse();
2525

2626
set_accessible(args.accessible);

src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ fn main() {
3535
}
3636

3737
fn run() -> Result<()> {
38-
let (args, skip_questions_positively, file_visibility_policy) = CliArgs::parse_args()?;
38+
let (args, skip_questions_positively, file_visibility_policy) = CliArgs::parse_and_validate_args()?;
3939
commands::run(args, skip_questions_positively, file_visibility_policy)
4040
}

0 commit comments

Comments
 (0)