"""Tests for domain value objects.""" import pytest from app.domain.value_objects import Content, Slug, Title class TestTitle: def test_valid_title(self) -> None: """Test creating a valid title.""" title = Title("Valid Title") assert title.value == "Valid Title" def test_title_too_short(self) -> None: """Test title that is too short.""" with pytest.raises(ValueError, match="at least"): Title("ab") def test_title_too_long(self) -> None: """Test title that is too long.""" with pytest.raises(ValueError, match="at most"): Title("a" * 201) def test_title_empty(self) -> None: """Test empty title.""" with pytest.raises(ValueError, match="empty"): Title(" ") def test_title_not_string(self) -> None: """Test non-string title.""" with pytest.raises(ValueError, match="string"): Title(123) # type: ignore[arg-type] class TestContent: def test_valid_content(self) -> None: """Test creating valid content.""" content = Content("This is valid content with enough characters") assert content.value == "This is valid content with enough characters" def test_content_too_short(self) -> None: """Test content that is too short.""" with pytest.raises(ValueError, match="at least"): Content("short") def test_content_too_long(self) -> None: """Test content that is too long.""" with pytest.raises(ValueError, match="at most"): Content("a" * 50001) def test_content_empty(self) -> None: """Test empty content.""" with pytest.raises(ValueError, match="empty"): Content(" ") class TestSlug: def test_valid_slug(self) -> None: """Test creating a valid slug.""" slug = Slug("valid-slug") assert slug.value == "valid-slug" def test_slug_from_title(self) -> None: """Test generating slug from title.""" slug = Slug.from_title("Hello World Post") assert slug.value == "hello-world-post" def test_slug_from_title_with_special_chars(self) -> None: """Test generating slug from title with special characters.""" slug = Slug.from_title("Hello, World! Post @#$%") assert slug.value == "hello-world-post" def test_slug_from_title_only_special_chars(self) -> None: """Test generating slug from title with only special characters.""" slug = Slug.from_title("!@#$%") assert slug.value == "post" def test_slug_invalid_chars(self) -> None: """Test slug with invalid characters.""" with pytest.raises(ValueError, match="lowercase"): Slug("Invalid_Slug") def test_slug_uppercase(self) -> None: """Test slug with uppercase letters.""" with pytest.raises(ValueError, match="lowercase"): Slug("Uppercase-Slug") def test_slug_equality(self) -> None: """Test slug value equality.""" slug1 = Slug("test-slug") slug2 = Slug("test-slug") assert slug1 == slug2 assert hash(slug1) == hash(slug2) def test_slug_str_and_primitive(self) -> None: """Test slug string and primitive conversion.""" slug = Slug("test-slug") assert str(slug) == "test-slug" assert slug.to_primitive() == "test-slug" def test_slug_eq_with_non_value_object(self) -> None: """Test slug equality with non-ValueObject returns False.""" slug = Slug("test-slug") assert slug != "test-slug" def test_slug_not_string(self) -> None: """Test non-string slug raises ValueError.""" with pytest.raises(ValueError, match="string"): Slug(123) # type: ignore[arg-type] def test_slug_too_long(self) -> None: """Test slug exceeding max length raises ValueError.""" with pytest.raises(ValueError, match="at most"): Slug("a" * 201) class TestValueObjectBase: """Test base ValueObject behavior across types.""" def test_title_eq_with_non_value_object(self) -> None: """Test title equality with non-ValueObject returns False.""" title = Title("Test Title") assert title != "Test Title" def test_content_str_and_primitive(self) -> None: """Test content string and primitive conversion.""" content = Content("Enough characters for valid content") assert str(content) == "Enough characters for valid content" assert content.to_primitive() == "Enough characters for valid content" def test_content_not_string(self) -> None: """Test non-string content raises ValueError.""" with pytest.raises(ValueError, match="string"): Content(123) # type: ignore[arg-type] def test_value_object_eq_and_hash_directly(self) -> None: """Test ValueObject base eq and hash via direct call.""" from app.domain.value_objects.base import ValueObject class SimpleVO(ValueObject[str]): def _validate(self) -> None: pass vo1 = SimpleVO("test") vo2 = SimpleVO("test") vo3 = SimpleVO("other") assert ValueObject.__eq__(vo1, vo2) is True assert ValueObject.__eq__(vo1, vo3) is False assert ValueObject.__eq__(vo1, "test") is False assert ValueObject.__hash__(vo1) == hash("test") def test_content_exact_min_length(self) -> None: """Test content at exact minimum length boundary.""" min_content = "a" * 10 content = Content(min_content) assert content.value == min_content def test_slug_exact_max_length(self) -> None: """Test slug at exact maximum length boundary.""" max_slug = "a" * 200 slug = Slug(max_slug) assert slug.value == max_slug