aboutsummaryrefslogtreecommitdiff
path: root/semver/src/version.rs
diff options
context:
space:
mode:
authorDaniel Mueller <deso@posteo.net>2019-01-02 21:14:10 -0800
committerDaniel Mueller <deso@posteo.net>2019-01-02 21:14:10 -0800
commitecf3474223ca3d16a10f12dc2272e3b0ed72c1bb (patch)
tree03134a683791176b49ef5c92e8d6acd24c3b5a9b /semver/src/version.rs
parent686f61b75055ecb02baf9d9449525ae447a3bed1 (diff)
downloadnitrocli-ecf3474223ca3d16a10f12dc2272e3b0ed72c1bb.tar.gz
nitrocli-ecf3474223ca3d16a10f12dc2272e3b0ed72c1bb.tar.bz2
Update nitrokey crate to 0.2.3
This change updates the nitrokey crate to version 0.2.3. This version bumps the rand crate used to 0.6.1, which in turn requires an additional set of dependencies. Import subrepo nitrokey/:nitrokey at b3e2adc5bb1300441ca74cc7672617c042f3ea31 Import subrepo rand/:rand at 73613ff903512e9503e41cc8ba9eae76269dc598 Import subrepo rustc_version/:rustc_version at 0294f2ba2018bf7be672abd53db351ce5055fa02 Import subrepo semver-parser/:semver-parser at 750da9b11a04125231b1fb293866ca036845acee Import subrepo semver/:semver at 5eb6db94fa03f4d5c64a625a56188f496be47598
Diffstat (limited to 'semver/src/version.rs')
-rw-r--r--semver/src/version.rs759
1 files changed, 759 insertions, 0 deletions
diff --git a/semver/src/version.rs b/semver/src/version.rs
new file mode 100644
index 0000000..38de133
--- /dev/null
+++ b/semver/src/version.rs
@@ -0,0 +1,759 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The `version` module gives you tools to create and compare SemVer-compliant
+//! versions.
+
+use std::cmp::{self, Ordering};
+use std::fmt;
+use std::hash;
+use std::error::Error;
+
+use std::result;
+use std::str;
+
+use semver_parser;
+
+#[cfg(feature = "serde")]
+use serde::ser::{Serialize, Serializer};
+#[cfg(feature = "serde")]
+use serde::de::{self, Deserialize, Deserializer, Visitor};
+
+/// An identifier in the pre-release or build metadata.
+///
+/// See sections 9 and 10 of the spec for more about pre-release identifers and
+/// build metadata.
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum Identifier {
+ /// An identifier that's solely numbers.
+ Numeric(u64),
+ /// An identifier with letters and numbers.
+ AlphaNumeric(String),
+}
+
+impl From<semver_parser::version::Identifier> for Identifier {
+ fn from(other: semver_parser::version::Identifier) -> Identifier {
+ match other {
+ semver_parser::version::Identifier::Numeric(n) => Identifier::Numeric(n),
+ semver_parser::version::Identifier::AlphaNumeric(s) => Identifier::AlphaNumeric(s),
+ }
+ }
+}
+
+impl fmt::Display for Identifier {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Identifier::Numeric(ref n) => fmt::Display::fmt(n, f),
+ Identifier::AlphaNumeric(ref s) => fmt::Display::fmt(s, f),
+ }
+ }
+}
+
+#[cfg(feature = "serde")]
+impl Serialize for Identifier {
+ fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
+ where S: Serializer
+ {
+ // Serialize Identifier as a number or string.
+ match *self {
+ Identifier::Numeric(n) => serializer.serialize_u64(n),
+ Identifier::AlphaNumeric(ref s) => serializer.serialize_str(s),
+ }
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<'de> Deserialize<'de> for Identifier {
+ fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
+ where D: Deserializer<'de>
+ {
+ struct IdentifierVisitor;
+
+ // Deserialize Identifier from a number or string.
+ impl<'de> Visitor<'de> for IdentifierVisitor {
+ type Value = Identifier;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a SemVer pre-release or build identifier")
+ }
+
+ fn visit_u64<E>(self, numeric: u64) -> result::Result<Self::Value, E>
+ where E: de::Error
+ {
+ Ok(Identifier::Numeric(numeric))
+ }
+
+ fn visit_str<E>(self, alphanumeric: &str) -> result::Result<Self::Value, E>
+ where E: de::Error
+ {
+ Ok(Identifier::AlphaNumeric(alphanumeric.to_owned()))
+ }
+ }
+
+ deserializer.deserialize_any(IdentifierVisitor)
+ }
+}
+
+/// Represents a version number conforming to the semantic versioning scheme.
+#[derive(Clone, Eq, Debug)]
+pub struct Version {
+ /// The major version, to be incremented on incompatible changes.
+ pub major: u64,
+ /// The minor version, to be incremented when functionality is added in a
+ /// backwards-compatible manner.
+ pub minor: u64,
+ /// The patch version, to be incremented when backwards-compatible bug
+ /// fixes are made.
+ pub patch: u64,
+ /// The pre-release version identifier, if one exists.
+ pub pre: Vec<Identifier>,
+ /// The build metadata, ignored when determining version precedence.
+ pub build: Vec<Identifier>,
+}
+
+impl From<semver_parser::version::Version> for Version {
+ fn from(other: semver_parser::version::Version) -> Version {
+ Version {
+ major: other.major,
+ minor: other.minor,
+ patch: other.patch,
+ pre: other.pre.into_iter().map(From::from).collect(),
+ build: other.build.into_iter().map(From::from).collect(),
+ }
+ }
+}
+
+#[cfg(feature = "serde")]
+impl Serialize for Version {
+ fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
+ where S: Serializer
+ {
+ // Serialize Version as a string.
+ serializer.collect_str(self)
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<'de> Deserialize<'de> for Version {
+ fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
+ where D: Deserializer<'de>
+ {
+ struct VersionVisitor;
+
+ // Deserialize Version from a string.
+ impl<'de> Visitor<'de> for VersionVisitor {
+ type Value = Version;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a SemVer version as a string")
+ }
+
+ fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E>
+ where E: de::Error
+ {
+ Version::parse(v).map_err(de::Error::custom)
+ }
+ }
+
+ deserializer.deserialize_str(VersionVisitor)
+ }
+}
+
+/// An error type for this crate
+///
+/// Currently, just a generic error. Will make this nicer later.
+#[derive(Clone,PartialEq,Debug,PartialOrd)]
+pub enum SemVerError {
+ /// An error ocurred while parsing.
+ ParseError(String),
+}
+
+impl fmt::Display for SemVerError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ &SemVerError::ParseError(ref m) => write!(f, "{}", m),
+ }
+ }
+}
+
+impl Error for SemVerError {
+ fn description(&self) -> &str {
+ match self {
+ &SemVerError::ParseError(ref m) => m,
+ }
+ }
+}
+
+/// A Result type for errors
+pub type Result<T> = result::Result<T, SemVerError>;
+
+impl Version {
+
+ /// Contructs the simple case without pre or build.
+ pub fn new(major: u64, minor: u64, patch: u64) -> Version {
+ Version {
+ major: major,
+ minor: minor,
+ patch: patch,
+ pre: Vec::new(),
+ build: Vec::new()
+ }
+ }
+
+ /// Parse a string into a semver object.
+ pub fn parse(version: &str) -> Result<Version> {
+ let res = semver_parser::version::parse(version);
+
+ match res {
+ // Convert plain String error into proper ParseError
+ Err(e) => Err(SemVerError::ParseError(e)),
+ Ok(v) => Ok(From::from(v)),
+ }
+ }
+
+ /// Clears the build metadata
+ fn clear_metadata(&mut self) {
+ self.build = Vec::new();
+ self.pre = Vec::new();
+ }
+
+ /// Increments the patch number for this Version (Must be mutable)
+ pub fn increment_patch(&mut self) {
+ self.patch += 1;
+ self.clear_metadata();
+ }
+
+ /// Increments the minor version number for this Version (Must be mutable)
+ ///
+ /// As instructed by section 7 of the spec, the patch number is reset to 0.
+ pub fn increment_minor(&mut self) {
+ self.minor += 1;
+ self.patch = 0;
+ self.clear_metadata();
+ }
+
+ /// Increments the major version number for this Version (Must be mutable)
+ ///
+ /// As instructed by section 8 of the spec, the minor and patch numbers are
+ /// reset to 0
+ pub fn increment_major(&mut self) {
+ self.major += 1;
+ self.minor = 0;
+ self.patch = 0;
+ self.clear_metadata();
+ }
+
+ /// Checks to see if the current Version is in pre-release status
+ pub fn is_prerelease(&self) -> bool {
+ !self.pre.is_empty()
+ }
+}
+
+impl str::FromStr for Version {
+ type Err = SemVerError;
+
+ fn from_str(s: &str) -> Result<Version> {
+ Version::parse(s)
+ }
+}
+
+impl fmt::Display for Version {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch));
+ if !self.pre.is_empty() {
+ try!(write!(f, "-"));
+ for (i, x) in self.pre.iter().enumerate() {
+ if i != 0 {
+ try!(write!(f, "."))
+ }
+ try!(write!(f, "{}", x));
+ }
+ }
+ if !self.build.is_empty() {
+ try!(write!(f, "+"));
+ for (i, x) in self.build.iter().enumerate() {
+ if i != 0 {
+ try!(write!(f, "."))
+ }
+ try!(write!(f, "{}", x));
+ }
+ }
+ Ok(())
+ }
+}
+
+impl cmp::PartialEq for Version {
+ #[inline]
+ fn eq(&self, other: &Version) -> bool {
+ // We should ignore build metadata here, otherwise versions v1 and v2
+ // can exist such that !(v1 < v2) && !(v1 > v2) && v1 != v2, which
+ // violate strict total ordering rules.
+ self.major == other.major && self.minor == other.minor && self.patch == other.patch &&
+ self.pre == other.pre
+ }
+}
+
+impl cmp::PartialOrd for Version {
+ fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl cmp::Ord for Version {
+ fn cmp(&self, other: &Version) -> Ordering {
+ match self.major.cmp(&other.major) {
+ Ordering::Equal => {}
+ r => return r,
+ }
+
+ match self.minor.cmp(&other.minor) {
+ Ordering::Equal => {}
+ r => return r,
+ }
+
+ match self.patch.cmp(&other.patch) {
+ Ordering::Equal => {}
+ r => return r,
+ }
+
+ // NB: semver spec says 0.0.0-pre < 0.0.0
+ // but the version of ord defined for vec
+ // says that [] < [pre] so we alter it here
+ match (self.pre.len(), other.pre.len()) {
+ (0, 0) => Ordering::Equal,
+ (0, _) => Ordering::Greater,
+ (_, 0) => Ordering::Less,
+ (_, _) => self.pre.cmp(&other.pre),
+ }
+ }
+}
+
+impl hash::Hash for Version {
+ fn hash<H: hash::Hasher>(&self, into: &mut H) {
+ self.major.hash(into);
+ self.minor.hash(into);
+ self.patch.hash(into);
+ self.pre.hash(into);
+ }
+}
+
+impl From<(u64,u64,u64)> for Version {
+ fn from(tuple: (u64,u64,u64)) -> Version {
+ let (major, minor, patch) = tuple;
+ Version::new(major, minor, patch)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::result;
+ use super::Version;
+ use super::Identifier;
+ use super::SemVerError;
+
+ #[test]
+ fn test_parse() {
+ fn parse_error(e: &str) -> result::Result<Version, SemVerError> {
+ return Err(SemVerError::ParseError(e.to_string()));
+ }
+
+ assert_eq!(Version::parse(""),
+ parse_error("Error parsing major identifier"));
+ assert_eq!(Version::parse(" "),
+ parse_error("Error parsing major identifier"));
+ assert_eq!(Version::parse("1"),
+ parse_error("Expected dot"));
+ assert_eq!(Version::parse("1.2"),
+ parse_error("Expected dot"));
+ assert_eq!(Version::parse("1.2.3-"),
+ parse_error("Error parsing prerelease"));
+ assert_eq!(Version::parse("a.b.c"),
+ parse_error("Error parsing major identifier"));
+ assert_eq!(Version::parse("1.2.3 abc"),
+ parse_error("Extra junk after valid version: abc"));
+
+ assert_eq!(Version::parse("1.2.3"),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: Vec::new(),
+ }));
+
+ assert_eq!(Version::parse("1.2.3"),
+ Ok(Version::new(1,2,3)));
+
+ assert_eq!(Version::parse(" 1.2.3 "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: Vec::new(),
+ }));
+ assert_eq!(Version::parse("1.2.3-alpha1"),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: Vec::new(),
+ }));
+ assert_eq!(Version::parse(" 1.2.3-alpha1 "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: Vec::new(),
+ }));
+ assert_eq!(Version::parse("1.2.3+build5"),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(Version::parse(" 1.2.3+build5 "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(Version::parse("1.2.3-alpha1+build5"),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(Version::parse(" 1.2.3-alpha1+build5 "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(Version::parse("1.2.3-1.alpha1.9+build5.7.3aedf "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::Numeric(1),
+ Identifier::AlphaNumeric(String::from("alpha1")),
+ Identifier::Numeric(9),
+ ],
+ build: vec![Identifier::AlphaNumeric(String::from("build5")),
+ Identifier::Numeric(7),
+ Identifier::AlphaNumeric(String::from("3aedf")),
+ ],
+ }));
+ assert_eq!(Version::parse("0.4.0-beta.1+0851523"),
+ Ok(Version {
+ major: 0,
+ minor: 4,
+ patch: 0,
+ pre: vec![Identifier::AlphaNumeric(String::from("beta")),
+ Identifier::Numeric(1),
+ ],
+ build: vec![Identifier::AlphaNumeric(String::from("0851523"))],
+ }));
+
+ }
+
+ #[test]
+ fn test_increment_patch() {
+ let mut buggy_release = Version::parse("0.1.0").unwrap();
+ buggy_release.increment_patch();
+ assert_eq!(buggy_release, Version::parse("0.1.1").unwrap());
+ }
+
+ #[test]
+ fn test_increment_minor() {
+ let mut feature_release = Version::parse("1.4.6").unwrap();
+ feature_release.increment_minor();
+ assert_eq!(feature_release, Version::parse("1.5.0").unwrap());
+ }
+
+ #[test]
+ fn test_increment_major() {
+ let mut chrome_release = Version::parse("46.1.246773").unwrap();
+ chrome_release.increment_major();
+ assert_eq!(chrome_release, Version::parse("47.0.0").unwrap());
+ }
+
+ #[test]
+ fn test_increment_keep_prerelease() {
+ let mut release = Version::parse("1.0.0-alpha").unwrap();
+ release.increment_patch();
+
+ assert_eq!(release, Version::parse("1.0.1").unwrap());
+
+ release.increment_minor();
+
+ assert_eq!(release, Version::parse("1.1.0").unwrap());
+
+ release.increment_major();
+
+ assert_eq!(release, Version::parse("2.0.0").unwrap());
+ }
+
+
+ #[test]
+ fn test_increment_clear_metadata() {
+ let mut release = Version::parse("1.0.0+4442").unwrap();
+ release.increment_patch();
+
+ assert_eq!(release, Version::parse("1.0.1").unwrap());
+ release = Version::parse("1.0.1+hello").unwrap();
+
+ release.increment_minor();
+
+ assert_eq!(release, Version::parse("1.1.0").unwrap());
+ release = Version::parse("1.1.3747+hello").unwrap();
+
+ release.increment_major();
+
+ assert_eq!(release, Version::parse("2.0.0").unwrap());
+ }
+
+ #[test]
+ fn test_eq() {
+ assert_eq!(Version::parse("1.2.3"), Version::parse("1.2.3"));
+ assert_eq!(Version::parse("1.2.3-alpha1"),
+ Version::parse("1.2.3-alpha1"));
+ assert_eq!(Version::parse("1.2.3+build.42"),
+ Version::parse("1.2.3+build.42"));
+ assert_eq!(Version::parse("1.2.3-alpha1+42"),
+ Version::parse("1.2.3-alpha1+42"));
+ assert_eq!(Version::parse("1.2.3+23"), Version::parse("1.2.3+42"));
+ }
+
+ #[test]
+ fn test_ne() {
+ assert!(Version::parse("0.0.0") != Version::parse("0.0.1"));
+ assert!(Version::parse("0.0.0") != Version::parse("0.1.0"));
+ assert!(Version::parse("0.0.0") != Version::parse("1.0.0"));
+ assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
+ }
+
+ #[test]
+ fn test_show() {
+ assert_eq!(format!("{}", Version::parse("1.2.3").unwrap()),
+ "1.2.3".to_string());
+ assert_eq!(format!("{}", Version::parse("1.2.3-alpha1").unwrap()),
+ "1.2.3-alpha1".to_string());
+ assert_eq!(format!("{}", Version::parse("1.2.3+build.42").unwrap()),
+ "1.2.3+build.42".to_string());
+ assert_eq!(format!("{}", Version::parse("1.2.3-alpha1+42").unwrap()),
+ "1.2.3-alpha1+42".to_string());
+ }
+
+ #[test]
+ fn test_to_string() {
+ assert_eq!(Version::parse("1.2.3").unwrap().to_string(),
+ "1.2.3".to_string());
+ assert_eq!(Version::parse("1.2.3-alpha1").unwrap().to_string(),
+ "1.2.3-alpha1".to_string());
+ assert_eq!(Version::parse("1.2.3+build.42").unwrap().to_string(),
+ "1.2.3+build.42".to_string());
+ assert_eq!(Version::parse("1.2.3-alpha1+42").unwrap().to_string(),
+ "1.2.3-alpha1+42".to_string());
+ }
+
+ #[test]
+ fn test_lt() {
+ assert!(Version::parse("0.0.0") < Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.0.0") < Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.0") < Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3"));
+ assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3-alpha2"));
+ assert!(!(Version::parse("1.2.3-alpha2") < Version::parse("1.2.3-alpha2")));
+ assert!(!(Version::parse("1.2.3+23") < Version::parse("1.2.3+42")));
+ }
+
+ #[test]
+ fn test_le() {
+ assert!(Version::parse("0.0.0") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.0.0") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.0") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3-alpha1") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3-alpha2") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3+23") <= Version::parse("1.2.3+42"));
+ }
+
+ #[test]
+ fn test_gt() {
+ assert!(Version::parse("1.2.3-alpha2") > Version::parse("0.0.0"));
+ assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.0.0"));
+ assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0"));
+ assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha1"));
+ assert!(Version::parse("1.2.3") > Version::parse("1.2.3-alpha2"));
+ assert!(!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha2")));
+ assert!(!(Version::parse("1.2.3+23") > Version::parse("1.2.3+42")));
+ }
+
+ #[test]
+ fn test_ge() {
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("0.0.0"));
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.0.0"));
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.0"));
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha1"));
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3+23") >= Version::parse("1.2.3+42"));
+ }
+
+ #[test]
+ fn test_prerelease_check() {
+ assert!(Version::parse("1.0.0").unwrap().is_prerelease() == false);
+ assert!(Version::parse("0.0.1").unwrap().is_prerelease() == false);
+ assert!(Version::parse("4.1.4-alpha").unwrap().is_prerelease());
+ assert!(Version::parse("1.0.0-beta294296").unwrap().is_prerelease());
+ }
+
+ #[test]
+ fn test_spec_order() {
+ let vs = ["1.0.0-alpha",
+ "1.0.0-alpha.1",
+ "1.0.0-alpha.beta",
+ "1.0.0-beta",
+ "1.0.0-beta.2",
+ "1.0.0-beta.11",
+ "1.0.0-rc.1",
+ "1.0.0"];
+ let mut i = 1;
+ while i < vs.len() {
+ let a = Version::parse(vs[i - 1]);
+ let b = Version::parse(vs[i]);
+ assert!(a < b, "nope {:?} < {:?}", a, b);
+ i += 1;
+ }
+ }
+
+ #[test]
+ fn test_from_str() {
+ assert_eq!("1.2.3".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: Vec::new(),
+ }));
+ assert_eq!(" 1.2.3 ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: Vec::new(),
+ }));
+ assert_eq!("1.2.3-alpha1".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: Vec::new(),
+ }));
+ assert_eq!(" 1.2.3-alpha1 ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: Vec::new(),
+ }));
+ assert_eq!("1.2.3+build5".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(" 1.2.3+build5 ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!("1.2.3-alpha1+build5".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(" 1.2.3-alpha1+build5 ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!("1.2.3-1.alpha1.9+build5.7.3aedf ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::Numeric(1),
+ Identifier::AlphaNumeric(String::from("alpha1")),
+ Identifier::Numeric(9),
+ ],
+ build: vec![Identifier::AlphaNumeric(String::from("build5")),
+ Identifier::Numeric(7),
+ Identifier::AlphaNumeric(String::from("3aedf")),
+ ],
+ }));
+ assert_eq!("0.4.0-beta.1+0851523".parse(),
+ Ok(Version {
+ major: 0,
+ minor: 4,
+ patch: 0,
+ pre: vec![Identifier::AlphaNumeric(String::from("beta")),
+ Identifier::Numeric(1),
+ ],
+ build: vec![Identifier::AlphaNumeric(String::from("0851523"))],
+ }));
+
+ }
+
+ #[test]
+ fn test_from_str_errors() {
+ fn parse_error(e: &str) -> result::Result<Version, SemVerError> {
+ return Err(SemVerError::ParseError(e.to_string()));
+ }
+
+ assert_eq!("".parse(), parse_error("Error parsing major identifier"));
+ assert_eq!(" ".parse(), parse_error("Error parsing major identifier"));
+ assert_eq!("1".parse(), parse_error("Expected dot"));
+ assert_eq!("1.2".parse(),
+ parse_error("Expected dot"));
+ assert_eq!("1.2.3-".parse(),
+ parse_error("Error parsing prerelease"));
+ assert_eq!("a.b.c".parse(),
+ parse_error("Error parsing major identifier"));
+ assert_eq!("1.2.3 abc".parse(),
+ parse_error("Extra junk after valid version: abc"));
+ }
+}