# tests/unit/models/schema/test_order.py """Unit tests for order Pydantic schemas.""" import pytest from pydantic import ValidationError from models.schema.order import ( OrderAddressCreate, OrderCreate, OrderItemCreate, OrderItemResponse, OrderListResponse, OrderResponse, OrderUpdate, ) @pytest.mark.unit @pytest.mark.schema class TestOrderItemCreateSchema: """Test OrderItemCreate schema validation.""" def test_valid_order_item(self): """Test valid order item creation.""" item = OrderItemCreate( product_id=1, quantity=2, ) assert item.product_id == 1 assert item.quantity == 2 def test_product_id_required(self): """Test product_id is required.""" with pytest.raises(ValidationError) as exc_info: OrderItemCreate(quantity=2) assert "product_id" in str(exc_info.value).lower() def test_quantity_required(self): """Test quantity is required.""" with pytest.raises(ValidationError) as exc_info: OrderItemCreate(product_id=1) assert "quantity" in str(exc_info.value).lower() def test_quantity_must_be_at_least_1(self): """Test quantity must be >= 1.""" with pytest.raises(ValidationError) as exc_info: OrderItemCreate( product_id=1, quantity=0, ) assert "quantity" in str(exc_info.value).lower() def test_negative_quantity_invalid(self): """Test negative quantity is invalid.""" with pytest.raises(ValidationError): OrderItemCreate( product_id=1, quantity=-1, ) @pytest.mark.unit @pytest.mark.schema class TestOrderAddressCreateSchema: """Test OrderAddressCreate schema validation.""" def test_valid_address(self): """Test valid order address creation.""" address = OrderAddressCreate( first_name="John", last_name="Doe", address_line_1="123 Main St", city="Luxembourg", postal_code="L-1234", country="Luxembourg", ) assert address.first_name == "John" assert address.city == "Luxembourg" def test_required_fields(self): """Test required fields validation.""" with pytest.raises(ValidationError): OrderAddressCreate( first_name="John", # missing required fields ) def test_optional_company(self): """Test optional company field.""" address = OrderAddressCreate( first_name="John", last_name="Doe", company="Tech Corp", address_line_1="123 Main St", city="Luxembourg", postal_code="L-1234", country="Luxembourg", ) assert address.company == "Tech Corp" def test_optional_address_line_2(self): """Test optional address_line_2 field.""" address = OrderAddressCreate( first_name="John", last_name="Doe", address_line_1="123 Main St", address_line_2="Suite 500", city="Luxembourg", postal_code="L-1234", country="Luxembourg", ) assert address.address_line_2 == "Suite 500" def test_first_name_min_length(self): """Test first_name minimum length.""" with pytest.raises(ValidationError): OrderAddressCreate( first_name="", last_name="Doe", address_line_1="123 Main St", city="Luxembourg", postal_code="L-1234", country="Luxembourg", ) def test_country_min_length(self): """Test country minimum length (2).""" with pytest.raises(ValidationError): OrderAddressCreate( first_name="John", last_name="Doe", address_line_1="123 Main St", city="Luxembourg", postal_code="L-1234", country="L", ) @pytest.mark.unit @pytest.mark.schema class TestOrderCreateSchema: """Test OrderCreate schema validation.""" def test_valid_order(self): """Test valid order creation.""" order = OrderCreate( items=[ OrderItemCreate(product_id=1, quantity=2), OrderItemCreate(product_id=2, quantity=1), ], shipping_address=OrderAddressCreate( first_name="John", last_name="Doe", address_line_1="123 Main St", city="Luxembourg", postal_code="L-1234", country="Luxembourg", ), ) assert len(order.items) == 2 assert order.customer_id is None # Optional for guest checkout def test_items_required(self): """Test items are required.""" with pytest.raises(ValidationError) as exc_info: OrderCreate( shipping_address=OrderAddressCreate( first_name="John", last_name="Doe", address_line_1="123 Main St", city="Luxembourg", postal_code="L-1234", country="Luxembourg", ), ) assert "items" in str(exc_info.value).lower() def test_items_must_not_be_empty(self): """Test items list must have at least 1 item.""" with pytest.raises(ValidationError) as exc_info: OrderCreate( items=[], shipping_address=OrderAddressCreate( first_name="John", last_name="Doe", address_line_1="123 Main St", city="Luxembourg", postal_code="L-1234", country="Luxembourg", ), ) assert "items" in str(exc_info.value).lower() def test_shipping_address_required(self): """Test shipping_address is required.""" with pytest.raises(ValidationError) as exc_info: OrderCreate( items=[OrderItemCreate(product_id=1, quantity=1)], ) assert "shipping_address" in str(exc_info.value).lower() def test_optional_billing_address(self): """Test billing_address is optional.""" order = OrderCreate( items=[OrderItemCreate(product_id=1, quantity=1)], shipping_address=OrderAddressCreate( first_name="John", last_name="Doe", address_line_1="123 Main St", city="Luxembourg", postal_code="L-1234", country="Luxembourg", ), billing_address=OrderAddressCreate( first_name="Jane", last_name="Doe", address_line_1="456 Other St", city="Esch", postal_code="L-4321", country="Luxembourg", ), ) assert order.billing_address is not None assert order.billing_address.first_name == "Jane" def test_optional_customer_notes(self): """Test optional customer_notes.""" order = OrderCreate( items=[OrderItemCreate(product_id=1, quantity=1)], shipping_address=OrderAddressCreate( first_name="John", last_name="Doe", address_line_1="123 Main St", city="Luxembourg", postal_code="L-1234", country="Luxembourg", ), customer_notes="Please leave at door", ) assert order.customer_notes == "Please leave at door" @pytest.mark.unit @pytest.mark.schema class TestOrderUpdateSchema: """Test OrderUpdate schema validation.""" def test_status_update(self): """Test valid status update.""" update = OrderUpdate(status="processing") assert update.status == "processing" def test_valid_status_values(self): """Test all valid status values.""" valid_statuses = [ "pending", "processing", "shipped", "delivered", "cancelled", "refunded", ] for status in valid_statuses: update = OrderUpdate(status=status) assert update.status == status def test_invalid_status(self): """Test invalid status raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: OrderUpdate(status="invalid_status") assert "status" in str(exc_info.value).lower() def test_tracking_number_update(self): """Test tracking number update.""" update = OrderUpdate(tracking_number="TRACK123456") assert update.tracking_number == "TRACK123456" def test_internal_notes_update(self): """Test internal notes update.""" update = OrderUpdate(internal_notes="Customer requested expedited shipping") assert update.internal_notes == "Customer requested expedited shipping" def test_empty_update_is_valid(self): """Test empty update is valid.""" update = OrderUpdate() assert update.model_dump(exclude_unset=True) == {} @pytest.mark.unit @pytest.mark.schema class TestOrderResponseSchema: """Test OrderResponse schema.""" def test_from_dict(self): """Test creating response from dict.""" from datetime import datetime data = { "id": 1, "vendor_id": 1, "customer_id": 1, "order_number": "ORD-001", "status": "pending", "subtotal": 100.00, "tax_amount": 20.00, "shipping_amount": 10.00, "discount_amount": 5.00, "total_amount": 125.00, "currency": "EUR", "shipping_method": "standard", "tracking_number": None, "customer_notes": None, "internal_notes": None, "created_at": datetime.now(), "updated_at": datetime.now(), "paid_at": None, "shipped_at": None, "delivered_at": None, "cancelled_at": None, } response = OrderResponse(**data) assert response.id == 1 assert response.order_number == "ORD-001" assert response.total_amount == 125.00 @pytest.mark.unit @pytest.mark.schema class TestOrderItemResponseSchema: """Test OrderItemResponse schema.""" def test_from_dict(self): """Test creating response from dict.""" from datetime import datetime data = { "id": 1, "order_id": 1, "product_id": 1, "product_name": "Test Product", "product_sku": "SKU-001", "quantity": 2, "unit_price": 50.00, "total_price": 100.00, "inventory_reserved": True, "inventory_fulfilled": False, "created_at": datetime.now(), "updated_at": datetime.now(), } response = OrderItemResponse(**data) assert response.id == 1 assert response.quantity == 2 assert response.total_price == 100.00 @pytest.mark.unit @pytest.mark.schema class TestOrderListResponseSchema: """Test OrderListResponse schema.""" def test_valid_list_response(self): """Test valid list response structure.""" response = OrderListResponse( orders=[], total=0, skip=0, limit=10, ) assert response.orders == [] assert response.total == 0 assert response.skip == 0 assert response.limit == 10