pub const ZSH_PATCHLEVEL: &str = "zsh-5.9.1-0-g0e0d4ea";
pub const ZSH_VERSION: &str = "5.9.1";
pub const ZSHRS_VERSION: &str = "5.9.0.3-test";
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn patchlevel_value_and_git_describe_shape() {
let _g = crate::test_util::global_state_lock();
assert_eq!(ZSH_PATCHLEVEL, "zsh-5.9.1-0-g0e0d4ea");
assert!(
ZSH_PATCHLEVEL.contains("-g"),
"git-describe `-g<hash>` suffix is load-bearing"
);
}
#[test]
fn zsh_version_matches_upstream_config_version() {
let _g = crate::test_util::global_state_lock();
assert_eq!(ZSH_VERSION, "5.9.1");
assert_eq!(ZSHRS_VERSION, "5.9.0.3-test");
let major = ZSH_VERSION.split('.').next().unwrap_or("");
assert!(
major.chars().all(|c| c.is_ascii_digit()) && !major.is_empty(),
"ZSH_VERSION must start with numeric MAJOR (got {ZSH_VERSION:?})"
);
}
#[test]
fn patchlevel_corpus_nonempty() {
assert!(!ZSH_PATCHLEVEL.is_empty());
}
#[test]
fn patchlevel_corpus_zsh_prefix() {
assert!(
ZSH_PATCHLEVEL.starts_with("zsh-"),
"patchlevel must start with `zsh-`, got {ZSH_PATCHLEVEL:?}"
);
}
#[test]
fn patchlevel_corpus_version_has_dot() {
assert!(
ZSH_VERSION.contains('.'),
"ZSH_VERSION must contain a dot (MAJOR.MINOR), got {ZSH_VERSION:?}"
);
}
#[test]
fn patchlevel_corpus_version_major_is_five() {
let major = ZSH_VERSION.split('.').next().unwrap();
assert_eq!(major, "5", "current zsh is in the 5.x series");
}
#[test]
fn patchlevel_corpus_version_minor_parses() {
let parts: Vec<&str> = ZSH_VERSION.split('.').collect();
assert!(parts.len() >= 2, "must have MAJOR.MINOR");
let minor: Result<i32, _> = parts[1].parse();
assert!(minor.is_ok(), "MINOR must parse: {parts:?}");
}
#[test]
fn patchlevel_corpus_patchlevel_differs_from_version() {
assert_ne!(ZSH_PATCHLEVEL, ZSH_VERSION);
}
#[test]
fn patchlevel_has_four_dash_segments() {
let parts: Vec<&str> = ZSH_PATCHLEVEL.split('-').collect();
assert!(
parts.len() >= 4,
"patchlevel must have ≥ 4 dash segments, got {:?}",
parts
);
}
#[test]
fn patchlevel_hash_starts_with_g() {
let last = ZSH_PATCHLEVEL.rsplit('-').next().unwrap_or("");
assert!(
last.starts_with('g'),
"last segment {:?} must start with 'g'",
last
);
}
#[test]
fn patchlevel_commit_count_is_numeric() {
let parts: Vec<&str> = ZSH_PATCHLEVEL.split('-').collect();
if parts.len() >= 4 {
let count_part = parts[2];
let parsed: Result<i32, _> = count_part.parse();
assert!(parsed.is_ok(), "commit-count {:?} must parse", count_part);
}
}
#[test]
fn zsh_version_no_spaces() {
assert!(!ZSH_VERSION.contains(' '));
}
#[test]
fn zsh_patchlevel_no_spaces() {
assert!(!ZSH_PATCHLEVEL.contains(' '));
}
#[test]
fn version_strings_are_ascii() {
assert!(ZSH_VERSION.is_ascii());
assert!(ZSH_PATCHLEVEL.is_ascii());
}
#[test]
fn version_strings_no_trailing_ws() {
assert_eq!(ZSH_VERSION.trim_end(), ZSH_VERSION);
assert_eq!(ZSH_PATCHLEVEL.trim_end(), ZSH_PATCHLEVEL);
}
#[test]
fn patchlevel_contains_major_minor_from_version() {
let mm: String = ZSH_VERSION.split('.').take(2).collect::<Vec<_>>().join(".");
assert!(
ZSH_PATCHLEVEL.contains(&mm),
"patchlevel {:?} must contain {}",
ZSH_PATCHLEVEL,
mm
);
}
#[test]
fn patchlevel_hash_after_g_is_hex() {
let last = ZSH_PATCHLEVEL.rsplit('-').next().unwrap_or("");
let hash = last.trim_start_matches('g');
assert!(!hash.is_empty(), "hash must be non-empty after 'g'");
assert!(
hash.chars().all(|c| c.is_ascii_hexdigit()),
"git-describe hash {:?} must be hex",
hash
);
}
#[test]
fn patchlevel_hash_short_sha_length() {
let last = ZSH_PATCHLEVEL.rsplit('-').next().unwrap_or("");
let hash = last.trim_start_matches('g');
assert!(
hash.len() >= 7 && hash.len() <= 40,
"git short SHA must be 7-40 chars, got {} ({:?})",
hash.len(),
hash
);
}
#[test]
fn patchlevel_commit_count_non_negative() {
let parts: Vec<&str> = ZSH_PATCHLEVEL.split('-').collect();
if parts.len() >= 4 {
let count: i32 = parts[2].parse().unwrap_or(-1);
assert!(count >= 0, "commit count must be non-negative: {}", count);
}
}
#[test]
fn zsh_version_components_numeric_until_tag() {
let no_tag = ZSH_VERSION.split('-').next().unwrap_or("");
for (i, comp) in no_tag.split('.').enumerate() {
let parsed: Result<u32, _> = comp.parse();
assert!(
parsed.is_ok(),
"ZSH_VERSION component[{}] = {:?} must parse as u32",
i,
comp
);
}
}
#[test]
fn zsh_version_meets_minimum_5_9() {
let no_tag = ZSH_VERSION.split('-').next().unwrap_or("");
let parts: Vec<u32> = no_tag.split('.').filter_map(|s| s.parse().ok()).collect();
assert!(parts.len() >= 2, "MAJOR.MINOR required");
let major = parts[0];
let minor = parts[1];
assert!(
major > 5 || (major == 5 && minor >= 9),
"ZSH_VERSION must be ≥ 5.9, got {}.{}",
major,
minor
);
}
#[test]
fn zsh_patchlevel_has_no_nul_bytes() {
assert!(!ZSH_PATCHLEVEL.contains('\0'));
}
#[test]
fn zsh_version_has_no_nul_bytes() {
assert!(!ZSH_VERSION.contains('\0'));
}
#[test]
fn zsh_patchlevel_no_leading_whitespace() {
assert!(!ZSH_PATCHLEVEL.starts_with(char::is_whitespace));
}
#[test]
fn zsh_version_no_leading_whitespace() {
assert!(!ZSH_VERSION.starts_with(char::is_whitespace));
}
#[test]
fn version_constants_are_stable() {
for _ in 0..100 {
assert_eq!(ZSH_PATCHLEVEL, "zsh-5.9.1-0-g0e0d4ea");
assert_eq!(ZSH_VERSION, "5.9.1");
}
}
#[test]
fn version_constants_static_str_type() {
let _: &'static str = ZSH_PATCHLEVEL;
let _: &'static str = ZSH_VERSION;
}
#[test]
fn zsh_patchlevel_address_is_stable() {
let p1 = ZSH_PATCHLEVEL.as_ptr();
let p2 = ZSH_PATCHLEVEL.as_ptr();
assert_eq!(p1, p2, "PATCHLEVEL must have stable static address");
}
#[test]
fn zsh_version_address_is_stable() {
let p1 = ZSH_VERSION.as_ptr();
let p2 = ZSH_VERSION.as_ptr();
assert_eq!(p1, p2, "VERSION must have stable static address");
}
#[test]
fn zsh_patchlevel_length_in_sane_range() {
let n = ZSH_PATCHLEVEL.len();
assert!(
n >= 10 && n <= 200,
"PATCHLEVEL length {} must be in [10, 200]",
n
);
}
#[test]
fn zsh_version_length_in_sane_range() {
let n = ZSH_VERSION.len();
assert!(n >= 3 && n <= 30, "VERSION length {} must be in [3, 30]", n);
}
#[test]
fn zsh_patchlevel_hash_is_lowercase_hex() {
let last = ZSH_PATCHLEVEL.rsplit('-').next().unwrap_or("");
let hash = last.trim_start_matches('g');
for c in hash.chars() {
assert!(
!c.is_ascii_uppercase(),
"git-describe hash uses lowercase hex; found uppercase {:?}",
c
);
}
}
#[test]
fn zsh_patchlevel_no_empty_segments() {
for seg in ZSH_PATCHLEVEL.split('-') {
assert!(
!seg.is_empty(),
"PATCHLEVEL must have no empty segments (no consecutive dashes)"
);
}
}
#[test]
fn zsh_version_major_minor_segments_non_empty() {
let parts: Vec<&str> = ZSH_VERSION.split('.').collect();
assert!(parts.len() >= 2);
assert!(!parts[0].is_empty(), "MAJOR non-empty");
assert!(!parts[1].is_empty(), "MINOR non-empty");
}
#[test]
fn zsh_patchlevel_no_trailing_newline() {
assert!(!ZSH_PATCHLEVEL.ends_with('\n'));
assert!(!ZSH_PATCHLEVEL.ends_with('\r'));
}
#[test]
fn zsh_version_no_trailing_newline() {
assert!(!ZSH_VERSION.ends_with('\n'));
assert!(!ZSH_VERSION.ends_with('\r'));
}
#[test]
fn version_constants_valid_utf8() {
let _ = std::str::from_utf8(ZSH_PATCHLEVEL.as_bytes()).expect("PATCHLEVEL valid UTF-8");
let _ = std::str::from_utf8(ZSH_VERSION.as_bytes()).expect("VERSION valid UTF-8");
}
#[test]
fn zsh_patchlevel_starts_with_zsh_5_dot() {
assert!(
ZSH_PATCHLEVEL.starts_with("zsh-5."),
"ZSH_PATCHLEVEL must start `zsh-5.` (upstream major), got: {}",
ZSH_PATCHLEVEL
);
}
#[test]
fn zsh_version_starts_with_5_dot() {
assert!(
ZSH_VERSION.starts_with("5."),
"ZSH_VERSION must start `5.` (upstream-major sync), got: {}",
ZSH_VERSION
);
}
#[test]
fn zsh_patchlevel_has_four_dash_segments() {
let segs: Vec<&str> = ZSH_PATCHLEVEL.split('-').collect();
assert_eq!(
segs.len(),
4,
"ZSH_PATCHLEVEL must have 4 segments (zsh-X.Y-N-gHASH); got {} from {:?}",
segs.len(),
ZSH_PATCHLEVEL
);
assert_eq!(segs[0], "zsh");
assert!(segs[3].starts_with('g'), "4th segment must start `g`");
}
#[test]
fn zsh_patchlevel_commit_count_is_positive_integer() {
let segs: Vec<&str> = ZSH_PATCHLEVEL.split('-').collect();
let _n: u32 = segs[2].parse().expect("3rd segment must be u32");
}
#[test]
fn zsh_patchlevel_hash_is_7_or_more_hex_chars() {
let segs: Vec<&str> = ZSH_PATCHLEVEL.split('-').collect();
let hash = &segs[3][1..]; assert!(
hash.len() >= 7,
"git short hash must be ≥ 7 chars, got {} from {:?}",
hash.len(),
hash
);
assert!(
hash.chars().all(|c| c.is_ascii_hexdigit()),
"git hash must be all hex; got: {:?}",
hash
);
}
#[test]
fn zsh_version_major_parseable_as_u32() {
let major = ZSH_VERSION.split('.').next().unwrap();
let _: u32 = major.parse().expect("major must parse as u32");
}
#[test]
fn zsh_version_minor_parseable_as_u32() {
let mut iter = ZSH_VERSION.split('.');
let _ = iter.next();
let minor = iter.next().expect("VERSION must have minor segment");
let _: u32 = minor.parse().expect("minor must parse as u32");
}
#[test]
fn version_constants_are_ascii_only() {
assert!(ZSH_PATCHLEVEL.is_ascii(), "ZSH_PATCHLEVEL must be ASCII");
assert!(ZSH_VERSION.is_ascii(), "ZSH_VERSION must be ASCII");
}
#[test]
fn version_constants_have_no_spaces() {
assert!(
!ZSH_PATCHLEVEL.contains(' '),
"ZSH_PATCHLEVEL must not contain spaces: {:?}",
ZSH_PATCHLEVEL
);
assert!(
!ZSH_VERSION.contains(' '),
"ZSH_VERSION must not contain spaces: {:?}",
ZSH_VERSION
);
}
#[test]
fn zsh_version_major_minor_matches_patchlevel() {
let segs: Vec<&str> = ZSH_PATCHLEVEL.split('-').collect();
let pl_tag = segs[1];
let pl_parts: Vec<&str> = pl_tag.split('.').collect();
assert!(pl_parts.len() >= 2, "PATCHLEVEL tag must have MAJOR.MINOR");
let pl_mm = format!("{}.{}", pl_parts[0], pl_parts[1]);
let v_segs: Vec<&str> = ZSH_VERSION.split('.').collect();
let v_mm = format!("{}.{}", v_segs[0], v_segs[1]);
assert_eq!(
pl_mm, v_mm,
"PATCHLEVEL major.minor ({}) must match VERSION major.minor ({})",
pl_mm, v_mm
);
}
#[test]
fn zsh_patchlevel_is_not_bare_tag() {
assert_ne!(
ZSH_PATCHLEVEL, "zsh-5.9",
"PATCHLEVEL must include git-describe suffix, not bare tag"
);
assert_ne!(
ZSH_PATCHLEVEL, "5.9",
"PATCHLEVEL must include `zsh-` prefix"
);
}
#[test]
fn version_constants_non_empty() {
assert!(!ZSH_PATCHLEVEL.is_empty());
assert!(!ZSH_VERSION.is_empty());
assert!(!ZSH_PATCHLEVEL.trim().is_empty());
assert!(!ZSH_VERSION.trim().is_empty());
}
}