gitignore_template_generator/parser/
api.rs

1use std::ffi::OsString;
2
3pub use crate::parser::impls::DefaultArgsParser;
4use crate::{ProgramError, config::Args};
5
6pub trait ArgsParser {
7    fn parse(args: impl IntoIterator<Item = OsString>) -> Args;
8    fn try_parse(
9        args: impl IntoIterator<Item = OsString>,
10    ) -> Result<Args, ProgramError>;
11}
12
13#[cfg(test)]
14mod tests {
15    use rstest::*;
16
17    use super::*;
18    use crate::helper::*;
19
20    mod default_args_parser {
21        use super::*;
22
23        mod try_parse {
24            use super::*;
25
26            mod success {
27                use crate::{ErrorKind, constant};
28
29                use super::*;
30
31                #[rstest]
32                #[case("-V")]
33                #[case("--version")]
34                #[case("-V rust")]
35                #[case("rust -V")]
36                #[case("rust -s foo -V")]
37                #[case("-aV")]
38                fn it_parses_version_cli_option(#[case] cli_args: &str) {
39                    let cli_args = parse_cli_args(cli_args);
40                    let parsed_args = DefaultArgsParser::try_parse(cli_args);
41
42                    let actual_error = parsed_args.as_ref().err();
43                    let expected_error = ProgramError {
44                        message: format!(
45                            "{} {}",
46                            env!("CARGO_PKG_NAME"),
47                            env!("CARGO_PKG_VERSION")
48                        ),
49                        exit_status: 0,
50                        styled_message: None,
51                        error_kind: ErrorKind::VersionInfos,
52                    };
53                    let expected_error = Some(&expected_error);
54
55                    assert!(actual_error.is_some());
56                    assert_eq!(actual_error, expected_error);
57                }
58
59                #[rstest]
60                #[case("-h")]
61                #[case("--help")]
62                #[case("-h rust")]
63                #[case("rust -h")]
64                #[case("rust -s foo -h")]
65                #[case("-aVh")]
66                fn it_parses_help_cli_option(#[case] cli_args: &str) {
67                    let cli_args = parse_cli_args(cli_args);
68                    let parsed_args = DefaultArgsParser::try_parse(cli_args);
69
70                    let actual_error = parsed_args.as_ref().err();
71                    let expected_error = ProgramError {
72                        message: get_help_message(),
73                        exit_status: 0,
74                        styled_message: Some(get_ansi_help_message()),
75                        error_kind: ErrorKind::HelpInfos,
76                    };
77                    let expected_error = Some(&expected_error);
78
79                    assert!(actual_error.is_some());
80                    assert_eq!(actual_error, expected_error);
81                }
82
83                #[rstest]
84                #[case("-a")]
85                #[case("--author")]
86                #[case("-a rust")]
87                #[case("rust -a")]
88                #[case("rust -s foo -a")]
89                fn it_parses_author_cli_option_preemptively(
90                    #[case] cli_args: &str,
91                ) {
92                    let cli_args = parse_cli_args(cli_args);
93                    let parsed_args = DefaultArgsParser::try_parse(cli_args);
94
95                    let actual_error = parsed_args.as_ref().err();
96                    let expected_error = ProgramError {
97                        message: env!("CARGO_PKG_AUTHORS").to_string(),
98                        exit_status: 0,
99                        styled_message: None,
100                        error_kind: ErrorKind::AuthorInfos,
101                    };
102                    let expected_error = Some(&expected_error);
103
104                    assert!(actual_error.is_some());
105                    assert_eq!(actual_error, expected_error);
106                }
107
108                #[rstest]
109                #[case("rust")]
110                #[case("rust python node")]
111                fn it_parses_pos_args_without_server_url_cli_option(
112                    #[case] cli_options: &str,
113                ) {
114                    let cli_args = parse_cli_args(cli_options);
115                    let parsed_args = DefaultArgsParser::try_parse(cli_args);
116
117                    let actual_result = parsed_args.as_ref().ok();
118                    let expected_result = Args::default()
119                        .with_template_names(make_string_vec(cli_options))
120                        .with_server_url(
121                            constant::template_generator::BASE_URL,
122                        );
123                    let expected_result = Some(&expected_result);
124
125                    assert!(actual_result.is_some());
126                    assert_eq!(actual_result, expected_result);
127                }
128
129                #[rstest]
130                #[case("rust -s https://test.com")]
131                #[case("rust --server-url https://test.com")]
132                fn it_parses_pos_args_with_server_url_cli_option(
133                    #[case] cli_args: &str,
134                ) {
135                    let cli_args = parse_cli_args(cli_args);
136                    let parsed_args = DefaultArgsParser::try_parse(cli_args);
137
138                    let actual_result = parsed_args.as_ref().ok();
139                    let expected_result = Args::default()
140                        .with_template_names(make_string_vec("rust"))
141                        .with_server_url("https://test.com");
142                    let expected_result = Some(&expected_result);
143
144                    assert!(actual_result.is_some());
145                    assert_eq!(actual_result, expected_result);
146                }
147            }
148
149            mod failure {
150                use crate::{ErrorKind, constant};
151
152                use super::*;
153
154                #[test]
155                fn it_fails_parsing_when_no_pos_args_given() {
156                    let cli_args = parse_cli_args("");
157                    let parsed_args = DefaultArgsParser::try_parse(cli_args);
158
159                    let actual_error = parsed_args.as_ref().err();
160                    let expected_error = ProgramError {
161                        message: load_expectation_file_as_string(
162                            "no_pos_args_error",
163                        ),
164                        exit_status: constant::exit_status::GENERIC,
165
166                        styled_message: Some(load_expectation_file_as_string(
167                            "ansi_no_pos_args_error",
168                        )),
169                        error_kind: ErrorKind::Other,
170                    };
171                    let expected_error = Some(&expected_error);
172
173                    assert!(actual_error.is_some());
174                    assert_eq!(actual_error, expected_error);
175                }
176
177                #[test]
178                fn it_fails_parsing_when_commas_in_pos_args() {
179                    let cli_args = parse_cli_args("python,java");
180                    let parsed_args = DefaultArgsParser::try_parse(cli_args);
181
182                    let actual_error = parsed_args.as_ref().err();
183                    let expected_error = ProgramError {
184                        message: load_expectation_file_as_string(
185                            "comma_pos_args_error",
186                        ),
187                        exit_status: constant::exit_status::GENERIC,
188
189                        styled_message: Some(load_expectation_file_as_string(
190                            "ansi_comma_pos_args_error",
191                        )),
192                        error_kind: ErrorKind::Other,
193                    };
194                    let expected_error = Some(&expected_error);
195
196                    assert!(actual_error.is_some());
197                    assert_eq!(actual_error, expected_error);
198                }
199
200                #[test]
201                fn it_fails_parsing_when_server_url_but_no_pos_args() {
202                    let cli_args = parse_cli_args("-s https://test.com");
203                    let parsed_args = DefaultArgsParser::try_parse(cli_args);
204
205                    let actual_error = parsed_args.as_ref().err();
206                    let expected_error = ProgramError {
207                        message: load_expectation_file_as_string(
208                            "server_url_no_pos_args_error",
209                        ),
210                        exit_status: constant::exit_status::GENERIC,
211
212                        styled_message: Some(load_expectation_file_as_string(
213                            "ansi_server_url_no_pos_args_error",
214                        )),
215                        error_kind: ErrorKind::Other,
216                    };
217                    let expected_error = Some(&expected_error);
218
219                    assert!(actual_error.is_some());
220                    assert_eq!(actual_error, expected_error);
221                }
222
223                #[test]
224                fn it_fails_parsing_when_inexistent_cli_option() {
225                    let cli_args = parse_cli_args("-x");
226                    let parsed_args = DefaultArgsParser::try_parse(cli_args);
227
228                    let actual_error = parsed_args.as_ref().err();
229                    let expected_error = ProgramError {
230                        message: load_expectation_file_as_string(
231                            "unexpected_argument_error",
232                        ),
233                        exit_status: constant::exit_status::GENERIC,
234                        styled_message: Some(load_expectation_file_as_string(
235                            "ansi_unexpected_argument_error",
236                        )),
237                        error_kind: ErrorKind::Other,
238                    };
239                    let expected_error = Some(&expected_error);
240
241                    assert!(actual_error.is_some());
242                    assert_eq!(actual_error, expected_error);
243                }
244            }
245        }
246    }
247}