use crate::errors::*;
use semver::Version;
pub fn bump_is_greater(current: &str, other: &str) -> Result<bool> {
Ok(Version::parse(other)? > Version::parse(current)?)
}
pub fn cmp_versions(a: &str, b: &str) -> Result<std::cmp::Ordering> {
Ok(Version::parse(a)?.cmp(&Version::parse(b)?))
}
pub(crate) fn cmp_releases_newest_first(a: &str, b: &str) -> std::cmp::Ordering {
use std::cmp::Ordering;
match (Version::parse(a), Version::parse(b)) {
(Ok(a), Ok(b)) => b.cmp(&a),
(Ok(_), Err(_)) => Ordering::Less,
(Err(_), Ok(_)) => Ordering::Greater,
(Err(_), Err(_)) => Ordering::Equal,
}
}
pub fn bump_is_compatible(current: &str, other: &str) -> Result<bool> {
let current = Version::parse(current)?;
let other = Version::parse(other)?;
Ok(if !current.pre.is_empty() {
current.major == other.major
&& ((other.minor > current.minor) || (current.minor == other.minor && other > current))
} else if other.major == 0 && current.major == 0 {
current.minor == other.minor && other.patch > current.patch && other.pre.is_empty()
} else if other.major > 0 {
current.major == other.major
&& ((other.minor > current.minor)
|| (current.minor == other.minor && other.patch > current.patch))
&& other.pre.is_empty()
} else {
false
})
}
pub fn bump_is_major(current: &str, other: &str) -> Result<bool> {
let current = Version::parse(current)?;
let other = Version::parse(other)?;
Ok(other.major > current.major)
}
pub fn bump_is_minor(current: &str, other: &str) -> Result<bool> {
let current = Version::parse(current)?;
let other = Version::parse(other)?;
Ok(current.major == other.major && other.minor > current.minor)
}
pub fn bump_is_patch(current: &str, other: &str) -> Result<bool> {
let current = Version::parse(current)?;
let other = Version::parse(other)?;
Ok(current.major == other.major && current.minor == other.minor && other.patch > current.patch)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_bump_greater() {
assert!(bump_is_greater("1.2.0", "1.2.3").unwrap());
assert!(bump_is_greater("0.2.0", "1.2.3").unwrap());
assert!(bump_is_greater("0.2.0", "0.2.3").unwrap());
}
#[test]
fn test_bump_is_compatible() {
assert!(!bump_is_compatible("1.2.0", "2.3.1").unwrap());
assert!(!bump_is_compatible("0.2.0", "2.3.1").unwrap());
assert!(!bump_is_compatible("1.2.3", "3.3.0").unwrap());
assert!(!bump_is_compatible("1.2.3", "0.2.0").unwrap());
assert!(!bump_is_compatible("0.2.0", "0.3.0").unwrap());
assert!(!bump_is_compatible("0.3.0", "0.2.0").unwrap());
assert!(!bump_is_compatible("1.2.3", "1.1.0").unwrap());
assert!(!bump_is_compatible("2.0.0", "2.0.0-alpha.1").unwrap());
assert!(!bump_is_compatible("1.2.3", "2.0.0-alpha.1").unwrap());
assert!(!bump_is_compatible("2.0.0-alpha.1", "3.0.0").unwrap());
assert!(bump_is_compatible("1.2.0", "1.2.3").unwrap());
assert!(bump_is_compatible("0.2.0", "0.2.3").unwrap());
assert!(bump_is_compatible("1.2.0", "1.3.3").unwrap());
assert!(bump_is_compatible("2.0.0-alpha.0", "2.0.0-alpha.1").unwrap());
assert!(bump_is_compatible("2.0.0-alpha.0", "2.0.0").unwrap());
assert!(bump_is_compatible("2.0.0-alpha.0", "2.0.1").unwrap());
assert!(bump_is_compatible("2.0.0-alpha.0", "2.1.0").unwrap());
assert!(!bump_is_compatible("2.0.5-alpha.0", "2.0.3").unwrap());
assert!(!bump_is_compatible("2.0.5-alpha.0", "2.0.5-alpha.0").unwrap());
assert!(bump_is_compatible("2.0.5-alpha.0", "2.0.5").unwrap());
assert!(bump_is_compatible("2.0.5-alpha.0", "2.0.6").unwrap());
}
#[test]
fn test_bump_is_major() {
assert!(bump_is_major("1.2.0", "2.3.1").unwrap());
assert!(bump_is_major("0.2.0", "2.3.1").unwrap());
assert!(bump_is_major("1.2.3", "3.3.0").unwrap());
assert!(!bump_is_major("1.2.3", "1.2.0").unwrap());
assert!(!bump_is_major("1.2.3", "0.2.0").unwrap());
}
#[test]
fn test_bump_is_minor() {
assert!(!bump_is_minor("1.2.0", "2.3.1").unwrap());
assert!(!bump_is_minor("0.2.0", "2.3.1").unwrap());
assert!(!bump_is_minor("1.2.3", "3.3.0").unwrap());
assert!(bump_is_minor("1.2.3", "1.3.0").unwrap());
assert!(bump_is_minor("0.2.3", "0.4.0").unwrap());
}
#[test]
fn cmp_versions_returns_equal_for_equal_versions() {
use std::cmp::Ordering;
assert_eq!(cmp_versions("1.2.3", "1.2.3").unwrap(), Ordering::Equal);
assert_eq!(cmp_versions("0.0.0", "0.0.0").unwrap(), Ordering::Equal);
assert_eq!(
cmp_versions("2.0.0-alpha.1", "2.0.0-alpha.1").unwrap(),
Ordering::Equal
);
}
#[test]
fn cmp_versions_orders_and_is_antisymmetric() {
use std::cmp::Ordering;
assert_eq!(cmp_versions("1.2.3", "2.0.0").unwrap(), Ordering::Less);
assert_eq!(cmp_versions("2.0.0", "1.2.3").unwrap(), Ordering::Greater);
for (a, b) in [
("1.0.0", "1.0.1"),
("0.9.0", "1.0.0"),
("2.0.0-alpha.1", "2.0.0"),
("1.2.3", "1.2.3"),
] {
let ab = cmp_versions(a, b).unwrap();
let ba = cmp_versions(b, a).unwrap();
assert_eq!(
ab,
ba.reverse(),
"cmp_versions({a}, {b}) must be the reverse of cmp({b}, {a})"
);
}
}
#[test]
fn cmp_versions_errors_on_unparseable() {
assert!(cmp_versions("not-a-version", "1.0.0").is_err());
assert!(cmp_versions("1.0.0", "junk").is_err());
}
#[test]
fn cmp_releases_newest_first_orders_newest_first_and_pushes_junk_last() {
use std::cmp::Ordering;
assert_eq!(cmp_releases_newest_first("2.0.0", "1.0.0"), Ordering::Less);
assert_eq!(
cmp_releases_newest_first("1.0.0", "2.0.0"),
Ordering::Greater
);
assert_eq!(cmp_releases_newest_first("1.0.0", "1.0.0"), Ordering::Equal);
assert_eq!(
cmp_releases_newest_first("1.0.0", "junk"),
Ordering::Less,
"parseable sorts before junk"
);
assert_eq!(
cmp_releases_newest_first("junk", "1.0.0"),
Ordering::Greater,
"junk sorts after parseable"
);
assert_eq!(
cmp_releases_newest_first("junk", "garbage"),
Ordering::Equal
);
}
#[test]
fn cmp_releases_newest_first_sorts_a_list_descending_with_junk_last() {
let mut versions = ["1.0.0", "junk", "2.1.0", "1.5.0", "garbage"];
versions.sort_by(|a, b| cmp_releases_newest_first(a, b));
assert_eq!(&versions[..3], &["2.1.0", "1.5.0", "1.0.0"]);
assert!(Version::parse(versions[3]).is_err());
assert!(Version::parse(versions[4]).is_err());
}
#[test]
fn test_bump_is_patch() {
assert!(!bump_is_patch("1.2.0", "2.3.1").unwrap());
assert!(!bump_is_patch("0.2.0", "2.3.1").unwrap());
assert!(!bump_is_patch("1.2.3", "3.3.0").unwrap());
assert!(!bump_is_patch("1.2.3", "1.2.3").unwrap());
assert!(bump_is_patch("1.2.0", "1.2.3").unwrap());
assert!(bump_is_patch("0.2.3", "0.2.4").unwrap());
}
}