use dsfb_database::grammar::{MotifClass, MotifGrammar};
use serde::Deserialize;
use std::collections::HashSet;
use std::fs;
use std::path::PathBuf;
fn spec_path(file: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("spec")
.join(file)
}
fn motif_camel_names() -> HashSet<&'static str> {
HashSet::from([
"PlanRegressionOnset",
"CardinalityMismatchRegime",
"ContentionRamp",
"CacheCollapse",
"WorkloadPhaseTransition",
])
}
#[test]
fn motifs_yaml_parses_as_grammar_and_round_trips() {
let yaml = fs::read_to_string(spec_path("motifs.yaml"))
.expect("spec/motifs.yaml must be present alongside the crate");
let g: MotifGrammar =
serde_yaml::from_str(&yaml).expect("spec/motifs.yaml must deserialise as MotifGrammar");
for class in MotifClass::ALL {
let p = g.params(class);
assert!(
p.rho > 0.0 && p.rho < 1.0,
"spec/motifs.yaml: motif {:?} has invalid rho={}",
class,
p.rho
);
}
}
#[derive(Debug, Deserialize)]
struct PerturbationsFile {
perturbations: Vec<PerturbationEntry>,
}
#[derive(Debug, Deserialize)]
struct PerturbationEntry {
name: String,
motif: String,
}
#[test]
fn perturbations_yaml_motifs_resolve_to_real_classes() {
let yaml = fs::read_to_string(spec_path("perturbations.yaml"))
.expect("spec/perturbations.yaml must be present");
let parsed: PerturbationsFile =
serde_yaml::from_str(&yaml).expect("spec/perturbations.yaml must deserialise");
let valid = motif_camel_names();
assert_eq!(
parsed.perturbations.len(),
5,
"spec/perturbations.yaml: expected 5 injected windows (one per motif class); found {}",
parsed.perturbations.len()
);
for p in &parsed.perturbations {
assert!(
valid.contains(p.motif.as_str()),
"spec/perturbations.yaml: perturbation {:?} references unknown motif {:?}",
p.name,
p.motif
);
}
}
#[derive(Debug, Deserialize)]
struct ConcordanceFile {
facts: Vec<ConcordanceFact>,
}
#[derive(Debug, Deserialize)]
struct ConcordanceFact {
id: u32,
title: String,
motif: String,
}
#[test]
fn wizard_concordance_yaml_motifs_resolve_to_real_classes() {
let yaml = fs::read_to_string(spec_path("wizard_concordance.yaml"))
.expect("spec/wizard_concordance.yaml must be present");
let parsed: ConcordanceFile =
serde_yaml::from_str(&yaml).expect("spec/wizard_concordance.yaml must deserialise");
let valid = motif_camel_names();
assert!(
!parsed.facts.is_empty(),
"spec/wizard_concordance.yaml: facts list is empty"
);
for f in &parsed.facts {
assert!(
valid.contains(f.motif.as_str()),
"spec/wizard_concordance.yaml: fact #{} ({:?}) references unknown motif {:?}",
f.id,
f.title,
f.motif
);
}
}