Increase strictness of 'Version::parse()'.

Fixes #11.
This commit is contained in:
mibac138
2020-05-02 19:34:43 +02:00
committed by Sergio Benitez
parent 2cd670b246
commit 4ef0226d68
+60 -30
View File
@@ -1,7 +1,7 @@
use std::fmt;
/// Version number: `major.minor.patch`, ignoring release channel.
#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
#[derive(PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
pub struct Version(u64);
impl Version {
@@ -55,21 +55,25 @@ impl Version {
/// assert!(version.exactly("1.0.0"));
///
/// assert!(Version::parse("one.two.three").is_none());
/// assert!(Version::parse("1.65536.2").is_none());
/// assert!(Version::parse("1. 2").is_none());
/// assert!(Version::parse("").is_none());
/// assert!(Version::parse("1.").is_none());
/// assert!(Version::parse("1.2.3.4").is_none());
/// ```
pub fn parse(version: &str) -> Option<Version> {
let mut mmp: Vec<u16> = version.split('-')
let splits = version.split('-')
.nth(0)
.unwrap_or("")
.split('.')
.filter_map(|s| s.parse::<u16>().ok())
.collect();
.map(|s| s.parse::<u16>().ok());
if mmp.is_empty() {
return None
}
while mmp.len() < 3 {
mmp.push(0);
let mut mmp = [0u16; 3];
for (i, split) in splits.enumerate() {
mmp[i] = match (i, split) {
(3, _) | (_, None) => return None,
(_, Some(v)) => v,
};
}
let (maj, min, patch) = (mmp[0] as u64, mmp[1] as u64, mmp[2] as u64);
@@ -94,6 +98,11 @@ impl Version {
///
/// assert!(!version.at_least("1.35.1"));
/// assert!(!version.at_least("1.55.0"));
///
/// let version = Version::parse("1.12.5").unwrap();
///
/// assert!(version.at_least("1.12.0"));
/// assert!(!version.at_least("1.35.0"));
/// ```
pub fn at_least(&self, version: &str) -> bool {
Version::parse(version)
@@ -158,35 +167,56 @@ impl fmt::Display for Version {
}
}
impl fmt::Debug for Version {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// We don't use `debug_*` because it's not available in `1.0.0`.
write!(f, "Version({:?}, {:?})", self.0, self.to_mmp())
}
}
#[cfg(test)]
mod tests {
use super::Version;
macro_rules! check_mmp {
($s:expr => ($x:expr, $y:expr, $z:expr)) => (
if let Some(v) = Version::parse($s) {
if v.to_mmp() != ($x, $y, $z) {
panic!("{:?} ({}) didn't parse as {}.{}.{}.", $s, v, $x, $y, $z);
}
} else {
panic!("{:?} didn't parse for mmp testing.", $s);
}
macro_rules! assert_mmp {
// We don't use `.into::<Option<_>>` because it's not available in 1.0.
// We don't use the message part of `assert!` for the same reason.
($s:expr, None) => (
assert_eq!(Version::parse($s), None);
);
($s:expr, $mmp:expr) => (
assert_eq!(Version::parse($s).map(|v| v.to_mmp()), Some($mmp));
)
}
#[test]
fn test_str_to_mmp() {
check_mmp!("1.18.0" => (1, 18, 0));
check_mmp!("3.19.0" => (3, 19, 0));
check_mmp!("1.19.0-nightly" => (1, 19, 0));
check_mmp!("1.12.2349" => (1, 12, 2349));
check_mmp!("0.12" => (0, 12, 0));
check_mmp!("1.12.5" => (1, 12, 5));
check_mmp!("1.12" => (1, 12, 0));
check_mmp!("1" => (1, 0, 0));
check_mmp!("1.4.4-nightly (d84693b93 2017-07-09)" => (1, 4, 4));
check_mmp!("1.58879.4478-dev" => (1, 58879, 4478));
check_mmp!("1.58879.4478-dev (d84693b93 2017-07-09)" => (1, 58879, 4478));
assert_mmp!("1", (1, 0, 0));
assert_mmp!("1.2", (1, 2, 0));
assert_mmp!("1.18.0", (1, 18, 0));
assert_mmp!("3.19.0", (3, 19, 0));
assert_mmp!("1.19.0-nightly", (1, 19, 0));
assert_mmp!("1.12.2349", (1, 12, 2349));
assert_mmp!("0.12", (0, 12, 0));
assert_mmp!("1.12.5", (1, 12, 5));
assert_mmp!("1.12", (1, 12, 0));
assert_mmp!("1", (1, 0, 0));
assert_mmp!("1.4.4-nightly (d84693b93 2017-07-09))", (1, 4, 4));
assert_mmp!("1.58879.4478-dev", (1, 58879, 4478));
assert_mmp!("1.58879.4478-dev (d84693b93 2017-07-09))", (1, 58879, 4478));
}
#[test]
fn test_malformed() {
assert_mmp!("1.65536.2", None);
assert_mmp!("-1.2.3", None);
assert_mmp!("1. 2", None);
assert_mmp!("", None);
assert_mmp!(" ", None);
assert_mmp!(".", None);
assert_mmp!("one", None);
assert_mmp!("1.", None);
assert_mmp!("1.2.3.4.5.6", None);
}
#[test]