- pyproject.toml: add [tool.ruff] config suppressing E402/W293 globally, F841/E741/E702 in tests, E741 in scripts - inventory.py: split semicolon import (E702) - recipes.py: fix logger -> log (F821 undefined name) - shopping.py: rename l -> lnk in list comprehension (E741) - format_conversion.py: noqa F841 on CUDA flag (used as future hook) - backfill_keywords.py: rename done -> _done (F841) - ingest_purplecarrot.py: drop == True comparison (E712) - Auto-fix: I001 import sorting, F401 unused imports across all files
79 lines
2.1 KiB
Python
79 lines
2.1 KiB
Python
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.cloud_session import get_session
|
|
from app.db.session import get_store
|
|
from app.main import app
|
|
|
|
client = TestClient(app)
|
|
|
|
|
|
def _make_session(tier: str = "free", has_byok: bool = False) -> MagicMock:
|
|
mock = MagicMock()
|
|
mock.tier = tier
|
|
mock.has_byok = has_byok
|
|
return mock
|
|
|
|
|
|
def _make_store() -> MagicMock:
|
|
mock = MagicMock()
|
|
mock.search_recipes_by_ingredients.return_value = [
|
|
{
|
|
"id": 1,
|
|
"title": "Butter Pasta",
|
|
"ingredient_names": ["butter", "pasta"],
|
|
"element_coverage": {"Richness": 0.5},
|
|
"match_count": 2,
|
|
"directions": ["mix and heat"],
|
|
}
|
|
]
|
|
mock.check_and_increment_rate_limit.return_value = (True, 1)
|
|
return mock
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def override_deps():
|
|
session_mock = _make_session()
|
|
store_mock = _make_store()
|
|
app.dependency_overrides[get_session] = lambda: session_mock
|
|
app.dependency_overrides[get_store] = lambda: store_mock
|
|
yield session_mock, store_mock
|
|
app.dependency_overrides.clear()
|
|
|
|
|
|
def test_suggest_returns_200():
|
|
resp = client.post("/api/v1/recipes/suggest", json={
|
|
"pantry_items": ["butter", "pasta"],
|
|
"level": 1,
|
|
"constraints": [],
|
|
})
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert "suggestions" in data
|
|
assert "element_gaps" in data
|
|
assert "grocery_list" in data
|
|
assert "grocery_links" in data
|
|
|
|
|
|
def test_suggest_level4_requires_wildcard_confirmed():
|
|
resp = client.post("/api/v1/recipes/suggest", json={
|
|
"pantry_items": ["butter"],
|
|
"level": 4,
|
|
"constraints": [],
|
|
"wildcard_confirmed": False,
|
|
})
|
|
assert resp.status_code == 400
|
|
|
|
|
|
def test_suggest_level3_requires_paid_tier(override_deps):
|
|
session_mock, _ = override_deps
|
|
session_mock.tier = "free"
|
|
session_mock.has_byok = False
|
|
resp = client.post("/api/v1/recipes/suggest", json={
|
|
"pantry_items": ["butter"],
|
|
"level": 3,
|
|
"constraints": [],
|
|
})
|
|
assert resp.status_code == 403
|