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.
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.
11 use std
::error
::Error
;
16 use semver_parser
::{Compat, RangeSet}
;
17 use version
::Identifier
;
20 #[cfg(feature = "serde")]
21 use serde
::de
::{self, Deserialize, Deserializer, Visitor}
;
22 #[cfg(feature = "serde")]
23 use serde
::ser
::{Serialize, Serializer}
;
25 use self::Op
::{Ex, Gt, GtEq, Lt, LtEq}
;
26 use self::ReqParseError
::*;
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
{
36 compat
: Compat
, // defaults to Cargo
39 impl From
<semver_parser
::RangeSet
> for VersionReq
{
40 fn from(range_set
: semver_parser
::RangeSet
) -> VersionReq
{
42 ranges
: range_set
.ranges
.into_iter().map(From
::from
).collect(),
43 compat
: range_set
.compat
,
48 #[cfg(feature = "serde")]
49 impl Serialize
for VersionReq
{
50 fn serialize
<S
>(&self, serializer
: S
) -> ::std
::result
::Result
<S
::Ok
, S
::Error
>
54 // Serialize VersionReq as a string.
55 serializer
.collect_str(self)
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
>
66 struct VersionReqVisitor
;
68 /// Deserialize `VersionReq` from a string.
69 impl<'de
> Visitor
<'de
> for VersionReqVisitor
{
70 type Value
= VersionReq
;
72 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
73 formatter
.write_str("a SemVer version requirement as a string")
76 fn visit_str
<E
>(self, v
: &str) -> ::std
::result
::Result
<Self::Value
, E
>
80 VersionReq
::parse(v
).map_err(de
::Error
::custom
)
84 deserializer
.deserialize_str(VersionReqVisitor
)
88 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
92 GtEq
, // Greater than or equal to
94 LtEq
, // Less than or equal to
97 impl From
<semver_parser
::Op
> for Op
{
98 fn from(op
: semver_parser
::Op
) -> 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
,
109 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
111 predicates
: Vec
<Predicate
>,
115 impl From
<semver_parser
::Range
> for Range
{
116 fn from(range
: semver_parser
::Range
) -> Range
{
118 predicates
: range
.comparator_set
.into_iter().map(From
::from
).collect(),
119 compat
: range
.compat
,
124 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
130 pre
: Vec
<Identifier
>,
133 impl From
<semver_parser
::Comparator
> for Predicate
{
134 fn from(comparator
: semver_parser
::Comparator
) -> 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(),
145 impl From
<semver_parser
::Identifier
> for Identifier
{
146 fn from(identifier
: semver_parser
::Identifier
) -> Identifier
{
148 semver_parser
::Identifier
::Numeric(n
) => Identifier
::Numeric(n
),
149 semver_parser
::Identifier
::AlphaNumeric(s
) => Identifier
::AlphaNumeric(s
),
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.
163 /// The sigil you have written is not correct.
165 /// All components of a version must be numeric.
166 VersionComponentsMustBeNumeric
,
167 /// There was an error parsing an identifier.
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
),
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",
182 "you have already provided an operation, such as =, ~, or ^; only use one"
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"
191 DeprecatedVersionRequirement(_
) => "This requirement is deprecated",
197 impl Error
for ReqParseError {}
199 impl From
<String
> for ReqParseError
{
200 fn from(other
: String
) -> ReqParseError
{
202 "Null is not a valid VersionReq" => ReqParseError
::InvalidVersionRequirement
,
203 "VersionReq did not parse properly." => ReqParseError
::OpAlreadySet
,
204 _
=> ReqParseError
::InvalidVersionRequirement
,
210 /// `any()` is a factory method which creates a `VersionReq` with no constraints. In other
211 /// words, any version will match against it.
216 /// use semver::VersionReq;
218 /// let anything = VersionReq::any();
220 pub fn any() -> VersionReq
{
223 compat
: Compat
::Cargo
,
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.
230 /// A `Result` is returned which contains a [`ReqParseError`] if there was a problem parsing the
232 /// [`ReqParseError`]: enum.ReqParseError.html
237 /// use semver::VersionReq;
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");
249 /// This example demonstrates error handling, and will panic.
252 /// use semver::VersionReq;
254 /// let version = match VersionReq::parse("not a version") {
255 /// Ok(version) => version,
256 /// Err(e) => panic!("There was a problem parsing: {}", e),
262 /// Returns an error variant if the input could not be parsed as a semver requirement.
264 /// Examples of common error causes are as follows:
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.*`.
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
>();
279 if let Ok(v
) = range_set
{
280 return Ok(From
::from(v
));
283 match VersionReq
::parse_deprecated(input
) {
284 Some(v
) => Err(ReqParseError
::DeprecatedVersionRequirement(v
)),
285 None
=> Err(From
::from(range_set
.err().unwrap())),
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.
294 /// A `Result` is returned which contains a [`ReqParseError`] if there was a problem parsing the
296 /// [`ReqParseError`]: enum.ReqParseError.html
301 /// extern crate semver_parser;
302 /// use semver::VersionReq;
303 /// use semver_parser::Compat;
306 /// let cargo_version = VersionReq::parse_compat("1.2.3", Compat::Cargo);
307 /// let npm_version = VersionReq::parse_compat("1.2.3", Compat::Npm);
310 pub fn parse_compat(input
: &str, compat
: Compat
) -> Result
<VersionReq
, ReqParseError
> {
311 let range_set
= RangeSet
::parse(input
, compat
);
313 if let Ok(v
) = range_set
{
314 return Ok(From
::from(v
));
317 match VersionReq
::parse_deprecated(input
) {
318 Some(v
) => Err(ReqParseError
::DeprecatedVersionRequirement(v
)),
319 None
=> Err(From
::from(range_set
.err().unwrap())),
323 fn parse_deprecated(version
: &str) -> Option
<VersionReq
> {
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()),
334 /// `exact()` is a factory method which creates a `VersionReq` with one exact constraint.
339 /// use semver::VersionReq;
340 /// use semver::Version;
342 /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] };
343 /// let exact = VersionReq::exact(&version);
345 pub fn exact(version
: &Version
) -> VersionReq
{
348 predicates
: vec
![Predicate
::exact(version
)],
349 compat
: Compat
::Cargo
,
351 compat
: Compat
::Cargo
,
355 /// `matches()` matches a given [`Version`] against this `VersionReq`.
356 /// [`Version`]: struct.Version.html
361 /// use semver::VersionReq;
362 /// use semver::Version;
364 /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] };
365 /// let exact = VersionReq::exact(&version);
367 /// assert!(exact.matches(&version));
369 pub fn matches(&self, version
: &Version
) -> bool
{
370 // no ranges means anything matches
371 if self.ranges
.is_empty() {
377 .any(|r
| r
.matches(version
) && r
.pre_tag_is_compatible(version
))
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.
389 /// use semver::ReqParseError;
390 /// use semver::VersionReq;
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());
399 /// use_is_exact().unwrap();
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();
412 impl str::FromStr
for VersionReq
{
413 type Err
= ReqParseError
;
415 fn from_str(s
: &str) -> Result
<VersionReq
, ReqParseError
> {
421 fn matches(&self, ver
: &Version
) -> bool
{
422 self.predicates
.iter().all(|p
| p
.matches(ver
))
425 fn pre_tag_is_compatible(&self, ver
: &Version
) -> bool
{
426 self.predicates
.iter().any(|p
| p
.pre_tag_is_compatible(ver
))
431 fn exact(version
: &Version
) -> Predicate
{
434 major
: version
.major
,
435 minor
: version
.minor
,
436 patch
: version
.patch
,
437 pre
: version
.pre
.clone(),
441 /// `matches()` takes a `Version` and determines if it matches this particular `Predicate`.
442 pub fn matches(&self, ver
: &Version
) -> bool
{
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
),
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
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
463 // allowed to satisfy comparator sets if at least one comparator with the same
465 // minor, patch] tuple also has a prerelease tag.
467 || (self.major
== ver
.major
468 && self.minor
== ver
.minor
469 && self.patch
== ver
.patch
470 && !self.pre
.is_empty())
473 fn matches_greater(&self, ver
: &Version
) -> bool
{
474 if self.major
!= ver
.major
{
475 return ver
.major
> self.major
;
478 if self.minor
!= ver
.minor
{
479 return ver
.minor
> self.minor
;
482 if self.patch
!= ver
.patch
{
483 return ver
.patch
> self.patch
;
486 if !self.pre
.is_empty() {
487 return ver
.pre
.is_empty() || ver
.pre
> self.pre
;
493 fn has_exactly_one_match(&self) -> bool
{
498 impl fmt
::Display
for VersionReq
{
499 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
500 if self.ranges
.is_empty() {
503 for (i
, ref pred
) in self.ranges
.iter().enumerate() {
505 write
!(fmt
, "{}", pred
)?
;
507 write
!(fmt
, " || {}", pred
)?
;
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() {
520 write
!(fmt
, "{}", pred
)?
;
521 } else if self.compat
== Compat
::Npm
{
522 // Node does not expect commas between predicates
523 write
!(fmt
, " {}", pred
)?
;
525 write
!(fmt
, ", {}", pred
)?
;
532 impl fmt
::Display
for Predicate
{
533 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
537 self.op
, self.major
, self.minor
, self.patch
540 if !self.pre
.is_empty() {
542 for (i
, x
) in self.pre
.iter().enumerate() {
546 write
!(fmt
, "{}", x
)?
;
554 impl fmt
::Display
for Op
{
555 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
557 Ex
=> write
!(fmt
, "=")?
,
558 Gt
=> write
!(fmt
, ">")?
,
559 GtEq
=> write
!(fmt
, ">=")?
,
560 Lt
=> write
!(fmt
, "<")?
,
561 LtEq
=> write
!(fmt
, "<=")?
,
569 use super::super::version
::Version
;
570 use super::{Compat, Op, VersionReq}
;
571 use std
::hash
::{Hash, Hasher}
;
573 fn req(s
: &str) -> VersionReq
{
574 VersionReq
::parse(s
).unwrap()
577 fn req_npm(s
: &str) -> VersionReq
{
578 VersionReq
::parse_compat(s
, Compat
::Npm
).unwrap()
581 fn version(s
: &str) -> Version
{
582 match Version
::parse(s
) {
584 Err(e
) => panic
!("`{}` is not a valid version. Reason: {:?}", s
, e
),
588 fn assert_match(req
: &VersionReq
, vers
: &[&str]) {
589 for ver
in vers
.iter() {
590 assert
!(req
.matches(&version(*ver
)), "did not match {}", ver
);
594 fn assert_not_match(req
: &VersionReq
, vers
: &[&str]) {
595 for ver
in vers
.iter() {
596 assert
!(!req
.matches(&version(*ver
)), "matched {}", ver
);
600 fn calculate_hash
<T
: Hash
>(t
: T
) -> u64 {
601 use std
::collections
::hash_map
::DefaultHasher
;
603 let mut s
= DefaultHasher
::new();
609 fn test_parsing_default() {
610 let r
= req("1.0.0");
612 assert_eq
!(r
.to_string(), ">=1.0.0, <2.0.0".to_string());
614 assert_match(&r
, &["1.0.0", "1.0.1"]);
615 assert_not_match(&r
, &["0.9.9", "0.10.0", "0.1.0"]);
619 fn test_parsing_default_npm() {
620 let r
= req_npm("1.0.0");
622 assert_eq
!(r
.to_string(), "=1.0.0".to_string());
624 assert_match(&r
, &["1.0.0"]);
625 assert_not_match(&r
, &["0.9.9", "0.10.0", "0.1.0", "1.0.1"]);
629 fn test_parsing_exact() {
630 let r
= req("=1.0.0");
632 assert
!(r
.to_string() == "=1.0.0".to_string());
633 assert_eq
!(r
.to_string(), "=1.0.0".to_string());
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"]);
638 let r
= req("=0.9.0");
640 assert_eq
!(r
.to_string(), "=0.9.0".to_string());
642 assert_match(&r
, &["0.9.0"]);
643 assert_not_match(&r
, &["0.9.1", "1.9.0", "0.0.9"]);
645 let r
= req("=0.1.0-beta2.a");
647 assert_eq
!(r
.to_string(), "=0.1.0-beta2.a".to_string());
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"]);
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
));
662 pub fn test_parsing_greater_than() {
663 let r
= req(">= 1.0.0");
665 assert_eq
!(r
.to_string(), ">=1.0.0".to_string());
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"]);
670 // https://github.com/steveklabnik/semver/issues/53
671 let r
= req(">= 2.1.0-alpha2");
673 assert_match(&r
, &["2.1.0-alpha2", "2.1.0-alpha3", "2.1.0", "3.0.0"]);
676 &["2.0.0", "2.1.0-alpha1", "2.0.0-alpha2", "3.0.0-alpha2"],
681 pub fn test_parsing_less_than() {
682 let r
= req("< 1.0.0");
684 assert_eq
!(r
.to_string(), "<1.0.0".to_string());
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"]);
689 let r
= req("<= 2.1.0-alpha2");
691 assert_match(&r
, &["2.1.0-alpha2", "2.1.0-alpha1", "2.0.0", "1.0.0"]);
694 &["2.1.0", "2.2.0-alpha1", "2.0.0-alpha2", "1.0.0-alpha2"],
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"]);
705 let r
= req("0.3.0, 0.4.0");
708 ">=0.3.0, <0.4.0, >=0.4.0, <0.5.0".to_string()
710 assert_not_match(&r
, &["0.0.8", "0.3.0", "0.4.0"]);
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"]);
716 let r
= req("0.1.0, 0.1.4, 0.1.6");
719 ">=0.1.0, <0.2.0, >=0.1.4, <0.2.0, >=0.1.6, <0.2.0".to_string()
721 assert_match(&r
, &["0.1.6", "0.1.9"]);
722 assert_not_match(&r
, &["0.1.0", "0.1.4", "0.2.0"]);
724 assert
!(VersionReq
::parse("> 0.1.0,").is_err());
725 assert
!(VersionReq
::parse("> 0.3.0, ,").is_err());
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());
741 &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre"],
743 assert_not_match(&r
, &["0.6.0", "0.6.0-pre"]);
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"]);
752 // https://github.com/steveklabnik/semver/issues/55
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"]);
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"]);
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"]);
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"]);
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"]);
780 assert
!(VersionReq
::parse("> 0.1.0,").is_err());
781 assert
!(VersionReq
::parse("> 0.3.0, ,").is_err());
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());
797 &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre"],
799 assert_not_match(&r
, &["0.6.0", "0.6.0-pre"]);
803 pub fn test_parsing_tilde() {
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"]);
809 assert_match(&r
, &["1.2.0", "1.2.1"]);
810 assert_not_match(&r
, &["1.1.1", "1.3.0", "0.0.9"]);
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"]);
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"]);
822 pub fn test_parsing_compatible() {
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"]);
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"]);
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"]);
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"]);
842 let r
= req("^0.5.1-alpha3");
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"]);
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"]);
873 assert_match(&r
, &["0.9.1", "0.0.2", "0.0.0"]);
874 assert_not_match(&r
, &["2.9.0", "1.1.1"]);
876 let r
= req("^1.4.2-beta.5");
879 &["1.4.2", "1.4.3", "1.4.2-beta.5", "1.4.2-beta.6", "1.4.2-c"],
894 pub fn test_parsing_wildcard() {
896 assert_match(&r
, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
897 assert_not_match(&r
, &[]);
899 assert_match(&r
, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
900 assert_not_match(&r
, &[]);
902 assert_match(&r
, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
903 assert_not_match(&r
, &[]);
905 assert_match(&r
, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
906 assert_not_match(&r
, &[]);
909 assert_match(&r
, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);
910 assert_not_match(&r
, &["0.0.9"]);
912 assert_match(&r
, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);
913 assert_not_match(&r
, &["0.0.9"]);
915 assert_match(&r
, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);
916 assert_not_match(&r
, &["0.0.9"]);
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"]);
929 // https://github.com/steveklabnik/semver/issues/57
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"]);
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"]);
943 let r
= req("6.* || 8.* || >= 10.*");
946 ">=6.0.0, <7.0.0 || >=8.0.0, <9.0.0 || >=10.0.0".to_string()
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"]);
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"]);
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"]);
967 let r
= req_npm("6.* || 8.* || >= 10.*");
970 ">=6.0.0 <7.0.0 || >=8.0.0 <9.0.0 || >=10.0.0".to_string()
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"]);
980 let r
= VersionReq
::any();
981 assert_match(&r
, &["0.0.1", "0.1.0", "1.0.0"]);
986 let r
= req("=2.1.1-really.0");
987 assert_match(&r
, &["2.1.1-really.0"]);
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(">="));
1002 pub fn test_from_str() {
1004 "1.0.0".parse
::<VersionReq
>().unwrap().to_string(),
1005 ">=1.0.0, <2.0.0".to_string()
1008 "=1.0.0".parse
::<VersionReq
>().unwrap().to_string(),
1009 "=1.0.0".to_string()
1012 "~1".parse
::<VersionReq
>().unwrap().to_string(),
1013 ">=1.0.0, <2.0.0".to_string()
1016 "~1.2".parse
::<VersionReq
>().unwrap().to_string(),
1017 ">=1.2.0, <1.3.0".to_string()
1020 "^1".parse
::<VersionReq
>().unwrap().to_string(),
1021 ">=1.0.0, <2.0.0".to_string()
1024 "^1.1".parse
::<VersionReq
>().unwrap().to_string(),
1025 ">=1.1.0, <2.0.0".to_string()
1028 "*".parse
::<VersionReq
>().unwrap().to_string(),
1029 ">=0.0.0".to_string()
1032 "1.*".parse
::<VersionReq
>().unwrap().to_string(),
1033 ">=1.0.0, <2.0.0".to_string()
1036 "< 1.0.0".parse
::<VersionReq
>().unwrap().to_string(),
1037 "<1.0.0".to_string()
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>());
1053 fn test_cargo3202() {
1054 let v
= "0.*.*".parse
::<VersionReq
>().unwrap();
1055 assert_eq
!(">=0.0.0, <1.0.0", format
!("{}", v
.ranges
[0]));
1057 let v
= "0.0.*".parse
::<VersionReq
>().unwrap();
1058 assert_eq
!(">=0.0.0, <0.1.0", format
!("{}", v
.ranges
[0]));
1060 let r
= req("0.*.*");
1061 assert_match(&r
, &["0.5.0"]);
1066 assert
!(req("^1") == req("^1"));
1067 assert
!(calculate_hash(req("^1")) == calculate_hash(req("^1")));
1068 assert
!(req("^1") != req("^2"));
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("*"));
1085 assert
!(req("=1.0.0").is_exact());
1086 assert
!(req("=1.0.0-alpha").is_exact());
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());