"""Column-contract guard for `Slot` (dcy-001 OQ-2 / REQ-003 FR-5). Asserts the `Slot` dataclass field set matches the declared `EXPECTED_SLOT_FIELDS` so any field add/remove fails loudly. Names/presence only — type mapping lives in dcy-001 부록 A / docs/data-model.md, not here. DB-side (information_schema) drift checking is out of scope for this iteration and is deferred to the persistence REQ (dcy-001 OQ-2). """ from __future__ import annotations import dataclasses from trex_core.domain.slot import EXPECTED_SLOT_FIELDS, Slot def test_slot_fields_match_expected_contract(): """AC-2: dataclass field set == declared contract.""" actual = {f.name for f in dataclasses.fields(Slot)} assert actual == set(EXPECTED_SLOT_FIELDS) def test_contract_detects_added_field(): """AC-3 negative case: an extra field on a Slot-like dataclass must be caught. Recreates the guard against a mutated copy so the test proves the assertion fails when fields drift, without mutating the real Slot. """ mutated_fields = {f.name for f in dataclasses.fields(Slot)} | {"unexpected_new_field"} assert mutated_fields != set(EXPECTED_SLOT_FIELDS) def test_contract_detects_removed_field(): """AC-3 negative case: a removed field must be caught.""" reduced_fields = {f.name for f in dataclasses.fields(Slot)} - {"forced_close_at"} assert reduced_fields != set(EXPECTED_SLOT_FIELDS)