import pytest @pytest.mark.asyncio async def test_user_cannot_add_fuel_to_foreign_car(client, auth_headers, other_auth_headers) -> None: created = await client.post("/api/cars", headers=auth_headers, json={"name": "Owner car"}) car_id = created.json()["id"] response = await client.post( "/api/fuel", headers=other_auth_headers, json={ "car_id": car_id, "entry_date": "2026-05-12", "odometer": 1000, "liters": 30, "price_per_liter": 2, }, ) assert response.status_code == 403 @pytest.mark.asyncio async def test_fuel_crud(client, auth_headers) -> None: car = (await client.post("/api/cars", headers=auth_headers, json={"name": "Fuel car"})).json() created = await client.post( "/api/fuel", headers=auth_headers, json={ "car_id": car["id"], "entry_date": "2026-05-12", "odometer": 1000, "liters": 30, "price_per_liter": 2, }, ) assert created.status_code == 201 entry_id = created.json()["id"] patched = await client.patch( f"/api/fuel/{entry_id}", headers=auth_headers, json={"liters": 35, "price_per_liter": 3}, ) assert patched.status_code == 200 assert patched.json()["total_cost"] == "105.00" deleted = await client.delete(f"/api/fuel/{entry_id}", headers=auth_headers) assert deleted.status_code == 204 @pytest.mark.asyncio async def test_service_crud(client, auth_headers) -> None: car = (await client.post("/api/cars", headers=auth_headers, json={"name": "Service car"})).json() created = await client.post( "/api/service", headers=auth_headers, json={ "car_id": car["id"], "entry_date": "2026-05-12", "service_type": "maintenance", "title": "Oil", "total_cost": 100, }, ) assert created.status_code == 201 entry_id = created.json()["id"] patched = await client.patch( f"/api/service/{entry_id}", headers=auth_headers, json={"title": "Oil and filter", "next_due_odometer": 2000}, ) assert patched.status_code == 200 assert patched.json()["title"] == "Oil and filter" deleted = await client.delete(f"/api/service/{entry_id}", headers=auth_headers) assert deleted.status_code == 204 @pytest.mark.asyncio async def test_stats_do_not_fail_with_insufficient_data(client, auth_headers) -> None: car = (await client.post("/api/cars", headers=auth_headers, json={"name": "Stats car"})).json() response = await client.get(f"/api/cars/{car['id']}/stats", headers=auth_headers) assert response.status_code == 200 assert response.json()["avg_consumption_l_per_100km"] is None @pytest.mark.asyncio async def test_expense_crud_and_insurance_allocation(client, auth_headers) -> None: car = (await client.post("/api/cars", headers=auth_headers, json={"name": "Cost car"})).json() created = await client.post( "/api/expenses", headers=auth_headers, json={ "car_id": car["id"], "entry_date": "2026-01-01", "category": "insurance", "title": "Insurance", "total_cost": 1200, "period_start": "2026-01-01", "period_end": "2026-12-31", "is_recurring": True, }, ) assert created.status_code == 201 entry_id = created.json()["id"] stats = await client.get( f"/api/cars/{car['id']}/stats?date_from=2026-01-01&date_to=2026-01-31", headers=auth_headers, ) assert stats.status_code == 200 body = stats.json() assert body["expenses_cost"] == "100.00" assert body["cost_by_category"]["insurance"] == "100.00" patched = await client.patch( f"/api/expenses/{entry_id}", headers=auth_headers, json={"title": "Insurance policy"}, ) assert patched.status_code == 200 assert patched.json()["title"] == "Insurance policy" deleted = await client.delete(f"/api/expenses/{entry_id}", headers=auth_headers) assert deleted.status_code == 204 @pytest.mark.asyncio async def test_my_data_export_preview_and_import(client, auth_headers, other_auth_headers) -> None: car = ( await client.post( "/api/cars", headers=auth_headers, json={ "name": "Export car", "make": "Kia", "model": "K5", "plate_number": "12가3456", "vin": "1HGCM82633A004352", "engine_oil_type": "5W-30 API SP", "current_odometer": 10000, }, ) ).json() await client.post( "/api/fuel", headers=auth_headers, json={ "car_id": car["id"], "entry_date": "2026-05-12", "odometer": 10100, "liters": 40, "price_per_liter": 2, }, ) await client.post( "/api/service", headers=auth_headers, json={ "car_id": car["id"], "entry_date": "2026-05-13", "odometer": 10200, "service_type": "maintenance", "title": "Oil change", "total_cost": 120, }, ) await client.post( "/api/expenses", headers=auth_headers, json={ "car_id": car["id"], "entry_date": "2026-05-14", "category": "parking", "title": "Parking", "total_cost": 10, }, ) exported = await client.get("/api/my/export", headers=auth_headers) assert exported.status_code == 200 payload = exported.json() assert payload["schema"] == "carpass.exchange.v1" assert payload["vehicles"][0]["vehicle"]["name"] == "Export car" preview = await client.post("/api/my/import/preview", headers=other_auth_headers, json=payload) assert preview.status_code == 200 assert preview.json()["counts"] == { "vehicles": 1, "fuel_entries": 1, "service_entries": 1, "expense_entries": 1, "appointments": 0, "service_visits": 0, } imported = await client.post("/api/my/import", headers=other_auth_headers, json=payload) assert imported.status_code == 200 assert imported.json()["imported"]["vehicles_created"] == 1 assert imported.json()["imported"]["fuel_entries"] == 1 repeated = await client.post("/api/my/import", headers=other_auth_headers, json=payload) assert repeated.status_code == 200 assert repeated.json()["imported"]["vehicles_matched"] == 1 assert repeated.json()["imported"]["fuel_entries"] == 0 imported_cars = await client.get("/api/cars", headers=other_auth_headers) assert imported_cars.status_code == 200 imported_car = imported_cars.json()[0] assert imported_car["name"] == "Export car" assert imported_car["engine_oil_type"] == "5W-30 API SP" assert imported_car["current_odometer"] == 10200