use std::str::FromStr; use cli_rs::{arg::Arg, command::Command, flag::Flag, parser::Cmd}; #[test] fn basic_command() { let mut called = false; Command::name("test") .handler(|| { called = true; Ok(()) }) .parse_args(&[]) .unwrap(); assert!(called); } #[test] fn with_1_arg() { let mut input_name = String::default(); Command::name("test") .input(Arg::str("name")) .handler(|name| { input_name = name.get().clone(); Ok(()) }) .parse_args(&["parth".to_string()]) .unwrap(); assert_eq!(input_name, "parth"); } #[test] fn with_2_args() { let mut name = String::default(); let mut age = 0; Command::name("nameage") .input(Arg::str("name")) .input(Arg::i32("age")) .handler(|n, a| { name = n.get().clone(); age = a.get(); Ok(()) }) .parse_args(&["parth".to_string(), "27".to_string()]) .unwrap(); assert_eq!(name, "parth"); assert_eq!(age, 27); } #[test] fn missing_arg() { let mut name = String::default(); let mut age = 0; Command::name("nameage") .input(Arg::str("name")) .input(Arg::i32("age")) .handler(|n, a| { name = n.get().clone(); age = a.get(); Ok(()) }) .parse_args(&["parth".to_string()]) .unwrap_err(); assert_eq!(name, String::default()); assert_eq!(age, 0); } #[test] fn arg_parsing_failure() { let mut file_type = FileType::Folder; Command::name("arg-test") .input(Arg::::name("type")) .handler(|t| { file_type = t.get(); Ok(()) }) .parse_args(&["not-a-doc".to_string()]) .unwrap_err(); } #[derive(Default, Debug, PartialEq, Clone, Copy)] pub enum FileType { #[default] Folder, Document, } impl FromStr for FileType { type Err = (); fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { "folder" | "dir" => Ok(Self::Folder), "doc" | "document" => Ok(Self::Document), _ => Err(()), } } } #[test] fn with_custom_args() { let mut name = String::default(); let mut ft = FileType::Folder; Command::name("create") .input(Arg::str("name")) .input(Arg::::name("type")) .handler(|n, f| { name = n.get().clone(); ft = f.get(); Ok(()) }) .parse_args(&["todo.md".to_string(), "doc".to_string()]) .unwrap(); assert_eq!(name, "todo.md"); assert_eq!(ft, FileType::Document); } #[test] fn with_flags() { let mut name = String::default(); let mut create = false; Command::name("edit") .input(Arg::str("name")) .input(Flag::bool("create")) .handler(|n, c| { name = n.get().clone(); create = c.get(); Ok(()) }) .parse_args(&["todo.md".to_string(), "--create=true".to_string()]) .unwrap(); assert_eq!(name, "todo.md"); assert!(create); } #[test] fn bool_flags() { let mut name = String::default(); let mut create = false; Command::name("edit") .input(Arg::str("name")) .input(Flag::bool("create")) .handler(|n, c| { name = n.get().clone(); create = c.get(); Ok(()) }) .parse_args(&["todo.md".to_string(), "--create".to_string()]) .unwrap(); assert_eq!(name, "todo.md"); assert!(create); } #[test] fn short_flag_lower() { let mut name = String::default(); let mut create = false; Command::name("edit") .input(Arg::str("name")) .input(Flag::bool("create")) .handler(|n, c| { name = n.get().clone(); create = c.get(); Ok(()) }) .parse_args(&["todo.md".to_string(), "-c".to_string()]) .unwrap(); assert_eq!(name, "todo.md"); assert!(create); } #[test] fn short_flag_upper() { let mut name = String::default(); let mut create = false; Command::name("edit") .input(Arg::str("name")) .input(Flag::bool("create")) .handler(|n, c| { name = n.get().clone(); create = c.get(); Ok(()) }) .parse_args(&["todo.md".to_string(), "-C".to_string()]) .unwrap(); assert_eq!(name, "todo.md"); assert!(create); } #[test] fn flag_order() { let mut name = String::default(); let mut create = false; Command::name("edit") .input(Arg::str("name")) .input(Flag::bool("create")) .handler(|n, c| { name = n.get().clone(); create = c.get(); Ok(()) }) .parse_args(&["todo.md".to_string(), "--create".to_string()]) .unwrap(); assert_eq!(name, "todo.md"); assert!(create); } #[test] fn flag_parsing_failure() { let mut name = String::default(); let mut f_type = FileType::Folder; Command::name("edit") .input(Arg::str("name")) .input(Flag::::new("type")) .handler(|n, t| { name = n.get().clone(); f_type = t.get(); Ok(()) }) .parse_args(&["todo.md".to_string(), "--create".to_string()]) .unwrap_err(); // todo could be more specific here } #[test] fn subcommands() { let mut path = String::default(); Command::name("lockbook") .subcommand(Command::name("edit").input(Arg::str("path")).handler(|n| { path = n.get().clone(); Ok(()) })) .parse_args(&["edit".to_string(), "path".to_string()]) .unwrap(); assert_eq!(path, "path"); } #[test] fn subcommand_missing_arg() { Command::name("lockbook") .subcommand( Command::name("edit") .input(Arg::str("path")) .handler(|_| unreachable! {}), ) .with_completions() .parse_args(&["completions".to_string()]) .unwrap_err(); } #[test] fn subcommand_arg() { Command::name("cli-rs") .subcommand( Command::name("edit") .input(Flag::::new("edit")) .input(Arg::::name("target")) .handler(|_, target| { println!("editing target file: {}", target.get()); Ok(()) }), ) .with_completions() .parse_args(&["edit".to_string(), "a.md".to_string()]) .unwrap() } #[test] fn subcommands_mismatch() { let mut path = String::default(); Command::name("lockbook") .subcommand(Command::name("new").input(Arg::str("path")).handler(|n| { path = n.get().clone(); Ok(()) })) .parse_args(&["edit".to_string(), "path".to_string()]) .unwrap_err(); assert_eq!(path, String::default()); }