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