forked from cartsnitch/cartsnitch
Merge commit '4cf6f91e954b770198578bcb8db5d98ac964bfed' as 'common'
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
"""Tests for Pydantic v2 schemas."""
|
||||
|
||||
import uuid
|
||||
from datetime import UTC, date, datetime
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from cartsnitch_common.constants import (
|
||||
AccountStatus,
|
||||
DiscountType,
|
||||
EventType,
|
||||
PriceSource,
|
||||
ProductCategory,
|
||||
SizeUnit,
|
||||
StoreSlug,
|
||||
)
|
||||
from cartsnitch_common.schemas import (
|
||||
CouponCreate,
|
||||
EventEnvelope,
|
||||
NormalizedProductCreate,
|
||||
PriceHistoryCreate,
|
||||
PurchaseCreate,
|
||||
PurchaseItemCreate,
|
||||
ShrinkflationEventCreate,
|
||||
StoreCreate,
|
||||
StoreLocationCreate,
|
||||
StoreRead,
|
||||
UserCreate,
|
||||
UserStoreAccountCreate,
|
||||
)
|
||||
|
||||
|
||||
class TestStoreSchemas:
|
||||
def test_store_create_valid(self):
|
||||
s = StoreCreate(name="Meijer", slug=StoreSlug.MEIJER)
|
||||
assert s.slug == StoreSlug.MEIJER
|
||||
|
||||
def test_store_create_invalid_slug(self):
|
||||
with pytest.raises(ValidationError):
|
||||
StoreCreate(name="Walmart", slug="walmart")
|
||||
|
||||
def test_store_read_from_attributes(self):
|
||||
data = {
|
||||
"id": uuid.uuid4(),
|
||||
"name": "Kroger",
|
||||
"slug": StoreSlug.KROGER,
|
||||
"logo_url": None,
|
||||
"website_url": None,
|
||||
"created_at": datetime.now(UTC),
|
||||
"updated_at": datetime.now(UTC),
|
||||
}
|
||||
s = StoreRead(**data)
|
||||
assert s.slug == StoreSlug.KROGER
|
||||
|
||||
|
||||
class TestStoreLocationSchemas:
|
||||
def test_location_create(self):
|
||||
loc = StoreLocationCreate(
|
||||
store_id=uuid.uuid4(),
|
||||
address="456 Oak Ave",
|
||||
city="Detroit",
|
||||
state="MI",
|
||||
zip="48201",
|
||||
)
|
||||
assert loc.city == "Detroit"
|
||||
|
||||
|
||||
class TestUserSchemas:
|
||||
def test_user_create_valid(self):
|
||||
u = UserCreate(email="test@example.com", password="secret123")
|
||||
assert u.email == "test@example.com"
|
||||
|
||||
def test_user_create_invalid_email(self):
|
||||
with pytest.raises(ValidationError):
|
||||
UserCreate(email="not-an-email", password="secret123")
|
||||
|
||||
|
||||
class TestUserStoreAccountSchemas:
|
||||
def test_account_create_with_status(self):
|
||||
a = UserStoreAccountCreate(
|
||||
user_id=uuid.uuid4(),
|
||||
store_id=uuid.uuid4(),
|
||||
status=AccountStatus.EXPIRED,
|
||||
)
|
||||
assert a.status == AccountStatus.EXPIRED
|
||||
|
||||
def test_account_create_default_status(self):
|
||||
a = UserStoreAccountCreate(
|
||||
user_id=uuid.uuid4(),
|
||||
store_id=uuid.uuid4(),
|
||||
)
|
||||
assert a.status == AccountStatus.ACTIVE
|
||||
|
||||
def test_account_create_invalid_status(self):
|
||||
with pytest.raises(ValidationError):
|
||||
UserStoreAccountCreate(
|
||||
user_id=uuid.uuid4(),
|
||||
store_id=uuid.uuid4(),
|
||||
status="invalid_status",
|
||||
)
|
||||
|
||||
|
||||
class TestPurchaseSchemas:
|
||||
def test_purchase_create_with_items(self):
|
||||
p = PurchaseCreate(
|
||||
user_id=uuid.uuid4(),
|
||||
store_id=uuid.uuid4(),
|
||||
receipt_id="RCP-001",
|
||||
purchase_date=date(2026, 3, 15),
|
||||
total=Decimal("42.50"),
|
||||
items=[
|
||||
PurchaseItemCreate(
|
||||
product_name_raw="Milk",
|
||||
unit_price=Decimal("3.49"),
|
||||
extended_price=Decimal("3.49"),
|
||||
),
|
||||
],
|
||||
)
|
||||
assert len(p.items) == 1
|
||||
assert p.items[0].quantity == Decimal("1")
|
||||
|
||||
|
||||
class TestNormalizedProductSchemas:
|
||||
def test_product_create_with_enums(self):
|
||||
p = NormalizedProductCreate(
|
||||
canonical_name="Whole Milk, 1 Gallon",
|
||||
category=ProductCategory.DAIRY,
|
||||
size_unit=SizeUnit.FL_OZ,
|
||||
upc_variants=["0041250000001"],
|
||||
)
|
||||
assert p.category == ProductCategory.DAIRY
|
||||
|
||||
def test_product_create_invalid_category(self):
|
||||
with pytest.raises(ValidationError):
|
||||
NormalizedProductCreate(
|
||||
canonical_name="Test",
|
||||
category="invalid_category",
|
||||
)
|
||||
|
||||
|
||||
class TestPriceHistorySchemas:
|
||||
def test_price_create(self):
|
||||
p = PriceHistoryCreate(
|
||||
normalized_product_id=uuid.uuid4(),
|
||||
store_id=uuid.uuid4(),
|
||||
observed_date=date(2026, 3, 15),
|
||||
regular_price=Decimal("4.99"),
|
||||
source=PriceSource.RECEIPT,
|
||||
)
|
||||
assert p.source == PriceSource.RECEIPT
|
||||
|
||||
def test_price_create_invalid_source(self):
|
||||
with pytest.raises(ValidationError):
|
||||
PriceHistoryCreate(
|
||||
normalized_product_id=uuid.uuid4(),
|
||||
store_id=uuid.uuid4(),
|
||||
observed_date=date(2026, 3, 15),
|
||||
regular_price=Decimal("4.99"),
|
||||
source="invalid_source",
|
||||
)
|
||||
|
||||
|
||||
class TestCouponSchemas:
|
||||
def test_coupon_create(self):
|
||||
c = CouponCreate(
|
||||
store_id=uuid.uuid4(),
|
||||
title="BOGO Chips",
|
||||
discount_type=DiscountType.BOGO,
|
||||
)
|
||||
assert c.discount_type == DiscountType.BOGO
|
||||
|
||||
def test_coupon_create_invalid_discount_type(self):
|
||||
with pytest.raises(ValidationError):
|
||||
CouponCreate(
|
||||
store_id=uuid.uuid4(),
|
||||
title="Test",
|
||||
discount_type="free_stuff",
|
||||
)
|
||||
|
||||
|
||||
class TestShrinkflationEventSchemas:
|
||||
def test_shrinkflation_create(self):
|
||||
s = ShrinkflationEventCreate(
|
||||
normalized_product_id=uuid.uuid4(),
|
||||
detected_date=date(2026, 3, 10),
|
||||
old_size="18",
|
||||
new_size="15.4",
|
||||
old_unit=SizeUnit.OZ,
|
||||
new_unit=SizeUnit.OZ,
|
||||
confidence=Decimal("0.95"),
|
||||
)
|
||||
assert s.old_unit == SizeUnit.OZ
|
||||
|
||||
def test_shrinkflation_create_invalid_unit(self):
|
||||
with pytest.raises(ValidationError):
|
||||
ShrinkflationEventCreate(
|
||||
normalized_product_id=uuid.uuid4(),
|
||||
detected_date=date(2026, 3, 10),
|
||||
old_size="18",
|
||||
new_size="15.4",
|
||||
old_unit="bushels",
|
||||
new_unit=SizeUnit.OZ,
|
||||
)
|
||||
|
||||
|
||||
class TestEventEnvelope:
|
||||
def test_valid_event(self):
|
||||
e = EventEnvelope(
|
||||
event_type=EventType.RECEIPTS_INGESTED,
|
||||
timestamp=datetime.now(UTC),
|
||||
service="receiptwitness",
|
||||
payload={"receipt_id": "RCP-001"},
|
||||
)
|
||||
assert e.event_type == EventType.RECEIPTS_INGESTED
|
||||
|
||||
def test_invalid_event_type(self):
|
||||
with pytest.raises(ValidationError):
|
||||
EventEnvelope(
|
||||
event_type="invalid.event",
|
||||
timestamp=datetime.now(UTC),
|
||||
service="test",
|
||||
payload={},
|
||||
)
|
||||
Reference in New Issue
Block a user