use super::*;
use crate::testing::fixtures::fixture_dir;
fn cpuinfo_fixture(name: &str) -> String {
std::fs::read_to_string(fixture_dir().join("qa").join(name))
.expect("cpuinfo fixture must exist under tests/fixtures/qa/")
}
#[test]
fn ryzen_like_fixture_classifies_x86_64_v3() {
let cpu = parse_cpuinfo(&cpuinfo_fixture("cpuinfo_ryzen_v3.txt"));
assert_eq!(cpu.effective_isa, ISA_X86_64_V3);
assert_eq!(cpu.model_name, "AMD Ryzen 9 5900X 12-Core Processor");
assert_eq!(cpu.physical_cores, 12);
}
#[test]
fn avx512_fixture_classifies_avx512() {
let cpu = parse_cpuinfo(&cpuinfo_fixture("cpuinfo_avx512.txt"));
assert_eq!(cpu.effective_isa, ISA_AVX512);
assert_eq!(cpu.model_name, "AMD Ryzen 9 7950X 16-Core Processor");
assert_eq!(cpu.physical_cores, 16);
}
#[test]
fn avx2_incomplete_fixture_classifies_incomplete() {
let cpu = parse_cpuinfo(&cpuinfo_fixture("cpuinfo_avx2_incomplete.txt"));
assert_eq!(cpu.effective_isa, ISA_AVX2_INCOMPLETE);
assert_eq!(cpu.physical_cores, 4);
}
#[test]
fn base_fixture_classifies_base() {
let cpu = parse_cpuinfo(&cpuinfo_fixture("cpuinfo_base.txt"));
assert_eq!(cpu.effective_isa, ISA_X86_64_BASE);
assert_eq!(
cpu.model_name,
"Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz"
);
assert_eq!(cpu.physical_cores, 2);
}
#[test]
fn avx512f_takes_precedence_over_v3_set() {
let flags = "flags : fpu sse avx avx2 bmi1 bmi2 f16c fma abm movbe avx512f";
assert_eq!(classify_isa(flags), ISA_AVX512);
}
#[test]
fn v3_gate_accepts_lzcnt_or_abm() {
let base = "avx avx2 bmi1 bmi2 f16c fma movbe";
assert_eq!(
classify_isa(&format!("flags : {base} lzcnt")),
ISA_X86_64_V3
);
assert_eq!(classify_isa(&format!("flags : {base} abm")), ISA_X86_64_V3);
}
#[test]
fn v3_gate_requires_the_full_feature_set() {
for missing in ["avx", "bmi1", "bmi2", "f16c", "fma", "movbe", "abm"] {
let flags: Vec<&str> = "avx avx2 bmi1 bmi2 f16c fma abm movbe"
.split_whitespace()
.filter(|flag| *flag != missing)
.collect();
let line = format!("flags : {}", flags.join(" "));
assert_eq!(
classify_isa(&line),
ISA_AVX2_INCOMPLETE,
"missing {missing} must demote to AVX2 incomplete"
);
}
let no_avx2: Vec<&str> = "avx bmi1 bmi2 f16c fma abm movbe"
.split_whitespace()
.collect();
assert_eq!(
classify_isa(&format!("flags : {}", no_avx2.join(" "))),
ISA_X86_64_BASE,
"without avx2 the classifier must fall back to base"
);
}
#[test]
fn classification_is_whole_word_and_fail_safe() {
assert_eq!(classify_isa("flags : noavx2 avx512f_sim"), ISA_X86_64_BASE);
assert_eq!(classify_isa(""), ISA_X86_64_BASE);
assert_eq!(classify_isa("garbage without flags"), ISA_X86_64_BASE);
}
#[test]
fn parse_cpuinfo_uses_first_match_and_defaults() {
let text = "model name : First CPU\n\
flags : avx\n\
cpu cores : 8\n\
model name : Second CPU\n\
flags : avx2\n\
cpu cores : 16\n";
let cpu = parse_cpuinfo(text);
assert_eq!(cpu.model_name, "First CPU");
assert_eq!(
cpu.effective_isa, ISA_AVX2_INCOMPLETE,
"first flags line wins"
);
assert_eq!(cpu.physical_cores, 8);
let bare = parse_cpuinfo("processor : 0\nwp : yes\n");
assert_eq!(bare.model_name, "");
assert_eq!(bare.effective_isa, ISA_X86_64_BASE);
assert_eq!(bare.physical_cores, 0);
}
#[test]
fn probe_from_cpuinfo_combines_fixture_cpu_with_live_toolchain() {
let probe = EnvProbe::probe_from_cpuinfo(&cpuinfo_fixture("cpuinfo_ryzen_v3.txt"));
assert_eq!(probe.effective_isa, ISA_X86_64_V3);
assert_eq!(probe.cpu_model, "AMD Ryzen 9 5900X 12-Core Processor");
assert_eq!(probe.physical_cores, 12);
assert!(!probe.rustc_version.is_empty(), "rustc must be available");
assert!(
!probe.host_triple.is_empty(),
"host triple must be available"
);
}
#[test]
fn live_probe_yields_canonical_isa_and_toolchain() {
let probe = EnvProbe::probe();
assert!(
matches!(
probe.effective_isa,
ISA_AVX512 | ISA_X86_64_V3 | ISA_AVX2_INCOMPLETE | ISA_X86_64_BASE
),
"effective_isa must be one of the canonical strings, got {}",
probe.effective_isa
);
assert!(!probe.cpu_model.is_empty());
assert!(!probe.rustc_version.is_empty());
assert!(!probe.host_triple.is_empty());
assert!(probe.physical_cores >= 1);
}