Files
mealie-mcp/tests/test_normalize.py
T
2026-07-31 08:38:11 +02:00

135 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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,
has_extraction_failure,
ingredient_display_lines,
line_remainder,
looks_mangled,
match_unit,
normalize_for_parser,
same_line,
slugify,
unit_token,
)
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")