pyreq_rs/
parser.rs

1pub mod requirement_specifier;
2pub mod version;
3
4//pub fn pip_option(input: &str) -> IResult<&str, &str> {}
5//pub fn requirement_specifier(input: &str) -> IResult<&str, &str> {}
6//pub fn archive_url(input: &str) -> IResult<&str, &str> {}
7//pub fn archive_path(input: &str) -> IResult<&str, &str> {}
8//pub fn local_project_path(input: &str) -> IResult<&str, &str> {}
9//pub fn vcs_project_url(input: &str) -> IResult<&str, &str> {}
10//pub fn comment(input: &str) -> IResult<&str, &str> {}
11//pub fn line(input: &str) -> IResult<&str, &str> {
12//escaped(not_line_ending, '\\', line_ending)(input)
13//}
14//
15#[cfg(test)]
16mod tests {
17    use super::requirement_specifier::specification;
18    use super::version::version_scheme;
19    use crate::requirements::{
20        Comparison, LocalVersionPart, MarkerExpr, MarkerOp, RequirementSpecifier, Version,
21    };
22
23    #[test]
24    fn test_requirement_specifier() {
25        // samples from https://peps.python.org/pep-0508/
26        // ```python
27        // tests = [
28        //     "A",
29        //     "A.B-C_D",
30        //     "aa",
31        //     "name",
32        //     "name<=1",
33        //     "name>=3",
34        //     "name>=3,<2",
35        //     "name@http://foo.com",
36        //     "name [fred,bar] @ http://foo.com ; python_version=='2.7'",
37        //     "name[quux, strange];python_version<'2.7' and platform_version=='2'",
38        //     "name; os_name=='a' or os_name=='b'",
39        //     # Should parse as (a and b) or c
40        //     "name; os_name=='a' and os_name=='b' or os_name=='c'",
41        //     # Overriding precedence -> a and (b or c)
42        //     "name; os_name=='a' and (os_name=='b' or os_name=='c')",
43        //     # should parse as a or (b and c)
44        //     "name; os_name=='a' or os_name=='b' and os_name=='c'",
45        //     # Overriding precedence -> (a or b) and c
46        //     "name; (os_name=='a' or os_name=='b') and os_name=='c'",
47        // ]
48        // ```
49        assert_eq!(
50            specification("A"),
51            Ok((
52                "",
53                RequirementSpecifier {
54                    name: "A".to_string(),
55                    ..Default::default()
56                }
57            ))
58        );
59        assert_eq!(
60            specification("A.B-C_D"),
61            Ok((
62                "",
63                RequirementSpecifier {
64                    name: "A.B-C_D".to_string(),
65                    ..Default::default()
66                }
67            ))
68        );
69        assert_eq!(
70            specification("aa"),
71            Ok((
72                "",
73                RequirementSpecifier {
74                    name: "aa".to_string(),
75                    ..Default::default()
76                }
77            ))
78        );
79        assert_eq!(
80            specification("name"),
81            Ok((
82                "",
83                RequirementSpecifier {
84                    name: "name".to_string(),
85                    ..Default::default()
86                }
87            ))
88        );
89        assert_eq!(
90            specification("name<=1"),
91            Ok((
92                "",
93                RequirementSpecifier {
94                    name: "name".to_string(),
95                    version_specs: vec![(Comparison::LessThanOrEqual, "1".to_string()).into()],
96                    ..Default::default()
97                }
98            ))
99        );
100        assert_eq!(
101            specification("name>=3"),
102            Ok((
103                "",
104                RequirementSpecifier {
105                    name: "name".to_string(),
106                    version_specs: vec![(Comparison::GreaterThanOrEqual, "3".to_string()).into()],
107                    ..Default::default()
108                }
109            ))
110        );
111        assert_eq!(
112            specification("name>=3,<2"),
113            Ok((
114                "",
115                RequirementSpecifier {
116                    name: "name".to_string(),
117                    version_specs: vec![
118                        (Comparison::GreaterThanOrEqual, "3".to_string()).into(),
119                        (Comparison::LessThan, "2".to_string()).into()
120                    ],
121                    ..Default::default()
122                }
123            ))
124        );
125        assert_eq!(
126            specification("name@http://foo.com"),
127            Ok((
128                "",
129                RequirementSpecifier {
130                    name: "name".to_string(),
131                    urlspec: Some("http://foo.com".to_string()),
132                    ..Default::default()
133                }
134            ))
135        );
136        assert_eq!(
137            specification("name [fred,bar] @ http://foo.com ; python_version=='2.7'"),
138            Ok((
139                "",
140                RequirementSpecifier {
141                    name: "name".to_string(),
142                    extras: vec!["fred".to_string(), "bar".to_string()],
143                    urlspec: Some("http://foo.com".to_string()),
144                    marker_expr: Some(MarkerExpr::Basic(
145                        "python_version".to_string(),
146                        MarkerOp::Comparison(Comparison::Equal),
147                        "2.7".to_string()
148                    )),
149                    ..Default::default()
150                }
151            ))
152        );
153        assert_eq!(
154            specification("name[quux, strange];python_version<'2.7' and platform_version=='2'"),
155            Ok((
156                "",
157                RequirementSpecifier {
158                    name: "name".to_string(),
159                    extras: vec!["quux".to_string(), "strange".to_string()],
160                    marker_expr: Some(MarkerExpr::And(
161                        Box::new(MarkerExpr::Basic(
162                            "python_version".to_string(),
163                            MarkerOp::Comparison(Comparison::LessThan),
164                            "2.7".to_string()
165                        )),
166                        Box::new(MarkerExpr::Basic(
167                            "platform_version".to_string(),
168                            MarkerOp::Comparison(Comparison::Equal),
169                            "2".to_string()
170                        ))
171                    )),
172                    ..Default::default()
173                }
174            ))
175        );
176        assert_eq!(
177            specification("name; os_name=='a' or os_name=='b'"),
178            Ok((
179                "",
180                RequirementSpecifier {
181                    name: "name".to_string(),
182                    marker_expr: Some(MarkerExpr::Or(
183                        Box::new(MarkerExpr::Basic(
184                            "os_name".to_string(),
185                            MarkerOp::Comparison(Comparison::Equal),
186                            "a".to_string()
187                        )),
188                        Box::new(MarkerExpr::Basic(
189                            "os_name".to_string(),
190                            MarkerOp::Comparison(Comparison::Equal),
191                            "b".to_string()
192                        ))
193                    )),
194                    ..Default::default()
195                }
196            ))
197        );
198        assert_eq!(
199            specification("name; os_name=='a' and os_name=='b' or os_name=='c'"),
200            Ok((
201                "",
202                RequirementSpecifier {
203                    name: "name".to_string(),
204                    marker_expr: Some(MarkerExpr::Or(
205                        Box::new(MarkerExpr::And(
206                            Box::new(MarkerExpr::Basic(
207                                "os_name".to_string(),
208                                MarkerOp::Comparison(Comparison::Equal),
209                                "a".to_string()
210                            )),
211                            Box::new(MarkerExpr::Basic(
212                                "os_name".to_string(),
213                                MarkerOp::Comparison(Comparison::Equal),
214                                "b".to_string()
215                            ))
216                        )),
217                        Box::new(MarkerExpr::Basic(
218                            "os_name".to_string(),
219                            MarkerOp::Comparison(Comparison::Equal),
220                            "c".to_string()
221                        ))
222                    )),
223                    ..Default::default()
224                }
225            ))
226        );
227        assert_eq!(
228            specification("name; os_name=='a' and (os_name=='b' or os_name=='c')"),
229            Ok((
230                "",
231                RequirementSpecifier {
232                    name: "name".to_string(),
233                    marker_expr: Some(MarkerExpr::And(
234                        Box::new(MarkerExpr::Basic(
235                            "os_name".to_string(),
236                            MarkerOp::Comparison(Comparison::Equal),
237                            "a".to_string()
238                        )),
239                        Box::new(MarkerExpr::Or(
240                            Box::new(MarkerExpr::Basic(
241                                "os_name".to_string(),
242                                MarkerOp::Comparison(Comparison::Equal),
243                                "b".to_string()
244                            )),
245                            Box::new(MarkerExpr::Basic(
246                                "os_name".to_string(),
247                                MarkerOp::Comparison(Comparison::Equal),
248                                "c".to_string()
249                            ))
250                        ))
251                    )),
252                    ..Default::default()
253                }
254            ))
255        );
256        assert_eq!(
257            specification("name; os_name=='a' or os_name=='b' and os_name=='c'"),
258            Ok((
259                "",
260                RequirementSpecifier {
261                    name: "name".to_string(),
262                    marker_expr: Some(MarkerExpr::Or(
263                        Box::new(MarkerExpr::Basic(
264                            "os_name".to_string(),
265                            MarkerOp::Comparison(Comparison::Equal),
266                            "a".to_string()
267                        )),
268                        Box::new(MarkerExpr::And(
269                            Box::new(MarkerExpr::Basic(
270                                "os_name".to_string(),
271                                MarkerOp::Comparison(Comparison::Equal),
272                                "b".to_string()
273                            )),
274                            Box::new(MarkerExpr::Basic(
275                                "os_name".to_string(),
276                                MarkerOp::Comparison(Comparison::Equal),
277                                "c".to_string()
278                            ))
279                        ))
280                    )),
281                    ..Default::default()
282                }
283            ))
284        );
285        assert_eq!(
286            specification("name; (os_name=='a' or os_name=='b') and os_name=='c'"),
287            Ok((
288                "",
289                RequirementSpecifier {
290                    name: "name".to_string(),
291                    marker_expr: Some(MarkerExpr::And(
292                        Box::new(MarkerExpr::Or(
293                            Box::new(MarkerExpr::Basic(
294                                "os_name".to_string(),
295                                MarkerOp::Comparison(Comparison::Equal),
296                                "a".to_string()
297                            )),
298                            Box::new(MarkerExpr::Basic(
299                                "os_name".to_string(),
300                                MarkerOp::Comparison(Comparison::Equal),
301                                "b".to_string()
302                            ))
303                        )),
304                        Box::new(MarkerExpr::Basic(
305                            "os_name".to_string(),
306                            MarkerOp::Comparison(Comparison::Equal),
307                            "c".to_string()
308                        ))
309                    )),
310                    ..Default::default()
311                }
312            ))
313        );
314    }
315
316    #[test]
317    fn test_version_scheme() {
318        // samples from https://peps.python.org/pep-0440/#examples-of-compliant-version-schemes
319        assert_eq!(
320            version_scheme("0.1"),
321            Ok((
322                "",
323                Version {
324                    epoch: 0,
325                    release: vec![0, 1],
326                    ..Default::default()
327                }
328            ))
329        );
330        assert_eq!(
331            version_scheme("1.1.0"),
332            Ok((
333                "",
334                Version {
335                    epoch: 0,
336                    release: vec![1, 1, 0],
337                    ..Default::default()
338                }
339            ))
340        );
341        assert_eq!(
342            version_scheme("1.1a1"),
343            Ok((
344                "",
345                Version {
346                    epoch: 0,
347                    release: vec![1, 1],
348                    pre: Some(("a".to_string(), 1)),
349                    ..Default::default()
350                }
351            ))
352        );
353        assert_eq!(
354            version_scheme("1.1.0.PoSt1"),
355            Ok((
356                "",
357                Version {
358                    epoch: 0,
359                    release: vec![1, 1, 0],
360                    post: Some(("post".to_string(), 1)),
361                    ..Default::default()
362                }
363            ))
364        );
365        assert_eq!(
366            version_scheme("3!1.1.2-Beta3+Ubuntu.3-release"),
367            Ok((
368                "",
369                Version {
370                    epoch: 3,
371                    release: vec![1, 1, 2],
372                    pre: Some(("b".to_string(), 3)),
373                    local: Some(vec![
374                        LocalVersionPart::LowerStr("ubuntu".to_string()),
375                        LocalVersionPart::Num(3),
376                        LocalVersionPart::LowerStr("release".to_string()),
377                    ]),
378                    ..Default::default()
379                }
380            ))
381        );
382    }
383}