1// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
2// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
3// Ana Hobden (@hoverbear) <operator@hoverbear.org>
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10//
11// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
12// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
13// MIT/Apache 2.0 license.
14
15use clap::Parser;
16
17use std::num::ParseIntError;
18use std::path::PathBuf;
19
20#[derive(Parser, PartialEq, Debug)]
21struct PathOpt {
22    #[arg(short, long)]
23    path: PathBuf,
24
25    #[arg(short, default_value = "../")]
26    default_path: PathBuf,
27
28    #[arg(short)]
29    vector_path: Vec<PathBuf>,
30
31    #[arg(short)]
32    option_path_1: Option<PathBuf>,
33
34    #[arg(short = 'q')]
35    option_path_2: Option<PathBuf>,
36}
37
38#[test]
39fn test_path_opt_simple() {
40    assert_eq!(
41        PathOpt {
42            path: PathBuf::from("/usr/bin"),
43            default_path: PathBuf::from("../"),
44            vector_path: vec![
45                PathBuf::from("/a/b/c"),
46                PathBuf::from("/d/e/f"),
47                PathBuf::from("/g/h/i"),
48            ],
49            option_path_1: None,
50            option_path_2: Some(PathBuf::from("j.zip")),
51        },
52        PathOpt::try_parse_from([
53            "test", "-p", "/usr/bin", "-v", "/a/b/c", "-v", "/d/e/f", "-v", "/g/h/i", "-q",
54            "j.zip",
55        ])
56        .unwrap()
57    );
58}
59
60fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
61    u64::from_str_radix(input, 16)
62}
63
64#[derive(Parser, PartialEq, Debug)]
65struct HexOpt {
66    #[arg(short, value_parser = parse_hex)]
67    number: u64,
68}
69
70#[test]
71#[cfg(feature = "error-context")]
72fn test_parse_hex() {
73    assert_eq!(
74        HexOpt { number: 5 },
75        HexOpt::try_parse_from(["test", "-n", "5"]).unwrap()
76    );
77    assert_eq!(
78        HexOpt {
79            number: 0x00ab_cdef
80        },
81        HexOpt::try_parse_from(["test", "-n", "abcdef"]).unwrap()
82    );
83
84    let err = HexOpt::try_parse_from(["test", "-n", "gg"]).unwrap_err();
85    assert!(
86        err.to_string().contains("invalid digit found in string"),
87        "{}",
88        err
89    );
90}
91
92#[derive(Debug)]
93struct ErrCode(u32);
94impl std::error::Error for ErrCode {}
95impl std::fmt::Display for ErrCode {
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        std::fmt::Display::fmt(&self.0, f)
98    }
99}
100fn custom_parser_2(_: &str) -> Result<&'static str, ErrCode> {
101    Ok("B")
102}
103
104#[derive(Parser, PartialEq, Debug)]
105struct NoOpOpt {
106    #[arg(short, value_parser = custom_parser_2)]
107    b: &'static str,
108}
109
110#[test]
111fn test_every_custom_parser() {
112    assert_eq!(
113        NoOpOpt { b: "B" },
114        NoOpOpt::try_parse_from(["test", "-b=?"]).unwrap()
115    );
116}
117
118#[test]
119fn update_every_custom_parser() {
120    let mut opt = NoOpOpt { b: "0" };
121
122    opt.try_update_from(["test", "-b=?"]).unwrap();
123
124    assert_eq!(NoOpOpt { b: "B" }, opt);
125}
126
127#[derive(Parser, PartialEq, Debug)]
128struct DefaultedOpt {
129    #[arg(short)]
130    integer: u64,
131
132    #[arg(short)]
133    path: PathBuf,
134}
135
136#[test]
137fn test_parser_with_default_value() {
138    assert_eq!(
139        DefaultedOpt {
140            integer: 9000,
141            path: PathBuf::from("src/lib.rs"),
142        },
143        DefaultedOpt::try_parse_from(["test", "-i", "9000", "-p", "src/lib.rs",]).unwrap()
144    );
145}
146