feat(tags): TagService.merge guards + MergeResult + repoint stubs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import pytest
|
||||
from backend.app.models import Tag, TagKind, image_tag
|
||||
from backend.app.models.tag_allowlist import TagAllowlist
|
||||
from backend.app.services.tag_service import (
|
||||
MergeResult,
|
||||
TagMergeConflict,
|
||||
TagService,
|
||||
TagValidationError,
|
||||
@@ -76,3 +77,55 @@ async def test_will_alias_true_when_allowlisted(db):
|
||||
with pytest.raises(TagMergeConflict) as ei:
|
||||
await svc.rename(source.id, "Canon2")
|
||||
assert ei.value.will_alias is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_merge_rejects_self_merge(db):
|
||||
svc = TagService(db)
|
||||
t = await svc.find_or_create("Solo", TagKind.general)
|
||||
with pytest.raises(TagValidationError, match="into itself"):
|
||||
await svc.merge(t.id, t.id)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_merge_rejects_missing_tag(db):
|
||||
svc = TagService(db)
|
||||
t = await svc.find_or_create("Real", TagKind.general)
|
||||
with pytest.raises(TagValidationError, match="not found"):
|
||||
await svc.merge(t.id, 999999)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_merge_rejects_cross_kind(db):
|
||||
svc = TagService(db)
|
||||
a = await svc.find_or_create("NameA", TagKind.general)
|
||||
b = await svc.find_or_create("NameB", TagKind.artist)
|
||||
with pytest.raises(TagValidationError, match="same kind"):
|
||||
await svc.merge(a.id, b.id)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_merge_rejects_cross_fandom(db):
|
||||
svc = TagService(db)
|
||||
f1 = await svc.find_or_create("Fandom1", TagKind.fandom)
|
||||
f2 = await svc.find_or_create("Fandom2", TagKind.fandom)
|
||||
c1 = await svc.find_or_create("Char", TagKind.character, fandom_id=f1.id)
|
||||
c2 = await svc.find_or_create("Char2", TagKind.character, fandom_id=f2.id)
|
||||
with pytest.raises(TagValidationError, match="same kind and fandom"):
|
||||
await svc.merge(c1.id, c2.id)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_merge_empty_tags_returns_result(db):
|
||||
svc = TagService(db)
|
||||
a = await svc.find_or_create("EmptyA", TagKind.general)
|
||||
b = await svc.find_or_create("EmptyB", TagKind.general)
|
||||
result = await svc.merge(a.id, b.id)
|
||||
assert isinstance(result, MergeResult)
|
||||
assert result.target_id == b.id
|
||||
assert result.target_name == "EmptyB"
|
||||
assert result.target_kind == "general"
|
||||
assert result.merged_count == 0
|
||||
assert result.alias_created is False
|
||||
assert result.source_deleted is True
|
||||
assert await db.get(Tag, a.id) is None
|
||||
|
||||
Reference in New Issue
Block a user