| // Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu> | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | 
 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | 
 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | 
 | // option. This file may not be copied, modified, or distributed | 
 | // except according to those terms. | 
 |  | 
 | use structopt::StructOpt; | 
 |  | 
 | use std::ffi::{CString, OsStr, OsString}; | 
 | use std::num::ParseIntError; | 
 | use std::path::PathBuf; | 
 |  | 
 | #[derive(StructOpt, PartialEq, Debug)] | 
 | struct PathOpt { | 
 |     #[structopt(short, long, parse(from_os_str))] | 
 |     path: PathBuf, | 
 |  | 
 |     #[structopt(short, default_value = "../", parse(from_os_str))] | 
 |     default_path: PathBuf, | 
 |  | 
 |     #[structopt(short, parse(from_os_str))] | 
 |     vector_path: Vec<PathBuf>, | 
 |  | 
 |     #[structopt(short, parse(from_os_str))] | 
 |     option_path_1: Option<PathBuf>, | 
 |  | 
 |     #[structopt(short = "q", parse(from_os_str))] | 
 |     option_path_2: Option<PathBuf>, | 
 | } | 
 |  | 
 | #[test] | 
 | fn test_path_opt_simple() { | 
 |     assert_eq!( | 
 |         PathOpt { | 
 |             path: PathBuf::from("/usr/bin"), | 
 |             default_path: PathBuf::from("../"), | 
 |             vector_path: vec![ | 
 |                 PathBuf::from("/a/b/c"), | 
 |                 PathBuf::from("/d/e/f"), | 
 |                 PathBuf::from("/g/h/i"), | 
 |             ], | 
 |             option_path_1: None, | 
 |             option_path_2: Some(PathBuf::from("j.zip")), | 
 |         }, | 
 |         PathOpt::from_clap(&PathOpt::clap().get_matches_from(&[ | 
 |             "test", "-p", "/usr/bin", "-v", "/a/b/c", "-v", "/d/e/f", "-v", "/g/h/i", "-q", | 
 |             "j.zip", | 
 |         ])) | 
 |     ); | 
 | } | 
 |  | 
 | fn parse_hex(input: &str) -> Result<u64, ParseIntError> { | 
 |     u64::from_str_radix(input, 16) | 
 | } | 
 |  | 
 | #[derive(StructOpt, PartialEq, Debug)] | 
 | struct HexOpt { | 
 |     #[structopt(short, parse(try_from_str = parse_hex))] | 
 |     number: u64, | 
 | } | 
 |  | 
 | #[test] | 
 | #[allow(clippy::unreadable_literal)] | 
 | fn test_parse_hex() { | 
 |     assert_eq!( | 
 |         HexOpt { number: 5 }, | 
 |         HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "5"])) | 
 |     ); | 
 |     assert_eq!( | 
 |         HexOpt { number: 0xabcdef }, | 
 |         HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "abcdef"])) | 
 |     ); | 
 |  | 
 |     let err = HexOpt::clap() | 
 |         .get_matches_from_safe(&["test", "-n", "gg"]) | 
 |         .unwrap_err(); | 
 |     assert!(err.message.contains("invalid digit found in string"), err); | 
 | } | 
 |  | 
 | fn custom_parser_1(_: &str) -> &'static str { | 
 |     "A" | 
 | } | 
 | fn custom_parser_2(_: &str) -> Result<&'static str, u32> { | 
 |     Ok("B") | 
 | } | 
 | fn custom_parser_3(_: &OsStr) -> &'static str { | 
 |     "C" | 
 | } | 
 | fn custom_parser_4(_: &OsStr) -> Result<&'static str, OsString> { | 
 |     Ok("D") | 
 | } | 
 |  | 
 | #[derive(StructOpt, PartialEq, Debug)] | 
 | struct NoOpOpt { | 
 |     #[structopt(short, parse(from_str = custom_parser_1))] | 
 |     a: &'static str, | 
 |     #[structopt(short, parse(try_from_str = custom_parser_2))] | 
 |     b: &'static str, | 
 |     #[structopt(short, parse(from_os_str = custom_parser_3))] | 
 |     c: &'static str, | 
 |     #[structopt(short, parse(try_from_os_str = custom_parser_4))] | 
 |     d: &'static str, | 
 | } | 
 |  | 
 | #[test] | 
 | fn test_every_custom_parser() { | 
 |     assert_eq!( | 
 |         NoOpOpt { | 
 |             a: "A", | 
 |             b: "B", | 
 |             c: "C", | 
 |             d: "D" | 
 |         }, | 
 |         NoOpOpt::from_clap( | 
 |             &NoOpOpt::clap().get_matches_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?"]) | 
 |         ) | 
 |     ); | 
 | } | 
 |  | 
 | // Note: can't use `Vec<u8>` directly, as structopt would instead look for | 
 | // conversion function from `&str` to `u8`. | 
 | type Bytes = Vec<u8>; | 
 |  | 
 | #[derive(StructOpt, PartialEq, Debug)] | 
 | struct DefaultedOpt { | 
 |     #[structopt(short, parse(from_str))] | 
 |     bytes: Bytes, | 
 |  | 
 |     #[structopt(short, parse(try_from_str))] | 
 |     integer: u64, | 
 |  | 
 |     #[structopt(short, parse(from_os_str))] | 
 |     path: PathBuf, | 
 | } | 
 |  | 
 | #[test] | 
 | fn test_parser_with_default_value() { | 
 |     assert_eq!( | 
 |         DefaultedOpt { | 
 |             bytes: b"E\xc2\xb2=p\xc2\xb2c\xc2\xb2+m\xc2\xb2c\xe2\x81\xb4".to_vec(), | 
 |             integer: 9000, | 
 |             path: PathBuf::from("src/lib.rs"), | 
 |         }, | 
 |         DefaultedOpt::from_clap(&DefaultedOpt::clap().get_matches_from(&[ | 
 |             "test", | 
 |             "-b", | 
 |             "E²=p²c²+m²c⁴", | 
 |             "-i", | 
 |             "9000", | 
 |             "-p", | 
 |             "src/lib.rs", | 
 |         ])) | 
 |     ); | 
 | } | 
 |  | 
 | #[derive(PartialEq, Debug)] | 
 | struct Foo(u8); | 
 |  | 
 | fn foo(value: u64) -> Foo { | 
 |     Foo(value as u8) | 
 | } | 
 |  | 
 | #[derive(StructOpt, PartialEq, Debug)] | 
 | struct Occurrences { | 
 |     #[structopt(short, long, parse(from_occurrences))] | 
 |     signed: i32, | 
 |  | 
 |     #[structopt(short, parse(from_occurrences))] | 
 |     little_signed: i8, | 
 |  | 
 |     #[structopt(short, parse(from_occurrences))] | 
 |     unsigned: usize, | 
 |  | 
 |     #[structopt(short = "r", parse(from_occurrences))] | 
 |     little_unsigned: u8, | 
 |  | 
 |     #[structopt(short, long, parse(from_occurrences = foo))] | 
 |     custom: Foo, | 
 | } | 
 |  | 
 | #[test] | 
 | fn test_parser_occurrences() { | 
 |     assert_eq!( | 
 |         Occurrences { | 
 |             signed: 3, | 
 |             little_signed: 1, | 
 |             unsigned: 0, | 
 |             little_unsigned: 4, | 
 |             custom: Foo(5), | 
 |         }, | 
 |         Occurrences::from_clap(&Occurrences::clap().get_matches_from(&[ | 
 |             "test", "-s", "--signed", "--signed", "-l", "-rrrr", "-cccc", "--custom", | 
 |         ])) | 
 |     ); | 
 | } | 
 |  | 
 | #[test] | 
 | fn test_custom_bool() { | 
 |     fn parse_bool(s: &str) -> Result<bool, String> { | 
 |         match s { | 
 |             "true" => Ok(true), | 
 |             "false" => Ok(false), | 
 |             _ => Err(format!("invalid bool {}", s)), | 
 |         } | 
 |     } | 
 |     #[derive(StructOpt, PartialEq, Debug)] | 
 |     struct Opt { | 
 |         #[structopt(short, parse(try_from_str = parse_bool))] | 
 |         debug: bool, | 
 |         #[structopt( | 
 |             short, | 
 |             default_value = "false", | 
 |             parse(try_from_str = parse_bool) | 
 |         )] | 
 |         verbose: bool, | 
 |         #[structopt(short, parse(try_from_str = parse_bool))] | 
 |         tribool: Option<bool>, | 
 |         #[structopt(short, parse(try_from_str = parse_bool))] | 
 |         bitset: Vec<bool>, | 
 |     } | 
 |  | 
 |     assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); | 
 |     assert!(Opt::clap().get_matches_from_safe(&["test", "-d"]).is_err()); | 
 |     assert!(Opt::clap() | 
 |         .get_matches_from_safe(&["test", "-dfoo"]) | 
 |         .is_err()); | 
 |     assert_eq!( | 
 |         Opt { | 
 |             debug: false, | 
 |             verbose: false, | 
 |             tribool: None, | 
 |             bitset: vec![], | 
 |         }, | 
 |         Opt::from_iter(&["test", "-dfalse"]) | 
 |     ); | 
 |     assert_eq!( | 
 |         Opt { | 
 |             debug: true, | 
 |             verbose: false, | 
 |             tribool: None, | 
 |             bitset: vec![], | 
 |         }, | 
 |         Opt::from_iter(&["test", "-dtrue"]) | 
 |     ); | 
 |     assert_eq!( | 
 |         Opt { | 
 |             debug: true, | 
 |             verbose: false, | 
 |             tribool: None, | 
 |             bitset: vec![], | 
 |         }, | 
 |         Opt::from_iter(&["test", "-dtrue", "-vfalse"]) | 
 |     ); | 
 |     assert_eq!( | 
 |         Opt { | 
 |             debug: true, | 
 |             verbose: true, | 
 |             tribool: None, | 
 |             bitset: vec![], | 
 |         }, | 
 |         Opt::from_iter(&["test", "-dtrue", "-vtrue"]) | 
 |     ); | 
 |     assert_eq!( | 
 |         Opt { | 
 |             debug: true, | 
 |             verbose: false, | 
 |             tribool: Some(false), | 
 |             bitset: vec![], | 
 |         }, | 
 |         Opt::from_iter(&["test", "-dtrue", "-tfalse"]) | 
 |     ); | 
 |     assert_eq!( | 
 |         Opt { | 
 |             debug: true, | 
 |             verbose: false, | 
 |             tribool: Some(true), | 
 |             bitset: vec![], | 
 |         }, | 
 |         Opt::from_iter(&["test", "-dtrue", "-ttrue"]) | 
 |     ); | 
 |     assert_eq!( | 
 |         Opt { | 
 |             debug: true, | 
 |             verbose: false, | 
 |             tribool: None, | 
 |             bitset: vec![false, true, false, false], | 
 |         }, | 
 |         Opt::from_iter(&["test", "-dtrue", "-bfalse", "-btrue", "-bfalse", "-bfalse"]) | 
 |     ); | 
 | } | 
 |  | 
 | #[test] | 
 | fn test_cstring() { | 
 |     #[derive(StructOpt)] | 
 |     struct Opt { | 
 |         #[structopt(parse(try_from_str = CString::new))] | 
 |         c_string: CString, | 
 |     } | 
 |     assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); | 
 |     assert_eq!(Opt::from_iter(&["test", "bla"]).c_string.to_bytes(), b"bla"); | 
 |     assert!(Opt::clap() | 
 |         .get_matches_from_safe(&["test", "bla\0bla"]) | 
 |         .is_err()); | 
 | } |