use jayver::{Version, VersionReq};
use proptest::prelude::*;
fn years() -> impl Strategy<Value = i32> {
prop_oneof![
1..=99i32, -50..0i32 ]
}
fn weeks() -> impl Strategy<Value = u8> {
1..=53u8
}
fn patches() -> impl Strategy<Value = u32> {
0..1000u32
}
fn valid_versions() -> impl Strategy<Value = Version> {
(years(), weeks(), patches())
.prop_filter_map("valid calendar combinations", |(year, week, patch)| {
Version::new(year, week, patch).ok()
})
}
fn operators() -> impl Strategy<Value = &'static str> {
prop::sample::select(&["=", ">", ">=", "<", "<=", "~>"])
}
fn valid_requirements() -> impl Strategy<Value = VersionReq> {
prop::collection::vec(
(operators(), valid_versions()).prop_map(|(op, ver)| format!("{op}{ver}")),
1..3,
)
.prop_filter_map("valid requirements", |comps| {
VersionReq::parse(comps.join(",")).ok()
})
}
proptest! {
#[test]
fn parse_display_roundtrip(v in valid_versions()) {
let string = v.to_string();
let parsed = Version::parse(&string).unwrap();
prop_assert_eq!(v, parsed);
}
#[test]
fn version_ordering_is_transitive(
v1 in valid_versions(),
v2 in valid_versions(),
v3 in valid_versions()
) {
if v1 < v2 && v2 < v3 {
prop_assert!(v1 < v3);
}
}
#[test]
fn requirement_consistency(
req in valid_requirements(),
v1 in valid_versions(),
v2 in valid_versions()
) {
if v1 == v2 {
prop_assert_eq!(req.matches(&v1), req.matches(&v2));
}
}
#[test]
fn compatible_operator_behavior(
year in years(),
week in weeks(),
base_patch in 0..50u32,
test_patch in 0..100u32
) {
if let Ok(base) = Version::new(year, week, base_patch) {
if let Ok(test) = Version::new(year, week, test_patch) {
let req = VersionReq::parse(format!("~>{base}")).unwrap();
prop_assert_eq!(req.matches(&test), test_patch >= base_patch);
if let Ok(other_week) = Version::new(year, if week < 53 { week + 1 } else { 1 }, test_patch) {
prop_assert!(!req.matches(&other_week));
}
}
}
}
}