The serialiser carries status through and computes no totals of its own. The only aggregates in the payload are ones DfE published itself; whether showing one is safe depends on how many of its components are suppressed, which the frontend decides. The batch guard grows from six tables to eight. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BvdDKvFFSZuMVDH5fEyTob
113 lines
4.3 KiB
Python
113 lines
4.3 KiB
Python
"""The destinations serialiser's contract: it carries suppression through, and
|
|
never emits a total that closes a gap left by a suppressed category.
|
|
|
|
The destination categories sum to the cohort, so an aggregate that happens to
|
|
equal the residual names the withheld figure exactly. See
|
|
docs/superpowers/specs/2026-08-28-destination-measures-design.md.
|
|
"""
|
|
|
|
from backend.data_loader import _destinations_block, _format_cohort_year
|
|
|
|
|
|
def _row(group, measure, pupils, status, cohort=180, percentage=None, year=202223):
|
|
return {
|
|
"pupil_group": group,
|
|
"destination_measure": measure,
|
|
"pupils": pupils,
|
|
"percentage": percentage,
|
|
"status": status,
|
|
"cohort_pupils": cohort,
|
|
"year": year,
|
|
}
|
|
|
|
|
|
def test_suppressed_category_serialises_as_suppressed_with_null_pupils():
|
|
rows = [
|
|
_row("all", "school_sixth_form", 75, "published", percentage=41.7),
|
|
_row("all", "sixth_form_college", None, "suppressed"),
|
|
]
|
|
block = _destinations_block(rows)
|
|
cats = {c["category"]: c for c in block["groups"]["all"]["categories"]}
|
|
assert cats["sixth_form_college"]["status"] == "suppressed"
|
|
assert cats["sixth_form_college"]["pupils"] is None
|
|
assert cats["sixth_form_college"]["percentage"] is None
|
|
|
|
|
|
def test_published_category_keeps_its_figures():
|
|
block = _destinations_block([
|
|
_row("all", "school_sixth_form", 75, "published", percentage=41.7),
|
|
])
|
|
cat = block["groups"]["all"]["categories"][0]
|
|
assert cat["pupils"] == 75
|
|
assert cat["percentage"] == 41.7
|
|
assert cat["status"] == "published"
|
|
|
|
|
|
def test_no_closing_total_is_emitted_for_a_partially_suppressed_group():
|
|
rows = [
|
|
_row("all", "school_sixth_form", 75, "published", percentage=41.7),
|
|
_row("all", "sixth_form_college", None, "suppressed"),
|
|
_row("all", "further_education", 61, "published", percentage=33.9),
|
|
_row("all", "apprenticeship", 8, "published", percentage=4.4),
|
|
_row("all", "employment", 6, "published", percentage=3.3),
|
|
_row("all", "not_sustained", 5, "published", percentage=2.8),
|
|
_row("all", "not_captured", 4, "published", percentage=2.2),
|
|
]
|
|
block = _destinations_block(rows)
|
|
group = block["groups"]["all"]
|
|
published = sum(c["pupils"] for c in group["categories"] if c["pupils"] is not None)
|
|
residual = group["cohort"] - published
|
|
for value in group["aggregates"].values():
|
|
if value is None or value.get("pupils") is None:
|
|
continue
|
|
assert value["pupils"] != residual, (
|
|
"an aggregate equal to the residual identifies the suppressed cell"
|
|
)
|
|
|
|
|
|
def test_aggregates_are_separated_from_categories():
|
|
rows = [
|
|
_row("all", "school_sixth_form", 75, "published", percentage=41.7),
|
|
_row("all", "agg_sustained_all", 171, "published", percentage=95.0),
|
|
]
|
|
block = _destinations_block(rows)
|
|
group = block["groups"]["all"]
|
|
assert [c["category"] for c in group["categories"]] == ["school_sixth_form"]
|
|
assert group["aggregates"]["sustained_all"]["pupils"] == 171
|
|
|
|
|
|
def test_only_the_latest_year_is_served():
|
|
rows = [
|
|
_row("all", "school_sixth_form", 60, "published", year=202122),
|
|
_row("all", "school_sixth_form", 75, "published", year=202223),
|
|
]
|
|
block = _destinations_block(rows)
|
|
assert block["cohort_year"] == "2022/23"
|
|
assert len(block["groups"]["all"]["categories"]) == 1
|
|
assert block["groups"]["all"]["categories"][0]["pupils"] == 75
|
|
|
|
|
|
def test_all_three_pupil_groups_are_carried():
|
|
rows = [
|
|
_row("all", "school_sixth_form", 75, "published"),
|
|
_row("disadvantaged", "school_sixth_form", 17, "published", cohort=62),
|
|
_row("other", "school_sixth_form", 58, "published", cohort=118),
|
|
]
|
|
block = _destinations_block(rows)
|
|
assert set(block["groups"]) == {"all", "disadvantaged", "other"}
|
|
assert block["groups"]["disadvantaged"]["cohort"] == 62
|
|
|
|
|
|
def test_cohort_year_is_reported_so_the_page_can_date_itself():
|
|
block = _destinations_block([_row("all", "school_sixth_form", 75, "published")])
|
|
assert block["cohort_year"] == "2022/23"
|
|
|
|
|
|
def test_format_cohort_year_handles_the_six_digit_form():
|
|
assert _format_cohort_year(202223) == "2022/23"
|
|
assert _format_cohort_year(None) is None
|
|
|
|
|
|
def test_empty_rows_yield_none_not_an_empty_shell():
|
|
assert _destinations_block([]) is None
|