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
173 #[test]
test_whitespace_delimited_comparator_sets()174 pub fn test_whitespace_delimited_comparator_sets() {
175 // https://github.com/steveklabnik/semver/issues/55
176 let err = req_err("> 0.0.9 <= 2.5.3");
177 assert_to_string(err, "expected comma after patch version number, found '<'");
178 }
179
180 #[test]
test_tilde()181 pub fn test_tilde() {
182 let ref r = req("~1");
183 assert_match_all(r, &["1.0.0", "1.0.1", "1.1.1"]);
184 assert_match_none(r, &["0.9.1", "2.9.0", "0.0.9"]);
185
186 let ref r = req("~1.2");
187 assert_match_all(r, &["1.2.0", "1.2.1"]);
188 assert_match_none(r, &["1.1.1", "1.3.0", "0.0.9"]);
189
190 let ref r = req("~1.2.2");
191 assert_match_all(r, &["1.2.2", "1.2.4"]);
192 assert_match_none(r, &["1.2.1", "1.9.0", "1.0.9", "2.0.1", "0.1.3"]);
193
194 let ref r = req("~1.2.3-beta.2");
195 assert_match_all(r, &["1.2.3", "1.2.4", "1.2.3-beta.2", "1.2.3-beta.4"]);
196 assert_match_none(r, &["1.3.3", "1.1.4", "1.2.3-beta.1", "1.2.4-beta.2"]);
197 }
198
199 #[test]
test_caret()200 pub fn test_caret() {
201 let ref r = req("^1");
202 assert_match_all(r, &["1.1.2", "1.1.0", "1.2.1", "1.0.1"]);
203 assert_match_none(r, &["0.9.1", "2.9.0", "0.1.4"]);
204 assert_match_none(r, &["1.0.0-beta1", "0.1.0-alpha", "1.0.1-pre"]);
205
206 let ref r = req("^1.1");
207 assert_match_all(r, &["1.1.2", "1.1.0", "1.2.1"]);
208 assert_match_none(r, &["0.9.1", "2.9.0", "1.0.1", "0.1.4"]);
209
210 let ref r = req("^1.1.2");
211 assert_match_all(r, &["1.1.2", "1.1.4", "1.2.1"]);
212 assert_match_none(r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]);
213 assert_match_none(r, &["1.1.2-alpha1", "1.1.3-alpha1", "2.9.0-alpha1"]);
214
215 let ref r = req("^0.1.2");
216 assert_match_all(r, &["0.1.2", "0.1.4"]);
217 assert_match_none(r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]);
218 assert_match_none(r, &["0.1.2-beta", "0.1.3-alpha", "0.2.0-pre"]);
219
220 let ref r = req("^0.5.1-alpha3");
221 assert_match_all(
222 r,
223 &[
224 "0.5.1-alpha3",
225 "0.5.1-alpha4",
226 "0.5.1-beta",
227 "0.5.1",
228 "0.5.5",
229 ],
230 );
231 assert_match_none(
232 r,
233 &[
234 "0.5.1-alpha1",
235 "0.5.2-alpha3",
236 "0.5.5-pre",
237 "0.5.0-pre",
238 "0.6.0",
239 ],
240 );
241
242 let ref r = req("^0.0.2");
243 assert_match_all(r, &["0.0.2"]);
244 assert_match_none(r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1", "0.1.4"]);
245
246 let ref r = req("^0.0");
247 assert_match_all(r, &["0.0.2", "0.0.0"]);
248 assert_match_none(r, &["0.9.1", "2.9.0", "1.1.1", "0.1.4"]);
249
250 let ref r = req("^0");
251 assert_match_all(r, &["0.9.1", "0.0.2", "0.0.0"]);
252 assert_match_none(r, &["2.9.0", "1.1.1"]);
253
254 let ref r = req("^1.4.2-beta.5");
255 assert_match_all(
256 r,
257 &["1.4.2", "1.4.3", "1.4.2-beta.5", "1.4.2-beta.6", "1.4.2-c"],
258 );
259 assert_match_none(
260 r,
261 &[
262 "0.9.9",
263 "2.0.0",
264 "1.4.2-alpha",
265 "1.4.2-beta.4",
266 "1.4.3-beta.5",
267 ],
268 );
269 }
270
271 #[test]
test_wildcard()272 pub fn test_wildcard() {
273 let err = req_err("");
274 assert_to_string(
275 err,
276 "unexpected end of input while parsing major version number",
277 );
278
279 let ref r = req("*");
280 assert_match_all(r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
281 assert_match_none(r, &["1.0.0-pre"]);
282
283 for s in &["x", "X"] {
284 assert_eq!(*r, req(s));
285 }
286
287 let ref r = req("1.*");
288 assert_match_all(r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);
289 assert_match_none(r, &["0.0.9", "1.2.0-pre"]);
290
291 for s in &["1.x", "1.X", "1.*.*"] {
292 assert_eq!(*r, req(s));
293 }
294
295 let ref r = req("1.2.*");
296 assert_match_all(r, &["1.2.0", "1.2.2", "1.2.4"]);
297 assert_match_none(r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3", "1.2.2-pre"]);
298
299 for s in &["1.2.x", "1.2.X"] {
300 assert_eq!(*r, req(s));
301 }
302 }
303
304 #[test]
test_logical_or()305 pub fn test_logical_or() {
306 // https://github.com/steveklabnik/semver/issues/57
307 let err = req_err("=1.2.3 || =2.3.4");
308 assert_to_string(err, "expected comma after patch version number, found '|'");
309
310 let err = req_err("1.1 || =1.2.3");
311 assert_to_string(err, "expected comma after minor version number, found '|'");
312
313 let err = req_err("6.* || 8.* || >= 10.*");
314 assert_to_string(err, "expected comma after minor version number, found '|'");
315 }
316
317 #[test]
test_any()318 pub fn test_any() {
319 #[cfg(not(no_const_vec_new))]
320 let ref r = VersionReq::STAR;
321 #[cfg(no_const_vec_new)]
322 let ref r = VersionReq {
323 comparators: Vec::new(),
324 };
325 assert_match_all(r, &["0.0.1", "0.1.0", "1.0.0"]);
326 }
327
328 #[test]
test_pre()329 pub fn test_pre() {
330 let ref r = req("=2.1.1-really.0");
331 assert_match_all(r, &["2.1.1-really.0"]);
332 }
333
334 #[test]
test_parse_errors()335 pub fn test_parse_errors() {
336 let err = req_err("\0");
337 assert_to_string(
338 err,
339 "unexpected character '\\u{0}' while parsing major version number",
340 );
341
342 let err = req_err(">= >= 0.0.2");
343 assert_to_string(
344 err,
345 "unexpected character '>' while parsing major version number",
346 );
347
348 let err = req_err(">== 0.0.2");
349 assert_to_string(
350 err,
351 "unexpected character '=' while parsing major version number",
352 );
353
354 let err = req_err("a.0.0");
355 assert_to_string(
356 err,
357 "unexpected character 'a' while parsing major version number",
358 );
359
360 let err = req_err("1.0.0-");
361 assert_to_string(err, "empty identifier segment in pre-release identifier");
362
363 let err = req_err(">=");
364 assert_to_string(
365 err,
366 "unexpected end of input while parsing major version number",
367 );
368 }
369
370 #[test]
test_cargo3202()371 fn test_cargo3202() {
372 let ref r = req("0.*.*");
373 assert_to_string(r, "0.*");
374 assert_match_all(r, &["0.5.0"]);
375
376 let ref r = req("0.0.*");
377 assert_to_string(r, "0.0.*");
378 }
379
380 #[test]
test_digit_after_wildcard()381 fn test_digit_after_wildcard() {
382 let err = req_err("*.1");
383 assert_to_string(err, "unexpected character after wildcard in version req");
384
385 let err = req_err("1.*.1");
386 assert_to_string(err, "unexpected character after wildcard in version req");
387
388 let err = req_err(">=1.*.1");
389 assert_to_string(err, "unexpected character after wildcard in version req");
390 }
391
392 #[test]
test_eq_hash()393 fn test_eq_hash() {
394 fn calculate_hash(value: impl Hash) -> u64 {
395 let mut hasher = DefaultHasher::new();
396 value.hash(&mut hasher);
397 hasher.finish()
398 }
399
400 assert!(req("^1") == req("^1"));
401 assert!(calculate_hash(req("^1")) == calculate_hash(req("^1")));
402 assert!(req("^1") != req("^2"));
403 }
404
405 #[test]
test_leading_digit_in_pre_and_build()406 fn test_leading_digit_in_pre_and_build() {
407 for op in &["=", ">", ">=", "<", "<=", "~", "^"] {
408 // digit then alpha
409 req(&format!("{} 1.2.3-1a", op));
410 req(&format!("{} 1.2.3+1a", op));
411
412 // digit then alpha (leading zero)
413 req(&format!("{} 1.2.3-01a", op));
414 req(&format!("{} 1.2.3+01", op));
415
416 // multiple
417 req(&format!("{} 1.2.3-1+1", op));
418 req(&format!("{} 1.2.3-1-1+1-1-1", op));
419 req(&format!("{} 1.2.3-1a+1a", op));
420 req(&format!("{} 1.2.3-1a-1a+1a-1a-1a", op));
421 }
422 }
423
424 #[test]
test_wildcard_and_another()425 fn test_wildcard_and_another() {
426 let err = req_err("*, 0.20.0-any");
427 assert_to_string(
428 err,
429 "wildcard req (*) must be the only comparator in the version req",
430 );
431
432 let err = req_err("0.20.0-any, *");
433 assert_to_string(
434 err,
435 "wildcard req (*) must be the only comparator in the version req",
436 );
437
438 let err = req_err("0.20.0-any, *, 1.0");
439 assert_to_string(
440 err,
441 "wildcard req (*) must be the only comparator in the version req",
442 );
443 }
444