177 lines
6.1 KiB
Python
177 lines
6.1 KiB
Python
import pytest
|
|
|
|
|
|
async def test_update_product_returns_200(auth_client, product):
|
|
response = await auth_client.patch(
|
|
f"/api/product/{product.id}", json={"name": "Updated Name"}
|
|
)
|
|
assert response.status_code == 200
|
|
assert response.json()["name"] == "Updated Name"
|
|
|
|
|
|
async def test_update_product_recalculates_calories_when_macros_change(
|
|
auth_client, product
|
|
):
|
|
response = await auth_client.patch(
|
|
f"/api/product/{product.id}", json={"protein": 10.0}
|
|
)
|
|
# protein=10, carb=0, fat=3.6, fiber=0 → 10*4 + 3.6*9 = 40 + 32.4 = 72.4
|
|
assert response.json()["calories"] == pytest.approx(72.4)
|
|
|
|
|
|
async def test_update_product_uses_explicit_calories(auth_client, product):
|
|
response = await auth_client.patch(
|
|
f"/api/product/{product.id}", json={"protein": 10.0, "calories": 99.0}
|
|
)
|
|
assert response.json()["calories"] == 99.0
|
|
|
|
|
|
async def test_update_product_not_found_returns_404(auth_client):
|
|
response = await auth_client.patch("/api/product/99999", json={"name": "Ghost"})
|
|
assert response.status_code == 404
|
|
|
|
|
|
async def test_update_product_duplicate_barcode_returns_409(
|
|
auth_client, product, product_payload
|
|
):
|
|
await auth_client.post(
|
|
"/api/product", json={**product_payload, "name": "Other", "barcode": "AAA"}
|
|
)
|
|
response = await auth_client.patch(
|
|
f"/api/product/{product.id}", json={"barcode": "AAA"}
|
|
)
|
|
assert response.status_code == 409
|
|
|
|
|
|
async def test_update_product_without_auth_returns_401(client, product):
|
|
response = await client.patch(f"/api/product/{product.id}", json={"name": "x"})
|
|
assert response.status_code == 401
|
|
|
|
|
|
async def test_create_product_returns_201(auth_client, product_payload):
|
|
response = await auth_client.post("/api/product", json=product_payload)
|
|
assert response.status_code == 201
|
|
|
|
|
|
async def test_create_product_returns_correct_fields(auth_client, product_payload):
|
|
response = await auth_client.post("/api/product", json=product_payload)
|
|
body = response.json()
|
|
assert body["name"] == product_payload["name"]
|
|
assert body["protein"] == product_payload["protein"]
|
|
assert body["carb"] == product_payload["carb"]
|
|
assert body["fat"] == product_payload["fat"]
|
|
assert body["fiber"] == product_payload["fiber"]
|
|
assert "id" in body
|
|
|
|
|
|
async def test_create_product_calculates_calories(auth_client, product_payload):
|
|
response = await auth_client.post("/api/product", json=product_payload)
|
|
# 31*4 + 0*4 + 3.6*9 + 0*2 = 124 + 32.4 = 156.4
|
|
assert response.json()["calories"] == pytest.approx(156.4)
|
|
|
|
|
|
async def test_create_product_uses_explicit_calories(auth_client, product_payload):
|
|
response = await auth_client.post(
|
|
"/api/product", json={**product_payload, "calories": 50.0}
|
|
)
|
|
assert response.json()["calories"] == 50.0
|
|
|
|
|
|
async def test_create_product_duplicate_barcode_returns_409(
|
|
auth_client, product_payload
|
|
):
|
|
await auth_client.post(
|
|
"/api/product", json={**product_payload, "barcode": "123456"}
|
|
)
|
|
response = await auth_client.post(
|
|
"/api/product", json={**product_payload, "barcode": "123456"}
|
|
)
|
|
assert response.status_code == 409
|
|
|
|
|
|
async def test_create_product_invalid_protein_returns_422(auth_client, product_payload):
|
|
response = await auth_client.post(
|
|
"/api/product", json={**product_payload, "protein": -1.0}
|
|
)
|
|
assert response.status_code == 422
|
|
|
|
|
|
async def test_create_product_protein_over_100_returns_422(
|
|
auth_client, product_payload
|
|
):
|
|
response = await auth_client.post(
|
|
"/api/product", json={**product_payload, "protein": 101.0}
|
|
)
|
|
assert response.status_code == 422
|
|
|
|
|
|
async def test_create_product_without_auth_returns_401(client, product_payload):
|
|
response = await client.post("/api/product", json=product_payload)
|
|
assert response.status_code == 401
|
|
|
|
|
|
async def test_list_products_returns_200(auth_client, product):
|
|
response = await auth_client.get("/api/product")
|
|
assert response.status_code == 200
|
|
assert isinstance(response.json(), list)
|
|
|
|
|
|
async def test_list_products_contains_created(auth_client, product):
|
|
response = await auth_client.get("/api/product")
|
|
ids = [p["id"] for p in response.json()]
|
|
assert product.id in ids
|
|
|
|
|
|
async def test_list_products_filters_by_name(auth_client, product):
|
|
response = await auth_client.get("/api/product", params={"q": product.name})
|
|
assert all(product.name.lower() in p["name"].lower() for p in response.json())
|
|
|
|
|
|
async def test_list_products_without_auth_returns_401(client):
|
|
response = await client.get("/api/product")
|
|
assert response.status_code == 401
|
|
|
|
|
|
async def test_get_by_barcode_returns_product_from_db(
|
|
auth_client, product_with_barcode
|
|
):
|
|
response = await auth_client.get(
|
|
f"/api/product/barcode/{product_with_barcode.barcode}"
|
|
)
|
|
assert response.status_code == 200
|
|
assert response.json()["id"] == product_with_barcode.id
|
|
|
|
|
|
async def test_get_by_barcode_imports_when_not_in_db(
|
|
auth_client, mock_product_finder, external_product
|
|
):
|
|
response = await auth_client.get("/api/product/barcode/9999999999")
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert body["name"] == external_product.name
|
|
assert body["protein"] == external_product.protein
|
|
assert body["fat"] == external_product.fat
|
|
assert body["carb"] == external_product.carb
|
|
assert body["fiber"] == external_product.fiber
|
|
assert body["calories"] == external_product.kcal
|
|
assert body["barcode"] == "9999999999"
|
|
|
|
|
|
async def test_get_by_barcode_persists_imported_product(
|
|
auth_client, mock_product_finder
|
|
):
|
|
await auth_client.get("/api/product/barcode/8888888888")
|
|
response = await auth_client.get("/api/product/barcode/8888888888")
|
|
assert response.status_code == 200
|
|
|
|
|
|
async def test_get_by_barcode_not_found_returns_404(
|
|
auth_client, mock_product_finder_not_found
|
|
):
|
|
response = await auth_client.get("/api/product/barcode/0000000000")
|
|
assert response.status_code == 404
|
|
|
|
|
|
async def test_get_by_barcode_without_auth_returns_401(client):
|
|
response = await client.get("/api/product/barcode/1234567890")
|
|
assert response.status_code == 401
|