1#![cfg(not(windows))]
2
3use clap::error::ErrorKind;
4use clap::Parser;
5use std::ffi::OsString;
6use std::os::unix::ffi::OsStringExt;
7
8#[derive(Parser, Debug, PartialEq, Eq)]
9struct Positional {
10    arg: String,
11}
12
13#[derive(Parser, Debug, PartialEq, Eq)]
14struct Named {
15    #[arg(short, long)]
16    arg: String,
17}
18
19#[test]
20fn invalid_utf8_strict_positional() {
21    let m = Positional::try_parse_from(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
22    assert!(m.is_err());
23    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
24}
25
26#[test]
27fn invalid_utf8_strict_option_short_space() {
28    let m = Named::try_parse_from(vec![
29        OsString::from(""),
30        OsString::from("-a"),
31        OsString::from_vec(vec![0xe9]),
32    ]);
33    assert!(m.is_err());
34    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
35}
36
37#[test]
38fn invalid_utf8_strict_option_short_equals() {
39    let m = Named::try_parse_from(vec![
40        OsString::from(""),
41        OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
42    ]);
43    assert!(m.is_err());
44    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
45}
46
47#[test]
48fn invalid_utf8_strict_option_short_no_space() {
49    let m = Named::try_parse_from(vec![
50        OsString::from(""),
51        OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
52    ]);
53    assert!(m.is_err());
54    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
55}
56
57#[test]
58fn invalid_utf8_strict_option_long_space() {
59    let m = Named::try_parse_from(vec![
60        OsString::from(""),
61        OsString::from("--arg"),
62        OsString::from_vec(vec![0xe9]),
63    ]);
64    assert!(m.is_err());
65    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
66}
67
68#[test]
69fn invalid_utf8_strict_option_long_equals() {
70    let m = Named::try_parse_from(vec![
71        OsString::from(""),
72        OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
73    ]);
74    assert!(m.is_err());
75    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
76}
77
78#[derive(Parser, Debug, PartialEq, Eq)]
79struct PositionalOs {
80    arg: OsString,
81}
82
83#[derive(Parser, Debug, PartialEq, Eq)]
84struct NamedOs {
85    #[arg(short, long)]
86    arg: OsString,
87}
88
89#[test]
90fn invalid_utf8_positional() {
91    let r = PositionalOs::try_parse_from(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
92    assert_eq!(
93        r.unwrap(),
94        PositionalOs {
95            arg: OsString::from_vec(vec![0xe9])
96        }
97    );
98}
99
100#[test]
101fn invalid_utf8_option_short_space() {
102    let r = NamedOs::try_parse_from(vec![
103        OsString::from(""),
104        OsString::from("-a"),
105        OsString::from_vec(vec![0xe9]),
106    ]);
107    assert_eq!(
108        r.unwrap(),
109        NamedOs {
110            arg: OsString::from_vec(vec![0xe9])
111        }
112    );
113}
114
115#[test]
116fn invalid_utf8_option_short_equals() {
117    let r = NamedOs::try_parse_from(vec![
118        OsString::from(""),
119        OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
120    ]);
121    assert_eq!(
122        r.unwrap(),
123        NamedOs {
124            arg: OsString::from_vec(vec![0xe9])
125        }
126    );
127}
128
129#[test]
130fn invalid_utf8_option_short_no_space() {
131    let r = NamedOs::try_parse_from(vec![
132        OsString::from(""),
133        OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
134    ]);
135    assert_eq!(
136        r.unwrap(),
137        NamedOs {
138            arg: OsString::from_vec(vec![0xe9])
139        }
140    );
141}
142
143#[test]
144fn invalid_utf8_option_long_space() {
145    let r = NamedOs::try_parse_from(vec![
146        OsString::from(""),
147        OsString::from("--arg"),
148        OsString::from_vec(vec![0xe9]),
149    ]);
150    assert_eq!(
151        r.unwrap(),
152        NamedOs {
153            arg: OsString::from_vec(vec![0xe9])
154        }
155    );
156}
157
158#[test]
159fn invalid_utf8_option_long_equals() {
160    let r = NamedOs::try_parse_from(vec![
161        OsString::from(""),
162        OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
163    ]);
164    assert_eq!(
165        r.unwrap(),
166        NamedOs {
167            arg: OsString::from_vec(vec![0xe9])
168        }
169    );
170}
171
172#[derive(Debug, PartialEq, Parser)]
173enum External {
174    #[command(external_subcommand)]
175    Other(Vec<String>),
176}
177
178#[test]
179fn refuse_invalid_utf8_subcommand_with_allow_external_subcommands() {
180    let m = External::try_parse_from(vec![
181        OsString::from(""),
182        OsString::from_vec(vec![0xe9]),
183        OsString::from("normal"),
184    ]);
185    assert!(m.is_err());
186    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
187}
188
189#[test]
190fn refuse_invalid_utf8_subcommand_args_with_allow_external_subcommands() {
191    let m = External::try_parse_from(vec![
192        OsString::from(""),
193        OsString::from("subcommand"),
194        OsString::from("normal"),
195        OsString::from_vec(vec![0xe9]),
196        OsString::from("--another_normal"),
197    ]);
198    assert!(m.is_err());
199    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
200}
201
202#[derive(Debug, PartialEq, Parser)]
203enum ExternalOs {
204    #[command(external_subcommand)]
205    Other(Vec<OsString>),
206}
207
208#[test]
209fn allow_invalid_utf8_subcommand_args_with_allow_external_subcommands() {
210    let m = ExternalOs::try_parse_from(vec![
211        OsString::from(""),
212        OsString::from("subcommand"),
213        OsString::from("normal"),
214        OsString::from_vec(vec![0xe9]),
215        OsString::from("--another_normal"),
216    ]);
217    assert_eq!(
218        m.unwrap(),
219        ExternalOs::Other(vec![
220            OsString::from("subcommand"),
221            OsString::from("normal"),
222            OsString::from_vec(vec![0xe9]),
223            OsString::from("--another_normal"),
224        ])
225    );
226}
227