use super::*;
use crate::product_group::BatteryData;
use crate::product_group::ProductGroupData;
use crate::product_group::data::unsold_goods::{CnCategory, DiscardReason};
use chrono::Utc;
fn battery() -> BatteryData {
BatteryData {
nominal_voltage_v: 3.7,
nominal_capacity_ah: 10.0,
expected_lifetime_cycles: Some(500),
co2e_per_unit_kg: 5.0,
rated_energy_wh: Some(37.0),
..crate::test_support::sample_battery_data()
}
}
#[test]
fn clean_battery_produces_no_findings() {
let data = ProductGroupData::Battery(Box::new(battery()));
assert!(lint_product_group_data(&data, Utc::now()).is_empty());
}
#[test]
fn battery_energy_mismatch_surfaces_as_domain_finding() {
let mut b = battery();
b.rated_energy_wh = Some(500.0); let data = ProductGroupData::Battery(Box::new(b));
let findings = lint_product_group_data(&data, Utc::now());
assert_eq!(findings.len(), 1);
assert_eq!(findings[0].code, "battery.energy_capacity_mismatch");
assert_eq!(findings[0].severity, LintSeverity::Notice);
}
#[test]
fn a_well_formed_disclosure_produces_no_findings() {
let data = ProductGroupData::UnsoldGoods(crate::test_support::sample_unsold_goods_report());
assert_eq!(lint_product_group_data(&data, Utc::now()), Vec::new());
}
#[test]
fn a_treatment_split_that_misses_100_is_flagged() {
let mut report = crate::test_support::sample_unsold_goods_report();
report.lines[0].treatment.disposal_pct = 1;
let data = ProductGroupData::UnsoldGoods(report);
let findings = lint_product_group_data(&data, Utc::now());
assert!(
findings
.iter()
.any(|f| f.code == "unsold_goods.treatment_split_does_not_total_100"),
"{findings:?}"
);
}
#[test]
fn a_chapter_holding_annex_ii_headings_is_flagged() {
let mut report = crate::test_support::sample_unsold_goods_report();
report.lines[0].cn_categories = vec![CnCategory::parse("85").expect("valid chapter")];
let data = ProductGroupData::UnsoldGoods(report);
let findings = lint_product_group_data(&data, Utc::now());
assert!(
findings
.iter()
.any(|f| f.code == "unsold_goods.cn_category_needs_four_digits"),
"{findings:?}"
);
}
#[test]
fn donation_claimed_beside_a_stronger_reason_is_flagged() {
let mut report = crate::test_support::sample_unsold_goods_report();
let mut second = report.lines[0].clone();
second.reason = DiscardReason::OfferedForDonationNotAccepted;
report.lines.push(second);
let data = ProductGroupData::UnsoldGoods(report);
let findings = lint_product_group_data(&data, Utc::now());
assert!(
findings
.iter()
.any(|f| f.code == "unsold_goods.donation_reason_alongside_stronger_reason"),
"{findings:?}"
);
}
#[test]
fn other_product_group_produces_no_findings() {
let data = ProductGroupData::other(serde_json::json!({"productGroup": "packaging"}))
.expect("packaging has no typed variant");
assert!(lint_product_group_data(&data, Utc::now()).is_empty());
}
#[test]
fn lint_result_compute_stamps_pack_version_and_timestamp() {
let data = ProductGroupData::Battery(Box::new(battery()));
let result = LintResult::compute(&data);
assert_eq!(result.pack_version, dpp_rules::lint::LINT_PACK_VERSION);
assert!(result.findings.is_empty());
}
#[test]
fn lint_result_serde_round_trip() {
let data = ProductGroupData::Battery(Box::new(battery()));
let result = LintResult::compute(&data);
let json = serde_json::to_value(&result).unwrap();
let back: LintResult = serde_json::from_value(json).unwrap();
assert_eq!(back, result);
}