use super::*;
use crate::catalog::{ProductGroupCatalog, ProductGroupDescriptor, RegulatoryStatus};
#[test]
fn most_product_groups_are_not_reached_by_espr() {
let instruments = InstrumentCatalog::new();
let non_espr = ProductGroupCatalog::new()
.all()
.iter()
.filter(|d| {
instruments
.bindings_for(&d.key)
.iter()
.all(|(i, _)| i.id != "espr")
})
.count();
assert_eq!(
non_espr, 5,
"expected 5 product groups reached by something other than ESPR \
(battery, toy, detergent, construction, electronics)"
);
}
#[test]
fn instrument_kind_does_not_affect_determination_gating() {
for instrument in InstrumentCatalog::new().all() {
for binding in &instrument.product_groups {
if binding.status == RegulatoryStatus::InForce {
continue;
}
assert!(
!binding.allows_determination(),
"'{}' under '{}' (kind {:?}) must not allow determinations",
binding.product_group,
instrument.id,
instrument.kind
);
}
}
}
#[test]
fn watch_never_allows_determination() {
assert!(!RegulatoryStatus::Watch.allows_determination());
}
#[test]
fn in_force_with_future_passport_date_still_determines() {
let catalog = InstrumentCatalog::new();
let due = catalog.passport_due_for("battery").expect("a fixed date");
assert_eq!(due.date, "2027-02-18");
let determinable = catalog.determinable_for("battery");
assert_eq!(determinable.len(), 1);
assert_eq!(determinable[0].0.id, "battery-reg-2023-1542");
}
#[test]
fn every_manifest_round_trips() {
for d in ProductGroupCatalog::new().all().iter() {
let json = serde_json::to_string(d).expect("serialise");
let back: ProductGroupDescriptor = serde_json::from_str(&json).expect("deserialise");
assert_eq!(
serde_json::to_value(&back).expect("re-serialise"),
serde_json::to_value(d).expect("serialise"),
"round-trip changed product_group '{}'",
d.key
);
}
}
const CATEGORY_ENUM_PROPERTY: &[(&str, &str)] = &[
("aluminium", "productionRoute"),
("battery", "batteryType"),
("construction", "productFamily"),
("detergent", "productType"),
("electronics", "productCategory"),
("furniture", "productType"),
("steel", "productCategory"),
("tyre", "tyreClass"),
];
#[test]
fn product_categories_are_legal_values_of_their_schema_enum() {
use crate::schemas::VersionedSchemaRegistry;
let catalog = ProductGroupCatalog::new();
let registry = VersionedSchemaRegistry::new();
for (product_group_key, property) in CATEGORY_ENUM_PROPERTY {
let descriptor = catalog.get(product_group_key).unwrap_or_else(|| {
panic!("product_group '{product_group_key}' is in the table but not the catalog")
});
let version: semver::Version = descriptor
.current_schema_version
.parse()
.expect("currentSchemaVersion is valid semver");
let schema_json = registry
.get(product_group_key, &version)
.unwrap_or_else(|| panic!("no schema for '{product_group_key}' v{version}"));
let schema: serde_json::Value =
serde_json::from_str(schema_json).expect("schema is valid JSON");
let allowed: Vec<&str> = schema["properties"][property]["enum"]
.as_array()
.unwrap_or_else(|| {
panic!("'{product_group_key}' schema property '{property}' has no enum — stale table row")
})
.iter()
.filter_map(serde_json::Value::as_str)
.collect();
for category in &descriptor.product_categories {
assert!(
allowed.contains(&category.as_str()),
"product_group '{product_group_key}' lists product category '{category}', which is not a legal \
value of schema property '{property}' ({allowed:?})"
);
}
}
}