use super::policy::ProductGroupAccessPolicy;
#[test]
fn every_property_declares_a_valid_disclosure_class() {
let reg = crate::schemas::VersionedSchemaRegistry::new();
let (version, json) = reg.latest("battery").expect("battery schema exists");
let schema: serde_json::Value = serde_json::from_str(json).expect("valid JSON");
let bad = undeclared_properties(&schema);
assert!(
bad.is_empty(),
"battery v{version}: these properties declare no usable x-disclosure class, so they \
would default to public: {bad:?}"
);
}
const VALID_DISCLOSURE_TOKENS: [&str; 4] = ["public", "restricted", "conformity", "individual"];
fn undeclared_properties(schema: &serde_json::Value) -> Vec<(String, String)> {
fn walk(node: &serde_json::Value, path: &str, out: &mut Vec<(String, String)>) {
let Some(object) = node.as_object() else {
return;
};
if let Some(properties) = object.get("properties").and_then(|p| p.as_object()) {
for (name, prop) in properties {
let child = if path.is_empty() {
name.clone()
} else {
format!("{path}.{name}")
};
let class = prop
.get("x-disclosure")
.and_then(serde_json::Value::as_str)
.unwrap_or("<missing>");
if !VALID_DISCLOSURE_TOKENS.contains(&class) {
out.push((child.clone(), class.to_owned()));
}
walk(prop, &child, out);
}
}
for key in ["items", "additionalProperties"] {
if let Some(child) = object.get(key) {
walk(child, &format!("{path}[]"), out);
}
}
for key in ["definitions", "$defs"] {
if let Some(block) = object.get(key).and_then(|b| b.as_object()) {
for (name, definition) in block {
walk(definition, &format!("{key}.{name}"), out);
}
}
}
for key in ["allOf", "anyOf", "oneOf"] {
if let Some(branches) = object.get(key).and_then(|b| b.as_array()) {
for branch in branches {
walk(branch, path, out);
}
}
}
}
let mut out = Vec::new();
walk(schema, "", &mut out);
out
}
#[test]
fn every_product_group_version_yields_a_fully_classified_policy() {
let reg = crate::schemas::VersionedSchemaRegistry::new();
let mut checked = 0usize;
for product_group in reg.product_groups() {
for version in reg.versions_for(product_group) {
let json = reg.get(product_group, version).expect("registry listed it");
let schema: serde_json::Value = serde_json::from_str(json).expect("valid JSON");
let Some(properties) = schema.get("properties").and_then(|p| p.as_object()) else {
continue;
};
let _ = properties;
let undeclared = undeclared_properties(&schema);
assert!(
undeclared.is_empty(),
"{product_group} v{version}: unclassified properties {undeclared:?}"
);
assert!(
ProductGroupAccessPolicy::for_schema_version(product_group, &version.to_string())
.is_some(),
"{product_group} v{version} yields no policy"
);
checked += 1;
}
}
assert!(checked > 20, "only {checked} schema versions walked");
}