]> git.proxmox.com Git - rustc.git/blame - vendor/semver-0.10.0/src/version_req.rs
New upstream version 1.54.0+dfsg1
[rustc.git] / vendor / semver-0.10.0 / src / version_req.rs
CommitLineData
3dfed10e
XL
1// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT\r
2// file at the top-level directory of this distribution and at\r
3// http://rust-lang.org/COPYRIGHT.\r
4//\r
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\r
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\r
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your\r
8// option. This file may not be copied, modified, or distributed\r
9// except according to those terms.\r
10\r
11use std::error::Error;\r
12use std::fmt;\r
13use std::str;\r
14\r
15use semver_parser;\r
16use version::Identifier;\r
17use Version;\r
18\r
19#[cfg(feature = "serde")]\r
20use serde::de::{self, Deserialize, Deserializer, Visitor};\r
21#[cfg(feature = "serde")]\r
22use serde::ser::{Serialize, Serializer};\r
23\r
24use self::Op::{Compatible, Ex, Gt, GtEq, Lt, LtEq, Tilde, Wildcard};\r
25use self::ReqParseError::*;\r
26use self::WildcardVersion::{Major, Minor, Patch};\r
27\r
28/// A `VersionReq` is a struct containing a list of predicates that can apply to ranges of version\r
29/// numbers. Matching operations can then be done with the `VersionReq` against a particular\r
30/// version to see if it satisfies some or all of the constraints.\r
31#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]\r
32#[cfg_attr(feature = "diesel", derive(AsExpression, FromSqlRow))]\r
33#[cfg_attr(feature = "diesel", sql_type = "diesel::sql_types::Text")]\r
34pub struct VersionReq {\r
35 predicates: Vec<Predicate>,\r
36}\r
37\r
38impl From<semver_parser::range::VersionReq> for VersionReq {\r
39 fn from(other: semver_parser::range::VersionReq) -> VersionReq {\r
40 VersionReq {\r
41 predicates: other.predicates.into_iter().map(From::from).collect(),\r
42 }\r
43 }\r
44}\r
45\r
46#[cfg(feature = "serde")]\r
47impl Serialize for VersionReq {\r
48 fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>\r
49 where\r
50 S: Serializer,\r
51 {\r
52 // Serialize VersionReq as a string.\r
53 serializer.collect_str(self)\r
54 }\r
55}\r
56\r
57#[cfg(feature = "serde")]\r
58impl<'de> Deserialize<'de> for VersionReq {\r
59 fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>\r
60 where\r
61 D: Deserializer<'de>,\r
62 {\r
63 struct VersionReqVisitor;\r
64\r
65 /// Deserialize `VersionReq` from a string.\r
66 impl<'de> Visitor<'de> for VersionReqVisitor {\r
67 type Value = VersionReq;\r
68\r
69 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\r
70 formatter.write_str("a SemVer version requirement as a string")\r
71 }\r
72\r
73 fn visit_str<E>(self, v: &str) -> ::std::result::Result<Self::Value, E>\r
74 where\r
75 E: de::Error,\r
76 {\r
77 VersionReq::parse(v).map_err(de::Error::custom)\r
78 }\r
79 }\r
80\r
81 deserializer.deserialize_str(VersionReqVisitor)\r
82 }\r
83}\r
84\r
85#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]\r
86enum WildcardVersion {\r
87 Major,\r
88 Minor,\r
89 Patch,\r
90}\r
91\r
92#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]\r
93enum Op {\r
94 Ex, // Exact\r
95 Gt, // Greater than\r
96 GtEq, // Greater than or equal to\r
97 Lt, // Less than\r
98 LtEq, // Less than or equal to\r
99 Tilde, // e.g. ~1.0.0\r
100 Compatible, // compatible by definition of semver, indicated by ^\r
101 Wildcard(WildcardVersion), // x.y.*, x.*, *\r
102}\r
103\r
104impl From<semver_parser::range::Op> for Op {\r
105 fn from(other: semver_parser::range::Op) -> Op {\r
106 use semver_parser::range;\r
107 match other {\r
108 range::Op::Ex => Op::Ex,\r
109 range::Op::Gt => Op::Gt,\r
110 range::Op::GtEq => Op::GtEq,\r
111 range::Op::Lt => Op::Lt,\r
112 range::Op::LtEq => Op::LtEq,\r
113 range::Op::Tilde => Op::Tilde,\r
114 range::Op::Compatible => Op::Compatible,\r
115 range::Op::Wildcard(version) => match version {\r
116 range::WildcardVersion::Major => Op::Wildcard(WildcardVersion::Major),\r
117 range::WildcardVersion::Minor => Op::Wildcard(WildcardVersion::Minor),\r
118 range::WildcardVersion::Patch => Op::Wildcard(WildcardVersion::Patch),\r
119 },\r
120 }\r
121 }\r
122}\r
123\r
124#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]\r
125struct Predicate {\r
126 op: Op,\r
127 major: u64,\r
128 minor: Option<u64>,\r
129 patch: Option<u64>,\r
130 pre: Vec<Identifier>,\r
131}\r
132\r
133impl From<semver_parser::range::Predicate> for Predicate {\r
134 fn from(other: semver_parser::range::Predicate) -> Predicate {\r
135 Predicate {\r
136 op: From::from(other.op),\r
137 major: other.major,\r
138 minor: other.minor,\r
139 patch: other.patch,\r
140 pre: other.pre.into_iter().map(From::from).collect(),\r
141 }\r
142 }\r
143}\r
144\r
145/// A `ReqParseError` is returned from methods which parse a string into a [`VersionReq`]. Each\r
146/// enumeration is one of the possible errors that can occur.\r
147/// [`VersionReq`]: struct.VersionReq.html\r
148#[derive(Clone, Debug, PartialEq)]\r
149pub enum ReqParseError {\r
150 /// The given version requirement is invalid.\r
151 InvalidVersionRequirement,\r
152 /// You have already provided an operation, such as `=`, `~`, or `^`. Only use one.\r
153 OpAlreadySet,\r
154 /// The sigil you have written is not correct.\r
155 InvalidSigil,\r
156 /// All components of a version must be numeric.\r
157 VersionComponentsMustBeNumeric,\r
158 /// There was an error parsing an identifier.\r
159 InvalidIdentifier,\r
160 /// At least a major version is required.\r
161 MajorVersionRequired,\r
162 /// An unimplemented version requirement.\r
163 UnimplementedVersionRequirement,\r
164 /// This form of requirement is deprecated.\r
165 DeprecatedVersionRequirement(VersionReq),\r
166}\r
167\r
168impl fmt::Display for ReqParseError {\r
169 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\r
170 let msg = match self {\r
171 InvalidVersionRequirement => "the given version requirement is invalid",\r
172 OpAlreadySet => {\r
173 "you have already provided an operation, such as =, ~, or ^; only use one"\r
174 }\r
175 InvalidSigil => "the sigil you have written is not correct",\r
176 VersionComponentsMustBeNumeric => "version components must be numeric",\r
177 InvalidIdentifier => "invalid identifier",\r
178 MajorVersionRequired => "at least a major version number is required",\r
179 UnimplementedVersionRequirement => {\r
180 "the given version requirement is not implemented, yet"\r
181 }\r
182 DeprecatedVersionRequirement(_) => "This requirement is deprecated",\r
183 };\r
184 msg.fmt(f)\r
185 }\r
186}\r
187\r
188impl Error for ReqParseError {}\r
189\r
190impl From<String> for ReqParseError {\r
191 fn from(other: String) -> ReqParseError {\r
192 match &*other {\r
193 "Null is not a valid VersionReq" => ReqParseError::InvalidVersionRequirement,\r
194 "VersionReq did not parse properly." => ReqParseError::OpAlreadySet,\r
195 _ => ReqParseError::InvalidVersionRequirement,\r
196 }\r
197 }\r
198}\r
199\r
200impl VersionReq {\r
201 /// `any()` is a factory method which creates a `VersionReq` with no constraints. In other\r
202 /// words, any version will match against it.\r
203 ///\r
204 /// # Examples\r
205 ///\r
206 /// ```\r
207 /// use semver::VersionReq;\r
208 ///\r
209 /// let anything = VersionReq::any();\r
210 /// ```\r
211 pub fn any() -> VersionReq {\r
212 VersionReq { predicates: vec![] }\r
213 }\r
214\r
215 /// `parse()` is the main constructor of a `VersionReq`. It takes a string like `"^1.2.3"`\r
216 /// and turns it into a `VersionReq` that matches that particular constraint.\r
217 ///\r
218 /// A `Result` is returned which contains a [`ReqParseError`] if there was a problem parsing the\r
219 /// `VersionReq`.\r
220 /// [`ReqParseError`]: enum.ReqParseError.html\r
221 ///\r
222 /// # Examples\r
223 ///\r
224 /// ```\r
225 /// use semver::VersionReq;\r
226 ///\r
227 /// let version = VersionReq::parse("=1.2.3");\r
228 /// let version = VersionReq::parse(">1.2.3");\r
229 /// let version = VersionReq::parse("<1.2.3");\r
230 /// let version = VersionReq::parse("~1.2.3");\r
231 /// let version = VersionReq::parse("^1.2.3");\r
232 /// let version = VersionReq::parse("1.2.3"); // synonym for ^1.2.3\r
233 /// let version = VersionReq::parse("<=1.2.3");\r
234 /// let version = VersionReq::parse(">=1.2.3");\r
235 /// ```\r
236 ///\r
237 /// This example demonstrates error handling, and will panic.\r
238 ///\r
239 /// ```should_panic\r
240 /// use semver::VersionReq;\r
241 ///\r
242 /// let version = match VersionReq::parse("not a version") {\r
243 /// Ok(version) => version,\r
244 /// Err(e) => panic!("There was a problem parsing: {}", e),\r
245 /// };\r
246 /// ```\r
247 ///\r
248 /// # Errors\r
249 ///\r
250 /// Returns an error variant if the input could not be parsed as a semver requirement.\r
251 ///\r
252 /// Examples of common error causes are as follows:\r
253 ///\r
254 /// * `\0` - an invalid version requirement is used.\r
255 /// * `>= >= 1.2.3` - multiple operations are used. Only use one.\r
256 /// * `>== 1.2.3` - an invalid operation is used.\r
257 /// * `a.0.0` - version components are not numeric.\r
258 /// * `1.2.3-` - an invalid identifier is present.\r
259 /// * `>=` - major version was not specified. At least a major version is required.\r
260 /// * `0.2*` - deprecated requirement syntax. Equivalent would be `0.2.*`.\r
261 ///\r
262 /// You may also encounter an `UnimplementedVersionRequirement` error, which indicates that a\r
263 /// given requirement syntax is not yet implemented in this crate.\r
264 pub fn parse(input: &str) -> Result<VersionReq, ReqParseError> {\r
265 let res = semver_parser::range::parse(input);\r
266\r
267 if let Ok(v) = res {\r
268 return Ok(From::from(v));\r
269 }\r
270\r
271 match VersionReq::parse_deprecated(input) {\r
272 Some(v) => Err(ReqParseError::DeprecatedVersionRequirement(v)),\r
273 None => Err(From::from(res.err().unwrap())),\r
274 }\r
275 }\r
276\r
277 fn parse_deprecated(version: &str) -> Option<VersionReq> {\r
278 match version {\r
279 ".*" => Some(VersionReq::any()),\r
280 "0.1.0." => Some(VersionReq::parse("0.1.0").unwrap()),\r
281 "0.3.1.3" => Some(VersionReq::parse("0.3.13").unwrap()),\r
282 "0.2*" => Some(VersionReq::parse("0.2.*").unwrap()),\r
283 "*.0" => Some(VersionReq::any()),\r
284 _ => None,\r
285 }\r
286 }\r
287\r
288 /// `exact()` is a factory method which creates a `VersionReq` with one exact constraint.\r
289 ///\r
290 /// # Examples\r
291 ///\r
292 /// ```\r
293 /// use semver::VersionReq;\r
294 /// use semver::Version;\r
295 ///\r
296 /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] };\r
297 /// let exact = VersionReq::exact(&version);\r
298 /// ```\r
299 pub fn exact(version: &Version) -> VersionReq {\r
300 VersionReq {\r
301 predicates: vec![Predicate::exact(version)],\r
302 }\r
303 }\r
304\r
305 /// `matches()` matches a given [`Version`] against this `VersionReq`.\r
306 /// [`Version`]: struct.Version.html\r
307 ///\r
308 /// # Examples\r
309 ///\r
310 /// ```\r
311 /// use semver::VersionReq;\r
312 /// use semver::Version;\r
313 ///\r
314 /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] };\r
315 /// let exact = VersionReq::exact(&version);\r
316 ///\r
317 /// assert!(exact.matches(&version));\r
318 /// ```\r
319 pub fn matches(&self, version: &Version) -> bool {\r
320 // no predicates means anything matches\r
321 if self.predicates.is_empty() {\r
322 return true;\r
323 }\r
324\r
325 self.predicates.iter().all(|p| p.matches(version))\r
326 && self\r
327 .predicates\r
328 .iter()\r
329 .any(|p| p.pre_tag_is_compatible(version))\r
330 }\r
331\r
332 /// `is_exact()` returns `true` if there is exactly one version which could match this\r
333 /// `VersionReq`. If `false` is returned, it is possible that there may still only be exactly\r
334 /// one version which could match this `VersionReq`. This function is intended do allow\r
335 /// short-circuiting more complex logic where being able to handle only the possibility of a\r
336 /// single exact version may be cheaper.\r
337 ///\r
338 /// # Examples\r
339 ///\r
340 /// ```\r
341 /// use semver::ReqParseError;\r
342 /// use semver::VersionReq;\r
343 ///\r
344 /// fn use_is_exact() -> Result<(), ReqParseError> {\r
345 /// assert!(VersionReq::parse("=1.0.0")?.is_exact());\r
346 /// assert!(!VersionReq::parse("=1.0")?.is_exact());\r
347 /// assert!(!VersionReq::parse(">=1.0.0")?.is_exact());\r
348 /// Ok(())\r
349 /// }\r
350 ///\r
351 /// use_is_exact().unwrap();\r
352 /// ```\r
353 pub fn is_exact(&self) -> bool {\r
354 if let [predicate] = self.predicates.as_slice() {\r
355 predicate.has_exactly_one_match()\r
356 } else {\r
357 false\r
358 }\r
359 }\r
360}\r
361\r
362impl str::FromStr for VersionReq {\r
363 type Err = ReqParseError;\r
364\r
365 fn from_str(s: &str) -> Result<VersionReq, ReqParseError> {\r
366 VersionReq::parse(s)\r
367 }\r
368}\r
369\r
370impl Predicate {\r
371 fn exact(version: &Version) -> Predicate {\r
372 Predicate {\r
373 op: Ex,\r
374 major: version.major,\r
375 minor: Some(version.minor),\r
376 patch: Some(version.patch),\r
377 pre: version.pre.clone(),\r
378 }\r
379 }\r
380\r
381 /// `matches()` takes a `Version` and determines if it matches this particular `Predicate`.\r
382 pub fn matches(&self, ver: &Version) -> bool {\r
383 match self.op {\r
384 Ex => self.matches_exact(ver),\r
385 Gt => self.matches_greater(ver),\r
386 GtEq => self.matches_exact(ver) || self.matches_greater(ver),\r
387 Lt => !self.matches_exact(ver) && !self.matches_greater(ver),\r
388 LtEq => !self.matches_greater(ver),\r
389 Tilde => self.matches_tilde(ver),\r
390 Compatible => self.is_compatible(ver),\r
391 Wildcard(_) => self.matches_wildcard(ver),\r
392 }\r
393 }\r
394\r
395 fn matches_exact(&self, ver: &Version) -> bool {\r
396 if self.major != ver.major {\r
397 return false;\r
398 }\r
399\r
400 match self.minor {\r
401 Some(minor) => {\r
402 if minor != ver.minor {\r
403 return false;\r
404 }\r
405 }\r
406 None => return true,\r
407 }\r
408\r
409 match self.patch {\r
410 Some(patch) => {\r
411 if patch != ver.patch {\r
412 return false;\r
413 }\r
414 }\r
415 None => return true,\r
416 }\r
417\r
418 if self.pre != ver.pre {\r
419 return false;\r
420 }\r
421\r
422 true\r
423 }\r
424\r
425 // https://docs.npmjs.com/misc/semver#prerelease-tags\r
426 fn pre_tag_is_compatible(&self, ver: &Version) -> bool {\r
427 // If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it will\r
428 // only be\r
429 // allowed to satisfy comparator sets if at least one comparator with the same\r
430 // [major,\r
431 // minor, patch] tuple also has a prerelease tag.\r
432 !ver.is_prerelease()\r
433 || (self.major == ver.major\r
434 && self.minor == Some(ver.minor)\r
435 && self.patch == Some(ver.patch)\r
436 && !self.pre.is_empty())\r
437 }\r
438\r
439 fn matches_greater(&self, ver: &Version) -> bool {\r
440 if self.major != ver.major {\r
441 return ver.major > self.major;\r
442 }\r
443\r
444 match self.minor {\r
445 Some(minor) => {\r
446 if minor != ver.minor {\r
447 return ver.minor > minor;\r
448 }\r
449 }\r
450 None => return false,\r
451 }\r
452\r
453 match self.patch {\r
454 Some(patch) => {\r
455 if patch != ver.patch {\r
456 return ver.patch > patch;\r
457 }\r
458 }\r
459 None => return false,\r
460 }\r
461\r
462 if !self.pre.is_empty() {\r
463 return ver.pre.is_empty() || ver.pre > self.pre;\r
464 }\r
465\r
466 false\r
467 }\r
468\r
469 // see https://www.npmjs.com/package/semver for behavior\r
470 fn matches_tilde(&self, ver: &Version) -> bool {\r
471 let minor = match self.minor {\r
472 Some(n) => n,\r
473 None => return self.major == ver.major,\r
474 };\r
475\r
476 match self.patch {\r
477 Some(patch) => {\r
478 self.major == ver.major\r
479 && minor == ver.minor\r
480 && (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver)))\r
481 }\r
482 None => self.major == ver.major && minor == ver.minor,\r
483 }\r
484 }\r
485\r
486 // see https://www.npmjs.com/package/semver for behavior\r
487 fn is_compatible(&self, ver: &Version) -> bool {\r
488 if self.major != ver.major {\r
489 return false;\r
490 }\r
491\r
492 let minor = match self.minor {\r
493 Some(n) => n,\r
494 None => return self.major == ver.major,\r
495 };\r
496\r
497 match self.patch {\r
498 Some(patch) => {\r
499 if self.major == 0 {\r
500 if minor == 0 {\r
501 ver.minor == minor && ver.patch == patch && self.pre_is_compatible(ver)\r
502 } else {\r
503 ver.minor == minor\r
504 && (ver.patch > patch\r
505 || (ver.patch == patch && self.pre_is_compatible(ver)))\r
506 }\r
507 } else {\r
508 ver.minor > minor\r
509 || (ver.minor == minor\r
510 && (ver.patch > patch\r
511 || (ver.patch == patch && self.pre_is_compatible(ver))))\r
512 }\r
513 }\r
514 None => {\r
515 if self.major == 0 {\r
516 ver.minor == minor\r
517 } else {\r
518 ver.minor >= minor\r
519 }\r
520 }\r
521 }\r
522 }\r
523\r
524 fn pre_is_compatible(&self, ver: &Version) -> bool {\r
525 ver.pre.is_empty() || ver.pre >= self.pre\r
526 }\r
527\r
528 // see https://www.npmjs.com/package/semver for behavior\r
529 fn matches_wildcard(&self, ver: &Version) -> bool {\r
530 match self.op {\r
531 Wildcard(Major) => true,\r
532 Wildcard(Minor) => self.major == ver.major,\r
533 Wildcard(Patch) => {\r
534 match self.minor {\r
535 Some(minor) => self.major == ver.major && minor == ver.minor,\r
536 None => {\r
537 // minor and patch version astericks mean match on major\r
538 self.major == ver.major\r
539 }\r
540 }\r
541 }\r
542 _ => false, // unreachable\r
543 }\r
544 }\r
545\r
546 fn has_exactly_one_match(&self) -> bool {\r
547 self.op == Ex && self.minor.is_some() && self.patch.is_some()\r
548 }\r
549}\r
550\r
551impl fmt::Display for VersionReq {\r
552 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\r
553 if self.predicates.is_empty() {\r
554 write!(fmt, "*")?;\r
555 } else {\r
556 for (i, ref pred) in self.predicates.iter().enumerate() {\r
557 if i == 0 {\r
558 write!(fmt, "{}", pred)?;\r
559 } else {\r
560 write!(fmt, ", {}", pred)?;\r
561 }\r
562 }\r
563 }\r
564\r
565 Ok(())\r
566 }\r
567}\r
568\r
569impl fmt::Display for Predicate {\r
570 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\r
571 match self.op {\r
572 Wildcard(Major) => write!(fmt, "*")?,\r
573 Wildcard(Minor) => write!(fmt, "{}.*", self.major)?,\r
574 Wildcard(Patch) => {\r
575 if let Some(minor) = self.minor {\r
576 write!(fmt, "{}.{}.*", self.major, minor)?\r
577 } else {\r
578 write!(fmt, "{}.*.*", self.major)?\r
579 }\r
580 }\r
581 _ => {\r
582 write!(fmt, "{}{}", self.op, self.major)?;\r
583\r
584 if let Some(v) = self.minor {\r
585 write!(fmt, ".{}", v)?;\r
586 }\r
587\r
588 if let Some(v) = self.patch {\r
589 write!(fmt, ".{}", v)?;\r
590 }\r
591\r
592 if !self.pre.is_empty() {\r
593 write!(fmt, "-")?;\r
594 for (i, x) in self.pre.iter().enumerate() {\r
595 if i != 0 {\r
596 write!(fmt, ".")?\r
597 }\r
598 write!(fmt, "{}", x)?;\r
599 }\r
600 }\r
601 }\r
602 }\r
603\r
604 Ok(())\r
605 }\r
606}\r
607\r
608impl fmt::Display for Op {\r
609 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\r
610 match *self {\r
611 Ex => write!(fmt, "=")?,\r
612 Gt => write!(fmt, ">")?,\r
613 GtEq => write!(fmt, ">=")?,\r
614 Lt => write!(fmt, "<")?,\r
615 LtEq => write!(fmt, "<=")?,\r
616 Tilde => write!(fmt, "~")?,\r
617 Compatible => write!(fmt, "^")?,\r
618 // gets handled specially in Predicate::fmt\r
619 Wildcard(_) => write!(fmt, "")?,\r
620 }\r
621 Ok(())\r
622 }\r
623}\r
624\r
625#[cfg(test)]\r
626mod test {\r
627 use super::super::version::Version;\r
628 use super::{Op, VersionReq};\r
629 use std::hash::{Hash, Hasher};\r
630\r
631 fn req(s: &str) -> VersionReq {\r
632 VersionReq::parse(s).unwrap()\r
633 }\r
634\r
635 fn version(s: &str) -> Version {\r
636 match Version::parse(s) {\r
637 Ok(v) => v,\r
638 Err(e) => panic!("`{}` is not a valid version. Reason: {:?}", s, e),\r
639 }\r
640 }\r
641\r
642 fn assert_match(req: &VersionReq, vers: &[&str]) {\r
643 for ver in vers.iter() {\r
644 assert!(req.matches(&version(*ver)), "did not match {}", ver);\r
645 }\r
646 }\r
647\r
648 fn assert_not_match(req: &VersionReq, vers: &[&str]) {\r
649 for ver in vers.iter() {\r
650 assert!(!req.matches(&version(*ver)), "matched {}", ver);\r
651 }\r
652 }\r
653\r
654 fn calculate_hash<T: Hash>(t: T) -> u64 {\r
655 use std::collections::hash_map::DefaultHasher;\r
656\r
657 let mut s = DefaultHasher::new();\r
658 t.hash(&mut s);\r
659 s.finish()\r
660 }\r
661\r
662 #[test]\r
663 fn test_parsing_default() {\r
664 let r = req("1.0.0");\r
665\r
666 assert_eq!(r.to_string(), "^1.0.0".to_string());\r
667\r
668 assert_match(&r, &["1.0.0", "1.0.1"]);\r
669 assert_not_match(&r, &["0.9.9", "0.10.0", "0.1.0"]);\r
670 }\r
671\r
672 #[test]\r
673 fn test_parsing_exact() {\r
674 let r = req("=1.0.0");\r
675\r
676 assert!(r.to_string() == "=1.0.0".to_string());\r
677 assert_eq!(r.to_string(), "=1.0.0".to_string());\r
678\r
679 assert_match(&r, &["1.0.0"]);\r
680 assert_not_match(&r, &["1.0.1", "0.9.9", "0.10.0", "0.1.0", "1.0.0-pre"]);\r
681\r
682 let r = req("=0.9.0");\r
683\r
684 assert_eq!(r.to_string(), "=0.9.0".to_string());\r
685\r
686 assert_match(&r, &["0.9.0"]);\r
687 assert_not_match(&r, &["0.9.1", "1.9.0", "0.0.9"]);\r
688\r
689 let r = req("=0.1.0-beta2.a");\r
690\r
691 assert_eq!(r.to_string(), "=0.1.0-beta2.a".to_string());\r
692\r
693 assert_match(&r, &["0.1.0-beta2.a"]);\r
694 assert_not_match(&r, &["0.9.1", "0.1.0", "0.1.1-beta2.a", "0.1.0-beta2"]);\r
695 }\r
696\r
697 #[test]\r
698 fn test_parse_metadata_see_issue_88_see_issue_88() {\r
699 for op in &[\r
700 Op::Compatible,\r
701 Op::Ex,\r
702 Op::Gt,\r
703 Op::GtEq,\r
704 Op::Lt,\r
705 Op::LtEq,\r
706 Op::Tilde,\r
707 ] {\r
708 req(&format!("{} 1.2.3+meta", op));\r
709 }\r
710 }\r
711\r
712 #[test]\r
713 pub fn test_parsing_greater_than() {\r
714 let r = req(">= 1.0.0");\r
715\r
716 assert_eq!(r.to_string(), ">=1.0.0".to_string());\r
717\r
718 assert_match(&r, &["1.0.0", "2.0.0"]);\r
719 assert_not_match(&r, &["0.1.0", "0.0.1", "1.0.0-pre", "2.0.0-pre"]);\r
720\r
721 let r = req(">= 2.1.0-alpha2");\r
722\r
723 assert_match(&r, &["2.1.0-alpha2", "2.1.0-alpha3", "2.1.0", "3.0.0"]);\r
724 assert_not_match(\r
725 &r,\r
726 &["2.0.0", "2.1.0-alpha1", "2.0.0-alpha2", "3.0.0-alpha2"],\r
727 );\r
728 }\r
729\r
730 #[test]\r
731 pub fn test_parsing_less_than() {\r
732 let r = req("< 1.0.0");\r
733\r
734 assert_eq!(r.to_string(), "<1.0.0".to_string());\r
735\r
736 assert_match(&r, &["0.1.0", "0.0.1"]);\r
737 assert_not_match(&r, &["1.0.0", "1.0.0-beta", "1.0.1", "0.9.9-alpha"]);\r
738\r
739 let r = req("<= 2.1.0-alpha2");\r
740\r
741 assert_match(&r, &["2.1.0-alpha2", "2.1.0-alpha1", "2.0.0", "1.0.0"]);\r
742 assert_not_match(\r
743 &r,\r
744 &["2.1.0", "2.2.0-alpha1", "2.0.0-alpha2", "1.0.0-alpha2"],\r
745 );\r
746 }\r
747\r
748 #[test]\r
749 pub fn test_multiple() {\r
750 let r = req("> 0.0.9, <= 2.5.3");\r
751 assert_eq!(r.to_string(), ">0.0.9, <=2.5.3".to_string());\r
752 assert_match(&r, &["0.0.10", "1.0.0", "2.5.3"]);\r
753 assert_not_match(&r, &["0.0.8", "2.5.4"]);\r
754\r
755 let r = req("0.3.0, 0.4.0");\r
756 assert_eq!(r.to_string(), "^0.3.0, ^0.4.0".to_string());\r
757 assert_not_match(&r, &["0.0.8", "0.3.0", "0.4.0"]);\r
758\r
759 let r = req("<= 0.2.0, >= 0.5.0");\r
760 assert_eq!(r.to_string(), "<=0.2.0, >=0.5.0".to_string());\r
761 assert_not_match(&r, &["0.0.8", "0.3.0", "0.5.1"]);\r
762\r
763 let r = req("0.1.0, 0.1.4, 0.1.6");\r
764 assert_eq!(r.to_string(), "^0.1.0, ^0.1.4, ^0.1.6".to_string());\r
765 assert_match(&r, &["0.1.6", "0.1.9"]);\r
766 assert_not_match(&r, &["0.1.0", "0.1.4", "0.2.0"]);\r
767\r
768 assert!(VersionReq::parse("> 0.1.0,").is_err());\r
769 assert!(VersionReq::parse("> 0.3.0, ,").is_err());\r
770\r
771 let r = req(">=0.5.1-alpha3, <0.6");\r
772 assert_eq!(r.to_string(), ">=0.5.1-alpha3, <0.6".to_string());\r
773 assert_match(\r
774 &r,\r
775 &[\r
776 "0.5.1-alpha3",\r
777 "0.5.1-alpha4",\r
778 "0.5.1-beta",\r
779 "0.5.1",\r
780 "0.5.5",\r
781 ],\r
782 );\r
783 assert_not_match(\r
784 &r,\r
785 &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre"],\r
786 );\r
787 assert_not_match(&r, &["0.6.0", "0.6.0-pre"]);\r
788 }\r
789\r
790 #[test]\r
791 pub fn test_parsing_tilde() {\r
792 let r = req("~1");\r
793 assert_match(&r, &["1.0.0", "1.0.1", "1.1.1"]);\r
794 assert_not_match(&r, &["0.9.1", "2.9.0", "0.0.9"]);\r
795\r
796 let r = req("~1.2");\r
797 assert_match(&r, &["1.2.0", "1.2.1"]);\r
798 assert_not_match(&r, &["1.1.1", "1.3.0", "0.0.9"]);\r
799\r
800 let r = req("~1.2.2");\r
801 assert_match(&r, &["1.2.2", "1.2.4"]);\r
802 assert_not_match(&r, &["1.2.1", "1.9.0", "1.0.9", "2.0.1", "0.1.3"]);\r
803\r
804 let r = req("~1.2.3-beta.2");\r
805 assert_match(&r, &["1.2.3", "1.2.4", "1.2.3-beta.2", "1.2.3-beta.4"]);\r
806 assert_not_match(&r, &["1.3.3", "1.1.4", "1.2.3-beta.1", "1.2.4-beta.2"]);\r
807 }\r
808\r
809 #[test]\r
810 pub fn test_parsing_compatible() {\r
811 let r = req("^1");\r
812 assert_match(&r, &["1.1.2", "1.1.0", "1.2.1", "1.0.1"]);\r
813 assert_not_match(&r, &["0.9.1", "2.9.0", "0.1.4"]);\r
814 assert_not_match(&r, &["1.0.0-beta1", "0.1.0-alpha", "1.0.1-pre"]);\r
815\r
816 let r = req("^1.1");\r
817 assert_match(&r, &["1.1.2", "1.1.0", "1.2.1"]);\r
818 assert_not_match(&r, &["0.9.1", "2.9.0", "1.0.1", "0.1.4"]);\r
819\r
820 let r = req("^1.1.2");\r
821 assert_match(&r, &["1.1.2", "1.1.4", "1.2.1"]);\r
822 assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]);\r
823 assert_not_match(&r, &["1.1.2-alpha1", "1.1.3-alpha1", "2.9.0-alpha1"]);\r
824\r
825 let r = req("^0.1.2");\r
826 assert_match(&r, &["0.1.2", "0.1.4"]);\r
827 assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]);\r
828 assert_not_match(&r, &["0.1.2-beta", "0.1.3-alpha", "0.2.0-pre"]);\r
829\r
830 let r = req("^0.5.1-alpha3");\r
831 assert_match(\r
832 &r,\r
833 &[\r
834 "0.5.1-alpha3",\r
835 "0.5.1-alpha4",\r
836 "0.5.1-beta",\r
837 "0.5.1",\r
838 "0.5.5",\r
839 ],\r
840 );\r
841 assert_not_match(\r
842 &r,\r
843 &[\r
844 "0.5.1-alpha1",\r
845 "0.5.2-alpha3",\r
846 "0.5.5-pre",\r
847 "0.5.0-pre",\r
848 "0.6.0",\r
849 ],\r
850 );\r
851\r
852 let r = req("^0.0.2");\r
853 assert_match(&r, &["0.0.2"]);\r
854 assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1", "0.1.4"]);\r
855\r
856 let r = req("^0.0");\r
857 assert_match(&r, &["0.0.2", "0.0.0"]);\r
858 assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.1.4"]);\r
859\r
860 let r = req("^0");\r
861 assert_match(&r, &["0.9.1", "0.0.2", "0.0.0"]);\r
862 assert_not_match(&r, &["2.9.0", "1.1.1"]);\r
863\r
864 let r = req("^1.4.2-beta.5");\r
865 assert_match(\r
866 &r,\r
867 &["1.4.2", "1.4.3", "1.4.2-beta.5", "1.4.2-beta.6", "1.4.2-c"],\r
868 );\r
869 assert_not_match(\r
870 &r,\r
871 &[\r
872 "0.9.9",\r
873 "2.0.0",\r
874 "1.4.2-alpha",\r
875 "1.4.2-beta.4",\r
876 "1.4.3-beta.5",\r
877 ],\r
878 );\r
879 }\r
880\r
881 #[test]\r
882 pub fn test_parsing_wildcard() {\r
883 let r = req("");\r
884 assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);\r
885 assert_not_match(&r, &[]);\r
886 let r = req("*");\r
887 assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);\r
888 assert_not_match(&r, &[]);\r
889 let r = req("x");\r
890 assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);\r
891 assert_not_match(&r, &[]);\r
892 let r = req("X");\r
893 assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);\r
894 assert_not_match(&r, &[]);\r
895\r
896 let r = req("1.*");\r
897 assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);\r
898 assert_not_match(&r, &["0.0.9"]);\r
899 let r = req("1.x");\r
900 assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);\r
901 assert_not_match(&r, &["0.0.9"]);\r
902 let r = req("1.X");\r
903 assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);\r
904 assert_not_match(&r, &["0.0.9"]);\r
905\r
906 let r = req("1.2.*");\r
907 assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]);\r
908 assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]);\r
909 let r = req("1.2.x");\r
910 assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]);\r
911 assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]);\r
912 let r = req("1.2.X");\r
913 assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]);\r
914 assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]);\r
915 }\r
916\r
917 #[test]\r
918 pub fn test_any() {\r
919 let r = VersionReq::any();\r
920 assert_match(&r, &["0.0.1", "0.1.0", "1.0.0"]);\r
921 }\r
922\r
923 #[test]\r
924 pub fn test_pre() {\r
925 let r = req("=2.1.1-really.0");\r
926 assert_match(&r, &["2.1.1-really.0"]);\r
927 }\r
928\r
929 // #[test]\r
930 // pub fn test_parse_errors() {\r
931 // assert_eq!(Err(InvalidVersionRequirement), VersionReq::parse("\0"));\r
932 // assert_eq!(Err(OpAlreadySet), VersionReq::parse(">= >= 0.0.2"));\r
933 // assert_eq!(Err(InvalidSigil), VersionReq::parse(">== 0.0.2"));\r
934 // assert_eq!(Err(VersionComponentsMustBeNumeric),\r
935 // VersionReq::parse("a.0.0"));\r
936 // assert_eq!(Err(InvalidIdentifier), VersionReq::parse("1.0.0-"));\r
937 // assert_eq!(Err(MajorVersionRequired), VersionReq::parse(">="));\r
938 // }\r
939\r
940 #[test]\r
941 pub fn test_from_str() {\r
942 assert_eq!(\r
943 "1.0.0".parse::<VersionReq>().unwrap().to_string(),\r
944 "^1.0.0".to_string()\r
945 );\r
946 assert_eq!(\r
947 "=1.0.0".parse::<VersionReq>().unwrap().to_string(),\r
948 "=1.0.0".to_string()\r
949 );\r
950 assert_eq!(\r
951 "~1".parse::<VersionReq>().unwrap().to_string(),\r
952 "~1".to_string()\r
953 );\r
954 assert_eq!(\r
955 "~1.2".parse::<VersionReq>().unwrap().to_string(),\r
956 "~1.2".to_string()\r
957 );\r
958 assert_eq!(\r
959 "^1".parse::<VersionReq>().unwrap().to_string(),\r
960 "^1".to_string()\r
961 );\r
962 assert_eq!(\r
963 "^1.1".parse::<VersionReq>().unwrap().to_string(),\r
964 "^1.1".to_string()\r
965 );\r
966 assert_eq!(\r
967 "*".parse::<VersionReq>().unwrap().to_string(),\r
968 "*".to_string()\r
969 );\r
970 assert_eq!(\r
971 "1.*".parse::<VersionReq>().unwrap().to_string(),\r
972 "1.*".to_string()\r
973 );\r
974 assert_eq!(\r
975 "< 1.0.0".parse::<VersionReq>().unwrap().to_string(),\r
976 "<1.0.0".to_string()\r
977 );\r
978 }\r
979\r
980 // #[test]\r
981 // pub fn test_from_str_errors() {\r
982 // assert_eq!(Err(InvalidVersionRequirement), "\0".parse::<VersionReq>());\r
983 // assert_eq!(Err(OpAlreadySet), ">= >= 0.0.2".parse::<VersionReq>());\r
984 // assert_eq!(Err(InvalidSigil), ">== 0.0.2".parse::<VersionReq>());\r
985 // assert_eq!(Err(VersionComponentsMustBeNumeric),\r
986 // "a.0.0".parse::<VersionReq>());\r
987 // assert_eq!(Err(InvalidIdentifier), "1.0.0-".parse::<VersionReq>());\r
988 // assert_eq!(Err(MajorVersionRequired), ">=".parse::<VersionReq>());\r
989 // }\r
990\r
991 #[test]\r
992 fn test_cargo3202() {\r
993 let v = "0.*.*".parse::<VersionReq>().unwrap();\r
994 assert_eq!("0.*.*", format!("{}", v.predicates[0]));\r
995\r
996 let v = "0.0.*".parse::<VersionReq>().unwrap();\r
997 assert_eq!("0.0.*", format!("{}", v.predicates[0]));\r
998\r
999 let r = req("0.*.*");\r
1000 assert_match(&r, &["0.5.0"]);\r
1001 }\r
1002\r
1003 #[test]\r
1004 fn test_eq_hash() {\r
1005 assert!(req("^1") == req("^1"));\r
1006 assert!(calculate_hash(req("^1")) == calculate_hash(req("^1")));\r
1007 assert!(req("^1") != req("^2"));\r
1008 }\r
1009\r
1010 #[test]\r
1011 fn test_ordering() {\r
1012 assert!(req("=1") < req("*"));\r
1013 assert!(req(">1") < req("*"));\r
1014 assert!(req(">=1") < req("*"));\r
1015 assert!(req("<1") < req("*"));\r
1016 assert!(req("<=1") < req("*"));\r
1017 assert!(req("~1") < req("*"));\r
1018 assert!(req("^1") < req("*"));\r
1019 assert!(req("*") == req("*"));\r
1020 }\r
1021\r
1022 #[test]\r
1023 fn is_exact() {\r
1024 assert!(req("=1.0.0").is_exact());\r
1025 assert!(req("=1.0.0-alpha").is_exact());\r
1026\r
1027 assert!(!req("=1").is_exact());\r
1028 assert!(!req(">=1.0.0").is_exact());\r
1029 assert!(!req(">=1.0.0, <2.0.0").is_exact());\r
1030 }\r
1031}\r