"""Tests for the ``DEFAULT_CHECKS`` aggregate.

The aggregate is part of the public surface — its content + ordering
is consumed by ``Suite`` and external code that iterates it. These
tests pin both.
"""

from __future__ import annotations

from mgf.apiprobe.checks import DEFAULT_CHECKS
from mgf.apiprobe.core.check import Check


class TestDefaultChecks:
    def test_count_pinned(self) -> None:
        # 22 checks per HANDOFF (18 original + 4 P-1 in v0.5.0).md §6 + DEFERRED.md.
        # Adding/removing is a deliberate change.
        assert len(DEFAULT_CHECKS) == 22

    def test_all_subclass_check(self) -> None:
        for c in DEFAULT_CHECKS:
            assert isinstance(c, Check)

    def test_codes_are_unique(self) -> None:
        codes = [c.code for c in DEFAULT_CHECKS]
        assert len(codes) == len(set(codes)), f"duplicate codes: {codes}"

    def test_codes_pinned(self) -> None:
        # Renaming any code is a breaking change (rule SP-AP-03);
        # this set is the public contract for v0.1.
        expected = {
            "contract.status.unexpected",
            "contract.status.server-error",
            "contract.header.missing",
            "contract.content-type.missing",
            "contract.content-type.json-expected",
            "schema.body.shape-mismatch",
            "schema.body.invalid-json",
            "schema.body.empty-on-success",
            "quality.latency.over-budget",
            "quality.latency.suspicious-zero",
            "quality.body-size.over-budget",
            "security.headers.missing-hsts",
            "security.headers.missing-content-type-options",
            "security.headers.missing-frame-options",
            "security.headers.missing-csp",
            "security.headers.missing-referrer-policy",
            "security.headers.missing-permissions-policy",
            "security.cookies.insecure-attributes",
            "security.body.echoes-secret",
            "observability.headers.missing-request-id",
            "observability.headers.missing-rate-limit",
            "observability.headers.missing-server",
        }
        assert {c.code for c in DEFAULT_CHECKS} == expected

    def test_categories_present(self) -> None:
        # Smoke: at least one check from each category.
        categories = {c.code.split(".", 1)[0] for c in DEFAULT_CHECKS}
        assert categories == {
            "contract",
            "schema",
            "quality",
            "security",
            "observability",
        }
