use semver::{Version, VersionReq};
use crate::types::CompatStatus;
pub fn compat_check(require: Option<&VersionReq>, daemon: &Version) -> CompatStatus {
let Some(req) = require else {
return CompatStatus::Unknown;
};
if req.matches(daemon) {
return CompatStatus::Compatible;
}
let probes = [
Version::new(daemon.major + 1, 0, 0),
Version::new(daemon.major, daemon.minor + 1, 0),
Version::new(daemon.major, daemon.minor, daemon.patch + 1),
];
let needs_upgrade = probes.iter().any(|p| req.matches(p));
if needs_upgrade {
CompatStatus::NeedsUpgrade {
required: req.to_string(),
current: daemon.to_string(),
}
} else {
CompatStatus::Incompatible {
reason: format!(
"plugin requires {} but daemon is {} (no forward-compatible probe matches)",
req, daemon
),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use semver::VersionReq;
fn req(s: &str) -> VersionReq {
VersionReq::parse(s).unwrap()
}
fn v(s: &str) -> Version {
Version::parse(s).unwrap()
}
#[test]
fn unknown_when_no_requirement_declared() {
assert_eq!(compat_check(None, &v("0.1.0")), CompatStatus::Unknown);
}
#[test]
fn compatible_for_caret_range_within_minor() {
assert_eq!(
compat_check(Some(&req("^0.2")), &v("0.2.5")),
CompatStatus::Compatible
);
}
#[test]
fn needs_upgrade_when_daemon_below_minimum() {
match compat_check(Some(&req(">=0.3")), &v("0.2.0")) {
CompatStatus::NeedsUpgrade { required, current } => {
assert!(required.contains("0.3"), "required: {required}");
assert_eq!(current, "0.2.0");
}
other => panic!("expected NeedsUpgrade, got {other:?}"),
}
}
#[test]
fn incompatible_when_daemon_above_pinned_upper_bound() {
match compat_check(Some(&req("<0.2")), &v("1.0.0")) {
CompatStatus::Incompatible { reason } => {
assert!(reason.contains("daemon is 1.0.0"), "{reason}");
}
other => panic!("expected Incompatible, got {other:?}"),
}
}
#[test]
fn wildcard_matches_anything() {
assert_eq!(
compat_check(Some(&req("*")), &v("99.0.0")),
CompatStatus::Compatible
);
}
#[test]
fn exact_boundary_match_compatible() {
assert_eq!(
compat_check(Some(&req(">=0.2.0")), &v("0.2.0")),
CompatStatus::Compatible
);
}
}