2025-07-30 12:05:29 +00:00
|
|
|
import unittest
|
|
|
|
|
import asyncio
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
import importlib
|
|
|
|
|
|
|
|
|
|
import tests.test_data as test_data
|
|
|
|
|
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +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 12:05:29 +00:00
|
|
|
from db import connect, create
|
|
|
|
|
import meals
|
|
|
|
|
import meals.db as meals_db
|
|
|
|
|
from meals.db import Meal, MealRecipe
|
|
|
|
|
import persons
|
|
|
|
|
import recipes
|
|
|
|
|
import ingredients
|
|
|
|
|
import products
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMealsModels(unittest.IsolatedAsyncioTestCase):
|
|
|
|
|
"""Test the meals data models"""
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
async def asyncSetUp(self):
|
2025-10-18 03:26:42 +00:00
|
|
|
self.conn = await connect(":memory:")
|
2025-07-30 12:05:29 +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()
|
|
|
|
|
|
|
|
|
|
def test_meal_creation(self):
|
|
|
|
|
"""Test basic Meal creation"""
|
|
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 1, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie, test_data.Persons.chris],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
self.assertEqual(meal.id, -1) # Default ID
|
|
|
|
|
self.assertEqual(meal.suggested_date, datetime(2024, 1, 1, 18, 0))
|
|
|
|
|
self.assertIsNone(meal.consumed_date)
|
|
|
|
|
self.assertEqual(len(meal.chefs), 1)
|
|
|
|
|
self.assertEqual(len(meal.cleanup), 1)
|
|
|
|
|
self.assertEqual(len(meal.consumers), 2)
|
|
|
|
|
self.assertEqual(len(meal.recipes), 0)
|
|
|
|
|
self.assertEqual(len(meal.extra_ingredients), 0)
|
|
|
|
|
|
|
|
|
|
def test_meal_recipe_creation(self):
|
|
|
|
|
"""Test basic MealRecipe creation"""
|
2025-10-18 03:26:42 +00:00
|
|
|
meal_recipe = MealRecipe(meal_id=1, recipe_id=2, servings=4.0)
|
|
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
self.assertEqual(meal_recipe.meal_id, 1)
|
|
|
|
|
self.assertEqual(meal_recipe.recipe_id, 2)
|
|
|
|
|
self.assertEqual(meal_recipe.servings, 4.0)
|
|
|
|
|
self.assertIsNone(meal_recipe.recipe)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMealsCRUD(unittest.IsolatedAsyncioTestCase):
|
|
|
|
|
"""Test meals CRUD operations"""
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
async def asyncSetUp(self):
|
2025-10-18 03:26:42 +00:00
|
|
|
self.conn = await connect(":memory:")
|
2025-07-30 12:05:29 +00:00
|
|
|
await create(self.conn)
|
|
|
|
|
await test_data.create_test_data(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_insert_meal_basic(self):
|
|
|
|
|
"""Test inserting a basic meal with participants"""
|
|
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 1, 15, 19, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify meal was inserted and got an ID
|
|
|
|
|
self.assertGreater(meal.id, 0)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify we can find it by ID
|
|
|
|
|
found_meal = await meals_db.find_meal_by_id(self.conn, meal.id)
|
|
|
|
|
self.assertEqual(found_meal.suggested_date, meal.suggested_date)
|
|
|
|
|
self.assertEqual(len(found_meal.chefs), 1)
|
|
|
|
|
self.assertEqual(found_meal.chefs[0].name, "Jacob")
|
|
|
|
|
self.assertEqual(len(found_meal.cleanup), 1)
|
|
|
|
|
self.assertEqual(found_meal.cleanup[0].name, "Ryan")
|
|
|
|
|
self.assertEqual(len(found_meal.consumers), 1)
|
|
|
|
|
self.assertEqual(found_meal.consumers[0].name, "Ellie")
|
|
|
|
|
|
|
|
|
|
async def test_insert_meal_with_recipes(self):
|
|
|
|
|
"""Test inserting a meal with recipes"""
|
|
|
|
|
# First create a recipe
|
|
|
|
|
recipe = test_data.Recipes.broccoli_soup
|
|
|
|
|
recipe.id = -1 # Reset ID
|
|
|
|
|
await recipes.insert_recipe(self.conn, recipe)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
|
|
|
|
meal_recipe = MealRecipe(meal_id=-1, recipe_id=recipe.id, servings=3.0, recipe=recipe)
|
|
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 2, 1, 18, 30),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
|
|
|
|
consumers=[test_data.Persons.ellie, test_data.Persons.chris],
|
2025-10-18 03:26:42 +00:00
|
|
|
recipes=[meal_recipe],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify meal was inserted
|
|
|
|
|
self.assertGreater(meal.id, 0)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify recipe was associated
|
|
|
|
|
found_meal = await meals_db.find_meal_by_id(self.conn, meal.id)
|
|
|
|
|
self.assertEqual(len(found_meal.recipes), 1)
|
|
|
|
|
self.assertEqual(found_meal.recipes[0].recipe_id, recipe.id)
|
|
|
|
|
self.assertEqual(found_meal.recipes[0].servings, 3.0)
|
|
|
|
|
self.assertIsNotNone(found_meal.recipes[0].recipe)
|
|
|
|
|
self.assertEqual(found_meal.recipes[0].recipe.name, recipe.name)
|
|
|
|
|
|
|
|
|
|
async def test_insert_meal_with_extra_ingredients(self):
|
|
|
|
|
"""Test inserting a meal with extra ingredients"""
|
|
|
|
|
# Create a new product for testing
|
|
|
|
|
product = products.Product(
|
|
|
|
|
id=-1,
|
2025-10-18 03:26:42 +00:00
|
|
|
shop_code="woolworths",
|
2025-07-30 12:05:29 +00:00
|
|
|
name="Test Garlic Bread",
|
|
|
|
|
product_id="test_294517",
|
|
|
|
|
quantity=1,
|
|
|
|
|
unit="Loaf",
|
|
|
|
|
link="https://example.com/test-garlic-bread",
|
|
|
|
|
img_small="https://example.com/test-small.jpg",
|
|
|
|
|
img_large="https://example.com/test-large.jpg",
|
|
|
|
|
raw_data={},
|
|
|
|
|
)
|
|
|
|
|
await products.insert_product(self.conn, product, {})
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Create an ingredient
|
|
|
|
|
extra_ingredient = ingredients.Ingredient(
|
|
|
|
|
id=-1,
|
|
|
|
|
name="Test Garlic Bread",
|
|
|
|
|
line="1 loaf test garlic bread",
|
|
|
|
|
unit="loaf",
|
|
|
|
|
quantity=1.0,
|
|
|
|
|
preparation="",
|
2025-10-18 03:26:42 +00:00
|
|
|
product_id=product.id,
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 3, 1, 19, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
|
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-10-18 03:26:42 +00:00
|
|
|
extra_ingredients=[extra_ingredient],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify meal was inserted
|
|
|
|
|
self.assertGreater(meal.id, 0)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify extra ingredients were associated
|
|
|
|
|
found_meal = await meals_db.find_meal_by_id(self.conn, meal.id)
|
|
|
|
|
self.assertEqual(len(found_meal.extra_ingredients), 1)
|
|
|
|
|
self.assertEqual(found_meal.extra_ingredients[0].name, "Test Garlic Bread")
|
|
|
|
|
|
|
|
|
|
async def test_find_meal_by_id_not_found(self):
|
|
|
|
|
"""Test finding a meal that doesn't exist"""
|
|
|
|
|
result = await meals_db.find_meal_by_id(self.conn, 999)
|
|
|
|
|
self.assertIsNone(result)
|
|
|
|
|
|
|
|
|
|
async def test_update_meal(self):
|
|
|
|
|
"""Test updating a meal"""
|
|
|
|
|
# Create and insert initial meal
|
|
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 4, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
|
|
|
|
original_id = meal.id
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Update the meal
|
|
|
|
|
meal.suggested_date = datetime(2024, 4, 2, 19, 0)
|
|
|
|
|
meal.chefs = [test_data.Persons.ryan] # Change chef
|
|
|
|
|
meal.cleanup = [test_data.Persons.ellie] # Change cleanup
|
|
|
|
|
meal.consumers = [test_data.Persons.jacob, test_data.Persons.chris] # Change consumers
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.update_meal(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify updates
|
|
|
|
|
found_meal = await meals_db.find_meal_by_id(self.conn, original_id)
|
|
|
|
|
self.assertEqual(found_meal.suggested_date, datetime(2024, 4, 2, 19, 0))
|
|
|
|
|
self.assertEqual(len(found_meal.chefs), 1)
|
|
|
|
|
self.assertEqual(found_meal.chefs[0].name, "Ryan")
|
|
|
|
|
self.assertEqual(len(found_meal.cleanup), 1)
|
|
|
|
|
self.assertEqual(found_meal.cleanup[0].name, "Ellie")
|
|
|
|
|
self.assertEqual(len(found_meal.consumers), 2)
|
|
|
|
|
consumer_names = {p.name for p in found_meal.consumers}
|
|
|
|
|
self.assertIn("Jacob", consumer_names)
|
|
|
|
|
self.assertIn("Chris", consumer_names)
|
|
|
|
|
|
|
|
|
|
async def test_mark_consumed(self):
|
|
|
|
|
"""Test marking a meal as consumed"""
|
|
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 5, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Mark as consumed
|
|
|
|
|
consumed_date = datetime(2024, 5, 1, 19, 30)
|
|
|
|
|
await meals_db.mark_consumed(self.conn, meal, consumed_date)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify consumed date was set
|
|
|
|
|
self.assertEqual(meal.consumed_date, consumed_date)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify in database
|
|
|
|
|
found_meal = await meals_db.find_meal_by_id(self.conn, meal.id)
|
|
|
|
|
self.assertEqual(found_meal.consumed_date, consumed_date)
|
|
|
|
|
|
|
|
|
|
async def test_mark_purchased(self):
|
|
|
|
|
"""Test marking a meal as purchased"""
|
|
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 6, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Mark as purchased
|
|
|
|
|
updated_meal = await meals_db.mark_purchased(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify purchase date was set
|
|
|
|
|
self.assertIsNotNone(updated_meal.purchase_date)
|
|
|
|
|
self.assertIsNotNone(meal.purchase_date)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify in database
|
|
|
|
|
found_meal = await meals_db.find_meal_by_id(self.conn, meal.id)
|
|
|
|
|
self.assertIsNotNone(found_meal.purchase_date)
|
|
|
|
|
|
|
|
|
|
async def test_delete_meal(self):
|
|
|
|
|
"""Test soft deleting a meal"""
|
|
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 7, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
|
|
|
|
meal_id = meal.id
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify meal exists and is in upcoming meals before deletion
|
|
|
|
|
start_date = datetime(2024, 7, 1)
|
|
|
|
|
end_date = datetime(2024, 7, 31)
|
|
|
|
|
upcoming_meals_before = []
|
|
|
|
|
async for m in meals_db.find_upcoming_meals_by_date_range(self.conn, start_date, end_date):
|
|
|
|
|
if m.id == meal_id:
|
|
|
|
|
upcoming_meals_before.append(m)
|
|
|
|
|
self.assertEqual(len(upcoming_meals_before), 1)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Delete the meal
|
|
|
|
|
await meals_db.delete_meal(self.conn, meal_id)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify meal no longer appears in upcoming meals (soft deleted)
|
|
|
|
|
upcoming_meals_after = []
|
|
|
|
|
async for m in meals_db.find_upcoming_meals_by_date_range(self.conn, start_date, end_date):
|
|
|
|
|
if m.id == meal_id:
|
|
|
|
|
upcoming_meals_after.append(m)
|
|
|
|
|
self.assertEqual(len(upcoming_meals_after), 0)
|
|
|
|
|
|
|
|
|
|
async def test_find_upcoming_meals_by_date_range(self):
|
|
|
|
|
"""Test finding upcoming meals within a date range"""
|
|
|
|
|
# Create several meals with different dates
|
|
|
|
|
meal1 = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 8, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
meal2 = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 8, 15, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.ryan],
|
|
|
|
|
cleanup=[test_data.Persons.jacob],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.chris],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
meal3 = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 9, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.ellie],
|
|
|
|
|
cleanup=[test_data.Persons.chris],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.jacob],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Create a consumed meal (should not appear in upcoming)
|
|
|
|
|
consumed_meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 8, 10, 18, 0),
|
|
|
|
|
consumed_date=datetime(2024, 8, 10, 19, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal1)
|
|
|
|
|
await meals_db.insert_meal(self.conn, meal2)
|
|
|
|
|
await meals_db.insert_meal(self.conn, meal3)
|
|
|
|
|
await meals_db.insert_meal(self.conn, consumed_meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Mark consumed meal as consumed in DB
|
|
|
|
|
await meals_db.mark_consumed(self.conn, consumed_meal, consumed_meal.consumed_date)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Find meals in August 2024
|
|
|
|
|
start_date = datetime(2024, 8, 1)
|
|
|
|
|
end_date = datetime(2024, 8, 31)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
upcoming_meals = []
|
2025-10-18 03:26:42 +00:00
|
|
|
async for meal in meals_db.find_upcoming_meals_by_date_range(
|
|
|
|
|
self.conn, start_date, end_date
|
|
|
|
|
):
|
2025-07-30 12:05:29 +00:00
|
|
|
upcoming_meals.append(meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Should find meal1 and meal2, but not meal3 (outside range) or consumed_meal (consumed)
|
|
|
|
|
self.assertEqual(len(upcoming_meals), 2)
|
|
|
|
|
meal_dates = [meal.suggested_date for meal in upcoming_meals]
|
|
|
|
|
self.assertIn(datetime(2024, 8, 1, 18, 0), meal_dates)
|
|
|
|
|
self.assertIn(datetime(2024, 8, 15, 18, 0), meal_dates)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMealParticipants(unittest.IsolatedAsyncioTestCase):
|
|
|
|
|
"""Test meal participant management"""
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
async def asyncSetUp(self):
|
2025-10-18 03:26:42 +00:00
|
|
|
self.conn = await connect(":memory:")
|
2025-07-30 12:05:29 +00:00
|
|
|
await create(self.conn)
|
|
|
|
|
await test_data.create_test_data(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_sync_meal_participants(self):
|
|
|
|
|
"""Test syncing meal participants"""
|
|
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 10, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Update participants
|
|
|
|
|
new_chefs = [test_data.Persons.ryan, test_data.Persons.ellie]
|
2025-10-18 03:26:42 +00:00
|
|
|
await meals_db.sync_meal_participants(self.conn, meal.id, new_chefs, "chef")
|
|
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify participants were updated
|
|
|
|
|
found_meal = await meals_db.find_meal_by_id(self.conn, meal.id)
|
|
|
|
|
self.assertEqual(len(found_meal.chefs), 2)
|
|
|
|
|
chef_names = {chef.name for chef in found_meal.chefs}
|
|
|
|
|
self.assertIn("Ryan", chef_names)
|
|
|
|
|
self.assertIn("Ellie", chef_names)
|
|
|
|
|
self.assertNotIn("Jacob", chef_names)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Cleanup and consumers should remain unchanged
|
|
|
|
|
self.assertEqual(len(found_meal.cleanup), 1)
|
|
|
|
|
self.assertEqual(found_meal.cleanup[0].name, "Ryan")
|
|
|
|
|
self.assertEqual(len(found_meal.consumers), 1)
|
|
|
|
|
self.assertEqual(found_meal.consumers[0].name, "Ellie")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMealRecipes(unittest.IsolatedAsyncioTestCase):
|
|
|
|
|
"""Test meal recipe management"""
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
async def asyncSetUp(self):
|
2025-10-18 03:26:42 +00:00
|
|
|
self.conn = await connect(":memory:")
|
2025-07-30 12:05:29 +00:00
|
|
|
await create(self.conn)
|
|
|
|
|
await test_data.create_test_data(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_insert_meal_recipe_validation(self):
|
|
|
|
|
"""Test meal recipe validation during insertion"""
|
|
|
|
|
# Try to insert meal recipe without valid meal_id
|
|
|
|
|
meal_recipe = MealRecipe(meal_id=-1, recipe_id=1, servings=2.0)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
with self.assertRaises(ValueError) as context:
|
|
|
|
|
await meals_db.insert_meal_recipe(self.conn, meal_recipe)
|
|
|
|
|
self.assertIn("Meal must be inserted", str(context.exception))
|
|
|
|
|
|
|
|
|
|
async def test_sync_meal_recipes(self):
|
|
|
|
|
"""Test syncing meal recipes"""
|
|
|
|
|
# Create a recipe first
|
|
|
|
|
recipe = test_data.Recipes.broccoli_soup
|
|
|
|
|
recipe.id = -1 # Reset ID
|
|
|
|
|
await recipes.insert_recipe(self.conn, recipe)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 11, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Add recipes to meal
|
2025-10-18 03:26:42 +00:00
|
|
|
meal_recipes = [MealRecipe(meal_id=meal.id, recipe_id=recipe.id, servings=4.0)]
|
|
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.sync_meal_recipes(self.conn, meal.id, meal_recipes)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify recipes were added
|
|
|
|
|
found_meal = await meals_db.find_meal_by_id(self.conn, meal.id)
|
|
|
|
|
self.assertEqual(len(found_meal.recipes), 1)
|
|
|
|
|
self.assertEqual(found_meal.recipes[0].servings, 4.0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMealIngredients(unittest.IsolatedAsyncioTestCase):
|
|
|
|
|
"""Test meal extra ingredients management"""
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
async def asyncSetUp(self):
|
2025-10-18 03:26:42 +00:00
|
|
|
self.conn = await connect(":memory:")
|
2025-07-30 12:05:29 +00:00
|
|
|
await create(self.conn)
|
|
|
|
|
await test_data.create_test_data(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_sync_extra_ingredients(self):
|
|
|
|
|
"""Test syncing extra ingredients"""
|
|
|
|
|
# Create a new product for testing
|
|
|
|
|
product = products.Product(
|
|
|
|
|
id=-1,
|
2025-10-18 03:26:42 +00:00
|
|
|
shop_code="woolworths",
|
2025-07-30 12:05:29 +00:00
|
|
|
name="Test Bread Roll",
|
|
|
|
|
product_id="test_bread_123",
|
|
|
|
|
quantity=1,
|
|
|
|
|
unit="Roll",
|
|
|
|
|
link="https://example.com/test-bread-roll",
|
|
|
|
|
img_small="https://example.com/test-small.jpg",
|
|
|
|
|
img_large="https://example.com/test-large.jpg",
|
|
|
|
|
raw_data={},
|
|
|
|
|
)
|
|
|
|
|
await products.insert_product(self.conn, product, {})
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
meal = Meal(
|
|
|
|
|
suggested_date=datetime(2024, 12, 1, 18, 0),
|
|
|
|
|
chefs=[test_data.Persons.jacob],
|
|
|
|
|
cleanup=[test_data.Persons.ryan],
|
2025-10-18 03:26:42 +00:00
|
|
|
consumers=[test_data.Persons.ellie],
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.insert_meal(self.conn, meal)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Add extra ingredients
|
|
|
|
|
extra_ingredient = ingredients.Ingredient(
|
|
|
|
|
id=-1,
|
|
|
|
|
name="Test Bread Roll",
|
|
|
|
|
line="1 roll test bread",
|
|
|
|
|
unit="roll",
|
|
|
|
|
quantity=1.0,
|
|
|
|
|
preparation="",
|
2025-10-18 03:26:42 +00:00
|
|
|
product_id=product.id,
|
2025-07-30 12:05:29 +00:00
|
|
|
)
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
await meals_db.sync_extra_ingredients(self.conn, meal.id, [extra_ingredient])
|
2025-10-18 03:26:42 +00:00
|
|
|
|
2025-07-30 12:05:29 +00:00
|
|
|
# Verify ingredients were added
|
|
|
|
|
found_meal = await meals_db.find_meal_by_id(self.conn, meal.id)
|
|
|
|
|
self.assertEqual(len(found_meal.extra_ingredients), 1)
|
|
|
|
|
self.assertEqual(found_meal.extra_ingredients[0].name, "Test Bread Roll")
|
|
|
|
|
|
|
|
|
|
|
2025-10-18 03:26:42 +00:00
|
|
|
if __name__ == "__main__":
|
2025-07-30 12:05:29 +00:00
|
|
|
unittest.main()
|