diff --git a/src/eval.rs b/src/eval.rs index fe8a8f06..7d0e9473 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -31,30 +31,34 @@ pub(crate) fn matches_comparator(cmp: &Comparator, ver: &Version) -> bool { matches_impl(cmp, ver) && (ver.pre.is_empty() || pre_is_compatible(cmp, ver)) } // If VersionReq missing Minor, Patch, then filling them with 0 -fn fill_partial_req(cmp: &mut Comparator) { +fn fill_partial_req(cmp: &Comparator) -> Comparator { + let mut cmp = cmp.clone(); if cmp.minor.is_none() { cmp.minor = Some(0); cmp.patch = Some(0); } else if cmp.patch.is_none() { cmp.patch = Some(0); } + cmp } fn matches_prerelease_impl(cmp: &Comparator, ver: &Version) -> bool { - let cmp = &{ - let mut cmp = cmp.clone(); - match cmp.op { - Op::Greater | Op::GreaterEq | Op::Less | Op::LessEq => fill_partial_req(&mut cmp), - _ => {} - } - cmp - }; match cmp.op { Op::Exact | Op::Wildcard => matches_exact_prerelease(cmp, ver), Op::Greater => matches_greater(cmp, ver), - Op::GreaterEq => matches_exact(cmp, ver) || matches_greater(cmp, ver), - Op::Less => matches_less(cmp, ver), - Op::LessEq => matches_exact(cmp, ver) || matches_less(cmp, ver), + Op::GreaterEq => { + if matches_exact_prerelease(cmp, ver) { + return true; + } + matches_greater(cmp, ver) + } + Op::Less => matches_less(&fill_partial_req(cmp), ver), + Op::LessEq => { + if matches_exact_prerelease(cmp, ver) { + return true; + } + matches_less(&fill_partial_req(cmp), ver) + } Op::Tilde => matches_tilde_prerelease(cmp, ver), Op::Caret => matches_caret_prerelease(cmp, ver), #[cfg(no_non_exhaustive)] @@ -87,12 +91,7 @@ fn matches_exact_prerelease(cmp: &Comparator, ver: &Version) -> bool { return false; } - let mut lower = Comparator { - op: Op::Less, - ..cmp.clone() - }; - fill_partial_req(&mut lower); - if !matches_greater(&lower, ver) { + if !matches_greater(&fill_partial_req(cmp), ver) { return false; } @@ -200,9 +199,7 @@ fn matches_tilde_prerelease(cmp: &Comparator, ver: &Version) -> bool { return true; } - let mut lower = cmp.clone(); - fill_partial_req(&mut lower); - if !matches_greater(&lower, ver) { + if !matches_greater(&fill_partial_req(cmp), ver) { return false; } @@ -252,9 +249,8 @@ fn matches_caret_prerelease(cmp: &Comparator, ver: &Version) -> bool { if matches_exact(cmp, ver) { return true; } - let mut lower = cmp.clone(); - fill_partial_req(&mut lower); - if !matches_greater(&lower, ver) { + + if !matches_greater(&fill_partial_req(cmp), ver) { return false; } diff --git a/tests/test_matches_prerelease.rs b/tests/test_matches_prerelease.rs index 5ec93417..6515357e 100644 --- a/tests/test_matches_prerelease.rs +++ b/tests/test_matches_prerelease.rs @@ -126,16 +126,115 @@ fn major_caret() { assert_prerelease_match_none(r, &["1.2.0", "2.0.0-0", "2.0.0"]); } +#[test] +fn test_exact() { + // =I.J.K equivalent to >=I.J.K, =I.J.0, = 4.2.0, < 4.3.0-0 + assert_prerelease_match_all(r, &["4.2.0", "4.2.1", "4.2.4-pre", "4.2.9"]); + // Not Match < 4.2.0 + assert_prerelease_match_none(r, &["0.0.1", "2.1.2-pre", "4.0.0-pre"]); + // Not Match >= 4.3.0-0 + assert_prerelease_match_none(r, &["4.3.0-0", "4.3.0", "5.0.0-0", "5.0.0"]); + + // =I equivalent to >=I.0.0, <(I+1).0.0-0 + let ref r = req("=4"); + // Match >= 4.0.0, < 5.0.0-0 + assert_prerelease_match_all(r, &["4.0.0", "4.2.1", "4.2.4-pre", "4.9.9"]); + // Not Match < 4.0.0 + assert_prerelease_match_none(r, &["0.0.1", "2.1.2-pre", "4.0.0-pre"]); + // Not Match >= 5.0.0-0 + assert_prerelease_match_none(r, &["5.0.0-0", "5.0.0", "5.0.1"]); + + // =I.J.K-pre only match I.J.K-pre + let ref r = req("=4.2.1-0"); + // Only exactly match 4.2.1-0 + assert_prerelease_match_all(r, &["4.2.1-0"]); + // Not match others + assert_prerelease_match_none(r, &["1.2.3", "4.2.0", "4.2.1-1", "4.2.2", "4.3.5"]); +} + +#[test] +fn test_greater() { + // >I.J.K + let ref r = req(">4.2.1"); + assert_prerelease_match_all(r, &["4.2.2", "5.0.0-0", "5.0.0"]); + assert_prerelease_match_none(r, &["0.0.0", "4.2.1-pre", "4.2.1"]); + // >I.J equivalent to >=I.(J+1).0-0 + let ref r = req(">4.2"); + assert_prerelease_match_all(r, &["4.3.0-pre", "4.3.0", "5.0.0"]); + assert_prerelease_match_none(r, &["0.0.0", "4.2.1"]); + // >I equivalent to >=(I+1).0.0-0 + let ref r = req(">4"); + assert_prerelease_match_all(r, &["5.0.0-0", "5.0.0-1", "5.0.0"]); + assert_prerelease_match_none(r, &["0.0.0", "4.2.1"]); +} + +#[test] +fn test_greater_eq() { + // >=I.J.K + let ref r = req(">=4.2.1"); + assert_prerelease_match_all(r, &["4.2.1", "5.0.0-0", "5.0.0"]); + assert_prerelease_match_none(r, &["0.0.0", "4.2.1-pre"]); + // >=I.J equivalent to >=I.J.0 + let ref r = req(">=4.2"); + assert_prerelease_match_all(r, &["4.2.0", "4.2.1-pre", "4.3.0", "5.0.0"]); + assert_prerelease_match_none(r, &["0.0.0", "4.1.1", "4.2.0-0"]); + // >=I equivalent to >=I.0.0 + let ref r = req(">=4"); + assert_prerelease_match_all(r, &["4.0.0", "4.1.0-1", "5.0.0"]); + assert_prerelease_match_none(r, &["0.0.0", "4.0.0-pre"]); +} + +#[test] +fn test_less() { + // = 0.0.24, < 0.1.0-0 - assert_prerelease_match_all(r, &["0.0.24", "0.0.25-0", "0.0.25"]); - // Not Match < 0.0.24 - assert_prerelease_match_none(r, &["0.0.1", "0.0.9", "0.0.24-pre"]); - // Not Match >= 0.1.0-0 - assert_prerelease_match_none(r, &["0.1.0-0", "0.1.0", "1.2.3", "2.0.0"]); + // ~I.J.K — equivalent to >=I.J.K, = 1.2.3, < 1.3.0-0 + assert_prerelease_match_all(r, &["1.2.3", "1.2.4-pre", "1.2.4"]); + // Not Match < 1.2.3 + assert_prerelease_match_none(r, &["0.0.1", "1.0.0-pre", "1.1.0-0", "1.1.0"]); + // Not Match >= 1.3.0-0 + assert_prerelease_match_none(r, &["1.3.0-0", "1.3.0", "1.3.1-0", "1.3.1", "2.0.0"]); + // ~I.J — equivalent to >=I.J.0, = 0.24.0, < 0.25.0-0 assert_prerelease_match_all(r, &["0.24.0", "0.24.1-pre", "0.24.1", "0.24.9"]); @@ -144,6 +243,7 @@ fn test_tilde() { // Not Match >= 0.25.0-0 assert_prerelease_match_none(r, &["0.25.0-0", "1.1.0", "1.2.3", "2.0.0"]); + // ~I — >=I.0.0, <(I+1).0.0-0 let ref r = req("~1"); // Match >= 1.0.0, < 2.0.0-0 assert_prerelease_match_all(r, &["1.0.0", "1.1.0-0", "1.1.0", "1.2.3"]); @@ -152,22 +252,7 @@ fn test_tilde() { // Not Match >= 2.0.0-0 assert_prerelease_match_none(r, &["2.0.0-0", "2.0.0", "2.0.1"]); - let ref r = req("~1.2"); - // Match >= 1.2.0, < 1.3.0-0 - assert_prerelease_match_all(r, &["1.2.0", "1.2.1", "1.2.2-pre", "1.2.9"]); - // Not Match < 1.2.0 - assert_prerelease_match_none(r, &["0.0.1", "1.0.0-pre", "1.1.0-0", "1.1.0"]); - // Not Match >= 1.3.0-0 - assert_prerelease_match_none(r, &["1.3.0-0", "1.3.0", "1.4.3-pre", "1.8.9", "2.0.0"]); - - let ref r = req("~1.2.3"); - // Match >= 1.2.3, < 1.3.0-0 - assert_prerelease_match_all(r, &["1.2.3", "1.2.4-pre", "1.2.4"]); - // Not Match < 1.2.3 - assert_prerelease_match_none(r, &["0.0.1", "1.0.0-pre", "1.1.0-0", "1.1.0"]); - // Not Match >= 1.3.0-0 - assert_prerelease_match_none(r, &["1.3.0-0", "1.3.0", "1.3.1-0", "1.3.1", "2.0.0"]); - + // ~I.J.K-[pre] — equivalent to >=I.J.K-[pre], = 1.2.3-0, < 1.3.0-0 assert_prerelease_match_all(r, &["1.2.3-0", "1.2.3", "1.2.4-pre", "1.2.4"]); @@ -178,82 +263,47 @@ fn test_tilde() { } #[test] -fn test_range() { - let ref r = req(">=1.0.0"); - assert_prerelease_match_all(r, &["1.0.0", "1.0.1-pre", "2.0.0-0", "2.0.0"]); - assert_prerelease_match_none(r, &["0.9.9", "0.10.0", "1.0.0-pre.0"]); - - let ref r = req(">=1.0.0-pre.1"); - assert_prerelease_match_all(r, &["1.0.0-pre.1", "1.0.0", "1.0.1-pre", "2.0.0-0"]); - assert_prerelease_match_none(r, &["0.9.9", "0.10.0", "1.0.0-pre.0"]); - - let ref r = req("<=1.0.0"); - assert_prerelease_match_all(r, &["0.9.9", "0.10.0", "1.0.0-pre", "1.0.0"]); - assert_prerelease_match_none(r, &["1.0.1", "1.0.1-pre", "1.1.0", "2.0.0-0"]); - - let ref r = req("<=1.0.0-0"); - assert_prerelease_match_all(r, &["0.9.9", "0.1.0", "0.10.0", "1.0.0-0"]); - assert_prerelease_match_none(r, &["1.0.0-pre", "1.0.1-pre", "1.1.0", "2.0.0-0"]); - - let ref r = req(">1.0.0-0,<=1.1.0-0"); - assert_prerelease_match_all(r, &["1.0.0-pre", "1.0.0", "1.0.9", "1.1.0-0"]); - assert_prerelease_match_none(r, &["0.0.1", "1.0.0-0", "1.2.3-pre", "2.0.0"]); - - let ref r = req(">=1.0.0,<1.1.0-0"); - assert_prerelease_match_all(r, &["1.0.0", "1.0.0", "1.0.9"]); - assert_prerelease_match_none(r, &["0.0.1", "1.0.0-pre", "1.1.0-0", "1.1.0", "2.0.0"]); +fn test_caret() { + // ^I.J.K (for I>0) — equivalent to >=I.J.K, <(I+1).0.0-0 + let ref r = req("^1.2.3"); + assert_prerelease_match_all(r, &["1.2.3", "1.2.4-0", "1.8.9"]); + assert_prerelease_match_none(r, &["0.0.9", "1.1.1-0", "1.2.3-0", "2.0.0-pre", "2.1.1"]); + + // ^0.J.K (for J>0) — equivalent to >=0.J.K, <0.(J+1).0-0 + let ref r = req("^0.2.3"); + assert_prerelease_match_all(r, &["0.2.3", "0.2.9-0", "0.2.9"]); + assert_prerelease_match_none(r, &["0.0.9", "0.2.3-0", "0.3.0-0", "0.3.11", "1.1.1"]); + + // ^0.0.K — equivalent to >=0.0.K, <0.0.(K+1)-0 + let ref r = req("^0.0.3"); + assert_prerelease_match_all(r, &["0.0.3"]); + assert_prerelease_match_none( + r, + &["0.0.1", "0.0.4-0", "0.0.9", "0.3.0-0", "0.4.0-0", "1.1.1"], + ); + + // ^I.J (for I>0 or J>0) — equivalent to >=I.J.0, <(I+1).0.0-0) + let ref r = req("^1.2"); + assert_prerelease_match_all(r, &["1.2.0", "1.9.0-0", "1.9.9"]); + assert_prerelease_match_none(r, &["0.0.1", "0.0.4-0", "1.2.0-0", "2.0.0-0", "4.0.1"]); + + // ^0.0 — equivalent to >=0.0.0, <0.1.0-0 + let ref r = req("^0.0"); + assert_prerelease_match_all(r, &["0.0.0", "0.0.1", "0.0.4-0"]); + assert_prerelease_match_none(r, &["0.1.0-0", "0.1.0", "1.1.1"]); + + // ^I — equivalent to >=I.0.0, <(I+1).0.0-0 + let ref r = req("^1"); + assert_prerelease_match_all(r, &["1.0.0", "1.0.1", "1.0.4-0"]); + assert_prerelease_match_none(r, &["0.1.0-0", "0.1.0", "2.0.0-0", "3.1.2"]); } #[test] -fn test_range_partial() { - let ref r = req(">=0.24"); - assert_prerelease_match_all(r, &["0.24.0", "0.24.1", "2.0.0-0", "2.0.0"]); - assert_prerelease_match_none(r, &["0.9.9", "0.10.0", "0.24.0-pre.0"]); - - let ref r = req(">=1"); - assert_prerelease_match_all(r, &["1.0.0", "1.0.1-pre", "2.0.0-0", "2.0.0"]); - assert_prerelease_match_none(r, &["0.9.9", "0.10.0", "1.0.0-pre.0"]); - - let ref r = req("<1"); - assert_prerelease_match_none(r, &["1.0.0", "1.0.1-pre", "2.0.0-0", "2.0.0"]); - assert_prerelease_match_all(r, &["0.9.9", "0.10.0", "1.0.0-pre.0"]); - - let ref r = req(">=1.1"); - assert_prerelease_match_all(r, &["1.1.0", "1.1.1-pre", "2.0.0-0"]); - assert_prerelease_match_none(r, &["0.9.9", "0.10.0", "1.0.0-pre.0"]); - - let ref r = req("<1.1"); - assert_prerelease_match_none(r, &["1.1.0", "1.1.1-pre", "2.0.0-0"]); - assert_prerelease_match_all(r, &["0.9.9", "0.10.0", "1.0.0-pre.0"]); - - let ref r = req(">1,<=1.1"); - assert_prerelease_match_all(r, &["1.0.9", "1.1.0-0"]); - assert_prerelease_match_none(r, &["0.0.1", "1.0.0-0", "1.2.3-pre", "2.0.0"]); - - let ref r = req(">=1.1,<2"); - assert_prerelease_match_all(r, &["1.1.0", "1.2.9-pre", "1.2.9", "2.0.0-pre"]); - assert_prerelease_match_none(r, &["0.0.1", "1.0.0-pre", "1.1.0-pre"]); - - let ref r = req("*"); - assert_prerelease_match_all(r, &["0.0.1", "1.0.0", "1.2.9", "2.0.0-pre"]); - - let ref r = req("^1, <=1.9"); - assert_prerelease_match_all(r, &["1.1.1-pre", "1.1.1"]); - let ref r = req("^0, <=0.0.1-z0"); - assert_prerelease_match_all(r, &["0.0.1-z0"]); -} - -#[test] -fn test_exact() { - let ref r = req("=4"); - // Match >= 4.0.0, < 5.0.0-0 - assert_prerelease_match_all(r, &["4.0.0", "4.2.1", "4.2.4-pre", "4.9.9"]); - // Not Match < 4.0.0 - assert_prerelease_match_none(r, &["0.0.1", "2.1.2-pre", "4.0.0-pre"]); - // Not Match >= 5.0.0-0 - assert_prerelease_match_none(r, &["5.0.0-0", "5.0.0", "5.0.1"]); - - let ref r = req("=4.2"); +fn test_wildcard() { + // I.J.* — equivalent to =I.J + // + // =I.J equivalent to >=I.J.0, = 4.2.0, < 4.3.0-0 assert_prerelease_match_all(r, &["4.2.0", "4.2.1", "4.2.4-pre", "4.2.9"]); // Not Match < 4.2.0 @@ -261,22 +311,15 @@ fn test_exact() { // Not Match >= 4.3.0-0 assert_prerelease_match_none(r, &["4.3.0-0", "4.3.0", "5.0.0-0", "5.0.0", "5.0.1"]); - let ref r = req("=4.2.1"); - assert_prerelease_match_all(r, &["4.2.1"]); - assert_prerelease_match_none(r, &["1.2.3", "4.2.1-pre", "4.2.2", "5.0.0"]); - - let ref r = req("=4.2.1-0"); - // Only exactly match 4.2.1-0 - assert_prerelease_match_all(r, &["4.2.1-0"]); - // Not match others - assert_prerelease_match_none(r, &["1.2.3", "4.2.0", "4.2.1-1", "4.2.2", "4.3.5"]); - - // Speicial Case - let ref r = req("=0"); - // Match >= 0.0.0, < 1.0.0-0 - assert_prerelease_match_all(r, &["0.0.0", "0.1.1", "0.9.9"]); - // Not Match < 0.0.0 - assert_prerelease_match_none(r, &["0.0.0-0", "0.0.0-pre"]); - // Not Match >= 1.0.0-0 - assert_prerelease_match_none(r, &["1.0.0-0", "1.0.0", "2.0.1"]); + // I.* or I.*.* — equivalent to =I + // + // =I equivalent to >=I.0.0, <(I+1).0.0-0 + for r in &[req("4.*"), req("4.*.*")] { + // Match >= 4.0.0, < 5.0.0-0 + assert_prerelease_match_all(r, &["4.0.0", "4.2.1", "4.2.4-pre", "4.9.9"]); + // Not Match < 4.0.0 + assert_prerelease_match_none(r, &["0.0.1", "2.1.2-pre", "4.0.0-pre"]); + // Not Match >= 5.0.0-0 + assert_prerelease_match_none(r, &["5.0.0-0", "5.0.0", "5.0.1"]); + } }