# tests/unit/models/schema/test_inventory.py """Unit tests for inventory Pydantic schemas.""" import pytest from pydantic import ValidationError from models.schema.inventory import ( InventoryAdjust, InventoryCreate, InventoryLocationResponse, InventoryReserve, InventoryResponse, InventoryUpdate, ProductInventorySummary, ) @pytest.mark.unit @pytest.mark.schema class TestInventoryCreateSchema: """Test InventoryCreate schema validation.""" def test_valid_inventory_create(self): """Test valid inventory creation data.""" inventory = InventoryCreate( product_id=1, location="Warehouse A", quantity=100, ) assert inventory.product_id == 1 assert inventory.location == "Warehouse A" assert inventory.quantity == 100 def test_product_id_required(self): """Test product_id is required.""" with pytest.raises(ValidationError) as exc_info: InventoryCreate(location="Warehouse A", quantity=10) assert "product_id" in str(exc_info.value).lower() def test_location_required(self): """Test location is required.""" with pytest.raises(ValidationError) as exc_info: InventoryCreate(product_id=1, quantity=10) assert "location" in str(exc_info.value).lower() def test_quantity_required(self): """Test quantity is required.""" with pytest.raises(ValidationError) as exc_info: InventoryCreate(product_id=1, location="Warehouse A") assert "quantity" in str(exc_info.value).lower() def test_quantity_must_be_non_negative(self): """Test quantity must be >= 0.""" with pytest.raises(ValidationError) as exc_info: InventoryCreate( product_id=1, location="Warehouse A", quantity=-5, ) assert "quantity" in str(exc_info.value).lower() def test_quantity_zero_is_valid(self): """Test quantity of 0 is valid.""" inventory = InventoryCreate( product_id=1, location="Warehouse A", quantity=0, ) assert inventory.quantity == 0 @pytest.mark.unit @pytest.mark.schema class TestInventoryAdjustSchema: """Test InventoryAdjust schema validation.""" def test_positive_adjustment(self): """Test positive quantity adjustment (add stock).""" adjustment = InventoryAdjust( product_id=1, location="Warehouse A", quantity=50, ) assert adjustment.quantity == 50 def test_negative_adjustment(self): """Test negative quantity adjustment (remove stock).""" adjustment = InventoryAdjust( product_id=1, location="Warehouse A", quantity=-20, ) assert adjustment.quantity == -20 def test_zero_adjustment_is_valid(self): """Test zero adjustment is technically valid.""" adjustment = InventoryAdjust( product_id=1, location="Warehouse A", quantity=0, ) assert adjustment.quantity == 0 @pytest.mark.unit @pytest.mark.schema class TestInventoryUpdateSchema: """Test InventoryUpdate schema validation.""" def test_partial_update(self): """Test partial update with only some fields.""" update = InventoryUpdate(quantity=150) assert update.quantity == 150 assert update.reserved_quantity is None assert update.location is None def test_empty_update_is_valid(self): """Test empty update is valid.""" update = InventoryUpdate() assert update.model_dump(exclude_unset=True) == {} def test_quantity_must_be_non_negative(self): """Test quantity must be >= 0 in update.""" with pytest.raises(ValidationError): InventoryUpdate(quantity=-10) def test_reserved_quantity_must_be_non_negative(self): """Test reserved_quantity must be >= 0.""" with pytest.raises(ValidationError): InventoryUpdate(reserved_quantity=-5) def test_location_update(self): """Test location can be updated.""" update = InventoryUpdate(location="Warehouse B") assert update.location == "Warehouse B" @pytest.mark.unit @pytest.mark.schema class TestInventoryReserveSchema: """Test InventoryReserve schema validation.""" def test_valid_reservation(self): """Test valid inventory reservation.""" reservation = InventoryReserve( product_id=1, location="Warehouse A", quantity=10, ) assert reservation.product_id == 1 assert reservation.quantity == 10 def test_quantity_must_be_positive(self): """Test reservation quantity must be > 0.""" with pytest.raises(ValidationError) as exc_info: InventoryReserve( product_id=1, location="Warehouse A", quantity=0, ) assert "quantity" in str(exc_info.value).lower() def test_negative_quantity_invalid(self): """Test negative reservation quantity is invalid.""" with pytest.raises(ValidationError): InventoryReserve( product_id=1, location="Warehouse A", quantity=-5, ) @pytest.mark.unit @pytest.mark.schema class TestInventoryResponseSchema: """Test InventoryResponse schema.""" def test_from_dict(self): """Test creating response from dict.""" from datetime import datetime data = { "id": 1, "product_id": 1, "vendor_id": 1, "location": "Warehouse A", "quantity": 100, "reserved_quantity": 20, "gtin": "1234567890123", "created_at": datetime.now(), "updated_at": datetime.now(), } response = InventoryResponse(**data) assert response.id == 1 assert response.quantity == 100 assert response.reserved_quantity == 20 def test_available_quantity_property(self): """Test available_quantity calculated property.""" from datetime import datetime data = { "id": 1, "product_id": 1, "vendor_id": 1, "location": "Warehouse A", "quantity": 100, "reserved_quantity": 30, "gtin": None, "created_at": datetime.now(), "updated_at": datetime.now(), } response = InventoryResponse(**data) assert response.available_quantity == 70 def test_available_quantity_never_negative(self): """Test available_quantity is never negative.""" from datetime import datetime data = { "id": 1, "product_id": 1, "vendor_id": 1, "location": "Warehouse A", "quantity": 10, "reserved_quantity": 50, # Over-reserved "gtin": None, "created_at": datetime.now(), "updated_at": datetime.now(), } response = InventoryResponse(**data) assert response.available_quantity == 0 @pytest.mark.unit @pytest.mark.schema class TestInventoryLocationResponseSchema: """Test InventoryLocationResponse schema.""" def test_valid_location_response(self): """Test valid location response.""" location = InventoryLocationResponse( location="Warehouse A", quantity=100, reserved_quantity=20, available_quantity=80, ) assert location.location == "Warehouse A" assert location.quantity == 100 assert location.available_quantity == 80 @pytest.mark.unit @pytest.mark.schema class TestProductInventorySummarySchema: """Test ProductInventorySummary schema.""" def test_valid_summary(self): """Test valid inventory summary.""" summary = ProductInventorySummary( product_id=1, vendor_id=1, product_sku="SKU-001", product_title="Test Product", total_quantity=200, total_reserved=50, total_available=150, locations=[ InventoryLocationResponse( location="Warehouse A", quantity=100, reserved_quantity=25, available_quantity=75, ), InventoryLocationResponse( location="Warehouse B", quantity=100, reserved_quantity=25, available_quantity=75, ), ], ) assert summary.product_id == 1 assert summary.total_quantity == 200 assert len(summary.locations) == 2 def test_empty_locations(self): """Test summary with no locations.""" summary = ProductInventorySummary( product_id=1, vendor_id=1, product_sku=None, product_title="Test Product", total_quantity=0, total_reserved=0, total_available=0, locations=[], ) assert summary.locations == []