96 lines
4.0 KiB
Python
96 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Negative-authority contracts for flexible birth-time report projections."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from copy import deepcopy
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
SCRIPTS = os.path.join(os.path.dirname(__file__), "..", "scripts")
|
|
if SCRIPTS not in sys.path:
|
|
sys.path.insert(0, SCRIPTS)
|
|
|
|
from flexible_birth_time_full_report_projection import ( # noqa: E402
|
|
FlexibleBirthTimeFullReportProjectionError,
|
|
build_flexible_birth_time_full_report_projection,
|
|
)
|
|
from flexible_birth_time_profile import build_flexible_birth_time_profile # noqa: E402
|
|
from flexible_birth_time_report_section import ( # noqa: E402
|
|
FlexibleBirthTimeReportSectionError,
|
|
render_flexible_birth_time_report_section,
|
|
)
|
|
from flexible_birth_time_report_support import ( # noqa: E402
|
|
FlexibleBirthTimeReportSupportError,
|
|
build_flexible_birth_time_report_support,
|
|
)
|
|
|
|
|
|
def _profile() -> dict:
|
|
rows = [
|
|
{
|
|
"candidate_id": "fictional-a",
|
|
"candidate_time": "08:00",
|
|
"evidence": {"D1.ascendant": "Aries", "D10.ascendant": "Capricorn"},
|
|
"trace": [{"kind": "fictional_candidate", "reference": "fixture://08:00"}],
|
|
},
|
|
{
|
|
"candidate_id": "fictional-b",
|
|
"candidate_time": "08:01",
|
|
"evidence": {"D1.ascendant": "Aries", "D10.ascendant": "Aquarius"},
|
|
"trace": [{"kind": "fictional_candidate", "reference": "fixture://08:01"}],
|
|
},
|
|
]
|
|
profile = build_flexible_birth_time_profile(rows, source_reference={"review_id": "fictional-review"})
|
|
profile["birth_time_window"]["representative_time"] = "08:00"
|
|
return profile
|
|
|
|
|
|
def _packets() -> tuple[dict, dict, dict]:
|
|
profile = _profile()
|
|
support = build_flexible_birth_time_report_support(profile)
|
|
projection = build_flexible_birth_time_full_report_projection(support)
|
|
return profile, support, projection
|
|
|
|
|
|
def test_report_projection_is_hash_stable_and_renders_only_candidate_window_evidence() -> None:
|
|
_, support, projection = _packets()
|
|
reordered = deepcopy(support)
|
|
reordered["birth_time_window"] = dict(reversed(list(reordered["birth_time_window"].items())))
|
|
|
|
assert build_flexible_birth_time_full_report_projection(reordered)["projection_id"] == projection["projection_id"]
|
|
assert projection["status"] == "candidate_window_only"
|
|
assert "出生时间敏感度" in render_flexible_birth_time_report_section(projection)
|
|
|
|
|
|
@pytest.mark.parametrize("field", ["approved_birth_time", "final_birth_time", "winner", "approval"])
|
|
def test_every_report_layer_rejects_birth_minute_authority_fields(field: str) -> None:
|
|
profile, support, projection = _packets()
|
|
cases = [
|
|
(profile, build_flexible_birth_time_report_support, FlexibleBirthTimeReportSupportError),
|
|
(support, build_flexible_birth_time_full_report_projection, FlexibleBirthTimeFullReportProjectionError),
|
|
(projection, render_flexible_birth_time_report_section, FlexibleBirthTimeReportSectionError),
|
|
]
|
|
for packet, consumer, error_type in cases:
|
|
tampered = deepcopy(packet)
|
|
tampered["authority_probe"] = {field: "08:00"}
|
|
with pytest.raises(error_type, match="candidate_window_authority_forbidden"):
|
|
consumer(tampered)
|
|
|
|
|
|
@pytest.mark.parametrize("status", ["approved", "confirmed"])
|
|
def test_every_report_layer_rejects_approved_or_confirmed_source_reference(status: str) -> None:
|
|
profile, support, projection = _packets()
|
|
cases = [
|
|
(profile, build_flexible_birth_time_report_support, FlexibleBirthTimeReportSupportError),
|
|
(support, build_flexible_birth_time_full_report_projection, FlexibleBirthTimeFullReportProjectionError),
|
|
(projection, render_flexible_birth_time_report_section, FlexibleBirthTimeReportSectionError),
|
|
]
|
|
for packet, consumer, error_type in cases:
|
|
tampered = deepcopy(packet)
|
|
tampered["source_reference"] = {"review_id": "fictional-review", "status": status}
|
|
with pytest.raises(error_type, match="candidate_window_authority_forbidden"):
|
|
consumer(tampered)
|