use openmoat_hosts::{Advisory, Host, Platform};
use super::{advisory_line, cached, identify, parse, parse_any, remember};
#[test]
fn a_kept_version_lasts_until_the_program_file_changes() {
let dir = tempfile::tempdir().unwrap();
let program = dir.path().join("opencode");
std::fs::write(&program, "one").unwrap();
let seen = identify(&program).unwrap();
assert_eq!(cached(dir.path(), &seen), None);
remember(
dir.path(),
super::Seen {
version: (1, 19, 4),
..seen.clone()
},
);
assert_eq!(cached(dir.path(), &seen), Some((1, 19, 4)));
std::fs::write(&program, "an upgrade").unwrap();
let upgraded = identify(&program).unwrap();
assert_eq!(cached(dir.path(), &upgraded), None);
std::fs::write(dir.path().join("host-versions.json"), "{").unwrap();
assert_eq!(cached(dir.path(), &seen), None);
}
#[test]
fn versions_below_the_oldest_are_unsupported_and_others_name_their_hook() {
let gate = Host::OpenCode
.spec()
.install
.as_ref()
.and_then(|i| i.versions.as_ref())
.unwrap();
assert_ne!(gate.older, "");
let hook = |text| gate.hook_of(parse(text).unwrap());
assert_eq!(hook("1.3.3"), None);
assert_eq!(hook("1.0.0"), None);
assert!(hook("1.3.4").unwrap().contains("OpenCode 1"));
assert!(hook("1.19.4").unwrap().contains("tool.execute.before"));
assert!(hook("2.0.0").unwrap().contains("OpenCode 2"));
assert!(hook("2.2.0").unwrap().contains("`execute.before`"));
assert!(Host::ALL.iter().all(|h| {
*h == Host::OpenCode
|| h.spec()
.install
.as_ref()
.is_none_or(|i| i.versions.is_none())
}));
}
#[test]
fn a_version_after_a_program_name_is_read() {
assert_eq!(parse_any("1.19.4\n"), Some((1, 19, 4)));
assert_eq!(parse_any("codex-cli 0.164.0"), Some((0, 164, 0)));
assert_eq!(parse_any("Hermes Agent v0.22.5 (x)"), Some((0, 22, 5)));
assert_eq!(parse_any("no version here"), None);
}
#[test]
fn the_opencode_sign_in_advisory_names_its_range_and_systems() {
let spec = &Host::OpenCode.spec().advisories;
let pillar = |version, platform| {
spec.affecting(version, platform)
.any(|a| a.fixed == (1, 18, 33))
};
assert!(pillar((1, 18, 32), Platform::Windows));
assert!(pillar((1, 0, 137), Platform::Wsl));
assert!(!pillar((1, 0, 136), Platform::Windows));
assert!(!pillar((1, 18, 33), Platform::Windows));
assert!(!pillar((1, 18, 32), Platform::MacOs));
assert!(!pillar((1, 18, 32), Platform::Linux));
}
#[test]
fn the_pi_credentials_race_advisory_names_its_range() {
let spec = &Host::Pi.spec().advisories;
let race = |version| {
spec.affecting(version, Platform::MacOs)
.any(|a| a.id == "GHSA-r95r-rj6r-c39x")
};
assert!(!race((0, 27, 9)));
assert!(race((0, 28, 0)));
assert!(race((0, 78, 0)));
assert!(!race((0, 78, 1)));
}
#[test]
fn one_line_names_the_first_advisory_and_the_version_that_fixes_all() {
let spec = &Host::Pi.spec().advisories;
let affecting: Vec<&Advisory> = spec.affecting((0, 60, 0), Platform::Linux).collect();
assert_eq!(affecting.len(), 4);
let line = advisory_line("pi", (0, 60, 0), &affecting).unwrap();
assert!(
line.starts_with("pi 0.60.0 has a known security advisory, "),
"{line}"
);
assert!(
line.contains(" and 3 more; upgrade to 0.79.0 or later: https://"),
"{line}"
);
assert!(!line.contains('\n'), "{line}");
let later: Vec<&Advisory> = spec.affecting((0, 78, 1), Platform::MacOs).collect();
let line = advisory_line("pi", (0, 78, 1), &later).unwrap();
assert!(line.contains("; upgrade to 0.79.0 or later"), "{line}");
assert!(!line.contains("more"), "{line}");
assert_eq!(advisory_line("pi", (0, 79, 0), &[]), None);
}
#[test]
fn every_advisory_has_a_source_and_a_fix() {
let mut count = 0;
for host in Host::EVERY {
let advisories = &host.spec().advisories;
for a in advisories.list {
count += 1;
assert!(!advisories.program.is_empty(), "{}", host.id());
assert!(a.from < a.fixed, "{}", a.id);
assert!(a.source.starts_with("https://"), "{}", a.id);
assert!(!a.summary.is_empty() && !a.id.is_empty(), "{}", a.id);
}
}
assert!(count > 30, "{count}");
}