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}