diff --git a/.gitignore b/.gitignore index e5a4cfba..889fc906 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ coverage.xml *.py,cover .hypothesis/ .pytest_cache/ +cache # Translations *.mo diff --git a/tests/test_api.py b/tests/test_api.py index d4db62aa..7e384a8a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -40,10 +40,11 @@ def override_get_db(): client = TestClient(app) USER = UserBase(user_id="user1", token="user1__Utoken") -PRODUCT = ProductCreate(code="8001505005707") +PRODUCT = ProductCreate(code="8001505005592") LOCATION = LocationCreate(osm_id=3344841823, osm_type="NODE") PRICE_1 = PriceCreate( - product_code="1111111111111", + product_code="8001505005707", + # category="en:tomatoes", price=3.5, currency="EUR", location_osm_id=123, @@ -99,14 +100,14 @@ def test_create_price(user, db=override_get_db()): # assert db_prices[0]["owner"] == user.user_id -def test_create_price_validation(user): - for price_field in [ - "product_code", +def test_create_price_required_fields_validation(user): + REQUIRED_FIELDS = [ "price", "location_osm_id", "location_osm_type", "date", - ]: + ] + for price_field in REQUIRED_FIELDS: PRICE_WITH_FIELD_MISSING = PRICE_1.model_copy(update={price_field: None}) response = client.post( "/prices", @@ -116,11 +117,97 @@ def test_create_price_validation(user): assert response.status_code == 422 +def test_create_price_product_code_pattern_validation(user): + # product_code cannot be an empty string, nor contain letters + WRONG_PRICE_PRODUCT_CODES = ["", "en:tomates", "8001505005707XYZ"] + for wrong_price_product_code in WRONG_PRICE_PRODUCT_CODES: + PRICE_WITH_PRODUCT_CODE_ERROR = PRICE_1.model_copy( + update={"product_code": wrong_price_product_code} + ) + response = client.post( + "/prices", + json=jsonable_encoder(PRICE_WITH_PRODUCT_CODE_ERROR), + headers={"Authorization": f"Bearer {user.token}"}, + ) + assert response.status_code == 422 + + +def test_create_price_category_tag_pattern_validation(user): + # category_tag must follow a certain pattern (ex: "en:tomatoes") + WRONG_PRICE_CATEGORY_TAGS = ["", ":", "en", ":tomatoes"] + for wrong_price_category_tag in WRONG_PRICE_CATEGORY_TAGS: + PRICE_WITH_CATEGORY_TAG_ERROR = PRICE_1.model_copy( + update={"product_code": None, "category_tag": wrong_price_category_tag} + ) + response = client.post( + "/prices", + json=jsonable_encoder(PRICE_WITH_CATEGORY_TAG_ERROR), + headers={"Authorization": f"Bearer {user.token}"}, + ) + assert response.status_code == 422 + + +def test_create_price_currency_validation(user): + # currency must have a specific format (ex: "EUR") + WRONG_PRICE_CURRENCIES = ["", "€", "euro"] + for wrong_price_currency in WRONG_PRICE_CURRENCIES: + PRICE_WITH_CATEGORY_TAG_ERROR = PRICE_1.model_copy( + update={"currency": wrong_price_currency} + ) + response = client.post( + "/prices", + json=jsonable_encoder(PRICE_WITH_CATEGORY_TAG_ERROR), + headers={"Authorization": f"Bearer {user.token}"}, + ) + assert response.status_code == 422 + + +def test_create_price_code_category_exclusive_validation(user): + # both product_code & category_tag missing: error + PRICE_WITH_CODE_AND_CATEGORY_MISSING = PRICE_1.model_copy( + update={"product_code": None} + ) + response = client.post( + "/prices", + json=jsonable_encoder(PRICE_WITH_CODE_AND_CATEGORY_MISSING), + headers={"Authorization": f"Bearer {user.token}"}, + ) + assert response.status_code == 422 + # only product_code: ok + PRICE_WITH_ONLY_PRODUCT_CODE = PRICE_1.model_copy() + response = client.post( + "/prices", + json=jsonable_encoder(PRICE_WITH_ONLY_PRODUCT_CODE), + headers={"Authorization": f"Bearer {user.token}"}, + ) + assert response.status_code == 200 + # only category_tag: ok + PRICE_WITH_ONLY_CATEGORY = PRICE_1.model_copy( + update={"product_code": None, "category_tag": "en:tomatoes"} + ) + response = client.post( + "/prices", + json=jsonable_encoder(PRICE_WITH_ONLY_CATEGORY), + headers={"Authorization": f"Bearer {user.token}"}, + ) + assert response.status_code == 200 + # both product_code & category_tag present: error + PRICE_WITH_BOTH_CODE_AND_CATEGORY = PRICE_1.model_copy( + update={"category_tag": "en:tomatoes"} + ) + response = client.post( + "/prices", + json=jsonable_encoder(PRICE_WITH_BOTH_CODE_AND_CATEGORY), + headers={"Authorization": f"Bearer {user.token}"}, + ) + assert response.status_code == 422 + + def test_get_prices(): response = client.get("/prices") assert response.status_code == 200 - assert len(response.json()["items"]) == 1 - for price_field in ["location_id", "proof_id"]: + assert len(response.json()["items"]) == 3 + for price_field in ["product_id", "location_id", "proof_id"]: assert price_field in response.json()["items"][0] @@ -134,13 +221,13 @@ def test_get_prices_pagination(): def test_get_prices_filters(): response = client.get(f"/prices?product_code={PRICE_1.product_code}") assert response.status_code == 200 - assert len(response.json()["items"]) == 1 + assert len(response.json()["items"]) == 2 response = client.get("/prices?price__gt=5") assert response.status_code == 200 assert len(response.json()["items"]) == 0 response = client.get("/prices?date=2023-10-31") assert response.status_code == 200 - assert len(response.json()["items"]) == 1 + assert len(response.json()["items"]) == 3 def test_get_proofs(user):