use parser::{self, Parser};
use std::str::FromStr;
use version::Identifier;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct VersionReq {
pub predicates: Vec<Predicate>,
}
#[derive(PartialOrd, Ord, PartialEq, Eq, Debug, Hash, Clone)]
pub enum WildcardVersion {
Minor,
Patch,
}
#[derive(PartialOrd, Ord, PartialEq, Eq, Debug, Clone, Hash)]
pub enum Op {
Ex,
Gt,
GtEq,
Lt,
LtEq,
Tilde,
Compatible,
Wildcard(WildcardVersion),
}
impl FromStr for Op {
type Err = String;
fn from_str(s: &str) -> Result<Op, String> {
match s {
"=" => Ok(Op::Ex),
">" => Ok(Op::Gt),
">=" => Ok(Op::GtEq),
"<" => Ok(Op::Lt),
"<=" => Ok(Op::LtEq),
"~" => Ok(Op::Tilde),
"^" => Ok(Op::Compatible),
_ => Err(String::from("Could not parse Op")),
}
}
}
#[derive(PartialEq, Eq, Debug, Clone, Hash, PartialOrd, Ord)]
pub struct Predicate {
pub op: Op,
pub major: u64,
pub minor: Option<u64>,
pub patch: Option<u64>,
pub pre: Vec<Identifier>,
}
pub fn parse_predicate<'input>(
input: &'input str,
) -> Result<Option<Predicate>, parser::Error<'input>> {
let mut parser = Parser::new(input)?;
let predicate = parser.predicate()?;
if !parser.is_eof() {
return Err(parser::Error::MoreInput(parser.tail()?));
}
Ok(predicate)
}
pub fn parse<'input>(input: &'input str) -> Result<VersionReq, parser::Error<'input>> {
let mut parser = Parser::new(input)?;
let range = parser.range()?;
if !parser.is_eof() {
return Err(parser::Error::MoreInput(parser.tail()?));
}
Ok(range)
}
#[cfg(test)]
mod tests {
use super::*;
use range;
use version::Identifier;
#[test]
fn test_parsing_wildcards() {
assert_eq!(
Op::Wildcard(WildcardVersion::Patch),
range::parse("1.0.*").unwrap().predicates[0].op
);
assert_eq!(
Op::Wildcard(WildcardVersion::Patch),
range::parse("1.*.*").unwrap().predicates[0].op
);
assert_eq!(
Op::Wildcard(WildcardVersion::Minor),
parse("1.*.0").unwrap().predicates[0].op
);
}
#[test]
fn test_parsing_default() {
let r = range::parse("1.0.0").unwrap();
assert_eq!(
Predicate {
op: Op::Compatible,
major: 1,
minor: Some(0),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_exact_01() {
let r = range::parse("=1.0.0").unwrap();
assert_eq!(
Predicate {
op: Op::Ex,
major: 1,
minor: Some(0),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_exact_02() {
let r = range::parse("=0.9.0").unwrap();
assert_eq!(
Predicate {
op: Op::Ex,
major: 0,
minor: Some(9),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_exact_03() {
let r = range::parse("=0.1.0-beta2.a").unwrap();
assert_eq!(
Predicate {
op: Op::Ex,
major: 0,
minor: Some(1),
patch: Some(0),
pre: vec![
Identifier::AlphaNumeric(String::from("beta2")),
Identifier::AlphaNumeric(String::from("a")),
],
},
r.predicates[0]
);
}
#[test]
pub fn test_parsing_greater_than() {
let r = range::parse("> 1.0.0").unwrap();
assert_eq!(
Predicate {
op: Op::Gt,
major: 1,
minor: Some(0),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
pub fn test_parsing_greater_than_01() {
let r = range::parse(">= 1.0.0").unwrap();
assert_eq!(
Predicate {
op: Op::GtEq,
major: 1,
minor: Some(0),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
pub fn test_parsing_greater_than_02() {
let r = range::parse(">= 2.1.0-alpha2").unwrap();
assert_eq!(
Predicate {
op: Op::GtEq,
major: 2,
minor: Some(1),
patch: Some(0),
pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))],
},
r.predicates[0]
);
}
#[test]
pub fn test_parsing_less_than() {
let r = range::parse("< 1.0.0").unwrap();
assert_eq!(
Predicate {
op: Op::Lt,
major: 1,
minor: Some(0),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
pub fn test_parsing_less_than_eq() {
let r = range::parse("<= 2.1.0-alpha2").unwrap();
assert_eq!(
Predicate {
op: Op::LtEq,
major: 2,
minor: Some(1),
patch: Some(0),
pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))],
},
r.predicates[0]
);
}
#[test]
pub fn test_parsing_tilde() {
let r = range::parse("~1").unwrap();
assert_eq!(
Predicate {
op: Op::Tilde,
major: 1,
minor: None,
patch: None,
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
pub fn test_parsing_compatible() {
let r = range::parse("^0").unwrap();
assert_eq!(
Predicate {
op: Op::Compatible,
major: 0,
minor: None,
patch: None,
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_blank() {
let r = range::parse("").unwrap();
assert!(r.predicates.is_empty());
}
#[test]
fn test_parsing_wildcard() {
let r = range::parse("*").unwrap();
assert!(r.predicates.is_empty());
}
#[test]
fn test_uppercase_prereleases() {
assert_eq!(
vec![Identifier::AlphaNumeric("Foo".to_string())],
range::parse("0-Foo").unwrap().predicates[0].pre
);
assert_eq!(
vec![Identifier::AlphaNumeric("X".to_string())],
range::parse("0-X").unwrap().predicates[0].pre
);
}
#[test]
fn test_empty_prerelease() {
assert!(range::parse("0-").is_err());
}
#[test]
fn test_parsing_x() {
let r = range::parse("x").unwrap();
assert!(r.predicates.is_empty());
}
#[test]
fn test_parsing_capital_x() {
let r = range::parse("X").unwrap();
assert!(r.predicates.is_empty());
}
#[test]
fn test_parsing_wildcard_star_star() {
let r = range::parse("1.*.*").unwrap();
assert_eq!(
Predicate {
op: Op::Wildcard(WildcardVersion::Patch),
major: 1,
minor: None,
patch: None,
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_minor_wildcard_star() {
let r = range::parse("1.*").unwrap();
assert_eq!(
Predicate {
op: Op::Wildcard(WildcardVersion::Minor),
major: 1,
minor: None,
patch: None,
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_minor_wildcard_star_patch() {
let r = range::parse("1.*.0").unwrap();
assert_eq!(
Predicate {
op: Op::Wildcard(WildcardVersion::Minor),
major: 1,
minor: None,
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_minor_wildcard_x() {
let r = range::parse("1.x").unwrap();
assert_eq!(
Predicate {
op: Op::Wildcard(WildcardVersion::Minor),
major: 1,
minor: None,
patch: None,
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_minor_wildcard_capital_x() {
let r = range::parse("1.X").unwrap();
assert_eq!(
Predicate {
op: Op::Wildcard(WildcardVersion::Minor),
major: 1,
minor: None,
patch: None,
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_patch_wildcard_star() {
let r = range::parse("1.2.*").unwrap();
assert_eq!(
Predicate {
op: Op::Wildcard(WildcardVersion::Patch),
major: 1,
minor: Some(2),
patch: None,
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_patch_wildcard_x() {
let r = range::parse("1.2.x").unwrap();
assert_eq!(
Predicate {
op: Op::Wildcard(WildcardVersion::Patch),
major: 1,
minor: Some(2),
patch: None,
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
fn test_parsing_patch_wildcard_capital_x() {
let r = range::parse("1.2.X").unwrap();
assert_eq!(
Predicate {
op: Op::Wildcard(WildcardVersion::Patch),
major: 1,
minor: Some(2),
patch: None,
pre: Vec::new(),
},
r.predicates[0]
);
}
#[test]
pub fn test_multiple_01() {
let r = range::parse("> 0.0.9, <= 2.5.3").unwrap();
assert_eq!(
Predicate {
op: Op::Gt,
major: 0,
minor: Some(0),
patch: Some(9),
pre: Vec::new(),
},
r.predicates[0]
);
assert_eq!(
Predicate {
op: Op::LtEq,
major: 2,
minor: Some(5),
patch: Some(3),
pre: Vec::new(),
},
r.predicates[1]
);
}
#[test]
pub fn test_multiple_02() {
let r = range::parse("0.3.0, 0.4.0").unwrap();
assert_eq!(
Predicate {
op: Op::Compatible,
major: 0,
minor: Some(3),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
assert_eq!(
Predicate {
op: Op::Compatible,
major: 0,
minor: Some(4),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[1]
);
}
#[test]
pub fn test_multiple_03() {
let r = range::parse("<= 0.2.0, >= 0.5.0").unwrap();
assert_eq!(
Predicate {
op: Op::LtEq,
major: 0,
minor: Some(2),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
assert_eq!(
Predicate {
op: Op::GtEq,
major: 0,
minor: Some(5),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[1]
);
}
#[test]
pub fn test_multiple_04() {
let r = range::parse("0.1.0, 0.1.4, 0.1.6").unwrap();
assert_eq!(
Predicate {
op: Op::Compatible,
major: 0,
minor: Some(1),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
assert_eq!(
Predicate {
op: Op::Compatible,
major: 0,
minor: Some(1),
patch: Some(4),
pre: Vec::new(),
},
r.predicates[1]
);
assert_eq!(
Predicate {
op: Op::Compatible,
major: 0,
minor: Some(1),
patch: Some(6),
pre: Vec::new(),
},
r.predicates[2]
);
}
#[test]
pub fn test_multiple_05() {
let r = range::parse(">=0.5.1-alpha3, <0.6").unwrap();
assert_eq!(
Predicate {
op: Op::GtEq,
major: 0,
minor: Some(5),
patch: Some(1),
pre: vec![Identifier::AlphaNumeric(String::from("alpha3"))],
},
r.predicates[0]
);
assert_eq!(
Predicate {
op: Op::Lt,
major: 0,
minor: Some(6),
patch: None,
pre: Vec::new(),
},
r.predicates[1]
);
}
#[test]
pub fn test_multiple_06() {
let r = range::parse("<= 0.2.0 >= 0.5.0").unwrap();
assert_eq!(
Predicate {
op: Op::LtEq,
major: 0,
minor: Some(2),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[0]
);
assert_eq!(
Predicate {
op: Op::GtEq,
major: 0,
minor: Some(5),
patch: Some(0),
pre: Vec::new(),
},
r.predicates[1]
);
}
#[test]
fn test_parse_build_metadata_with_predicate() {
assert_eq!(
range::parse("^1.2.3+meta").unwrap().predicates[0].op,
Op::Compatible
);
assert_eq!(
range::parse("~1.2.3+meta").unwrap().predicates[0].op,
Op::Tilde
);
assert_eq!(
range::parse("=1.2.3+meta").unwrap().predicates[0].op,
Op::Ex
);
assert_eq!(
range::parse("<=1.2.3+meta").unwrap().predicates[0].op,
Op::LtEq
);
assert_eq!(
range::parse(">=1.2.3+meta").unwrap().predicates[0].op,
Op::GtEq
);
assert_eq!(
range::parse("<1.2.3+meta").unwrap().predicates[0].op,
Op::Lt
);
assert_eq!(
range::parse(">1.2.3+meta").unwrap().predicates[0].op,
Op::Gt
);
}
#[test]
pub fn test_parse_errors() {
assert!(range::parse("\0").is_err());
assert!(range::parse(">= >= 0.0.2").is_err());
assert!(range::parse(">== 0.0.2").is_err());
assert!(range::parse("a.0.0").is_err());
assert!(range::parse("1.0.0-").is_err());
assert!(range::parse(">=").is_err());
assert!(range::parse("> 0.1.0,").is_err());
assert!(range::parse("> 0.3.0, ,").is_err());
assert!(range::parse("> 0. 1").is_err());
}
#[test]
pub fn test_large_major_version() {
assert!(range::parse("18446744073709551617.0.0").is_err());
}
#[test]
pub fn test_large_minor_version() {
assert!(range::parse("0.18446744073709551617.0").is_err());
}
#[test]
pub fn test_large_patch_version() {
assert!(range::parse("0.0.18446744073709551617").is_err());
}
#[test]
pub fn test_op_partialord_lt() {
let expect_less = Op::Ex;
let other = Op::Gt;
assert!(expect_less.lt(&other));
}
#[test]
pub fn test_op_partialord_le() {
let strictly_lt = Op::Ex;
let other = Op::Lt;
assert!(strictly_lt.le(&other));
assert!(other.le(&other));
}
#[test]
pub fn test_op_partialord_gt() {
let expect_gt = Op::Compatible;
let other = Op::GtEq;
assert!(expect_gt.gt(&other));
}
#[test]
pub fn test_op_partialord_ge() {
let strictly_gt = Op::Compatible;
let other = Op::Tilde;
assert!(strictly_gt.ge(&other));
assert!(other.ge(&other));
}
#[test]
pub fn test_wildcard_partialord_lt() {
let expect_less = WildcardVersion::Minor;
let other = WildcardVersion::Patch;
assert!(expect_less.lt(&other));
}
#[test]
pub fn test_wildcard_partialord_le() {
let strictly_lt = WildcardVersion::Minor;
let other = WildcardVersion::Patch;
assert!(strictly_lt.le(&other));
assert!(other.le(&other));
}
#[test]
pub fn test_wildcard_partialord_gt() {
let expect_greater = WildcardVersion::Patch;
let other = WildcardVersion::Minor;
assert!(expect_greater.gt(&other));
}
#[test]
pub fn test_wildcard_partialord_ge() {
let strictly_gt = WildcardVersion::Patch;
let other = WildcardVersion::Minor;
assert!(strictly_gt.ge(&other));
assert!(other.ge(&other));
}
}