1use clap::Parser;
4
5#[derive(Parser, Debug)]
6#[command(
7 name = "rusty-pee",
8 version,
9 about = "Fan stdin out to N concurrent shell-spawned children.",
10 long_about = "A Rust port of moreutils `pee`. Reads stdin once and writes \
11 every byte to each child's stdin in argv order; aggregates \
12 exit codes; surfaces failures cleanly."
13)]
14pub struct Cli {
15 #[arg(long)]
19 pub capture: bool,
20
21 #[arg(long, conflicts_with = "no_strict")]
23 pub strict: bool,
24
25 #[arg(long = "no-strict")]
27 pub no_strict: bool,
28
29 #[arg(trailing_var_arg = true)]
31 pub commands: Vec<String>,
32
33 #[command(subcommand)]
35 pub command: Option<Subcommand>,
36}
37
38#[derive(clap::Subcommand, Debug)]
39pub enum Subcommand {
40 Completions { shell: clap_complete::Shell },
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47 use clap::CommandFactory;
48
49 #[test]
50 fn cli_command_factory_compiles() {
51 let cmd = Cli::command();
52 assert_eq!(cmd.get_name(), "rusty-pee");
53 }
54
55 #[test]
56 fn parse_no_args() {
57 let cli = Cli::try_parse_from(["rusty-pee"]).unwrap();
58 assert!(cli.commands.is_empty());
59 assert!(!cli.capture);
60 assert!(!cli.strict);
61 assert!(!cli.no_strict);
62 }
63
64 #[test]
65 fn parse_capture_flag() {
66 let cli = Cli::try_parse_from(["rusty-pee", "--capture", "cat"]).unwrap();
67 assert!(cli.capture);
68 assert_eq!(cli.commands, vec!["cat"]);
69 }
70
71 #[test]
72 fn parse_strict_conflicts_with_no_strict() {
73 let result = Cli::try_parse_from(["rusty-pee", "--strict", "--no-strict"]);
74 assert!(result.is_err());
75 }
76
77 #[test]
78 fn parse_two_commands() {
79 let cli = Cli::try_parse_from(["rusty-pee", "wc -l", "grep foo"]).unwrap();
80 assert_eq!(cli.commands, vec!["wc -l", "grep foo"]);
81 }
82}