1 #![allow(
2     clippy::missing_panics_doc,
3     clippy::shadow_unrelated,
4     clippy::toplevel_ref_arg,
5     clippy::wildcard_imports
6 )]
7 
8 mod node;
9 mod util;
10 
11 use crate::util::*;
12 use std::collections::hash_map::DefaultHasher;
13 use std::hash::{Hash, Hasher};
14 
15 #[cfg(test_node_semver)]
16 use node::{req, VersionReq};
17 #[cfg(not(test_node_semver))]
18 use semver::VersionReq;
19 
20 #[cfg_attr(not(no_track_caller), track_caller)]
assert_match_all(req: &VersionReq, versions: &[&str])21 fn assert_match_all(req: &VersionReq, versions: &[&str]) {
22     for string in versions {
23         let parsed = version(string);
24         assert!(req.matches(&parsed), "did not match {}", string);
25     }
26 }
27 
28 #[cfg_attr(not(no_track_caller), track_caller)]
assert_match_none(req: &VersionReq, versions: &[&str])29 fn assert_match_none(req: &VersionReq, versions: &[&str]) {
30     for string in versions {
31         let parsed = version(string);
32         assert!(!req.matches(&parsed), "matched {}", string);
33     }
34 }
35 
36 #[test]
test_basic()37 fn test_basic() {
38     let ref r = req("1.0.0");
39     assert_to_string(r, "^1.0.0");
40     assert_match_all(r, &["1.0.0", "1.1.0", "1.0.1"]);
41     assert_match_none(r, &["0.9.9", "0.10.0", "0.1.0", "1.0.0-pre", "1.0.1-pre"]);
42 }
43 
44 #[test]
45 #[cfg(not(no_const_vec_new))]
test_default()46 fn test_default() {
47     let ref r = VersionReq::default();
48     assert_eq!(r, &VersionReq::STAR);
49 }
50 
51 #[test]
test_exact()52 fn test_exact() {
53     let ref r = req("=1.0.0");
54     assert_to_string(r, "=1.0.0");
55     assert_match_all(r, &["1.0.0"]);
56     assert_match_none(r, &["1.0.1", "0.9.9", "0.10.0", "0.1.0", "1.0.0-pre"]);
57 
58     let ref r = req("=0.9.0");
59     assert_to_string(r, "=0.9.0");
60     assert_match_all(r, &["0.9.0"]);
61     assert_match_none(r, &["0.9.1", "1.9.0", "0.0.9", "0.9.0-pre"]);
62 
63     let ref r = req("=0.0.2");
64     assert_to_string(r, "=0.0.2");
65     assert_match_all(r, &["0.0.2"]);
66     assert_match_none(r, &["0.0.1", "0.0.3", "0.0.2-pre"]);
67 
68     let ref r = req("=0.1.0-beta2.a");
69     assert_to_string(r, "=0.1.0-beta2.a");
70     assert_match_all(r, &["0.1.0-beta2.a"]);
71     assert_match_none(r, &["0.9.1", "0.1.0", "0.1.1-beta2.a", "0.1.0-beta2"]);
72 
73     let ref r = req("=0.1.0+meta");
74     assert_to_string(r, "=0.1.0");
75     assert_match_all(r, &["0.1.0", "0.1.0+meta", "0.1.0+any"]);
76 }
77 
78 #[test]
test_greater_than()79 pub fn test_greater_than() {
80     let ref r = req(">= 1.0.0");
81     assert_to_string(r, ">=1.0.0");
82     assert_match_all(r, &["1.0.0", "2.0.0"]);
83     assert_match_none(r, &["0.1.0", "0.0.1", "1.0.0-pre", "2.0.0-pre"]);
84 
85     let ref r = req(">= 2.1.0-alpha2");
86     assert_to_string(r, ">=2.1.0-alpha2");
87     assert_match_all(r, &["2.1.0-alpha2", "2.1.0-alpha3", "2.1.0", "3.0.0"]);
88     assert_match_none(
89         r,
90         &["2.0.0", "2.1.0-alpha1", "2.0.0-alpha2", "3.0.0-alpha2"],
91     );
92 }
93 
94 #[test]
test_less_than()95 pub fn test_less_than() {
96     let ref r = req("< 1.0.0");
97     assert_to_string(r, "<1.0.0");
98     assert_match_all(r, &["0.1.0", "0.0.1"]);
99     assert_match_none(r, &["1.0.0", "1.0.0-beta", "1.0.1", "0.9.9-alpha"]);
100 
101     let ref r = req("<= 2.1.0-alpha2");
102     assert_match_all(r, &["2.1.0-alpha2", "2.1.0-alpha1", "2.0.0", "1.0.0"]);
103     assert_match_none(
104         r,
105         &["2.1.0", "2.2.0-alpha1", "2.0.0-alpha2", "1.0.0-alpha2"],
106     );
107 
108     let ref r = req(">1.0.0-alpha, <1.0.0");
109     assert_match_all(r, &["1.0.0-beta"]);
110 
111     let ref r = req(">1.0.0-alpha, <1.0");
112     assert_match_none(r, &["1.0.0-beta"]);
113 
114     let ref r = req(">1.0.0-alpha, <1");
115     assert_match_none(r, &["1.0.0-beta"]);
116 }
117 
118 #[test]
test_multiple()119 pub fn test_multiple() {
120     let ref r = req("> 0.0.9, <= 2.5.3");
121     assert_to_string(r, ">0.0.9, <=2.5.3");
122     assert_match_all(r, &["0.0.10", "1.0.0", "2.5.3"]);
123     assert_match_none(r, &["0.0.8", "2.5.4"]);
124 
125     let ref r = req("0.3.0, 0.4.0");
126     assert_to_string(r, "^0.3.0, ^0.4.0");
127     assert_match_none(r, &["0.0.8", "0.3.0", "0.4.0"]);
128 
129     let ref r = req("<= 0.2.0, >= 0.5.0");
130     assert_to_string(r, "<=0.2.0, >=0.5.0");
131     assert_match_none(r, &["0.0.8", "0.3.0", "0.5.1"]);
132 
133     let ref r = req("0.1.0, 0.1.4, 0.1.6");
134     assert_to_string(r, "^0.1.0, ^0.1.4, ^0.1.6");
135     assert_match_all(r, &["0.1.6", "0.1.9"]);
136     assert_match_none(r, &["0.1.0", "0.1.4", "0.2.0"]);
137 
138     let err = req_err("> 0.1.0,");
139     assert_to_string(
140         err,
141         "unexpected end of input while parsing major version number",
142     );
143 
144     let err = req_err("> 0.3.0, ,");
145     assert_to_string(
146         err,
147         "unexpected character ',' while parsing major version number",
148     );
149 
150     let ref r = req(">=0.5.1-alpha3, <0.6");
151     assert_to_string(r, ">=0.5.1-alpha3, <0.6");
152     assert_match_all(
153         r,
154         &[
155             "0.5.1-alpha3",
156             "0.5.1-alpha4",
157             "0.5.1-beta",
158             "0.5.1",
159             "0.5.5",
160         ],
161     );
162     assert_match_none(
163         r,
164         &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre"],
165     );
166     assert_match_none(r, &["0.6.0", "0.6.0-pre"]);
167 
168     // https://github.com/steveklabnik/semver/issues/56
169     let err = req_err("1.2.3 - 2.3.4");
170     assert_to_string(err, "expected comma after patch version number, found '-'");
171 
172     let err = req_err(">1, >2, >3, >4, >5, >6, >7, >8, >9, >10, >11, >12, >13, >14, >15, >16, >17, >18, >19, >20, >21, >22, >23, >24, >25, >26, >27, >28, >29, >30, >31, >32, >33");
173     assert_to_string(err, "excessive number of version comparators");
174 }
175 
176 #[test]
test_whitespace_delimited_comparator_sets()177 pub fn test_whitespace_delimited_comparator_sets() {
178     // https://github.com/steveklabnik/semver/issues/55
179     let err = req_err("> 0.0.9 <= 2.5.3");
180     assert_to_string(err, "expected comma after patch version number, found '<'");
181 }
182 
183 #[test]
test_tilde()184 pub fn test_tilde() {
185     let ref r = req("~1");
186     assert_match_all(r, &["1.0.0", "1.0.1", "1.1.1"]);
187     assert_match_none(r, &["0.9.1", "2.9.0", "0.0.9"]);
188 
189     let ref r = req("~1.2");
190     assert_match_all(r, &["1.2.0", "1.2.1"]);
191     assert_match_none(r, &["1.1.1", "1.3.0", "0.0.9"]);
192 
193     let ref r = req("~1.2.2");
194     assert_match_all(r, &["1.2.2", "1.2.4"]);
195     assert_match_none(r, &["1.2.1", "1.9.0", "1.0.9", "2.0.1", "0.1.3"]);
196 
197     let ref r = req("~1.2.3-beta.2");
198     assert_match_all(r, &["1.2.3", "1.2.4", "1.2.3-beta.2", "1.2.3-beta.4"]);
199     assert_match_none(r, &["1.3.3", "1.1.4", "1.2.3-beta.1", "1.2.4-beta.2"]);
200 }
201 
202 #[test]
test_caret()203 pub fn test_caret() {
204     let ref r = req("^1");
205     assert_match_all(r, &["1.1.2", "1.1.0", "1.2.1", "1.0.1"]);
206     assert_match_none(r, &["0.9.1", "2.9.0", "0.1.4"]);
207     assert_match_none(r, &["1.0.0-beta1", "0.1.0-alpha", "1.0.1-pre"]);
208 
209     let ref r = req("^1.1");
210     assert_match_all(r, &["1.1.2", "1.1.0", "1.2.1"]);
211     assert_match_none(r, &["0.9.1", "2.9.0", "1.0.1", "0.1.4"]);
212 
213     let ref r = req("^1.1.2");
214     assert_match_all(r, &["1.1.2", "1.1.4", "1.2.1"]);
215     assert_match_none(r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]);
216     assert_match_none(r, &["1.1.2-alpha1", "1.1.3-alpha1", "2.9.0-alpha1"]);
217 
218     let ref r = req("^0.1.2");
219     assert_match_all(r, &["0.1.2", "0.1.4"]);
220     assert_match_none(r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]);
221     assert_match_none(r, &["0.1.2-beta", "0.1.3-alpha", "0.2.0-pre"]);
222 
223     let ref r = req("^0.5.1-alpha3");
224     assert_match_all(
225         r,
226         &[
227             "0.5.1-alpha3",
228             "0.5.1-alpha4",
229             "0.5.1-beta",
230             "0.5.1",
231             "0.5.5",
232         ],
233     );
234     assert_match_none(
235         r,
236         &[
237             "0.5.1-alpha1",
238             "0.5.2-alpha3",
239             "0.5.5-pre",
240             "0.5.0-pre",
241             "0.6.0",
242         ],
243     );
244 
245     let ref r = req("^0.0.2");
246     assert_match_all(r, &["0.0.2"]);
247     assert_match_none(r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1", "0.1.4"]);
248 
249     let ref r = req("^0.0");
250     assert_match_all(r, &["0.0.2", "0.0.0"]);
251     assert_match_none(r, &["0.9.1", "2.9.0", "1.1.1", "0.1.4"]);
252 
253     let ref r = req("^0");
254     assert_match_all(r, &["0.9.1", "0.0.2", "0.0.0"]);
255     assert_match_none(r, &["2.9.0", "1.1.1"]);
256 
257     let ref r = req("^1.4.2-beta.5");
258     assert_match_all(
259         r,
260         &["1.4.2", "1.4.3", "1.4.2-beta.5", "1.4.2-beta.6", "1.4.2-c"],
261     );
262     assert_match_none(
263         r,
264         &[
265             "0.9.9",
266             "2.0.0",
267             "1.4.2-alpha",
268             "1.4.2-beta.4",
269             "1.4.3-beta.5",
270         ],
271     );
272 }
273 
274 #[test]
test_wildcard()275 pub fn test_wildcard() {
276     let err = req_err("");
277     assert_to_string(
278         err,
279         "unexpected end of input while parsing major version number",
280     );
281 
282     let ref r = req("*");
283     assert_match_all(r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
284     assert_match_none(r, &["1.0.0-pre"]);
285 
286     for s in &["x", "X"] {
287         assert_eq!(*r, req(s));
288     }
289 
290     let ref r = req("1.*");
291     assert_match_all(r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);
292     assert_match_none(r, &["0.0.9", "1.2.0-pre"]);
293 
294     for s in &["1.x", "1.X", "1.*.*"] {
295         assert_eq!(*r, req(s));
296     }
297 
298     let ref r = req("1.2.*");
299     assert_match_all(r, &["1.2.0", "1.2.2", "1.2.4"]);
300     assert_match_none(r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3", "1.2.2-pre"]);
301 
302     for s in &["1.2.x", "1.2.X"] {
303         assert_eq!(*r, req(s));
304     }
305 }
306 
307 #[test]
test_logical_or()308 pub fn test_logical_or() {
309     // https://github.com/steveklabnik/semver/issues/57
310     let err = req_err("=1.2.3 || =2.3.4");
311     assert_to_string(err, "expected comma after patch version number, found '|'");
312 
313     let err = req_err("1.1 || =1.2.3");
314     assert_to_string(err, "expected comma after minor version number, found '|'");
315 
316     let err = req_err("6.* || 8.* || >= 10.*");
317     assert_to_string(err, "expected comma after minor version number, found '|'");
318 }
319 
320 #[test]
test_any()321 pub fn test_any() {
322     #[cfg(not(no_const_vec_new))]
323     let ref r = VersionReq::STAR;
324     #[cfg(no_const_vec_new)]
325     let ref r = VersionReq {
326         comparators: Vec::new(),
327     };
328     assert_match_all(r, &["0.0.1", "0.1.0", "1.0.0"]);
329 }
330 
331 #[test]
test_pre()332 pub fn test_pre() {
333     let ref r = req("=2.1.1-really.0");
334     assert_match_all(r, &["2.1.1-really.0"]);
335 }
336 
337 #[test]
test_parse()338 pub fn test_parse() {
339     let err = req_err("\0");
340     assert_to_string(
341         err,
342         "unexpected character '\\0' while parsing major version number",
343     );
344 
345     let err = req_err(">= >= 0.0.2");
346     assert_to_string(
347         err,
348         "unexpected character '>' while parsing major version number",
349     );
350 
351     let err = req_err(">== 0.0.2");
352     assert_to_string(
353         err,
354         "unexpected character '=' while parsing major version number",
355     );
356 
357     let err = req_err("a.0.0");
358     assert_to_string(
359         err,
360         "unexpected character 'a' while parsing major version number",
361     );
362 
363     let err = req_err("1.0.0-");
364     assert_to_string(err, "empty identifier segment in pre-release identifier");
365 
366     let err = req_err(">=");
367     assert_to_string(
368         err,
369         "unexpected end of input while parsing major version number",
370     );
371 }
372 
373 #[test]
test_comparator_parse()374 fn test_comparator_parse() {
375     let parsed = comparator("1.2.3-alpha");
376     assert_to_string(parsed, "^1.2.3-alpha");
377 
378     let parsed = comparator("2.X");
379     assert_to_string(parsed, "2.*");
380 
381     let parsed = comparator("2");
382     assert_to_string(parsed, "^2");
383 
384     let parsed = comparator("2.x.x");
385     assert_to_string(parsed, "2.*");
386 
387     let err = comparator_err("1.2.3-01");
388     assert_to_string(err, "invalid leading zero in pre-release identifier");
389 
390     let err = comparator_err("1.2.3+4.");
391     assert_to_string(err, "empty identifier segment in build metadata");
392 
393     let err = comparator_err(">");
394     assert_to_string(
395         err,
396         "unexpected end of input while parsing major version number",
397     );
398 
399     let err = comparator_err("1.");
400     assert_to_string(
401         err,
402         "unexpected end of input while parsing minor version number",
403     );
404 
405     let err = comparator_err("1.*.");
406     assert_to_string(err, "unexpected character after wildcard in version req");
407 
408     let err = comparator_err("1.2.3+4ÿ");
409     assert_to_string(err, "unexpected character 'ÿ' after build metadata");
410 }
411 
412 #[test]
test_cargo3202()413 fn test_cargo3202() {
414     let ref r = req("0.*.*");
415     assert_to_string(r, "0.*");
416     assert_match_all(r, &["0.5.0"]);
417 
418     let ref r = req("0.0.*");
419     assert_to_string(r, "0.0.*");
420 }
421 
422 #[test]
test_digit_after_wildcard()423 fn test_digit_after_wildcard() {
424     let err = req_err("*.1");
425     assert_to_string(err, "unexpected character after wildcard in version req");
426 
427     let err = req_err("1.*.1");
428     assert_to_string(err, "unexpected character after wildcard in version req");
429 
430     let err = req_err(">=1.*.1");
431     assert_to_string(err, "unexpected character after wildcard in version req");
432 }
433 
434 #[test]
test_eq_hash()435 fn test_eq_hash() {
436     fn calculate_hash(value: impl Hash) -> u64 {
437         let mut hasher = DefaultHasher::new();
438         value.hash(&mut hasher);
439         hasher.finish()
440     }
441 
442     assert!(req("^1") == req("^1"));
443     assert!(calculate_hash(req("^1")) == calculate_hash(req("^1")));
444     assert!(req("^1") != req("^2"));
445 }
446 
447 #[test]
test_leading_digit_in_pre_and_build()448 fn test_leading_digit_in_pre_and_build() {
449     for op in &["=", ">", ">=", "<", "<=", "~", "^"] {
450         // digit then alpha
451         req(&format!("{} 1.2.3-1a", op));
452         req(&format!("{} 1.2.3+1a", op));
453 
454         // digit then alpha (leading zero)
455         req(&format!("{} 1.2.3-01a", op));
456         req(&format!("{} 1.2.3+01", op));
457 
458         // multiple
459         req(&format!("{} 1.2.3-1+1", op));
460         req(&format!("{} 1.2.3-1-1+1-1-1", op));
461         req(&format!("{} 1.2.3-1a+1a", op));
462         req(&format!("{} 1.2.3-1a-1a+1a-1a-1a", op));
463     }
464 }
465 
466 #[test]
test_wildcard_and_another()467 fn test_wildcard_and_another() {
468     let err = req_err("*, 0.20.0-any");
469     assert_to_string(
470         err,
471         "wildcard req (*) must be the only comparator in the version req",
472     );
473 
474     let err = req_err("0.20.0-any, *");
475     assert_to_string(
476         err,
477         "wildcard req (*) must be the only comparator in the version req",
478     );
479 
480     let err = req_err("0.20.0-any, *, 1.0");
481     assert_to_string(
482         err,
483         "wildcard req (*) must be the only comparator in the version req",
484     );
485 }
486