feat(fase1): dimension IR + admits, MAF-free guard extended (F1)
This commit is contained in:
parent
254e3da1d8
commit
a44256a994
3 changed files with 135 additions and 8 deletions
76
tests/test_dimension.py
Normal file
76
tests/test_dimension.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
"""Unit tests for the dimension IR + ``admits`` scoping gate (Fase 1, Step 1, SC1).
|
||||
|
||||
``admits`` must accept an in-dimension candidate (``measure_type`` in the allowed
|
||||
set) and reject an out-of-dimension one, exercising BOTH branches of the
|
||||
code-prefix logic — empty prefixes (measure_type-only) and non-empty prefixes
|
||||
where a matching vs non-matching code decides the outcome. A ``Dimension`` with an
|
||||
empty ``label`` must fail construction (Pydantic ``ValidationError``).
|
||||
|
||||
Model test: ``tests/test_validator.py`` (rejection assertions).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from portfolio_optimiser.dimension import Dimension, admits
|
||||
|
||||
|
||||
def _energy_dim(*, prefixes: frozenset[str] = frozenset()) -> Dimension:
|
||||
return Dimension(
|
||||
id="energi",
|
||||
label="Energi",
|
||||
allowed_measure_types=frozenset({"energy_efficiency"}),
|
||||
allowed_code_prefixes=prefixes,
|
||||
)
|
||||
|
||||
|
||||
def test_admits_in_dimension_measure_type_only() -> None:
|
||||
"""Empty ``allowed_code_prefixes``: only the measure_type gate applies."""
|
||||
dim = _energy_dim()
|
||||
assert (
|
||||
admits(measure_type="energy_efficiency", codes=frozenset({"07.1"}), dimension=dim) is True
|
||||
)
|
||||
|
||||
|
||||
def test_admits_rejects_out_of_dimension_measure_type() -> None:
|
||||
"""Out-of-dimension measure_type is rejected regardless of codes."""
|
||||
dim = _energy_dim()
|
||||
assert admits(measure_type="paving", codes=frozenset({"07.1"}), dimension=dim) is False
|
||||
|
||||
|
||||
def test_admits_prefix_branch_matching_code() -> None:
|
||||
"""Non-empty prefixes: a code matching a prefix is admitted."""
|
||||
dim = _energy_dim(prefixes=frozenset({"07"}))
|
||||
assert (
|
||||
admits(
|
||||
measure_type="energy_efficiency",
|
||||
codes=frozenset({"07.1", "99.9"}),
|
||||
dimension=dim,
|
||||
)
|
||||
is True
|
||||
)
|
||||
|
||||
|
||||
def test_admits_prefix_branch_no_matching_code() -> None:
|
||||
"""Non-empty prefixes: no code matches any prefix -> rejected even when measure_type is allowed."""
|
||||
dim = _energy_dim(prefixes=frozenset({"07"}))
|
||||
assert (
|
||||
admits(
|
||||
measure_type="energy_efficiency",
|
||||
codes=frozenset({"99.9"}),
|
||||
dimension=dim,
|
||||
)
|
||||
is False
|
||||
)
|
||||
|
||||
|
||||
def test_dimension_empty_label_raises() -> None:
|
||||
"""An empty ``label`` violates ``Field(min_length=1)`` -> ValidationError at construction."""
|
||||
with pytest.raises(ValidationError):
|
||||
Dimension(
|
||||
id="energi",
|
||||
label="",
|
||||
allowed_measure_types=frozenset({"energy_efficiency"}),
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue