1use clap::Args;
2use clap::Parser;
3
4#[test]
5fn test_standalone_long_generates_kebab_case() {
6    #[derive(Parser, Debug, PartialEq)]
7    #[allow(non_snake_case)]
8    struct Opt {
9        #[arg(long)]
10        FOO_OPTION: bool,
11    }
12
13    assert_eq!(
14        Opt { FOO_OPTION: true },
15        Opt::try_parse_from(["test", "--foo-option"]).unwrap()
16    );
17}
18
19#[test]
20fn test_custom_long_overwrites_default_name() {
21    #[derive(Parser, Debug, PartialEq)]
22    struct Opt {
23        #[arg(long = "foo")]
24        foo_option: bool,
25    }
26
27    assert_eq!(
28        Opt { foo_option: true },
29        Opt::try_parse_from(["test", "--foo"]).unwrap()
30    );
31}
32
33#[test]
34fn test_standalone_long_uses_previous_defined_custom_name() {
35    #[derive(Parser, Debug, PartialEq)]
36    struct Opt {
37        #[arg(id = "foo", long)]
38        foo_option: bool,
39    }
40
41    assert_eq!(
42        Opt { foo_option: true },
43        Opt::try_parse_from(["test", "--foo"]).unwrap()
44    );
45}
46
47#[test]
48fn test_standalone_long_ignores_afterwards_defined_custom_name() {
49    #[derive(Parser, Debug, PartialEq)]
50    struct Opt {
51        #[arg(long, id = "foo")]
52        foo_option: bool,
53    }
54
55    assert_eq!(
56        Opt { foo_option: true },
57        Opt::try_parse_from(["test", "--foo-option"]).unwrap()
58    );
59}
60
61#[test]
62fn test_standalone_long_uses_previous_defined_custom_id() {
63    #[derive(Parser, Debug, PartialEq)]
64    struct Opt {
65        #[arg(id = "foo", long)]
66        foo_option: bool,
67    }
68
69    assert_eq!(
70        Opt { foo_option: true },
71        Opt::try_parse_from(["test", "--foo"]).unwrap()
72    );
73}
74
75#[test]
76fn test_standalone_long_ignores_afterwards_defined_custom_id() {
77    #[derive(Parser, Debug, PartialEq)]
78    struct Opt {
79        #[arg(long, id = "foo")]
80        foo_option: bool,
81    }
82
83    assert_eq!(
84        Opt { foo_option: true },
85        Opt::try_parse_from(["test", "--foo-option"]).unwrap()
86    );
87}
88
89#[test]
90fn test_standalone_short_generates_kebab_case() {
91    #[derive(Parser, Debug, PartialEq)]
92    #[allow(non_snake_case)]
93    struct Opt {
94        #[arg(short)]
95        FOO_OPTION: bool,
96    }
97
98    assert_eq!(
99        Opt { FOO_OPTION: true },
100        Opt::try_parse_from(["test", "-f"]).unwrap()
101    );
102}
103
104#[test]
105fn test_custom_short_overwrites_default_name() {
106    #[derive(Parser, Debug, PartialEq)]
107    struct Opt {
108        #[arg(short = 'o')]
109        foo_option: bool,
110    }
111
112    assert_eq!(
113        Opt { foo_option: true },
114        Opt::try_parse_from(["test", "-o"]).unwrap()
115    );
116}
117
118#[test]
119fn test_standalone_short_uses_previous_defined_custom_name() {
120    #[derive(Parser, Debug, PartialEq)]
121    struct Opt {
122        #[arg(id = "option", short)]
123        foo_option: bool,
124    }
125
126    assert_eq!(
127        Opt { foo_option: true },
128        Opt::try_parse_from(["test", "-o"]).unwrap()
129    );
130}
131
132#[test]
133fn test_standalone_short_ignores_afterwards_defined_custom_name() {
134    #[derive(Parser, Debug, PartialEq)]
135    struct Opt {
136        #[arg(short, id = "option")]
137        foo_option: bool,
138    }
139
140    assert_eq!(
141        Opt { foo_option: true },
142        Opt::try_parse_from(["test", "-f"]).unwrap()
143    );
144}
145
146#[test]
147fn test_standalone_short_uses_previous_defined_custom_id() {
148    #[derive(Parser, Debug, PartialEq)]
149    struct Opt {
150        #[arg(id = "option", short)]
151        foo_option: bool,
152    }
153
154    assert_eq!(
155        Opt { foo_option: true },
156        Opt::try_parse_from(["test", "-o"]).unwrap()
157    );
158}
159
160#[test]
161fn test_standalone_short_ignores_afterwards_defined_custom_id() {
162    #[derive(Parser, Debug, PartialEq)]
163    struct Opt {
164        #[arg(short, id = "option")]
165        foo_option: bool,
166    }
167
168    assert_eq!(
169        Opt { foo_option: true },
170        Opt::try_parse_from(["test", "-f"]).unwrap()
171    );
172}
173
174#[test]
175fn test_standalone_long_uses_previous_defined_casing() {
176    #[derive(Parser, Debug, PartialEq)]
177    struct Opt {
178        #[arg(rename_all = "screaming_snake", long)]
179        foo_option: bool,
180    }
181
182    assert_eq!(
183        Opt { foo_option: true },
184        Opt::try_parse_from(["test", "--FOO_OPTION"]).unwrap()
185    );
186}
187
188#[test]
189fn test_standalone_short_uses_previous_defined_casing() {
190    #[derive(Parser, Debug, PartialEq)]
191    struct Opt {
192        #[arg(rename_all = "screaming_snake", short)]
193        foo_option: bool,
194    }
195
196    assert_eq!(
197        Opt { foo_option: true },
198        Opt::try_parse_from(["test", "-F"]).unwrap()
199    );
200}
201
202#[test]
203fn test_standalone_long_works_with_verbatim_casing() {
204    #[derive(Parser, Debug, PartialEq)]
205    #[allow(non_snake_case)]
206    struct Opt {
207        #[arg(rename_all = "verbatim", long)]
208        _fOO_oPtiON: bool,
209    }
210
211    assert_eq!(
212        Opt { _fOO_oPtiON: true },
213        Opt::try_parse_from(["test", "--_fOO_oPtiON"]).unwrap()
214    );
215}
216
217#[test]
218fn test_standalone_short_works_with_verbatim_casing() {
219    #[derive(Parser, Debug, PartialEq)]
220    struct Opt {
221        #[arg(rename_all = "verbatim", short)]
222        _foo: bool,
223    }
224
225    assert_eq!(
226        Opt { _foo: true },
227        Opt::try_parse_from(["test", "-_"]).unwrap()
228    );
229}
230
231#[test]
232fn test_rename_all_is_propagated_from_struct_to_fields() {
233    #[derive(Parser, Debug, PartialEq)]
234    #[command(rename_all = "screaming_snake")]
235    struct Opt {
236        #[arg(long)]
237        foo: bool,
238    }
239
240    assert_eq!(
241        Opt { foo: true },
242        Opt::try_parse_from(["test", "--FOO"]).unwrap()
243    );
244}
245
246#[test]
247fn test_rename_all_is_not_propagated_from_struct_into_flattened() {
248    #[derive(Parser, Debug, PartialEq)]
249    #[command(rename_all = "screaming_snake")]
250    struct Opt {
251        #[command(flatten)]
252        foo: Foo,
253    }
254
255    #[derive(Args, Debug, PartialEq)]
256    struct Foo {
257        #[arg(long)]
258        foo: bool,
259    }
260
261    assert_eq!(
262        Opt {
263            foo: Foo { foo: true }
264        },
265        Opt::try_parse_from(["test", "--foo"]).unwrap()
266    );
267}
268
269#[test]
270fn test_lower_is_renamed() {
271    #[derive(Parser, Debug, PartialEq)]
272    struct Opt {
273        #[arg(rename_all = "lower", long)]
274        foo_option: bool,
275    }
276
277    assert_eq!(
278        Opt { foo_option: true },
279        Opt::try_parse_from(["test", "--foooption"]).unwrap()
280    );
281}
282
283#[test]
284fn test_upper_is_renamed() {
285    #[derive(Parser, Debug, PartialEq)]
286    struct Opt {
287        #[arg(rename_all = "upper", long)]
288        foo_option: bool,
289    }
290
291    assert_eq!(
292        Opt { foo_option: true },
293        Opt::try_parse_from(["test", "--FOOOPTION"]).unwrap()
294    );
295}
296
297#[test]
298fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() {
299    #[derive(Parser, Debug, PartialEq)]
300    enum Opt {
301        Command { foo: u32 },
302    }
303
304    assert_eq!(
305        Opt::Command { foo: 0 },
306        Opt::try_parse_from(["test", "command", "0"]).unwrap()
307    );
308}
309
310#[test]
311fn test_multi_word_enum_variant_is_renamed() {
312    #[derive(Parser, Debug, PartialEq)]
313    enum Opt {
314        FirstCommand { foo: u32 },
315    }
316
317    assert_eq!(
318        Opt::FirstCommand { foo: 0 },
319        Opt::try_parse_from(["test", "first-command", "0"]).unwrap()
320    );
321}
322
323#[test]
324fn test_rename_all_is_not_propagated_from_struct_into_subcommand() {
325    #[derive(Parser, Debug, PartialEq)]
326    #[command(rename_all = "screaming_snake")]
327    struct Opt {
328        #[command(subcommand)]
329        foo: Foo,
330    }
331
332    #[derive(Parser, Debug, PartialEq)]
333    enum Foo {
334        Command {
335            #[arg(long)]
336            foo: bool,
337        },
338    }
339
340    assert_eq!(
341        Opt {
342            foo: Foo::Command { foo: true }
343        },
344        Opt::try_parse_from(["test", "command", "--foo"]).unwrap()
345    );
346}
347
348#[test]
349fn test_rename_all_is_propagated_from_enum_to_variants() {
350    #[derive(Parser, Debug, PartialEq)]
351    #[command(rename_all = "screaming_snake")]
352    enum Opt {
353        FirstVariant,
354        SecondVariant {
355            #[arg(long)]
356            foo: String,
357        },
358    }
359
360    assert_eq!(
361        Opt::FirstVariant,
362        Opt::try_parse_from(["test", "FIRST_VARIANT"]).unwrap()
363    );
364}
365
366#[test]
367fn test_rename_all_is_propagated_from_enum_to_variant_fields() {
368    #[derive(Parser, Debug, PartialEq)]
369    #[command(rename_all = "screaming_snake")]
370    enum Opt {
371        FirstVariant,
372        SecondVariant {
373            #[arg(long)]
374            foo: String,
375        },
376    }
377
378    assert_eq!(
379        Opt::SecondVariant {
380            foo: "value".into()
381        },
382        Opt::try_parse_from(["test", "SECOND_VARIANT", "--FOO", "value"]).unwrap()
383    );
384}
385
386#[test]
387fn test_rename_all_is_propagation_can_be_overridden() {
388    #[derive(Parser, Debug, PartialEq)]
389    #[command(rename_all = "screaming_snake")]
390    enum Opt {
391        #[command(rename_all = "kebab_case")]
392        FirstVariant {
393            #[arg(long)]
394            foo_option: bool,
395        },
396        SecondVariant {
397            #[arg(rename_all = "kebab_case", long)]
398            foo_option: bool,
399        },
400    }
401
402    assert_eq!(
403        Opt::FirstVariant { foo_option: true },
404        Opt::try_parse_from(["test", "first-variant", "--foo-option"]).unwrap()
405    );
406
407    assert_eq!(
408        Opt::SecondVariant { foo_option: true },
409        Opt::try_parse_from(["test", "SECOND_VARIANT", "--foo-option"]).unwrap()
410    );
411}
412