Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions component/scripts/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ def validate_benefit_data(benefits_data: dict) -> Tuple[bool, List[dict]]:

Checks:
- All benefit arrays have matching lengths
- Each benefit has valid weights (should be numeric 1-7)
- Each benefit has valid weights (should be numeric 0-4)

Args:
benefits_data: Dictionary containing benefit arrays
Expand Down Expand Up @@ -594,18 +594,20 @@ def validate_benefit_data(benefits_data: dict) -> Tuple[bool, List[dict]]:
name = benefits_data["names"][i]
weight = benefits_data["weights"][i]

# Validate the weight (should be numeric 1-7)
# Validate the weight. The benefit weight selector only offers
# values 0-4 (see component/widget/benefit_row.py), where 0 means
# the benefit is disabled, so that is the valid range.
is_valid = True
error_msg = ""

if not isinstance(weight, (int, float)):
is_valid = False
error_msg = (
f"Expected numeric weight (1-7), got {type(weight).__name__}"
f"Expected numeric weight (0-4), got {type(weight).__name__}"
)
elif weight < 1 or weight > 7:
elif weight < 0 or weight > 4:
is_valid = False
error_msg = f"Weight must be between 1 and 7, got {weight}"
error_msg = f"Weight must be between 0 and 4, got {weight}"

if not is_valid:
invalid_benefits.append(
Expand Down
4 changes: 3 additions & 1 deletion tests/test_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ def test_load_recipe(recipe: Recipe):
"wood",
]

assert recipe.benefit_model.weights == [4, 4, 2, 1, 1, 4]
# 0 is a valid weight (benefit disabled); it loads unchanged rather than
# being sanitized to the default of 4.
assert recipe.benefit_model.weights == [0, 0, 2, 1, 1, 0]

# Check the constraint model

Expand Down
57 changes: 56 additions & 1 deletion tests/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,67 @@
test_antq1_recipe_path,
test_antq2_recipe_path,
)
from component.scripts.validation import are_comparable, validate_scenarios_recipes
from component.scripts.validation import (
are_comparable,
validate_benefit_data,
validate_scenarios_recipes,
)


test_recipe_path, test_antq1_recipe_path, test_antq2_recipe_path


def _benefits(weights):
"""Build a minimal, length-consistent benefits dict for the given weights."""
n = len(weights)
return {
"names": [f"benefit_{i}" for i in range(n)],
"ids": [f"id_{i}" for i in range(n)],
"weights": weights,
"themes": ["bii"] * n,
"assets": ["asset"] * n,
"descs": ["desc"] * n,
"units": ["unit"] * n,
}


def test_benefit_weight_zero_is_valid():
"""Weight 0 means 'benefit disabled' and must pass validation.

The weight selector (component/widget/benefit_row.py) only offers
values 0-4, so 0 is a legitimate, app-produced value.
"""
is_valid, errors = validate_benefit_data(_benefits([0, 4, 0, 0]))

assert is_valid
assert errors == []


def test_benefit_full_weight_range_is_valid():
"""All selectable weights (0-4) are accepted."""
is_valid, errors = validate_benefit_data(_benefits([0, 1, 2, 3, 4]))

assert is_valid
assert errors == []


def test_benefit_weight_above_range_is_invalid():
"""Weights above the selectable range (>4) are rejected."""
is_valid, errors = validate_benefit_data(_benefits([5]))

assert not is_valid
assert len(errors) == 1
assert errors[0]["values"] == 5


def test_benefit_weight_below_range_is_invalid():
"""Negative weights are rejected."""
is_valid, errors = validate_benefit_data(_benefits([-1]))

assert not is_valid
assert len(errors) == 1


def test_validate_scenarios_recipes():

recipe_paths: RecipePaths = {
Expand Down
Loading