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