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 //! The `version` module gives you tools to create and compare SemVer-compliant
12 //! versions.
13 
14 use std::cmp::{self, Ordering};
15 use std::error::Error;
16 use std::fmt;
17 use std::hash;
18 
19 use std::result;
20 use std::str;
21 
22 use semver_parser;
23 
24 #[cfg(feature = "serde")]
25 use serde::de::{self, Deserialize, Deserializer, Visitor};
26 #[cfg(feature = "serde")]
27 use serde::ser::{Serialize, Serializer};
28 
29 /// An identifier in the pre-release or build metadata.
30 ///
31 /// See sections 9 and 10 of the spec for more about pre-release identifers and
32 /// build metadata.
33 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
34 pub enum Identifier {
35     /// An identifier that's solely numbers.
36     Numeric(u64),
37     /// An identifier with letters and numbers.
38     AlphaNumeric(String),
39 }
40 
41 impl From<semver_parser::version::Identifier> for Identifier {
from(other: semver_parser::version::Identifier) -> Identifier42     fn from(other: semver_parser::version::Identifier) -> Identifier {
43         match other {
44             semver_parser::version::Identifier::Numeric(n) => Identifier::Numeric(n),
45             semver_parser::version::Identifier::AlphaNumeric(s) => Identifier::AlphaNumeric(s),
46         }
47     }
48 }
49 
50 impl fmt::Display for Identifier {
51     #[inline]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result52     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53         match *self {
54             Identifier::Numeric(ref n) => fmt::Display::fmt(n, f),
55             Identifier::AlphaNumeric(ref s) => fmt::Display::fmt(s, f),
56         }
57     }
58 }
59 
60 #[cfg(feature = "serde")]
61 impl Serialize for Identifier {
serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error> where S: Serializer,62     fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
63     where
64         S: Serializer,
65     {
66         // Serialize Identifier as a number or string.
67         match *self {
68             Identifier::Numeric(n) => serializer.serialize_u64(n),
69             Identifier::AlphaNumeric(ref s) => serializer.serialize_str(s),
70         }
71     }
72 }
73 
74 #[cfg(feature = "serde")]
75 impl<'de> Deserialize<'de> for Identifier {
deserialize<D>(deserializer: D) -> result::Result<Self, D::Error> where D: Deserializer<'de>,76     fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
77     where
78         D: Deserializer<'de>,
79     {
80         struct IdentifierVisitor;
81 
82         // Deserialize Identifier from a number or string.
83         impl<'de> Visitor<'de> for IdentifierVisitor {
84             type Value = Identifier;
85 
86             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
87                 formatter.write_str("a SemVer pre-release or build identifier")
88             }
89 
90             fn visit_u64<E>(self, numeric: u64) -> result::Result<Self::Value, E>
91             where
92                 E: de::Error,
93             {
94                 Ok(Identifier::Numeric(numeric))
95             }
96 
97             fn visit_str<E>(self, alphanumeric: &str) -> result::Result<Self::Value, E>
98             where
99                 E: de::Error,
100             {
101                 Ok(Identifier::AlphaNumeric(alphanumeric.to_owned()))
102             }
103         }
104 
105         deserializer.deserialize_any(IdentifierVisitor)
106     }
107 }
108 
109 /// Represents a version number conforming to the semantic versioning scheme.
110 #[derive(Clone, Eq, Debug)]
111 #[cfg_attr(feature = "diesel", derive(AsExpression, FromSqlRow))]
112 #[cfg_attr(feature = "diesel", sql_type = "diesel::sql_types::Text")]
113 pub struct Version {
114     /// The major version, to be incremented on incompatible changes.
115     pub major: u64,
116     /// The minor version, to be incremented when functionality is added in a
117     /// backwards-compatible manner.
118     pub minor: u64,
119     /// The patch version, to be incremented when backwards-compatible bug
120     /// fixes are made.
121     pub patch: u64,
122     /// The pre-release version identifier, if one exists.
123     pub pre: Vec<Identifier>,
124     /// The build metadata, ignored when determining version precedence.
125     pub build: Vec<Identifier>,
126 }
127 
128 impl From<semver_parser::version::Version> for Version {
from(other: semver_parser::version::Version) -> Version129     fn from(other: semver_parser::version::Version) -> Version {
130         Version {
131             major: other.major,
132             minor: other.minor,
133             patch: other.patch,
134             pre: other.pre.into_iter().map(From::from).collect(),
135             build: other.build.into_iter().map(From::from).collect(),
136         }
137     }
138 }
139 
140 #[cfg(feature = "serde")]
141 impl Serialize for Version {
serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error> where S: Serializer,142     fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
143     where
144         S: Serializer,
145     {
146         // Serialize Version as a string.
147         serializer.collect_str(self)
148     }
149 }
150 
151 #[cfg(feature = "serde")]
152 impl<'de> Deserialize<'de> for Version {
deserialize<D>(deserializer: D) -> result::Result<Self, D::Error> where D: Deserializer<'de>,153     fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
154     where
155         D: Deserializer<'de>,
156     {
157         struct VersionVisitor;
158 
159         // Deserialize Version from a string.
160         impl<'de> Visitor<'de> for VersionVisitor {
161             type Value = Version;
162 
163             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
164                 formatter.write_str("a SemVer version as a string")
165             }
166 
167             fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E>
168             where
169                 E: de::Error,
170             {
171                 Version::parse(v).map_err(de::Error::custom)
172             }
173         }
174 
175         deserializer.deserialize_str(VersionVisitor)
176     }
177 }
178 
179 /// An error type for this crate
180 ///
181 /// Currently, just a generic error. Will make this nicer later.
182 #[derive(Clone, PartialEq, Debug, PartialOrd)]
183 pub enum SemVerError {
184     /// An error ocurred while parsing.
185     ParseError(String),
186 }
187 
188 impl fmt::Display for SemVerError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result189     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
190         match self {
191             SemVerError::ParseError(ref m) => write!(f, "{}", m),
192         }
193     }
194 }
195 
196 impl Error for SemVerError {}
197 
198 /// A Result type for errors
199 pub type Result<T> = result::Result<T, SemVerError>;
200 
201 impl Version {
202     /// Contructs the simple case without pre or build.
new(major: u64, minor: u64, patch: u64) -> Version203     pub fn new(major: u64, minor: u64, patch: u64) -> Version {
204         Version {
205             major,
206             minor,
207             patch,
208             pre: Vec::new(),
209             build: Vec::new(),
210         }
211     }
212 
213     /// Parse a string into a semver object.
214     ///
215     /// # Errors
216     ///
217     /// Returns an error variant if the input could not be parsed as a semver object.
218     ///
219     /// In general, this means that the provided string does not conform to the
220     /// [semver spec][semver].
221     ///
222     /// An error for overflow is returned if any numeric component is larger than what can be
223     /// stored in `u64`.
224     ///
225     /// The following are examples for other common error causes:
226     ///
227     /// * `1.0` - too few numeric components are used. Exactly 3 are expected.
228     /// * `1.0.01` - a numeric component has a leading zero.
229     /// * `1.0.foo` - uses a non-numeric components where one is expected.
230     /// * `1.0.0foo` - metadata is not separated using a legal character like, `+` or `-`.
231     /// * `1.0.0+foo_123` - contains metadata with an illegal character (`_`).
232     ///   Legal characters for metadata include `a-z`, `A-Z`, `0-9`, `-`, and `.` (dot).
233     ///
234     /// [semver]: https://semver.org
parse(version: &str) -> Result<Version>235     pub fn parse(version: &str) -> Result<Version> {
236         let res = semver_parser::version::parse(version);
237 
238         match res {
239             // Convert plain String error into proper ParseError
240             Err(e) => Err(SemVerError::ParseError(e.to_string())),
241             Ok(v) => Ok(From::from(v)),
242         }
243     }
244 
245     /// Clears the build metadata
clear_metadata(&mut self)246     fn clear_metadata(&mut self) {
247         self.build = Vec::new();
248         self.pre = Vec::new();
249     }
250 
251     /// Increments the patch number for this Version (Must be mutable)
increment_patch(&mut self)252     pub fn increment_patch(&mut self) {
253         self.patch += 1;
254         self.clear_metadata();
255     }
256 
257     /// Increments the minor version number for this Version (Must be mutable)
258     ///
259     /// As instructed by section 7 of the spec, the patch number is reset to 0.
increment_minor(&mut self)260     pub fn increment_minor(&mut self) {
261         self.minor += 1;
262         self.patch = 0;
263         self.clear_metadata();
264     }
265 
266     /// Increments the major version number for this Version (Must be mutable)
267     ///
268     /// As instructed by section 8 of the spec, the minor and patch numbers are
269     /// reset to 0
increment_major(&mut self)270     pub fn increment_major(&mut self) {
271         self.major += 1;
272         self.minor = 0;
273         self.patch = 0;
274         self.clear_metadata();
275     }
276 
277     /// Checks to see if the current Version is in pre-release status
is_prerelease(&self) -> bool278     pub fn is_prerelease(&self) -> bool {
279         !self.pre.is_empty()
280     }
281 }
282 
283 impl str::FromStr for Version {
284     type Err = SemVerError;
285 
from_str(s: &str) -> Result<Version>286     fn from_str(s: &str) -> Result<Version> {
287         Version::parse(s)
288     }
289 }
290 
291 impl fmt::Display for Version {
292     #[inline]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result293     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294         let mut result = format!("{}.{}.{}", self.major, self.minor, self.patch);
295 
296         if !self.pre.is_empty() {
297             result.push_str("-");
298             for (i, x) in self.pre.iter().enumerate() {
299                 if i != 0 {
300                     result.push_str(".");
301                 }
302                 result.push_str(format!("{}", x).as_ref());
303             }
304         }
305         if !self.build.is_empty() {
306             result.push_str("+");
307             for (i, x) in self.build.iter().enumerate() {
308                 if i != 0 {
309                     result.push_str(".");
310                 }
311                 result.push_str(format!("{}", x).as_ref());
312             }
313         }
314 
315         f.pad(result.as_ref())?;
316         Ok(())
317     }
318 }
319 
320 impl cmp::PartialEq for Version {
321     #[inline]
eq(&self, other: &Version) -> bool322     fn eq(&self, other: &Version) -> bool {
323         // We should ignore build metadata here, otherwise versions v1 and v2
324         // can exist such that !(v1 < v2) && !(v1 > v2) && v1 != v2, which
325         // violate strict total ordering rules.
326         self.major == other.major
327             && self.minor == other.minor
328             && self.patch == other.patch
329             && self.pre == other.pre
330     }
331 }
332 
333 impl cmp::PartialOrd for Version {
partial_cmp(&self, other: &Version) -> Option<Ordering>334     fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
335         Some(self.cmp(other))
336     }
337 }
338 
339 impl cmp::Ord for Version {
cmp(&self, other: &Version) -> Ordering340     fn cmp(&self, other: &Version) -> Ordering {
341         match self.major.cmp(&other.major) {
342             Ordering::Equal => {}
343             r => return r,
344         }
345 
346         match self.minor.cmp(&other.minor) {
347             Ordering::Equal => {}
348             r => return r,
349         }
350 
351         match self.patch.cmp(&other.patch) {
352             Ordering::Equal => {}
353             r => return r,
354         }
355 
356         // NB: semver spec says 0.0.0-pre < 0.0.0
357         // but the version of ord defined for vec
358         // says that [] < [pre] so we alter it here
359         match (self.pre.len(), other.pre.len()) {
360             (0, 0) => Ordering::Equal,
361             (0, _) => Ordering::Greater,
362             (_, 0) => Ordering::Less,
363             (_, _) => self.pre.cmp(&other.pre),
364         }
365     }
366 }
367 
368 impl hash::Hash for Version {
hash<H: hash::Hasher>(&self, into: &mut H)369     fn hash<H: hash::Hasher>(&self, into: &mut H) {
370         self.major.hash(into);
371         self.minor.hash(into);
372         self.patch.hash(into);
373         self.pre.hash(into);
374     }
375 }
376 
377 impl From<(u64, u64, u64)> for Version {
from(tuple: (u64, u64, u64)) -> Version378     fn from(tuple: (u64, u64, u64)) -> Version {
379         let (major, minor, patch) = tuple;
380         Version::new(major, minor, patch)
381     }
382 }
383 
384 #[cfg(test)]
385 mod tests {
386     use super::Identifier;
387     use super::SemVerError;
388     use super::Version;
389     use std::result;
390 
391     #[test]
test_parse()392     fn test_parse() {
393         fn parse_error(e: &str) -> result::Result<Version, SemVerError> {
394             return Err(SemVerError::ParseError(e.to_string()));
395         }
396 
397         assert_eq!(Version::parse(""), parse_error("expected more input"));
398         assert_eq!(Version::parse("  "), parse_error("expected more input"));
399         assert_eq!(Version::parse("1"), parse_error("expected more input"));
400         assert_eq!(Version::parse("1.2"), parse_error("expected more input"));
401         assert_eq!(Version::parse("1.2.3-"), parse_error("expected more input"));
402         assert_eq!(
403             Version::parse("a.b.c"),
404             parse_error("encountered unexpected token: AlphaNumeric(\"a\")")
405         );
406         assert_eq!(
407             Version::parse("1.2.3 abc"),
408             parse_error("expected end of input, but got: [AlphaNumeric(\"abc\")]")
409         );
410 
411         assert_eq!(
412             Version::parse("1.2.3"),
413             Ok(Version {
414                 major: 1,
415                 minor: 2,
416                 patch: 3,
417                 pre: Vec::new(),
418                 build: Vec::new(),
419             })
420         );
421 
422         assert_eq!(Version::parse("1.2.3"), Ok(Version::new(1, 2, 3)));
423 
424         assert_eq!(
425             Version::parse("  1.2.3  "),
426             Ok(Version {
427                 major: 1,
428                 minor: 2,
429                 patch: 3,
430                 pre: Vec::new(),
431                 build: Vec::new(),
432             })
433         );
434         assert_eq!(
435             Version::parse("1.2.3-alpha1"),
436             Ok(Version {
437                 major: 1,
438                 minor: 2,
439                 patch: 3,
440                 pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
441                 build: Vec::new(),
442             })
443         );
444         assert_eq!(
445             Version::parse("  1.2.3-alpha1  "),
446             Ok(Version {
447                 major: 1,
448                 minor: 2,
449                 patch: 3,
450                 pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
451                 build: Vec::new(),
452             })
453         );
454         assert_eq!(
455             Version::parse("1.2.3+build5"),
456             Ok(Version {
457                 major: 1,
458                 minor: 2,
459                 patch: 3,
460                 pre: Vec::new(),
461                 build: vec![Identifier::AlphaNumeric(String::from("build5"))],
462             })
463         );
464         assert_eq!(
465             Version::parse("  1.2.3+build5  "),
466             Ok(Version {
467                 major: 1,
468                 minor: 2,
469                 patch: 3,
470                 pre: Vec::new(),
471                 build: vec![Identifier::AlphaNumeric(String::from("build5"))],
472             })
473         );
474         assert_eq!(
475             Version::parse("1.2.3-alpha1+build5"),
476             Ok(Version {
477                 major: 1,
478                 minor: 2,
479                 patch: 3,
480                 pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
481                 build: vec![Identifier::AlphaNumeric(String::from("build5"))],
482             })
483         );
484         assert_eq!(
485             Version::parse("  1.2.3-alpha1+build5  "),
486             Ok(Version {
487                 major: 1,
488                 minor: 2,
489                 patch: 3,
490                 pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
491                 build: vec![Identifier::AlphaNumeric(String::from("build5"))],
492             })
493         );
494         assert_eq!(
495             Version::parse("1.2.3-1.alpha1.9+build5.7.3aedf  "),
496             Ok(Version {
497                 major: 1,
498                 minor: 2,
499                 patch: 3,
500                 pre: vec![
501                     Identifier::Numeric(1),
502                     Identifier::AlphaNumeric(String::from("alpha1")),
503                     Identifier::Numeric(9),
504                 ],
505                 build: vec![
506                     Identifier::AlphaNumeric(String::from("build5")),
507                     Identifier::Numeric(7),
508                     Identifier::AlphaNumeric(String::from("3aedf")),
509                 ],
510             })
511         );
512         assert_eq!(
513             Version::parse("0.4.0-beta.1+0851523"),
514             Ok(Version {
515                 major: 0,
516                 minor: 4,
517                 patch: 0,
518                 pre: vec![
519                     Identifier::AlphaNumeric(String::from("beta")),
520                     Identifier::Numeric(1),
521                 ],
522                 build: vec![Identifier::AlphaNumeric(String::from("0851523"))],
523             })
524         );
525         // for https://nodejs.org/dist/index.json, where some older npm versions are "1.1.0-beta-10"
526         assert_eq!(
527             Version::parse("1.1.0-beta-10"),
528             Ok(Version {
529                 major: 1,
530                 minor: 1,
531                 patch: 0,
532                 pre: vec![Identifier::AlphaNumeric(String::from("beta-10")),],
533                 build: Vec::new(),
534             })
535         );
536     }
537 
538     #[test]
test_increment_patch()539     fn test_increment_patch() {
540         let mut buggy_release = Version::parse("0.1.0").unwrap();
541         buggy_release.increment_patch();
542         assert_eq!(buggy_release, Version::parse("0.1.1").unwrap());
543     }
544 
545     #[test]
test_increment_minor()546     fn test_increment_minor() {
547         let mut feature_release = Version::parse("1.4.6").unwrap();
548         feature_release.increment_minor();
549         assert_eq!(feature_release, Version::parse("1.5.0").unwrap());
550     }
551 
552     #[test]
test_increment_major()553     fn test_increment_major() {
554         let mut chrome_release = Version::parse("46.1.246773").unwrap();
555         chrome_release.increment_major();
556         assert_eq!(chrome_release, Version::parse("47.0.0").unwrap());
557     }
558 
559     #[test]
test_increment_keep_prerelease()560     fn test_increment_keep_prerelease() {
561         let mut release = Version::parse("1.0.0-alpha").unwrap();
562         release.increment_patch();
563 
564         assert_eq!(release, Version::parse("1.0.1").unwrap());
565 
566         release.increment_minor();
567 
568         assert_eq!(release, Version::parse("1.1.0").unwrap());
569 
570         release.increment_major();
571 
572         assert_eq!(release, Version::parse("2.0.0").unwrap());
573     }
574 
575     #[test]
test_increment_clear_metadata()576     fn test_increment_clear_metadata() {
577         let mut release = Version::parse("1.0.0+4442").unwrap();
578         release.increment_patch();
579 
580         assert_eq!(release, Version::parse("1.0.1").unwrap());
581         release = Version::parse("1.0.1+hello").unwrap();
582 
583         release.increment_minor();
584 
585         assert_eq!(release, Version::parse("1.1.0").unwrap());
586         release = Version::parse("1.1.3747+hello").unwrap();
587 
588         release.increment_major();
589 
590         assert_eq!(release, Version::parse("2.0.0").unwrap());
591     }
592 
593     #[test]
test_eq()594     fn test_eq() {
595         assert_eq!(Version::parse("1.2.3"), Version::parse("1.2.3"));
596         assert_eq!(
597             Version::parse("1.2.3-alpha1"),
598             Version::parse("1.2.3-alpha1")
599         );
600         assert_eq!(
601             Version::parse("1.2.3+build.42"),
602             Version::parse("1.2.3+build.42")
603         );
604         assert_eq!(
605             Version::parse("1.2.3-alpha1+42"),
606             Version::parse("1.2.3-alpha1+42")
607         );
608         assert_eq!(Version::parse("1.2.3+23"), Version::parse("1.2.3+42"));
609     }
610 
611     #[test]
test_ne()612     fn test_ne() {
613         assert!(Version::parse("0.0.0") != Version::parse("0.0.1"));
614         assert!(Version::parse("0.0.0") != Version::parse("0.1.0"));
615         assert!(Version::parse("0.0.0") != Version::parse("1.0.0"));
616         assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
617     }
618 
619     #[test]
test_show()620     fn test_show() {
621         assert_eq!(
622             format!("{}", Version::parse("1.2.3").unwrap()),
623             "1.2.3".to_string()
624         );
625         assert_eq!(
626             format!("{}", Version::parse("1.2.3-alpha1").unwrap()),
627             "1.2.3-alpha1".to_string()
628         );
629         assert_eq!(
630             format!("{}", Version::parse("1.2.3+build.42").unwrap()),
631             "1.2.3+build.42".to_string()
632         );
633         assert_eq!(
634             format!("{}", Version::parse("1.2.3-alpha1+42").unwrap()),
635             "1.2.3-alpha1+42".to_string()
636         );
637     }
638 
639     #[test]
test_display()640     fn test_display() {
641         let version = Version::parse("1.2.3-rc1").unwrap();
642         assert_eq!(format!("{:20}", version), "1.2.3-rc1           ");
643         assert_eq!(format!("{:*^20}", version), "*****1.2.3-rc1******");
644         assert_eq!(format!("{:.4}", version), "1.2.");
645     }
646 
647     #[test]
test_to_string()648     fn test_to_string() {
649         assert_eq!(
650             Version::parse("1.2.3").unwrap().to_string(),
651             "1.2.3".to_string()
652         );
653         assert_eq!(
654             Version::parse("1.2.3-alpha1").unwrap().to_string(),
655             "1.2.3-alpha1".to_string()
656         );
657         assert_eq!(
658             Version::parse("1.2.3+build.42").unwrap().to_string(),
659             "1.2.3+build.42".to_string()
660         );
661         assert_eq!(
662             Version::parse("1.2.3-alpha1+42").unwrap().to_string(),
663             "1.2.3-alpha1+42".to_string()
664         );
665     }
666 
667     #[test]
test_lt()668     fn test_lt() {
669         assert!(Version::parse("0.0.0") < Version::parse("1.2.3-alpha2"));
670         assert!(Version::parse("1.0.0") < Version::parse("1.2.3-alpha2"));
671         assert!(Version::parse("1.2.0") < Version::parse("1.2.3-alpha2"));
672         assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3"));
673         assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3-alpha2"));
674         assert!(!(Version::parse("1.2.3-alpha2") < Version::parse("1.2.3-alpha2")));
675         assert!(!(Version::parse("1.2.3+23") < Version::parse("1.2.3+42")));
676     }
677 
678     #[test]
test_le()679     fn test_le() {
680         assert!(Version::parse("0.0.0") <= Version::parse("1.2.3-alpha2"));
681         assert!(Version::parse("1.0.0") <= Version::parse("1.2.3-alpha2"));
682         assert!(Version::parse("1.2.0") <= Version::parse("1.2.3-alpha2"));
683         assert!(Version::parse("1.2.3-alpha1") <= Version::parse("1.2.3-alpha2"));
684         assert!(Version::parse("1.2.3-alpha2") <= Version::parse("1.2.3-alpha2"));
685         assert!(Version::parse("1.2.3+23") <= Version::parse("1.2.3+42"));
686     }
687 
688     #[test]
test_gt()689     fn test_gt() {
690         assert!(Version::parse("1.2.3-alpha2") > Version::parse("0.0.0"));
691         assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.0.0"));
692         assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0"));
693         assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha1"));
694         assert!(Version::parse("1.2.3") > Version::parse("1.2.3-alpha2"));
695         assert!(!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha2")));
696         assert!(!(Version::parse("1.2.3+23") > Version::parse("1.2.3+42")));
697     }
698 
699     #[test]
test_ge()700     fn test_ge() {
701         assert!(Version::parse("1.2.3-alpha2") >= Version::parse("0.0.0"));
702         assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.0.0"));
703         assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.0"));
704         assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha1"));
705         assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha2"));
706         assert!(Version::parse("1.2.3+23") >= Version::parse("1.2.3+42"));
707     }
708 
709     #[test]
test_prerelease_check()710     fn test_prerelease_check() {
711         assert!(Version::parse("1.0.0").unwrap().is_prerelease() == false);
712         assert!(Version::parse("0.0.1").unwrap().is_prerelease() == false);
713         assert!(Version::parse("4.1.4-alpha").unwrap().is_prerelease());
714         assert!(Version::parse("1.0.0-beta294296").unwrap().is_prerelease());
715     }
716 
717     #[test]
test_spec_order()718     fn test_spec_order() {
719         let vs = [
720             "1.0.0-alpha",
721             "1.0.0-alpha.1",
722             "1.0.0-alpha.beta",
723             "1.0.0-beta",
724             "1.0.0-beta.2",
725             "1.0.0-beta.11",
726             "1.0.0-rc.1",
727             "1.0.0",
728         ];
729         let mut i = 1;
730         while i < vs.len() {
731             let a = Version::parse(vs[i - 1]);
732             let b = Version::parse(vs[i]);
733             assert!(a < b, "nope {:?} < {:?}", a, b);
734             i += 1;
735         }
736     }
737 
738     #[test]
test_from_str()739     fn test_from_str() {
740         assert_eq!(
741             "1.2.3".parse(),
742             Ok(Version {
743                 major: 1,
744                 minor: 2,
745                 patch: 3,
746                 pre: Vec::new(),
747                 build: Vec::new(),
748             })
749         );
750         assert_eq!(
751             "  1.2.3  ".parse(),
752             Ok(Version {
753                 major: 1,
754                 minor: 2,
755                 patch: 3,
756                 pre: Vec::new(),
757                 build: Vec::new(),
758             })
759         );
760         assert_eq!(
761             "1.2.3-alpha1".parse(),
762             Ok(Version {
763                 major: 1,
764                 minor: 2,
765                 patch: 3,
766                 pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
767                 build: Vec::new(),
768             })
769         );
770         assert_eq!(
771             "  1.2.3-alpha1  ".parse(),
772             Ok(Version {
773                 major: 1,
774                 minor: 2,
775                 patch: 3,
776                 pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
777                 build: Vec::new(),
778             })
779         );
780         assert_eq!(
781             "1.2.3+build5".parse(),
782             Ok(Version {
783                 major: 1,
784                 minor: 2,
785                 patch: 3,
786                 pre: Vec::new(),
787                 build: vec![Identifier::AlphaNumeric(String::from("build5"))],
788             })
789         );
790         assert_eq!(
791             "  1.2.3+build5  ".parse(),
792             Ok(Version {
793                 major: 1,
794                 minor: 2,
795                 patch: 3,
796                 pre: Vec::new(),
797                 build: vec![Identifier::AlphaNumeric(String::from("build5"))],
798             })
799         );
800         assert_eq!(
801             "1.2.3-alpha1+build5".parse(),
802             Ok(Version {
803                 major: 1,
804                 minor: 2,
805                 patch: 3,
806                 pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
807                 build: vec![Identifier::AlphaNumeric(String::from("build5"))],
808             })
809         );
810         assert_eq!(
811             "  1.2.3-alpha1+build5  ".parse(),
812             Ok(Version {
813                 major: 1,
814                 minor: 2,
815                 patch: 3,
816                 pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
817                 build: vec![Identifier::AlphaNumeric(String::from("build5"))],
818             })
819         );
820         assert_eq!(
821             "1.2.3-1.alpha1.9+build5.7.3aedf  ".parse(),
822             Ok(Version {
823                 major: 1,
824                 minor: 2,
825                 patch: 3,
826                 pre: vec![
827                     Identifier::Numeric(1),
828                     Identifier::AlphaNumeric(String::from("alpha1")),
829                     Identifier::Numeric(9),
830                 ],
831                 build: vec![
832                     Identifier::AlphaNumeric(String::from("build5")),
833                     Identifier::Numeric(7),
834                     Identifier::AlphaNumeric(String::from("3aedf")),
835                 ],
836             })
837         );
838         assert_eq!(
839             "0.4.0-beta.1+0851523".parse(),
840             Ok(Version {
841                 major: 0,
842                 minor: 4,
843                 patch: 0,
844                 pre: vec![
845                     Identifier::AlphaNumeric(String::from("beta")),
846                     Identifier::Numeric(1),
847                 ],
848                 build: vec![Identifier::AlphaNumeric(String::from("0851523"))],
849             })
850         );
851     }
852 
853     #[test]
test_from_str_errors()854     fn test_from_str_errors() {
855         fn parse_error(e: &str) -> result::Result<Version, SemVerError> {
856             return Err(SemVerError::ParseError(e.to_string()));
857         }
858 
859         assert_eq!("".parse(), parse_error("expected more input"));
860         assert_eq!("  ".parse(), parse_error("expected more input"));
861         assert_eq!("1".parse(), parse_error("expected more input"));
862         assert_eq!("1.2".parse(), parse_error("expected more input"));
863         assert_eq!("1.2.3-".parse(), parse_error("expected more input"));
864         assert_eq!(
865             "a.b.c".parse(),
866             parse_error("encountered unexpected token: AlphaNumeric(\"a\")")
867         );
868         assert_eq!(
869             "1.2.3 abc".parse(),
870             parse_error("expected end of input, but got: [AlphaNumeric(\"abc\")]")
871         );
872     }
873 }
874