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