Vibe coded some tests -_-
This commit is contained in:
parent
54f0dcbbb9
commit
2a66ff39be
2 changed files with 594 additions and 1 deletions
|
|
@ -53,7 +53,7 @@ async def find_ingredient_by_id(conn, ingredient_id: int) -> Optional[Ingredient
|
||||||
async with conn.execute(f'''
|
async with conn.execute(f'''
|
||||||
SELECT {','.join(ingredient_keys + product_keys)} FROM Ingredient
|
SELECT {','.join(ingredient_keys + product_keys)} FROM Ingredient
|
||||||
LEFT JOIN Product ON Ingredient.product_id = Product.id
|
LEFT JOIN Product ON Ingredient.product_id = Product.id
|
||||||
WHERE id = ?
|
WHERE Ingredient.id = ?
|
||||||
''', (ingredient_id,)) as cursor:
|
''', (ingredient_id,)) as cursor:
|
||||||
async for row in cursor:
|
async for row in cursor:
|
||||||
product_keys = {k:v for k,v in zip(Product.KEYS, row[len(Ingredient.KEYS):])}
|
product_keys = {k:v for k,v in zip(Product.KEYS, row[len(Ingredient.KEYS):])}
|
||||||
|
|
|
||||||
593
tests/test_ingredients.py
Normal file
593
tests/test_ingredients.py
Normal file
|
|
@ -0,0 +1,593 @@
|
||||||
|
import unittest
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
import tests.test_data as test_data
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
def reload_test_data():
|
||||||
|
global test_data
|
||||||
|
test_data = importlib.reload(test_data)
|
||||||
|
|
||||||
|
from db import connect, create
|
||||||
|
import ingredients
|
||||||
|
import ingredients.db as ingredients_db
|
||||||
|
import products.db as products_db
|
||||||
|
import units
|
||||||
|
|
||||||
|
|
||||||
|
class TestIngredient(unittest.IsolatedAsyncioTestCase):
|
||||||
|
async def asyncSetUp(self):
|
||||||
|
self.conn = await connect(':memory:')
|
||||||
|
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,
|
||||||
|
preparation="chopped"
|
||||||
|
)
|
||||||
|
|
||||||
|
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(
|
||||||
|
name="Garlic",
|
||||||
|
line="2 cloves garlic",
|
||||||
|
unit="Items",
|
||||||
|
quantity=2.0,
|
||||||
|
preparation="minced"
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient)
|
||||||
|
|
||||||
|
self.assertGreater(ingredient.id, 0)
|
||||||
|
|
||||||
|
# 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, {})
|
||||||
|
|
||||||
|
ingredient = ingredients_db.Ingredient(
|
||||||
|
name="Fresh Broccoli",
|
||||||
|
line="1 piece fresh broccoli",
|
||||||
|
unit="Items",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation="",
|
||||||
|
product_id=product.id,
|
||||||
|
product=product
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
ingredient1 = ingredients_db.Ingredient(
|
||||||
|
name="Flour",
|
||||||
|
line="2 cups flour",
|
||||||
|
unit="cups",
|
||||||
|
quantity=2.0,
|
||||||
|
preparation="",
|
||||||
|
recipe_id=recipe_id
|
||||||
|
)
|
||||||
|
|
||||||
|
ingredient2 = ingredients_db.Ingredient(
|
||||||
|
name="Sugar",
|
||||||
|
line="1 cup sugar",
|
||||||
|
unit="cups",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation="",
|
||||||
|
recipe_id=recipe_id
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient1)
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient2)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ingredient1 = ingredients_db.Ingredient(
|
||||||
|
name="Chicken",
|
||||||
|
line="1 lb chicken breast",
|
||||||
|
unit="lb",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation="diced",
|
||||||
|
meal_id=meal_id
|
||||||
|
)
|
||||||
|
|
||||||
|
ingredient2 = ingredients_db.Ingredient(
|
||||||
|
name="Rice",
|
||||||
|
line="2 cups rice",
|
||||||
|
unit="cups",
|
||||||
|
quantity=2.0,
|
||||||
|
preparation="",
|
||||||
|
meal_id=meal_id
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient1)
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient2)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ingredient = ingredients_db.Ingredient(
|
||||||
|
name="Tomato",
|
||||||
|
line="2 tomatoes",
|
||||||
|
unit="Items",
|
||||||
|
quantity=2.0,
|
||||||
|
preparation="sliced",
|
||||||
|
meal_id=meal_id
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# Delete ingredients by meal ID
|
||||||
|
await ingredients_db.delete_ingredients_by_meal_id(self.conn, meal_id)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
def reload_test_data():
|
||||||
|
global test_data
|
||||||
|
test_data = importlib.reload(test_data)
|
||||||
|
|
||||||
|
from db import connect, create
|
||||||
|
import ingredients
|
||||||
|
import ingredients.db as ingredients_db
|
||||||
|
import products.db as products_db
|
||||||
|
import units
|
||||||
|
|
||||||
|
|
||||||
|
class TestIngredient(unittest.IsolatedAsyncioTestCase):
|
||||||
|
async def asyncSetUp(self):
|
||||||
|
self.conn = await connect(':memory:')
|
||||||
|
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,
|
||||||
|
preparation="chopped"
|
||||||
|
)
|
||||||
|
|
||||||
|
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(
|
||||||
|
name="Garlic",
|
||||||
|
line="2 cloves garlic",
|
||||||
|
unit="Items",
|
||||||
|
quantity=2.0,
|
||||||
|
preparation="minced"
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient)
|
||||||
|
|
||||||
|
self.assertGreater(ingredient.id, 0)
|
||||||
|
|
||||||
|
# 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, {})
|
||||||
|
|
||||||
|
ingredient = ingredients_db.Ingredient(
|
||||||
|
name="Fresh Broccoli",
|
||||||
|
line="1 piece fresh broccoli",
|
||||||
|
unit="Items",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation="",
|
||||||
|
product_id=product.id,
|
||||||
|
product=product
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
ingredient1 = ingredients_db.Ingredient(
|
||||||
|
name="Flour",
|
||||||
|
line="2 cups flour",
|
||||||
|
unit="cups",
|
||||||
|
quantity=2.0,
|
||||||
|
preparation="",
|
||||||
|
recipe_id=recipe_id
|
||||||
|
)
|
||||||
|
|
||||||
|
ingredient2 = ingredients_db.Ingredient(
|
||||||
|
name="Sugar",
|
||||||
|
line="1 cup sugar",
|
||||||
|
unit="cups",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation="",
|
||||||
|
recipe_id=recipe_id
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient1)
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient2)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ingredient1 = ingredients_db.Ingredient(
|
||||||
|
name="Chicken",
|
||||||
|
line="1 lb chicken breast",
|
||||||
|
unit="lb",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation="diced",
|
||||||
|
meal_id=meal_id
|
||||||
|
)
|
||||||
|
|
||||||
|
ingredient2 = ingredients_db.Ingredient(
|
||||||
|
name="Rice",
|
||||||
|
line="2 cups rice",
|
||||||
|
unit="cups",
|
||||||
|
quantity=2.0,
|
||||||
|
preparation="",
|
||||||
|
meal_id=meal_id
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient1)
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient2)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ingredient = ingredients_db.Ingredient(
|
||||||
|
name="Tomato",
|
||||||
|
line="2 tomatoes",
|
||||||
|
unit="Items",
|
||||||
|
quantity=2.0,
|
||||||
|
preparation="sliced",
|
||||||
|
meal_id=meal_id
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# Delete ingredients by meal ID
|
||||||
|
await ingredients_db.delete_ingredients_by_meal_id(self.conn, meal_id)
|
||||||
|
|
||||||
|
# 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="",
|
||||||
|
product_id=-1
|
||||||
|
)
|
||||||
|
|
||||||
|
await ingredients_db.insert_ingredient(self.conn, ingredient)
|
||||||
|
|
||||||
|
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):
|
||||||
|
self.conn = await connect(':memory:')
|
||||||
|
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",
|
||||||
|
"",
|
||||||
|
"abc https://example.com"
|
||||||
|
]
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
result = await ingredients.parse_ingredient_from_link(self.conn, link)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Test the regex pattern used in parse_ingredient_from_link
|
||||||
|
test_cases = [
|
||||||
|
("2 https://example.com", "2", "https://example.com"),
|
||||||
|
("10 https://www.woolworths.com.au/product", "10", "https://www.woolworths.com.au/product"),
|
||||||
|
("https://example.com", None, "https://example.com"),
|
||||||
|
("1 https://test.com", "1", "https://test.com")
|
||||||
|
]
|
||||||
|
|
||||||
|
for link, expected_qty, expected_url in test_cases:
|
||||||
|
match = re.match(r'^(\d+)?\s*(http.*)$', link)
|
||||||
|
if match:
|
||||||
|
quantity = int(match.group(1)) if match.group(1) else 1
|
||||||
|
url = match.group(2)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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):
|
||||||
|
self.conn = await connect(':memory:')
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Create ingredients without products
|
||||||
|
ingredient1 = ingredients_db.Ingredient(
|
||||||
|
name="broccoli",
|
||||||
|
line="1 piece broccoli",
|
||||||
|
unit="Items",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation=""
|
||||||
|
)
|
||||||
|
|
||||||
|
ingredient2 = ingredients_db.Ingredient(
|
||||||
|
name="unknown vegetable",
|
||||||
|
line="1 piece unknown vegetable",
|
||||||
|
unit="Items",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation=""
|
||||||
|
)
|
||||||
|
|
||||||
|
ingredients_list = [ingredient1, ingredient2]
|
||||||
|
result = await ingredients.match_existing_products(self.conn, ingredients_list)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
ingredient = ingredients_db.Ingredient(
|
||||||
|
name="broccoli",
|
||||||
|
line="1 piece broccoli",
|
||||||
|
unit="Items",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation="",
|
||||||
|
product=product,
|
||||||
|
product_id=product.id
|
||||||
|
)
|
||||||
|
|
||||||
|
ingredients_list = [ingredient]
|
||||||
|
result = await ingredients.match_existing_products(self.conn, ingredients_list)
|
||||||
|
|
||||||
|
# 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"""
|
||||||
|
expected_keys = ['id', 'name', 'line', 'preparation', 'unit', 'quantity', 'product_id', 'recipe_id', 'meal_id']
|
||||||
|
self.assertEqual(ingredients_db.Ingredient.KEYS, expected_keys)
|
||||||
|
|
||||||
|
async def test_ingredient_default_values(self):
|
||||||
|
"""Test ingredient default values"""
|
||||||
|
ingredient = ingredients_db.Ingredient(
|
||||||
|
name="Test",
|
||||||
|
line="Test line",
|
||||||
|
unit="Items",
|
||||||
|
quantity=1.0,
|
||||||
|
preparation=""
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(ingredient.id, -1)
|
||||||
|
self.assertIsNone(ingredient.product_id)
|
||||||
|
self.assertIsNone(ingredient.recipe_id)
|
||||||
|
self.assertIsNone(ingredient.meal_id)
|
||||||
|
self.assertIsNone(ingredient.product)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Loading…
Reference in a new issue