Files
mealie-mcp/tests/test_normalize.py
T

135 lines
4.5 KiB
Python
Raw Normal View History

2026-07-31 07:31:10 +02:00
"""Cases taken from failures verified against the live Mealie instance."""
from __future__ import annotations
import pytest
from mealie_mcp.normalize import (
clean_title,
find_english_leftovers,
food_matches_line,
2026-07-31 07:31:10 +02:00
has_extraction_failure,
ingredient_display_lines,
line_remainder,
2026-07-31 07:31:10 +02:00
looks_mangled,
match_unit,
2026-07-31 07:31:10 +02:00
normalize_for_parser,
same_line,
2026-07-31 07:31:10 +02:00
slugify,
unit_token,
2026-07-31 07:31:10 +02:00
)
class TestNormalizeForParser:
def test_converts_swedish_decimal_comma(self):
assert normalize_for_parser("4,7 dl basmatiris") == "4.7 dl basmatiris"
def test_leaves_list_commas_alone(self):
assert normalize_for_parser("salt, peppar") == "salt, peppar"
def test_collapses_whitespace(self):
assert normalize_for_parser(" 2 msk olja ") == "2 msk olja"
def test_is_idempotent(self):
once = normalize_for_parser("0,6 dl grädde")
assert normalize_for_parser(once) == once
class TestCleanTitle:
@pytest.mark.parametrize(
"raw,expected",
[
("Fläskfilé med svampsås - se & gör", "Fläskfilé med svampsås"),
("Kycklinggryta | Köket.se", "Kycklinggryta"),
("Pannkakor - se och gör", "Pannkakor"),
("Lax i ugn", "Lax i ugn"),
],
)
def test_strips_campaign_suffixes(self, raw, expected):
assert clean_title(raw) == expected
def test_strips_stacked_suffixes(self):
assert clean_title("Ugnslax - se & gör | Köket.se") == "Ugnslax"
class TestSlugify:
def test_transliterates_swedish_characters(self):
assert slugify("Kycklinggryta med äpple och lök") == "kycklinggryta-med-apple-och-lok"
def test_expands_ampersand(self):
assert slugify("Förrätter & tilltugg") == "forratter-och-tilltugg"
class TestFindEnglishLeftovers:
def test_flags_untranslated_units(self):
assert set(find_english_leftovers("2 cups flour, 1 tbsp butter")) == {"cups", "tbsp"}
def test_clean_swedish_line_passes(self):
assert find_english_leftovers("2 dl vetemjöl, 1 msk smör") == []
def test_does_not_match_inside_swedish_words(self):
# "klyfta" contains no English token; substring matching would be wrong here.
assert find_english_leftovers("1 klyfta vitlök") == []
class TestLooksMangled:
def test_flags_composed_fraction_from_parser(self):
assert looks_mangled("4710 liter basmatiris")
def test_flags_duplicated_unit(self):
assert looks_mangled("2 dl dl grädde")
def test_clean_line_is_not_mangled(self):
assert not looks_mangled("4,7 dl basmatiris")
class TestExtractionFailure:
def test_detects_scraper_placeholder_in_ingredients(self):
recipe = {"recipeIngredient": [{"display": "Could not detect ingredients"}]}
assert has_extraction_failure(recipe)
def test_clean_recipe_passes(self):
recipe = {"recipeIngredient": [{"display": "2 dl grädde"}]}
assert not has_extraction_failure(recipe)
class TestIngredientDisplayLines:
def test_prefers_display_then_note_then_food(self):
recipe = {
"recipeIngredient": [
{"display": "2 dl grädde", "note": "ignored"},
{"display": "", "note": "1 gul lök"},
{"display": "", "note": "", "food": {"name": "salt"}},
]
}
assert ingredient_display_lines(recipe) == ["2 dl grädde", "1 gul lök", "salt"]
class TestParserStructureSafety:
def test_reads_the_written_unit_token(self):
assert unit_token("4,7 dl basmatiris") == "dl"
assert unit_token("1-1,5 msk fond") == "msk"
assert unit_token("salt") is None
def test_matches_instance_unit_by_abbreviation(self):
gram = {"id": "g", "name": "gram", "abbreviation": "g"}
assert match_unit("g", [gram]) == gram
assert match_unit("dl", [gram]) is None
def test_rejects_a_nearby_but_different_food(self):
assert food_matches_line("kycklinglårfilé", "800 g kycklinglårfilé")
assert not food_matches_line("kycklingfilé", "800 g kycklinglårfilé")
def test_builds_note_from_only_the_unstructured_remainder(self):
assert (
line_remainder(
"200 g körsbärstomater (i olika färger)",
"g",
"körsbärstomat",
)
== "(i olika färger)"
)
def test_same_line_ignores_only_whitespace(self):
assert same_line("3 dl grädde", " 3 dl grädde ")
assert not same_line("3 dl grädde", "3 liter grädde")