"""FOUND-04 class coverage test. Every one of the 10 disconnect classes has a registered generator emitting >=1 frame whose dict matches the TelemetryFrame field names. """ from __future__ import annotations from numpy.random import PCG64, Generator from model.synth.state_machines import GENERATORS EXPECTED_CLASSES: frozenset[str] = frozenset({ "auth_8021x_eap_fail", "ap_roam_rekey_fail", "radius_timeout", "captive_portal_expiry", "mac_randomization_reject", "dhcp_lease_churn", "dns_resolver_fail", "driver_power_save_wake", "rf_sticky_client", "isp_upstream_fail", }) CANONICAL_ORDER = [ "auth_8021x_eap_fail", "ap_roam_rekey_fail", "radius_timeout", "captive_portal_expiry", "mac_randomization_reject", "dhcp_lease_churn", "dns_resolver_fail", "driver_power_save_wake", "rf_sticky_client", "isp_upstream_fail", ] def test_all_ten_classes_registered(): assert set(GENERATORS.keys()) == EXPECTED_CLASSES, ( "GENERATORS must contain exactly the 10 canonical class slugs; " f"got {sorted(GENERATORS.keys())}" ) def test_generators_in_canonical_order(): """Insertion order matters for byte-identicality (RESEARCH Pattern 4 Critical note).""" assert list(GENERATORS.keys()) == CANONICAL_ORDER def test_each_class_emits_valid_frame(expected_field_names): rng = Generator(PCG64(42)) for cls, fn in GENERATORS.items(): frames = fn(rng) assert len(frames) >= 1, f"Class {cls} emitted zero frames" sample = frames[0] extra = set(sample.keys()) - expected_field_names missing = expected_field_names - set(sample.keys()) assert not extra, f"Class {cls} emitted unknown fields: {extra}" assert not missing, f"Class {cls} missing required fields: {missing}" def test_window_ms_per_class(): """D-04: 30000 ms for fast events, 120000 ms for driver / sticky-client.""" rng = Generator(PCG64(42)) slow_classes = {"driver_power_save_wake", "rf_sticky_client"} for cls, fn in GENERATORS.items(): sample = fn(rng)[0] expected_window = 120000 if cls in slow_classes else 30000 assert sample["window_ms"] == expected_window, ( f"Class {cls} window_ms={sample['window_ms']}, expected {expected_window} (D-04)" )