Files
holy-flavor-rater/backend/api/tests/test_merge.py
T
2026-05-27 17:07:46 +02:00

128 lines
5.0 KiB
Python

from io import StringIO
from django.test import TestCase
from api.management.commands.cleanup_duplicates import Command
from api.models import Category, Flavor, Notification, Rating, Reply, User
from api.services.flavor import merge_flavors
class FlavorMergeTests(TestCase):
def setUp(self):
self.cat = Category.objects.create(name="Energy", slug="energy")
self.user1 = User.objects.create_user(username="user1")
self.user2 = User.objects.create_user(username="user2")
self.keep = Flavor.objects.create(name="Dolphin Daiquiri", category=self.cat)
self.remove = Flavor.objects.create(name="Dolphin Daiquiri Energy", category=self.cat)
def test_basic_merge(self):
# User 1 rates 'remove'
r1 = Rating.objects.create(user=self.user1, flavor=self.remove, score=8, comment="Good!")
merge_flavors(self.keep, self.remove)
self.assertFalse(Flavor.objects.filter(id=self.remove.id).exists())
r1.refresh_from_db()
self.assertEqual(r1.flavor, self.keep)
def test_merge_with_conflict_keeps_longest_comment(self):
# User 1 rates both
Rating.objects.create(user=self.user1, flavor=self.keep, score=5, comment="Short")
r_long = Rating.objects.create(
user=self.user1, flavor=self.remove, score=9, comment="Very long and detailed review"
)
# Add a reply to the one being deleted
reply = Reply.objects.create(user=self.user2, rating=r_long, text="Nice review!")
merge_flavors(self.keep, self.remove)
self.assertEqual(Rating.objects.filter(user=self.user1, flavor=self.keep).count(), 1)
kept_rating = Rating.objects.get(user=self.user1, flavor=self.keep)
self.assertEqual(kept_rating.comment, "Very long and detailed review")
self.assertEqual(kept_rating.score, 9)
# Verify reply moved
reply.refresh_from_db()
self.assertEqual(reply.rating, kept_rating)
def test_merge_with_conflict_preserves_replies_from_discarded(self):
Rating.objects.create(user=self.user1, flavor=self.keep, score=10, comment="Best ever!")
r_remove = Rating.objects.create(
user=self.user1, flavor=self.remove, score=8, comment="Meh"
)
reply_on_remove = Reply.objects.create(user=self.user2, rating=r_remove, text="I disagree")
merge_flavors(self.keep, self.remove)
kept_rating = Rating.objects.get(user=self.user1, flavor=self.keep)
self.assertEqual(kept_rating.comment, "Best ever!")
reply_on_remove.refresh_from_db()
self.assertEqual(reply_on_remove.rating, kept_rating)
def test_merge_conflict_repoints_notifications(self):
# User 1 rated both; the discarded rating has a notification attached.
Rating.objects.create(user=self.user1, flavor=self.keep, score=10, comment="Best ever!")
r_remove = Rating.objects.create(
user=self.user1, flavor=self.remove, score=8, comment="Meh"
)
notif = Notification.objects.create(
recipient=self.user1,
actor=self.user2,
notification_type="reply",
rating=r_remove,
)
merge_flavors(self.keep, self.remove)
kept_rating = Rating.objects.get(user=self.user1, flavor=self.keep)
notif.refresh_from_db()
self.assertEqual(notif.rating, kept_rating)
def test_merge_transfers_external_id_when_keep_lacks_one(self):
self.assertIsNone(self.keep.external_id)
self.remove.external_id = 99887766
self.remove.save(update_fields=["external_id"])
merge_flavors(self.keep, self.remove)
self.keep.refresh_from_db()
self.assertEqual(self.keep.external_id, 99887766)
class CleanupDuplicatesTests(TestCase):
def setUp(self):
self.cat = Category.objects.create(name="Energy", slug="energy")
self.other_cat = Category.objects.create(name="Iced Tea", slug="iced-tea")
def test_normalization_logic(self):
f1 = Flavor.objects.create(name="Dolphin Daiquiri", category=self.cat)
f2 = Flavor.objects.create(name="Dolphin Daiquiri Energy", category=self.cat)
f3 = Flavor.objects.create(name="Dolphin Daiquiri", category=self.other_cat)
out = StringIO()
cmd = Command()
cmd.stdout = out
cmd.handle()
self.assertTrue(Flavor.objects.filter(id=f1.id).exists())
self.assertFalse(Flavor.objects.filter(id=f2.id).exists())
self.assertTrue(Flavor.objects.filter(id=f3.id).exists()) # Different category
def test_various_suffixes(self):
Flavor.objects.create(name="Berry", category=self.cat)
Flavor.objects.create(name="Berry Energy", category=self.cat)
Flavor.objects.create(name="Berry Hydration", category=self.cat)
Flavor.objects.create(name="Berry Iced Tea", category=self.cat)
Flavor.objects.create(name="Berry (Legacy)", category=self.cat)
cmd = Command()
cmd.stdout = StringIO()
cmd.handle()
self.assertEqual(Flavor.objects.filter(category=self.cat).count(), 1)