""" Unit tests for Cardset model. Tests data validation, field constraints, and model behavior. """ import pytest from pydantic import ValidationError from sqlmodel import Session, SQLModel, create_engine, text from app.models.cardset import Cardset, CardsetBase from tests.factories.cardset_factory import CardsetFactory # Using centralized fixtures from conftest.py for proper test isolation class TestCardsetBase: """Test CardsetBase model validation.""" def test_create_with_defaults(self): """Test creating Cardset with default values.""" cardset = CardsetBase(name="2024 Season") assert cardset.name == "2024 Season" assert cardset.ranked_legal is False # Default value def test_create_with_custom_values(self): """Test creating Cardset with custom values.""" cardset = CardsetBase( name="2023 Season", ranked_legal=True ) assert cardset.name == "2023 Season" assert cardset.ranked_legal is True def test_create_with_id(self): """Test creating Cardset with explicit ID.""" cardset = CardsetBase( id=100, name="Historic Set", ranked_legal=False ) assert cardset.id == 100 assert cardset.name == "Historic Set" assert cardset.ranked_legal is False def test_required_name_field(self): """Test that name field is required.""" with pytest.raises(ValidationError) as exc_info: CardsetBase() assert "Field required" in str(exc_info.value) def test_field_descriptions(self): """Test that field descriptions are properly set.""" # Access field descriptions through the model class using Pydantic v2 fields = CardsetBase.model_fields assert "Name of the card set" in str(fields['name']) assert "Whether this cardset is legal for ranked play" in str(fields['ranked_legal']) class TestCardset: """Test Cardset table model.""" def test_create_and_save(self, db_session): """Test creating and saving Cardset to database.""" cardset = CardsetFactory.create( db_session, name="2024 Season", ranked_legal=True ) assert cardset.id is not None assert cardset.name == "2024 Season" assert cardset.ranked_legal is True def test_retrieve_from_database(self, db_session): """Test retrieving Cardset from database.""" # Create and save cardset = CardsetFactory.create( db_session, name="Test Retrieval Set", ranked_legal=False ) # Retrieve retrieved = db_session.get(Cardset, cardset.id) assert retrieved is not None assert retrieved.name == "Test Retrieval Set" assert retrieved.ranked_legal is False def test_update_values(self, db_session): """Test updating Cardset values.""" cardset = Cardset(id=3, name="Update Test") db_session.add(cardset) db_session.commit() # Update values cardset.ranked_legal = True cardset.name = "Updated Name" db_session.commit() # Verify updates db_session.refresh(cardset) assert cardset.name == "Updated Name" assert cardset.ranked_legal is True def test_multiple_instances(self, db_session): """Test creating multiple Cardset instances.""" cardset1 = Cardset(id=10, name="Set A", ranked_legal=True) cardset2 = Cardset(id=11, name="Set B", ranked_legal=False) cardset3 = Cardset(id=12, name="Set C", ranked_legal=True) db_session.add_all([cardset1, cardset2, cardset3]) db_session.commit() # Verify all saved with correct values assert cardset1.name == "Set A" assert cardset1.ranked_legal is True assert cardset2.name == "Set B" assert cardset2.ranked_legal is False assert cardset3.name == "Set C" assert cardset3.ranked_legal is True def test_name_is_indexed(self): """Test that name field has index configuration.""" fields = Cardset.model_fields name_field = fields['name'] # Check if field has index configuration assert hasattr(name_field, 'json_schema_extra') or 'index' in str(name_field) class TestCardsetBusinessScenarios: """Test real-world Cardset usage scenarios.""" def test_ranked_legal_cardsets(self, db_session): """Test filtering for ranked legal cardsets.""" # Create multiple cardsets using factory ranked_set = CardsetFactory.create(db_session, name="2024 Ranked", ranked_legal=True) casual_set = CardsetFactory.create(db_session, name="2024 Casual", ranked_legal=False) historic_set = CardsetFactory.create(db_session, name="Historic Collection", ranked_legal=False) # Query for ranked legal sets (would be done in service layer) from sqlmodel import select ranked_cardsets = db_session.exec( select(Cardset).where(Cardset.ranked_legal == True) ).all() assert len(ranked_cardsets) == 1 assert ranked_cardsets[0].name == "2024 Ranked" def test_cardset_naming_conventions(self, db_session): """Test various cardset naming scenarios.""" cardsets = [ Cardset(id=30, name="2024 Season", ranked_legal=True), Cardset(id=31, name="2023 Season", ranked_legal=False), Cardset(id=32, name="Historic Collection", ranked_legal=False), Cardset(id=33, name="Special Event - All-Stars", ranked_legal=True), Cardset(id=34, name="Beta Test Set", ranked_legal=False), ] db_session.add_all(cardsets) db_session.commit() # Verify all names are preserved correctly for cardset in cardsets: db_session.refresh(cardset) # Names should be preserved exactly as entered assert len(cardset.name) > 0 assert cardset.name in [ "2024 Season", "2023 Season", "Historic Collection", "Special Event - All-Stars", "Beta Test Set" ] def test_default_ranked_legal_behavior(self, db_session): """Test that cardsets default to not ranked legal.""" cardset = Cardset(id=40, name="Default Test") db_session.add(cardset) db_session.commit() db_session.refresh(cardset) # Should default to False assert cardset.ranked_legal is False def test_explicit_id_assignment(self, db_session): """Test that IDs can be explicitly assigned (not auto-increment).""" # Based on Discord app model, ID is not auto-increment cardset1 = Cardset(id=1000, name="High ID Set") cardset2 = Cardset(id=2000, name="Another High ID Set") db_session.add_all([cardset1, cardset2]) db_session.commit() assert cardset1.id == 1000 assert cardset2.id == 2000 def test_unique_id_constraint(self, db_session): """Test that duplicate IDs are not allowed.""" cardset1 = Cardset(id=500, name="First Set") cardset2 = Cardset(id=500, name="Duplicate ID Set") db_session.add(cardset1) db_session.commit() # Adding second cardset with same ID should fail db_session.add(cardset2) with pytest.raises(Exception): # SQLAlchemy will raise an IntegrityError db_session.commit() class TestCardsetDataIntegrity: """Test data integrity and validation.""" def test_empty_name_not_allowed(self): """Test that empty name is not allowed.""" with pytest.raises(ValidationError): CardsetBase(name="") def test_none_name_not_allowed(self): """Test that None name is not allowed.""" with pytest.raises(ValidationError): CardsetBase(name=None) def test_boolean_validation_for_ranked_legal(self): """Test that ranked_legal field only accepts boolean values.""" # Valid boolean values cardset_true = CardsetBase(name="Test", ranked_legal=True) cardset_false = CardsetBase(name="Test", ranked_legal=False) assert cardset_true.ranked_legal is True assert cardset_false.ranked_legal is False # Invalid values should be coerced or raise validation error with pytest.raises(ValidationError): CardsetBase(name="Test", ranked_legal="invalid") def test_id_field_accepts_none(self): """Test that ID field can be None (for cases where ID isn't known yet).""" cardset = CardsetBase(name="No ID Set", id=None) assert cardset.id is None assert cardset.name == "No ID Set"