pub fn normalize_name(raw: &str) -> String {
    let s = raw.trim_start_matches('/');
    let mut out = String::new();
    for ch in s.chars() {
        if ch == '_' || ch == '-' || ch == '.' || ch == '/' {
            continue;
        }
        if ch.is_ascii_uppercase() {
            out.push(ch.to_ascii_lowercase());
        } else {
            out.push(ch);
        }
    }
    out
}

pub fn parse_test_id(raw: &str) -> Option<u32> {
    let s = raw.trim_start_matches('/');
    if !s.to_ascii_lowercase().starts_with("test") {
        return None;
    }
    let tail = s.get(4..)?;
    let digits = tail.trim_start_matches(['-', '_']);
    if digits.is_empty() {
        return None;
    }
    digits.parse::<u32>().ok()
}
