# tests/unit/models/schema/test_product.py """Unit tests for product Pydantic schemas.""" import pytest from pydantic import ValidationError from models.schema.product import ( ProductCreate, ProductListResponse, ProductResponse, ProductUpdate, ) @pytest.mark.unit @pytest.mark.schema class TestProductCreateSchema: """Test ProductCreate schema validation.""" def test_valid_product_create(self): """Test valid product creation data.""" product = ProductCreate( marketplace_product_id=1, vendor_sku="SKU-001", price=99.99, currency="EUR", ) assert product.marketplace_product_id == 1 assert product.vendor_sku == "SKU-001" assert product.price == 99.99 def test_marketplace_product_id_required(self): """Test marketplace_product_id is required.""" with pytest.raises(ValidationError) as exc_info: ProductCreate(price=99.99) assert "marketplace_product_id" in str(exc_info.value).lower() def test_price_must_be_non_negative(self): """Test price must be >= 0.""" with pytest.raises(ValidationError) as exc_info: ProductCreate( marketplace_product_id=1, price=-10.00, ) assert "price" in str(exc_info.value).lower() def test_price_zero_is_valid(self): """Test price of 0 is valid.""" product = ProductCreate( marketplace_product_id=1, price=0, ) assert product.price == 0 def test_sale_price_must_be_non_negative(self): """Test sale_price must be >= 0.""" with pytest.raises(ValidationError) as exc_info: ProductCreate( marketplace_product_id=1, sale_price=-5.00, ) assert "sale_price" in str(exc_info.value).lower() def test_min_quantity_default(self): """Test min_quantity defaults to 1.""" product = ProductCreate(marketplace_product_id=1) assert product.min_quantity == 1 def test_min_quantity_must_be_at_least_1(self): """Test min_quantity must be >= 1.""" with pytest.raises(ValidationError) as exc_info: ProductCreate( marketplace_product_id=1, min_quantity=0, ) assert "min_quantity" in str(exc_info.value).lower() def test_max_quantity_must_be_at_least_1(self): """Test max_quantity must be >= 1 if provided.""" with pytest.raises(ValidationError) as exc_info: ProductCreate( marketplace_product_id=1, max_quantity=0, ) assert "max_quantity" in str(exc_info.value).lower() def test_is_featured_default(self): """Test is_featured defaults to False.""" product = ProductCreate(marketplace_product_id=1) assert product.is_featured is False def test_all_optional_fields(self): """Test product with all optional fields.""" product = ProductCreate( marketplace_product_id=1, vendor_sku="SKU-001", price=100.00, sale_price=80.00, currency="EUR", availability="in_stock", condition="new", is_featured=True, min_quantity=2, max_quantity=10, ) assert product.sale_price == 80.00 assert product.availability == "in_stock" assert product.condition == "new" assert product.is_featured is True assert product.max_quantity == 10 @pytest.mark.unit @pytest.mark.schema class TestProductUpdateSchema: """Test ProductUpdate schema validation.""" def test_partial_update(self): """Test partial update with only some fields.""" update = ProductUpdate(price=150.00) assert update.price == 150.00 assert update.vendor_sku is None assert update.is_active is None def test_empty_update_is_valid(self): """Test empty update is valid (all fields optional).""" update = ProductUpdate() assert update.model_dump(exclude_unset=True) == {} def test_price_validation(self): """Test price must be >= 0 in update.""" with pytest.raises(ValidationError): ProductUpdate(price=-10.00) def test_is_active_update(self): """Test is_active can be updated.""" update = ProductUpdate(is_active=False) assert update.is_active is False def test_is_featured_update(self): """Test is_featured can be updated.""" update = ProductUpdate(is_featured=True) assert update.is_featured is True @pytest.mark.unit @pytest.mark.schema class TestProductResponseSchema: """Test ProductResponse schema.""" def test_from_dict(self): """Test creating response from dict.""" from datetime import datetime data = { "id": 1, "vendor_id": 1, "marketplace_product": { "id": 1, "marketplace_product_id": "TEST001", # Required field "gtin": "1234567890123", "title": "Test Product", "description": "A test product", "brand": "Test Brand", "google_product_category": "Electronics", "image_link": "https://example.com/image.jpg", "created_at": datetime.now(), "updated_at": datetime.now(), }, "vendor_sku": "SKU-001", "price": 99.99, "sale_price": None, "currency": "EUR", "availability": "in_stock", "condition": "new", "is_featured": False, "is_active": True, "display_order": 0, "min_quantity": 1, "max_quantity": None, "created_at": datetime.now(), "updated_at": datetime.now(), } response = ProductResponse(**data) assert response.id == 1 assert response.vendor_id == 1 assert response.is_active is True def test_optional_inventory_fields(self): """Test optional inventory summary fields.""" from datetime import datetime data = { "id": 1, "vendor_id": 1, "marketplace_product": { "id": 1, "marketplace_product_id": "TEST002", # Required field "gtin": "1234567890123", "title": "Test Product", "description": None, "brand": None, "google_product_category": None, "image_link": None, "created_at": datetime.now(), "updated_at": datetime.now(), }, "vendor_sku": None, "price": None, "sale_price": None, "currency": None, "availability": None, "condition": None, "is_featured": False, "is_active": True, "display_order": 0, "min_quantity": 1, "max_quantity": None, "created_at": datetime.now(), "updated_at": datetime.now(), "total_inventory": 100, "available_inventory": 80, } response = ProductResponse(**data) assert response.total_inventory == 100 assert response.available_inventory == 80 @pytest.mark.unit @pytest.mark.schema class TestProductListResponseSchema: """Test ProductListResponse schema.""" def test_valid_list_response(self): """Test valid list response structure.""" response = ProductListResponse( products=[], total=0, skip=0, limit=10, ) assert response.products == [] assert response.total == 0 assert response.skip == 0 assert response.limit == 10