import shutil from dataclasses import dataclass from fractions import Fraction import pytest from mealie.services.parser_services import RegisteredParser, get_parser from mealie.services.parser_services.crfpp.processor import CRFIngredient, convert_list_to_crf_model @dataclass class TestIngredient: input: str quantity: float unit: str food: str comments: str def crf_exists() -> bool: return shutil.which("crf_test") is not None # TODO - add more robust test cases test_ingredients = [ TestIngredient("½ cup all-purpose flour", 0.5, "cup", "all-purpose flour", ""), TestIngredient("1 ½ teaspoons ground black pepper", 1.5, "teaspoon", "black pepper", "ground"), TestIngredient("⅔ cup unsweetened flaked coconut", 0.667, "cup", "coconut", "unsweetened flaked"), TestIngredient("⅓ cup panko bread crumbs", 0.333, "cup", "panko bread crumbs", ""), # Small Fraction Tests - PR #1369 # Reported error is was for 1/8 - new lowest expected threshold is 1/32 TestIngredient("1/8 cup all-purpose flour", 0.125, "cup", "all-purpose flour", ""), TestIngredient("1/32 cup all-purpose flour", 0.031, "cup", "all-purpose flour", ""), ] @pytest.mark.skipif(not crf_exists(), reason="CRF++ not installed") def test_nlp_parser(): models: list[CRFIngredient] = convert_list_to_crf_model([x.input for x in test_ingredients]) # Itterate over mdoels and test_ingreidnets to gether for model, test_ingredient in zip(models, test_ingredients): assert round(float(sum(Fraction(s) for s in model.qty.split())), 3) == pytest.approx(test_ingredient.quantity) assert model.comment == test_ingredient.comments assert model.name == test_ingredient.food assert model.unit == test_ingredient.unit def test_brute_parser(): # input: (quantity, unit, food, comments) expectations = { # Dutch "1 theelepel koffie": (1, "theelepel", "koffie", ""), "3 theelepels koffie": (3, "theelepels", "koffie", ""), "1 eetlepel tarwe": (1, "eetlepel", "tarwe", ""), "20 eetlepels bloem": (20, "eetlepels", "bloem", ""), "1 mespunt kaneel": (1, "mespunt", "kaneel", ""), "1 snuf(je) zout": (1, "snuf(je)", "zout", ""), "2 tbsp minced cilantro, leaves and stems": (2, "tbsp", "minced cilantro", "leaves and stems"), "1 large yellow onion, coarsely chopped": (1, "large", "yellow onion", "coarsely chopped"), "1 1/2 tsp garam masala": (1.5, "tsp", "garam masala", ""), "2 cups mango chunks, (2 large mangoes) (fresh or frozen)": ( 2, "cups", "mango chunks, (2 large mangoes)", "fresh or frozen", ), } parser = get_parser(RegisteredParser.brute) for key, val in expectations.items(): parsed = parser.parse_one(key) assert parsed.ingredient.quantity == val[0] assert parsed.ingredient.unit.name == val[1] assert parsed.ingredient.food.name == val[2] assert parsed.ingredient.note in {val[3], None}