use hyperdb_mcp::version::{hyper_api_version_string, mcp_version_string, GIT_HASH, MCP_VERSION};
fn is_valid_build_timestamp(ts: &str) -> bool {
let bytes = ts.as_bytes();
if bytes.len() != 16 {
return false;
}
bytes.iter().enumerate().all(|(i, &b)| match i {
8 => b == b'T',
15 => b == b'Z',
_ => b.is_ascii_digit(),
})
}
fn is_valid_hash(hash: &str) -> bool {
if hash == "unknown" {
return true;
}
if let Some(rest) = hash.strip_prefix("unknown-dirty-") {
return is_valid_build_timestamp(rest);
}
if let Some((base, rest)) = hash.split_once("-dirty-") {
return base.len() == 8
&& base.chars().all(|c| c.is_ascii_hexdigit())
&& is_valid_build_timestamp(rest);
}
hash.len() == 8 && hash.chars().all(|c| c.is_ascii_hexdigit())
}
#[test]
fn mcp_version_has_semver_and_r_suffix() {
let v = mcp_version_string();
let (semver, hash) = v
.split_once(".r")
.unwrap_or_else(|| panic!("expected `<semver>.r<hash>`; got: {v}"));
assert_eq!(semver, MCP_VERSION);
assert!(
is_valid_hash(hash),
"hash portion of {v:?} is not 8 hex chars or 'unknown' (got {hash:?})",
);
}
#[test]
fn hyper_api_version_has_hyperdb_api_semver_and_r_suffix() {
let v = hyper_api_version_string();
let (semver, hash) = v
.split_once(".r")
.unwrap_or_else(|| panic!("expected `<semver>.r<hash>`; got: {v}"));
assert_eq!(
semver,
hyperdb_api::VERSION,
"hyper_api_version must report hyperdb_api::VERSION, not hyperdb-mcp's"
);
assert!(is_valid_hash(hash));
}
#[test]
fn both_versions_share_the_same_git_hash() {
let mcp = mcp_version_string();
let hyper = hyper_api_version_string();
let mcp_hash = mcp.split_once(".r").unwrap().1;
let hyper_hash = hyper.split_once(".r").unwrap().1;
assert_eq!(mcp_hash, hyper_hash);
assert_eq!(mcp_hash, GIT_HASH);
}
#[test]
fn dirty_builds_have_timestamp_clean_builds_do_not() {
if GIT_HASH.contains("-dirty") {
let (_base, ts) = GIT_HASH.split_once("-dirty-").unwrap_or_else(|| {
panic!("dirty hash must carry `-dirty-<timestamp>`; got {GIT_HASH}")
});
assert!(
is_valid_build_timestamp(ts),
"dirty-build timestamp {ts:?} is not ISO 8601 basic UTC (YYYYMMDDTHHMMSSZ)",
);
} else {
assert!(
!GIT_HASH.contains('T') && !GIT_HASH.contains('Z'),
"clean build hash should not contain a timestamp; got {GIT_HASH:?}",
);
}
}
#[test]
fn print_live_version_strings() {
println!(" GIT_HASH = {GIT_HASH}");
println!(" mcp_version_string = {}", mcp_version_string());
println!(" hyper_api_version = {}", hyper_api_version_string());
}
#[test]
fn timestamp_shape_validator_accepts_and_rejects() {
assert!(is_valid_build_timestamp("20260423T184900Z"));
assert!(is_valid_build_timestamp("20000101T000000Z"));
assert!(!is_valid_build_timestamp("20260423T184900"));
assert!(!is_valid_build_timestamp("20260423-184900Z"));
assert!(!is_valid_build_timestamp("20260423T1849Z"));
assert!(!is_valid_build_timestamp("2026042XT184900Z"));
}