munch-ease-backend/tests/test_ingredients.py

594 lines
21 KiB
Python
Raw Normal View History

2025-07-30 08:55:51 +00:00
import unittest
import asyncio
import tests.test_data as test_data
import importlib
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
def reload_test_data():
global test_data
test_data = importlib.reload(test_data)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
from db import connect, create
import ingredients
Squashed commit of the following: commit fcd005b8624023547f28b7b28e59e6099bcfc7d4 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 20:24:07 2025 +1100 Openapi tightening commit f93bd8f641d561052c7bd075bae321b4ff3b676d Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 19:03:52 2025 +1100 Removed refactor strategy doc commit 0c5a61092f522be0c47cbbe86917c8a7e4e2d339 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 17:48:33 2025 +1100 mypy & ruff checks commit 23d66d6b18984127e17c73c3063f6120385935e9 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 16:49:35 2025 +1100 Final removal of db.py files commit f454aed1ca9783cc558cc203f29a7fe31b62a975 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:42:31 2025 +1100 Finalise restructure, remove db.py files commit 7187f6dd89489521538791c6bdebb426514beb99 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:34:54 2025 +1100 commit 6fea227ae20d32b8eb1e7a4885006a620fcc7bb1 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:32:53 2025 +1100 commit 27415e7e02d89195ad514cb017a9dbbf84d7a5e4 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:31:10 2025 +1100 commit b773428033d855f9ad82005602e049c1a2e3c585 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:28:58 2025 +1100 commit 116592c95278d995f4c516e87f2cea43cf5b7735 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:25:21 2025 +1100 commit 03ec565faea088971968ee2f9bb83e2de16b21f3 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:21:29 2025 +1100 Plan
2025-10-19 09:24:23 +00:00
import ingredients.repository as ingredients_db
import products.repository as products_db
2025-07-30 08:55:51 +00:00
import units
class TestIngredient(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
2025-10-18 03:26:42 +00:00
self.conn = await connect(":memory:")
2025-07-30 08:55:51 +00:00
await create(self.conn)
await test_data.create_persons(self.conn)
reload_test_data()
return await super().asyncSetUp()
async def asyncTearDown(self) -> None:
await self.conn.close()
return await super().asyncTearDown()
async def test_ingredient_creation(self):
"""Test basic ingredient creation"""
ingredient = ingredients_db.Ingredient(
name="Broccoli",
line="500g fresh broccoli",
unit="g",
quantity=500.0,
2025-10-18 03:26:42 +00:00
preparation="chopped",
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
self.assertEqual(ingredient.name, "Broccoli")
self.assertEqual(ingredient.line, "500g fresh broccoli")
self.assertEqual(ingredient.unit, "g")
self.assertEqual(ingredient.quantity, 500.0)
self.assertEqual(ingredient.preparation, "chopped")
async def test_insert_ingredient(self):
"""Test inserting an ingredient into the database"""
ingredient = ingredients_db.Ingredient(
2025-10-18 03:26:42 +00:00
name="Garlic", line="2 cloves garlic", unit="Items", quantity=2.0, preparation="minced"
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
self.assertGreater(ingredient.id, 0)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Verify it was inserted correctly
found_ingredient = await ingredients_db.find_ingredient_by_id(self.conn, ingredient.id)
self.assertIsNotNone(found_ingredient)
self.assertEqual(found_ingredient.name, "Garlic")
self.assertEqual(found_ingredient.quantity, 2.0)
async def test_insert_ingredient_with_product(self):
"""Test inserting an ingredient with an associated product"""
# First create and insert a product
product = test_data.Products.broccoli
await products_db.insert_product(self.conn, product, {})
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient = ingredients_db.Ingredient(
name="Fresh Broccoli",
line="1 piece fresh broccoli",
unit="Items",
quantity=1.0,
preparation="",
product_id=product.id,
2025-10-18 03:26:42 +00:00
product=product,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Verify the ingredient was inserted with the product reference
found_ingredient = await ingredients_db.find_ingredient_by_id(self.conn, ingredient.id)
self.assertIsNotNone(found_ingredient)
self.assertEqual(found_ingredient.product_id, product.id)
self.assertIsNotNone(found_ingredient.product)
self.assertEqual(found_ingredient.product.name, product.name)
async def test_find_ingredient_by_id_not_found(self):
"""Test finding a non-existent ingredient returns None"""
result = await ingredients_db.find_ingredient_by_id(self.conn, 999)
self.assertIsNone(result)
async def test_find_ingredients_by_recipe_id(self):
"""Test finding ingredients by recipe ID"""
# Create ingredients with the same recipe_id
recipe_id = 1
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient1 = ingredients_db.Ingredient(
name="Flour",
line="2 cups flour",
unit="cups",
quantity=2.0,
preparation="",
2025-10-18 03:26:42 +00:00
recipe_id=recipe_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient2 = ingredients_db.Ingredient(
name="Sugar",
line="1 cup sugar",
unit="cups",
quantity=1.0,
preparation="",
2025-10-18 03:26:42 +00:00
recipe_id=recipe_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient1)
await ingredients_db.insert_ingredient(self.conn, ingredient2)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Find ingredients by recipe ID
ingredients_list = []
async for ingredient in ingredients_db.find_ingredients_by_recipe_id(self.conn, recipe_id):
ingredients_list.append(ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
self.assertEqual(len(ingredients_list), 2)
names = [ing.name for ing in ingredients_list]
self.assertIn("Flour", names)
self.assertIn("Sugar", names)
async def test_find_ingredients_by_meal_id(self):
"""Test finding ingredients by meal ID"""
# Create ingredients with the same meal_id
meal_id = 1
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient1 = ingredients_db.Ingredient(
name="Chicken",
line="1 lb chicken breast",
unit="lb",
quantity=1.0,
preparation="diced",
2025-10-18 03:26:42 +00:00
meal_id=meal_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient2 = ingredients_db.Ingredient(
name="Rice",
line="2 cups rice",
unit="cups",
quantity=2.0,
preparation="",
2025-10-18 03:26:42 +00:00
meal_id=meal_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient1)
await ingredients_db.insert_ingredient(self.conn, ingredient2)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Find ingredients by meal ID
ingredients_list = []
async for ingredient in ingredients_db.find_ingredients_by_meal_id(self.conn, meal_id):
ingredients_list.append(ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
self.assertEqual(len(ingredients_list), 2)
names = [ing.name for ing in ingredients_list]
self.assertIn("Chicken", names)
self.assertIn("Rice", names)
async def test_delete_ingredients_by_meal_id(self):
"""Test deleting ingredients by meal ID"""
meal_id = 1
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient = ingredients_db.Ingredient(
name="Tomato",
line="2 tomatoes",
unit="Items",
quantity=2.0,
preparation="sliced",
2025-10-18 03:26:42 +00:00
meal_id=meal_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Verify ingredient exists
ingredients_list = []
async for ing in ingredients_db.find_ingredients_by_meal_id(self.conn, meal_id):
ingredients_list.append(ing)
self.assertEqual(len(ingredients_list), 1)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Delete ingredients by meal ID
await ingredients_db.delete_ingredients_by_meal_id(self.conn, meal_id)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Verify ingredients are deleted
ingredients_list = []
async for ing in ingredients_db.find_ingredients_by_meal_id(self.conn, meal_id):
ingredients_list.append(ing)
self.assertEqual(len(ingredients_list), 0)
import unittest
import asyncio
import tests.test_data as test_data
import importlib
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
def reload_test_data():
global test_data
test_data = importlib.reload(test_data)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
from db import connect, create
import ingredients
Squashed commit of the following: commit fcd005b8624023547f28b7b28e59e6099bcfc7d4 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 20:24:07 2025 +1100 Openapi tightening commit f93bd8f641d561052c7bd075bae321b4ff3b676d Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 19:03:52 2025 +1100 Removed refactor strategy doc commit 0c5a61092f522be0c47cbbe86917c8a7e4e2d339 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 17:48:33 2025 +1100 mypy & ruff checks commit 23d66d6b18984127e17c73c3063f6120385935e9 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 16:49:35 2025 +1100 Final removal of db.py files commit f454aed1ca9783cc558cc203f29a7fe31b62a975 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:42:31 2025 +1100 Finalise restructure, remove db.py files commit 7187f6dd89489521538791c6bdebb426514beb99 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:34:54 2025 +1100 commit 6fea227ae20d32b8eb1e7a4885006a620fcc7bb1 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:32:53 2025 +1100 commit 27415e7e02d89195ad514cb017a9dbbf84d7a5e4 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:31:10 2025 +1100 commit b773428033d855f9ad82005602e049c1a2e3c585 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:28:58 2025 +1100 commit 116592c95278d995f4c516e87f2cea43cf5b7735 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:25:21 2025 +1100 commit 03ec565faea088971968ee2f9bb83e2de16b21f3 Author: jableader <jacobdunk@gmail.com> Date: Sun Oct 19 15:21:29 2025 +1100 Plan
2025-10-19 09:24:23 +00:00
import ingredients.repository as ingredients_db
import products.repository as products_db
2025-07-30 08:55:51 +00:00
import units
class TestIngredient(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
2025-10-18 03:26:42 +00:00
self.conn = await connect(":memory:")
2025-07-30 08:55:51 +00:00
await create(self.conn)
await test_data.create_persons(self.conn)
reload_test_data()
return await super().asyncSetUp()
async def asyncTearDown(self) -> None:
await self.conn.close()
return await super().asyncTearDown()
async def test_ingredient_creation(self):
"""Test basic ingredient creation"""
ingredient = ingredients_db.Ingredient(
name="Broccoli",
line="500g fresh broccoli",
unit="g",
quantity=500.0,
2025-10-18 03:26:42 +00:00
preparation="chopped",
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
self.assertEqual(ingredient.name, "Broccoli")
self.assertEqual(ingredient.line, "500g fresh broccoli")
self.assertEqual(ingredient.unit, "g")
self.assertEqual(ingredient.quantity, 500.0)
self.assertEqual(ingredient.preparation, "chopped")
async def test_insert_ingredient(self):
"""Test inserting an ingredient into the database"""
ingredient = ingredients_db.Ingredient(
2025-10-18 03:26:42 +00:00
name="Garlic", line="2 cloves garlic", unit="Items", quantity=2.0, preparation="minced"
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
self.assertGreater(ingredient.id, 0)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Verify it was inserted correctly
found_ingredient = await ingredients_db.find_ingredient_by_id(self.conn, ingredient.id)
self.assertIsNotNone(found_ingredient)
self.assertEqual(found_ingredient.name, "Garlic")
self.assertEqual(found_ingredient.quantity, 2.0)
async def test_insert_ingredient_with_product(self):
"""Test inserting an ingredient with an associated product"""
# First create and insert a product
product = test_data.Products.broccoli
await products_db.insert_product(self.conn, product, {})
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient = ingredients_db.Ingredient(
name="Fresh Broccoli",
line="1 piece fresh broccoli",
unit="Items",
quantity=1.0,
preparation="",
product_id=product.id,
2025-10-18 03:26:42 +00:00
product=product,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Verify the ingredient was inserted with the product reference
found_ingredient = await ingredients_db.find_ingredient_by_id(self.conn, ingredient.id)
self.assertIsNotNone(found_ingredient)
self.assertEqual(found_ingredient.product_id, product.id)
self.assertIsNotNone(found_ingredient.product)
self.assertEqual(found_ingredient.product.name, product.name)
async def test_find_ingredient_by_id_not_found(self):
"""Test finding a non-existent ingredient returns None"""
result = await ingredients_db.find_ingredient_by_id(self.conn, 999)
self.assertIsNone(result)
async def test_find_ingredients_by_recipe_id(self):
"""Test finding ingredients by recipe ID"""
# Create ingredients with the same recipe_id
recipe_id = 1
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient1 = ingredients_db.Ingredient(
name="Flour",
line="2 cups flour",
unit="cups",
quantity=2.0,
preparation="",
2025-10-18 03:26:42 +00:00
recipe_id=recipe_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient2 = ingredients_db.Ingredient(
name="Sugar",
line="1 cup sugar",
unit="cups",
quantity=1.0,
preparation="",
2025-10-18 03:26:42 +00:00
recipe_id=recipe_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient1)
await ingredients_db.insert_ingredient(self.conn, ingredient2)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Find ingredients by recipe ID
ingredients_list = []
async for ingredient in ingredients_db.find_ingredients_by_recipe_id(self.conn, recipe_id):
ingredients_list.append(ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
self.assertEqual(len(ingredients_list), 2)
names = [ing.name for ing in ingredients_list]
self.assertIn("Flour", names)
self.assertIn("Sugar", names)
async def test_find_ingredients_by_meal_id(self):
"""Test finding ingredients by meal ID"""
# Create ingredients with the same meal_id
meal_id = 1
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient1 = ingredients_db.Ingredient(
name="Chicken",
line="1 lb chicken breast",
unit="lb",
quantity=1.0,
preparation="diced",
2025-10-18 03:26:42 +00:00
meal_id=meal_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient2 = ingredients_db.Ingredient(
name="Rice",
line="2 cups rice",
unit="cups",
quantity=2.0,
preparation="",
2025-10-18 03:26:42 +00:00
meal_id=meal_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient1)
await ingredients_db.insert_ingredient(self.conn, ingredient2)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Find ingredients by meal ID
ingredients_list = []
async for ingredient in ingredients_db.find_ingredients_by_meal_id(self.conn, meal_id):
ingredients_list.append(ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
self.assertEqual(len(ingredients_list), 2)
names = [ing.name for ing in ingredients_list]
self.assertIn("Chicken", names)
self.assertIn("Rice", names)
async def test_delete_ingredients_by_meal_id(self):
"""Test deleting ingredients by meal ID"""
meal_id = 1
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient = ingredients_db.Ingredient(
name="Tomato",
line="2 tomatoes",
unit="Items",
quantity=2.0,
preparation="sliced",
2025-10-18 03:26:42 +00:00
meal_id=meal_id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Verify ingredient exists
ingredients_list = []
async for ing in ingredients_db.find_ingredients_by_meal_id(self.conn, meal_id):
ingredients_list.append(ing)
self.assertEqual(len(ingredients_list), 1)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Delete ingredients by meal ID
await ingredients_db.delete_ingredients_by_meal_id(self.conn, meal_id)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Verify ingredients are deleted
ingredients_list = []
async for ing in ingredients_db.find_ingredients_by_meal_id(self.conn, meal_id):
ingredients_list.append(ing)
self.assertEqual(len(ingredients_list), 0)
async def test_ingredient_with_negative_product_id(self):
"""Test that negative product_id is converted to None during insertion"""
ingredient = ingredients_db.Ingredient(
name="Test Ingredient",
line="1 test ingredient",
unit="Items",
quantity=1.0,
preparation="",
2025-10-18 03:26:42 +00:00
product_id=-1,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
await ingredients_db.insert_ingredient(self.conn, ingredient)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
found_ingredient = await ingredients_db.find_ingredient_by_id(self.conn, ingredient.id)
self.assertIsNone(found_ingredient.product_id)
class TestIngredientParsing(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
2025-10-18 03:26:42 +00:00
self.conn = await connect(":memory:")
2025-07-30 08:55:51 +00:00
await create(self.conn)
await test_data.create_persons(self.conn)
reload_test_data()
return await super().asyncSetUp()
async def asyncTearDown(self) -> None:
await self.conn.close()
return await super().asyncTearDown()
async def test_parse_ingredient_from_link_invalid_format(self):
"""Test parsing ingredient from invalid link format returns None"""
invalid_links = [
"invalid link format",
"just a url https://example.com",
"no quantity https://example.com",
"",
2025-10-18 03:26:42 +00:00
"abc https://example.com",
2025-07-30 08:55:51 +00:00
]
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
for invalid_link in invalid_links:
result = await ingredients.parse_ingredient_from_link(self.conn, invalid_link)
self.assertIsNone(result, f"Should return None for: {invalid_link}")
async def test_parse_ingredient_from_link_valid_format_no_quantity(self):
"""Test parsing ingredient from valid link format without explicit quantity"""
link = "https://www.woolworths.com.au/shop/productdetails/134681/fresh-broccoli"
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
result = await ingredients.parse_ingredient_from_link(self.conn, link)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# The scraper actually works for this URL, so we should get a result
self.assertIsNotNone(result)
self.assertEqual(result.quantity, 1.0) # Default quantity when none specified
self.assertEqual(result.unit, units.ITEMS.name)
self.assertIsInstance(result, ingredients_db.Ingredient)
async def test_parse_ingredient_from_link_regex_parsing(self):
"""Test that the regex correctly parses quantity and URL from valid links"""
import re
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Test the regex pattern used in parse_ingredient_from_link
test_cases = [
("2 https://example.com", "2", "https://example.com"),
2025-10-18 03:26:42 +00:00
(
"10 https://www.woolworths.com.au/product",
"10",
"https://www.woolworths.com.au/product",
),
2025-07-30 08:55:51 +00:00
("https://example.com", None, "https://example.com"),
2025-10-18 03:26:42 +00:00
("1 https://test.com", "1", "https://test.com"),
2025-07-30 08:55:51 +00:00
]
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
for link, expected_qty, expected_url in test_cases:
2025-10-18 03:26:42 +00:00
match = re.match(r"^(\d+)?\s*(http.*)$", link)
2025-07-30 08:55:51 +00:00
if match:
quantity = int(match.group(1)) if match.group(1) else 1
url = match.group(2)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
if expected_qty:
self.assertEqual(quantity, int(expected_qty))
else:
self.assertEqual(quantity, 1) # Default quantity
self.assertEqual(url, expected_url)
async def test_parse_ingredient_from_nlp_simple_cases(self):
"""Test parsing simple ingredient cases that don't require external dependencies"""
# Test the basic structure without relying on ingredient_parser
# Since ingredient_parser is an external dependency, we'll test what we can
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# We can test that the function exists and handles basic error cases
try:
result = ingredients.parse_ingredient_from_nlp("2 cups flour")
# The function may fail due to missing ingredient_parser, but it should not crash
# If it works, result should be an Ingredient object
if result is not None:
self.assertIsInstance(result, ingredients_db.Ingredient)
except ImportError:
# If ingredient_parser is not available, that's expected
self.skipTest("ingredient_parser not available")
except Exception as e:
# Other exceptions should not occur in normal operation
self.fail(f"Unexpected exception: {e}")
class TestIngredientMatching(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
2025-10-18 03:26:42 +00:00
self.conn = await connect(":memory:")
2025-07-30 08:55:51 +00:00
await create(self.conn)
await test_data.create_persons(self.conn)
reload_test_data()
return await super().asyncSetUp()
async def asyncTearDown(self) -> None:
await self.conn.close()
return await super().asyncTearDown()
async def test_match_existing_products_with_real_data(self):
"""Test matching ingredients to existing products using real operations"""
# Setup: Create and insert a product with tags
product = test_data.Products.broccoli
await products_db.insert_product(self.conn, product, {})
await products_db.add_tag(self.conn, product, "broccoli")
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Create ingredients without products
ingredient1 = ingredients_db.Ingredient(
2025-10-18 03:26:42 +00:00
name="broccoli", line="1 piece broccoli", unit="Items", quantity=1.0, preparation=""
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient2 = ingredients_db.Ingredient(
name="unknown vegetable",
line="1 piece unknown vegetable",
unit="Items",
quantity=1.0,
2025-10-18 03:26:42 +00:00
preparation="",
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredients_list = [ingredient1, ingredient2]
result = await ingredients.match_existing_products(self.conn, ingredients_list)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Check that first ingredient got matched
self.assertEqual(result[0].product_id, product.id)
self.assertIsNotNone(result[0].product)
self.assertEqual(result[0].product.name, product.name)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Check that second ingredient remained unmatched
self.assertIsNone(result[1].product)
async def test_match_existing_products_already_has_product(self):
"""Test that ingredients with existing products are not re-matched"""
product = test_data.Products.broccoli
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredient = ingredients_db.Ingredient(
name="broccoli",
line="1 piece broccoli",
unit="Items",
quantity=1.0,
preparation="",
product=product,
2025-10-18 03:26:42 +00:00
product_id=product.id,
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
ingredients_list = [ingredient]
result = await ingredients.match_existing_products(self.conn, ingredients_list)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
# Should remain unchanged
self.assertEqual(result[0].product_id, product.id)
self.assertEqual(result[0].product, product)
async def test_match_existing_products_empty_list(self):
"""Test matching empty ingredients list"""
result = await ingredients.match_existing_products(self.conn, [])
self.assertEqual(result, [])
async def test_ingredient_keys_constant(self):
"""Test that the KEYS constant contains expected fields"""
2025-10-18 03:26:42 +00:00
expected_keys = [
"id",
"name",
"line",
"preparation",
"unit",
"quantity",
"product_id",
"recipe_id",
"meal_id",
]
2025-07-30 08:55:51 +00:00
self.assertEqual(ingredients_db.Ingredient.KEYS, expected_keys)
async def test_ingredient_default_values(self):
"""Test ingredient default values"""
ingredient = ingredients_db.Ingredient(
2025-10-18 03:26:42 +00:00
name="Test", line="Test line", unit="Items", quantity=1.0, preparation=""
2025-07-30 08:55:51 +00:00
)
2025-10-18 03:26:42 +00:00
2025-07-30 08:55:51 +00:00
self.assertEqual(ingredient.id, -1)
self.assertIsNone(ingredient.product_id)
self.assertIsNone(ingredient.recipe_id)
self.assertIsNone(ingredient.meal_id)
self.assertIsNone(ingredient.product)
2025-10-18 03:26:42 +00:00
if __name__ == "__main__":
2025-07-30 08:55:51 +00:00
unittest.main()