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
15 use clap::error::ErrorKind;
16 use clap::Parser;
17 use std::num::ParseIntError;
18
19 pub const DISPLAY_ORDER: usize = 2;
20
21 // Check if the global settings compile
22 #[derive(Parser, Debug, PartialEq, Eq)]
23 #[command(group = clap::ArgGroup::new("foo"))]
24 struct Opt {
25 #[arg(
26 long = "x",
27 display_order = DISPLAY_ORDER,
28 next_line_help = true,
29 default_value = "0",
30 require_equals = true,
31 )]
32 x: i32,
33
34 #[arg(short = 'l', long = "level", aliases = ["set-level", "lvl"])]
35 level: String,
36
37 #[arg(long("values"))]
38 values: Vec<i32>,
39
40 #[arg(id = "FILE", requires_if("FILE", "values"))]
41 files: Vec<String>,
42 }
43
44 #[test]
test_slice()45 fn test_slice() {
46 assert_eq!(
47 Opt {
48 x: 0,
49 level: "1".to_string(),
50 files: Vec::new(),
51 values: vec![],
52 },
53 Opt::try_parse_from(["test", "-l", "1"]).unwrap()
54 );
55 assert_eq!(
56 Opt {
57 x: 0,
58 level: "1".to_string(),
59 files: Vec::new(),
60 values: vec![],
61 },
62 Opt::try_parse_from(["test", "--level", "1"]).unwrap()
63 );
64 assert_eq!(
65 Opt {
66 x: 0,
67 level: "1".to_string(),
68 files: Vec::new(),
69 values: vec![],
70 },
71 Opt::try_parse_from(["test", "--set-level", "1"]).unwrap()
72 );
73 assert_eq!(
74 Opt {
75 x: 0,
76 level: "1".to_string(),
77 files: Vec::new(),
78 values: vec![],
79 },
80 Opt::try_parse_from(["test", "--lvl", "1"]).unwrap()
81 );
82 }
83
84 #[test]
test_multi_args()85 fn test_multi_args() {
86 assert_eq!(
87 Opt {
88 x: 0,
89 level: "1".to_string(),
90 files: vec!["file".to_string()],
91 values: vec![],
92 },
93 Opt::try_parse_from(["test", "-l", "1", "file"]).unwrap()
94 );
95 assert_eq!(
96 Opt {
97 x: 0,
98 level: "1".to_string(),
99 files: vec!["FILE".to_string()],
100 values: vec![1],
101 },
102 Opt::try_parse_from(["test", "-l", "1", "--values", "1", "--", "FILE"]).unwrap()
103 );
104 }
105
106 #[test]
test_multi_args_fail()107 fn test_multi_args_fail() {
108 let result = Opt::try_parse_from(["test", "-l", "1", "--", "FILE"]);
109 assert!(result.is_err());
110 }
111
112 #[test]
test_bool()113 fn test_bool() {
114 assert_eq!(
115 Opt {
116 x: 1,
117 level: "1".to_string(),
118 files: vec![],
119 values: vec![],
120 },
121 Opt::try_parse_from(["test", "-l", "1", "--x=1"]).unwrap()
122 );
123 let result = Opt::try_parse_from(["test", "-l", "1", "--x", "1"]);
124 assert!(result.is_err());
125 assert_eq!(result.unwrap_err().kind(), ErrorKind::NoEquals);
126 }
127
parse_hex(input: &str) -> Result<u64, ParseIntError>128 fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
129 u64::from_str_radix(input, 16)
130 }
131
132 #[derive(Parser, PartialEq, Debug)]
133 struct HexOpt {
134 #[arg(short, value_parser = parse_hex)]
135 number: u64,
136 }
137
138 #[test]
139 #[cfg(feature = "error-context")]
test_parse_hex_function_path()140 fn test_parse_hex_function_path() {
141 assert_eq!(
142 HexOpt { number: 5 },
143 HexOpt::try_parse_from(["test", "-n", "5"]).unwrap()
144 );
145 assert_eq!(
146 HexOpt {
147 number: 0x00ab_cdef
148 },
149 HexOpt::try_parse_from(["test", "-n", "abcdef"]).unwrap()
150 );
151
152 let err = HexOpt::try_parse_from(["test", "-n", "gg"]).unwrap_err();
153 assert!(
154 err.to_string().contains("invalid digit found in string"),
155 "{}",
156 err
157 );
158 }
159