use super::*;
use semver::Version;
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn validate_valid_battery_data() {
let reg = VersionedSchemaRegistry::new();
let v1: Version = "1.0.0".parse().unwrap();
let data = serde_json::json!({
"gtin": "12345678901234",
"batteryChemistry": "LFP",
"nominalVoltageV": 48.0,
"nominalCapacityAh": 100.0,
"expectedLifetimeCycles": 3000,
"co2ePerUnitKg": 85.4
});
assert!(reg.validate("battery", &v1, &data).is_ok());
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn validate_invalid_battery_data() {
let reg = VersionedSchemaRegistry::new();
let v1: Version = "1.0.0".parse().unwrap();
let data = serde_json::json!({
"batteryChemistry": "LFP"
});
assert!(reg.validate("battery", &v1, &data).is_err());
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn validate_if_present_enforces_existing_schema_and_skips_absent() {
let reg = VersionedSchemaRegistry::new();
let valid = serde_json::json!({
"gtin": "12345678901234",
"batteryChemistry": "LFP",
"nominalVoltageV": 48.0,
"nominalCapacityAh": 100.0,
"expectedLifetimeCycles": 3000,
"co2ePerUnitKg": 85.4
});
assert!(reg.validate_if_present("battery", "1.0.0", &valid).is_ok());
let invalid = serde_json::json!({ "batteryChemistry": "LFP" });
assert!(
reg.validate_if_present("battery", "1.0.0", &invalid)
.is_err()
);
assert!(
reg.validate_if_present("no-such-product_group", "1.0.0", &invalid)
.is_ok()
);
assert!(
reg.validate_if_present("battery", "9.9.9", &invalid)
.is_ok()
);
assert!(
reg.validate_if_present("battery", "not-a-version", &invalid)
.is_ok()
);
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn validate_strict_is_fail_closed_unlike_validate_if_present() {
let reg = VersionedSchemaRegistry::new();
let valid = serde_json::json!({
"gtin": "12345678901234",
"batteryChemistry": "LFP",
"nominalVoltageV": 48.0,
"nominalCapacityAh": 100.0,
"expectedLifetimeCycles": 3000,
"co2ePerUnitKg": 85.4
});
let invalid = serde_json::json!({ "batteryChemistry": "LFP" });
assert!(reg.validate_strict("battery", "1.0.0", &valid).is_ok());
assert!(reg.validate_strict("battery", "1.0.0", &invalid).is_err());
assert!(
reg.validate_strict("no-such-product_group", "1.0.0", &invalid)
.is_err()
);
assert!(reg.validate_strict("battery", "9.9.9", &invalid).is_err());
assert!(
reg.validate_strict("battery", "not-a-version", &invalid)
.is_err()
);
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn validate_textile_v1_1_with_new_fields() {
let reg = VersionedSchemaRegistry::new();
let v11: Version = "1.1.0".parse().unwrap();
let data = serde_json::json!({
"gtin": "09506000134352",
"fibreComposition": [
{ "fibre": "cotton", "pct": 70.0, "countryOfOrigin": "IN" },
{ "fibre": "polyester", "pct": 30.0, "countryOfOrigin": "CN" }
],
"countryOfManufacturing": "BD",
"careInstructions": "Machine wash 40°C",
"chemicalComplianceStandard": "OEKO-TEX 100",
"durabilityScore": 7.5,
"microplasticSheddingMgPerWash": 12.3,
"expectedWashCycles": 50,
"svhcSubstances": [
{
"casNumber": "80-05-7",
"substanceName": "Bisphenol A",
"concentrationPct": 0.15,
"locationInProduct": "coating"
}
],
"disassemblyInstructions": "Remove buttons, separate layers",
"sparePartsAvailable": true,
"productWeightGrams": 250.0
});
assert!(reg.validate("textile", &v11, &data).is_ok());
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn validate_textile_v1_1_rejects_invalid_fibre_country() {
let reg = VersionedSchemaRegistry::new();
let v11: Version = "1.1.0".parse().unwrap();
let data = serde_json::json!({
"fibreComposition": [
{ "fibre": "cotton", "pct": 100.0, "countryOfOrigin": "india" }
],
"countryOfManufacturing": "BD",
"careInstructions": "Hand wash",
"chemicalComplianceStandard": "REACH"
});
assert!(reg.validate("textile", &v11, &data).is_err());
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn validate_runtime_registered_schema() {
let mut reg = VersionedSchemaRegistry::new();
let schema = r#"{
"type": "object",
"required": ["material"],
"properties": {
"material": { "type": "string", "minLength": 1 }
},
"additionalProperties": false
}"#;
reg.register("plastics", "1.0.0", schema.to_owned())
.unwrap();
let v1: Version = "1.0.0".parse().unwrap();
let valid = serde_json::json!({ "material": "PET" });
assert!(reg.validate("plastics", &v1, &valid).is_ok());
let invalid = serde_json::json!({});
assert!(reg.validate("plastics", &v1, &invalid).is_err());
}
#[test]
fn carbon_footprint_class_bound_matches_the_schema() {
use crate::product_group::CarbonFootprintClass;
let reg = VersionedSchemaRegistry::new();
let json = reg
.get("battery", &"2.2.0".parse::<Version>().unwrap())
.expect("battery v2.2.0 is embedded");
let schema: serde_json::Value = serde_json::from_str(json).unwrap();
let max_length = schema["properties"]["carbonFootprintClass"]["maxLength"]
.as_u64()
.expect("carbonFootprintClass must declare maxLength");
assert_eq!(max_length as usize, CarbonFootprintClass::MAX_LEN);
assert!(
schema["properties"]["carbonFootprintClass"]
.get("enum")
.is_none(),
"carbonFootprintClass must not enumerate labels"
);
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn schema_rejects_a_state_of_health_mixing_both_annex_vii_lists() {
let reg = VersionedSchemaRegistry::new();
let v = "2.2.0".parse::<Version>().unwrap();
let base = serde_json::json!({
"gtin": "12345678901231",
"batteryChemistry": "LFP",
"nominalVoltageV": 48.0,
"nominalCapacityAh": 100.0,
"expectedLifetimeCycles": 3000,
"co2ePerUnitKg": 85.4,
});
let mut mixed = base.clone();
mixed["stateOfHealth"] = serde_json::json!({
"parameterSet": "electricVehicle",
"socePct": 90.0,
"ohmicResistanceMohm": 3.2,
});
assert!(
reg.validate("battery", &v, &mixed).is_err(),
"an EV parameter set must not carry stationary parameters"
);
let mut valid = base;
valid["stateOfHealth"] = serde_json::json!({
"parameterSet": "electricVehicle",
"socePct": 90.0,
});
assert!(reg.validate("battery", &v, &valid).is_ok());
}