use std::collections::BTreeMap;
use std::path::Path;
use serde::Deserialize;
use warble::{ContextLoader, PreparedContext};
fn golden(rel: &str) -> String {
let path = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../golden/bootstrap-context")
.join(rel);
std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()))
}
fn example(rel: &str) -> String {
let path = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../examples/bootstrap-agent")
.join(rel);
std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()))
}
#[derive(Debug, Deserialize)]
struct Column {
name: String,
#[serde(rename = "type")]
col_type: String,
}
#[derive(Debug, Deserialize)]
struct Model {
name: String,
columns: Vec<Column>,
}
#[derive(Debug, Deserialize)]
struct Mdl {
models: Vec<Model>,
}
#[derive(Debug, Deserialize)]
struct SchemaFidelityGroundTruth {
expected: Mdl,
cases: Vec<SchemaFidelityCase>,
}
#[derive(Debug, Deserialize)]
struct SchemaFidelityCase {
id: String,
produced: Mdl,
expected_correct: usize,
expected_total: usize,
}
fn columns_of(mdl: &Mdl) -> BTreeMap<String, String> {
let mut map = BTreeMap::new();
for model in &mdl.models {
for col in &model.columns {
map.insert(
format!("{}.{}", model.name, col.name),
col.col_type.to_uppercase(),
);
}
}
map
}
fn schema_fidelity(expected: &Mdl, produced: &Mdl) -> (usize, usize) {
let exp = columns_of(expected);
let prod = columns_of(produced);
let total = exp.len();
let correct = exp
.iter()
.filter(|(key, ty)| prod.get(*key).map(|p| p == *ty).unwrap_or(false))
.count();
(correct, total)
}
#[test]
fn schema_fidelity_scorer_reproduces_every_labelled_case() {
let gt: SchemaFidelityGroundTruth =
serde_yaml::from_str(&golden("schema_fidelity_ground_truth.yaml"))
.expect("schema_fidelity ground truth parses");
assert!(
gt.cases.len() >= 4,
"want faithful + missing-column + wrong-type + missing-table"
);
let mut reproduced = 0usize;
for case in >.cases {
let (correct, total) = schema_fidelity(>.expected, &case.produced);
assert_eq!(
(correct, total),
(case.expected_correct, case.expected_total),
"case '{}': scorer gave ({correct}/{total}) but ground truth expects ({}/{})",
case.id,
case.expected_correct,
case.expected_total
);
reproduced += 1;
}
assert_eq!(reproduced, gt.cases.len());
let faithful = gt.cases.iter().find(|c| c.id == "faithful").unwrap();
let (correct, total) = schema_fidelity(>.expected, &faithful.produced);
assert_eq!(
correct, total,
"a faithful bootstrap must score fidelity 1.0"
);
}
#[test]
fn expected_mdl_fixture_matches_ground_truth() {
let gt: SchemaFidelityGroundTruth =
serde_yaml::from_str(&golden("schema_fidelity_ground_truth.yaml")).unwrap();
let manifest: Mdl =
serde_json::from_str(&example("expected-mdl/manifest.json")).expect("expected MDL parses");
assert_eq!(
columns_of(>.expected),
columns_of(&manifest),
"the schema_fidelity ground truth must mirror examples/bootstrap-agent/expected-mdl/manifest.json"
);
}
#[test]
fn a_prepared_bootstrapped_context_satisfies_downstream_consumer_preconditions() {
let ctx = PreparedContext::from_json(&golden("expected_mdl_prepared_context.json"))
.expect("the committed prepared-context document loads");
assert!(ctx.is_parseable(), "bootstrapped MDL must parse");
assert!(
!ctx.metrics().is_empty(),
"has_metric: bootstrapped MDL exposes queryable metrics (answer_query needs this)"
);
assert!(
!ctx.time_dimensions().is_empty(),
"has_time_dimension: bootstrapped MDL exposes a time dimension (explain_change/dashboards need this)"
);
assert!(
ctx.can_answer("metric_additive"),
"the bootstrapped cube declares a measure, so metric_additive is answerable"
);
let total_revenue = ctx
.metrics()
.iter()
.find(|m| m.name == "total_revenue")
.expect("the revenue cube's total_revenue measure is bootstrapped");
assert!(
total_revenue.declared,
"total_revenue is a declared measure"
);
assert_eq!(
total_revenue.additivity,
Some(warble::Additivity::Additive),
"SUM(amount) is additive — decomposition-safe for downstream consumers"
);
}