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