314 lines
12 KiB
Python
314 lines
12 KiB
Python
"""Tests for chat badge models and functionality."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from django.db import IntegrityError
|
|
from pydantic import ValidationError
|
|
|
|
from twitch.models import ChatBadge
|
|
from twitch.models import ChatBadgeSet
|
|
from twitch.schemas import ChatBadgeSetSchema
|
|
from twitch.schemas import ChatBadgeVersionSchema
|
|
from twitch.schemas import GlobalChatBadgesResponse
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestChatBadgeSetModel:
|
|
"""Tests for the ChatBadgeSet model."""
|
|
|
|
def test_create_badge_set(self) -> None:
|
|
"""Test creating a new badge set."""
|
|
badge_set = ChatBadgeSet.objects.create(set_id="vip")
|
|
assert badge_set.set_id == "vip"
|
|
assert badge_set.added_at is not None
|
|
assert badge_set.updated_at is not None
|
|
assert str(badge_set) == "vip"
|
|
|
|
def test_unique_set_id(self) -> None:
|
|
"""Test that set_id must be unique."""
|
|
ChatBadgeSet.objects.create(set_id="vip")
|
|
with pytest.raises(IntegrityError):
|
|
ChatBadgeSet.objects.create(set_id="vip")
|
|
|
|
def test_badge_set_ordering(self) -> None:
|
|
"""Test that badge sets are ordered by set_id."""
|
|
ChatBadgeSet.objects.create(set_id="subscriber")
|
|
ChatBadgeSet.objects.create(set_id="bits")
|
|
ChatBadgeSet.objects.create(set_id="vip")
|
|
|
|
badge_sets = list(ChatBadgeSet.objects.all())
|
|
assert badge_sets[0].set_id == "bits"
|
|
assert badge_sets[1].set_id == "subscriber"
|
|
assert badge_sets[2].set_id == "vip"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestChatBadgeModel:
|
|
"""Tests for the ChatBadge model."""
|
|
|
|
def test_create_badge(self) -> None:
|
|
"""Test creating a new badge."""
|
|
badge_set = ChatBadgeSet.objects.create(set_id="vip")
|
|
badge = ChatBadge.objects.create(
|
|
badge_set=badge_set,
|
|
badge_id="1",
|
|
image_url_1x="https://example.com/1x.png",
|
|
image_url_2x="https://example.com/2x.png",
|
|
image_url_4x="https://example.com/4x.png",
|
|
title="VIP",
|
|
description="VIP Badge",
|
|
click_action="visit_url",
|
|
click_url="https://help.twitch.tv",
|
|
)
|
|
|
|
assert badge.badge_set == badge_set
|
|
assert badge.badge_id == "1"
|
|
assert badge.title == "VIP"
|
|
assert badge.description == "VIP Badge"
|
|
assert badge.click_action == "visit_url"
|
|
assert badge.click_url == "https://help.twitch.tv"
|
|
assert str(badge) == "vip/1: VIP"
|
|
|
|
def test_unique_badge_set_and_id(self) -> None:
|
|
"""Test that badge_set and badge_id combination must be unique."""
|
|
badge_set = ChatBadgeSet.objects.create(set_id="vip")
|
|
ChatBadge.objects.create(
|
|
badge_set=badge_set,
|
|
badge_id="1",
|
|
image_url_1x="https://example.com/1x.png",
|
|
image_url_2x="https://example.com/2x.png",
|
|
image_url_4x="https://example.com/4x.png",
|
|
title="VIP",
|
|
description="VIP Badge",
|
|
)
|
|
|
|
with pytest.raises(IntegrityError):
|
|
ChatBadge.objects.create(
|
|
badge_set=badge_set,
|
|
badge_id="1",
|
|
image_url_1x="https://example.com/1x.png",
|
|
image_url_2x="https://example.com/2x.png",
|
|
image_url_4x="https://example.com/4x.png",
|
|
title="VIP Duplicate",
|
|
description="Duplicate Badge",
|
|
)
|
|
|
|
def test_different_badge_ids_same_set(self) -> None:
|
|
"""Test that different badge_ids can exist in the same set."""
|
|
badge_set = ChatBadgeSet.objects.create(set_id="bits")
|
|
badge1 = ChatBadge.objects.create(
|
|
badge_set=badge_set,
|
|
badge_id="1",
|
|
image_url_1x="https://example.com/1x.png",
|
|
image_url_2x="https://example.com/2x.png",
|
|
image_url_4x="https://example.com/4x.png",
|
|
title="Bits 1",
|
|
description="1 Bit",
|
|
)
|
|
badge2 = ChatBadge.objects.create(
|
|
badge_set=badge_set,
|
|
badge_id="100",
|
|
image_url_1x="https://example.com/1x.png",
|
|
image_url_2x="https://example.com/2x.png",
|
|
image_url_4x="https://example.com/4x.png",
|
|
title="Bits 100",
|
|
description="100 Bits",
|
|
)
|
|
|
|
assert badge1.badge_id == "1"
|
|
assert badge2.badge_id == "100"
|
|
assert badge1.badge_set == badge2.badge_set
|
|
|
|
def test_nullable_click_fields(self) -> None:
|
|
"""Test that click_action and click_url can be null."""
|
|
badge_set = ChatBadgeSet.objects.create(set_id="moderator")
|
|
badge = ChatBadge.objects.create(
|
|
badge_set=badge_set,
|
|
badge_id="1",
|
|
image_url_1x="https://example.com/1x.png",
|
|
image_url_2x="https://example.com/2x.png",
|
|
image_url_4x="https://example.com/4x.png",
|
|
title="Moderator",
|
|
description="Channel Moderator",
|
|
click_action=None,
|
|
click_url=None,
|
|
)
|
|
|
|
assert badge.click_action is None
|
|
assert badge.click_url is None
|
|
|
|
def test_badge_cascade_delete(self) -> None:
|
|
"""Test that badges are deleted when their badge set is deleted."""
|
|
badge_set = ChatBadgeSet.objects.create(set_id="test_set")
|
|
ChatBadge.objects.create(
|
|
badge_set=badge_set,
|
|
badge_id="1",
|
|
image_url_1x="https://example.com/1x.png",
|
|
image_url_2x="https://example.com/2x.png",
|
|
image_url_4x="https://example.com/4x.png",
|
|
title="Test Badge",
|
|
description="Test Description",
|
|
)
|
|
|
|
assert ChatBadge.objects.filter(badge_set=badge_set).count() == 1
|
|
badge_set.delete()
|
|
assert ChatBadge.objects.filter(badge_set__set_id="test_set").count() == 0
|
|
|
|
|
|
class TestChatBadgeSchemas:
|
|
"""Tests for chat badge Pydantic schemas."""
|
|
|
|
def test_chat_badge_version_schema_valid(self) -> None:
|
|
"""Test that ChatBadgeVersionSchema validates correct data."""
|
|
data = {
|
|
"id": "1",
|
|
"image_url_1x": "https://static-cdn.jtvnw.net/badges/v1/example/1",
|
|
"image_url_2x": "https://static-cdn.jtvnw.net/badges/v1/example/2",
|
|
"image_url_4x": "https://static-cdn.jtvnw.net/badges/v1/example/3",
|
|
"title": "VIP",
|
|
"description": "VIP Badge",
|
|
"click_action": "visit_url",
|
|
"click_url": "https://help.twitch.tv",
|
|
}
|
|
|
|
schema = ChatBadgeVersionSchema.model_validate(data)
|
|
assert schema.badge_id == "1"
|
|
assert schema.title == "VIP"
|
|
assert schema.click_action == "visit_url"
|
|
|
|
def test_chat_badge_version_schema_nullable_fields(self) -> None:
|
|
"""Test that nullable fields in ChatBadgeVersionSchema work correctly."""
|
|
data = {
|
|
"id": "1",
|
|
"image_url_1x": "https://static-cdn.jtvnw.net/badges/v1/example/1",
|
|
"image_url_2x": "https://static-cdn.jtvnw.net/badges/v1/example/2",
|
|
"image_url_4x": "https://static-cdn.jtvnw.net/badges/v1/example/3",
|
|
"title": "VIP",
|
|
"description": "VIP Badge",
|
|
"click_action": None,
|
|
"click_url": None,
|
|
}
|
|
|
|
schema = ChatBadgeVersionSchema.model_validate(data)
|
|
assert schema.click_action is None
|
|
assert schema.click_url is None
|
|
|
|
def test_chat_badge_version_schema_missing_required(self) -> None:
|
|
"""Test that ChatBadgeVersionSchema raises error on missing required fields."""
|
|
data = {
|
|
"id": "1",
|
|
"title": "VIP",
|
|
# Missing required image URLs and description
|
|
}
|
|
|
|
with pytest.raises(ValidationError):
|
|
ChatBadgeVersionSchema.model_validate(data)
|
|
|
|
def test_chat_badge_set_schema_valid(self) -> None:
|
|
"""Test that ChatBadgeSetSchema validates correct data."""
|
|
data = {
|
|
"set_id": "vip",
|
|
"versions": [
|
|
{
|
|
"id": "1",
|
|
"image_url_1x": "https://static-cdn.jtvnw.net/badges/v1/example/1",
|
|
"image_url_2x": "https://static-cdn.jtvnw.net/badges/v1/example/2",
|
|
"image_url_4x": "https://static-cdn.jtvnw.net/badges/v1/example/3",
|
|
"title": "VIP",
|
|
"description": "VIP Badge",
|
|
"click_action": "visit_url",
|
|
"click_url": "https://help.twitch.tv",
|
|
},
|
|
],
|
|
}
|
|
|
|
schema = ChatBadgeSetSchema.model_validate(data)
|
|
assert schema.set_id == "vip"
|
|
assert len(schema.versions) == 1
|
|
assert schema.versions[0].badge_id == "1"
|
|
|
|
def test_chat_badge_set_schema_multiple_versions(self) -> None:
|
|
"""Test that ChatBadgeSetSchema handles multiple badge versions."""
|
|
data = {
|
|
"set_id": "bits",
|
|
"versions": [
|
|
{
|
|
"id": "1",
|
|
"image_url_1x": "https://example.com/1/1x.png",
|
|
"image_url_2x": "https://example.com/1/2x.png",
|
|
"image_url_4x": "https://example.com/1/4x.png",
|
|
"title": "Bits 1",
|
|
"description": "1 Bit",
|
|
"click_action": None,
|
|
"click_url": None,
|
|
},
|
|
{
|
|
"id": "100",
|
|
"image_url_1x": "https://example.com/100/1x.png",
|
|
"image_url_2x": "https://example.com/100/2x.png",
|
|
"image_url_4x": "https://example.com/100/4x.png",
|
|
"title": "Bits 100",
|
|
"description": "100 Bits",
|
|
"click_action": None,
|
|
"click_url": None,
|
|
},
|
|
],
|
|
}
|
|
|
|
schema = ChatBadgeSetSchema.model_validate(data)
|
|
assert schema.set_id == "bits"
|
|
assert len(schema.versions) == 2
|
|
assert schema.versions[0].badge_id == "1"
|
|
assert schema.versions[1].badge_id == "100"
|
|
|
|
def test_global_chat_badges_response_valid(self) -> None:
|
|
"""Test that GlobalChatBadgesResponse validates correct API response."""
|
|
data = {
|
|
"data": [
|
|
{
|
|
"set_id": "vip",
|
|
"versions": [
|
|
{
|
|
"id": "1",
|
|
"image_url_1x": "https://static-cdn.jtvnw.net/badges/v1/example/1",
|
|
"image_url_2x": "https://static-cdn.jtvnw.net/badges/v1/example/2",
|
|
"image_url_4x": "https://static-cdn.jtvnw.net/badges/v1/example/3",
|
|
"title": "VIP",
|
|
"description": "VIP Badge",
|
|
"click_action": "visit_url",
|
|
"click_url": "https://help.twitch.tv",
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}
|
|
|
|
response = GlobalChatBadgesResponse.model_validate(data)
|
|
assert len(response.data) == 1
|
|
assert response.data[0].set_id == "vip"
|
|
|
|
def test_global_chat_badges_response_empty(self) -> None:
|
|
"""Test that GlobalChatBadgesResponse validates empty response."""
|
|
data = {"data": []}
|
|
|
|
response = GlobalChatBadgesResponse.model_validate(data)
|
|
assert len(response.data) == 0
|
|
|
|
def test_chat_badge_schema_extra_forbidden(self) -> None:
|
|
"""Test that extra fields are forbidden in schemas."""
|
|
data = {
|
|
"id": "1",
|
|
"image_url_1x": "https://example.com/1x.png",
|
|
"image_url_2x": "https://example.com/2x.png",
|
|
"image_url_4x": "https://example.com/4x.png",
|
|
"title": "VIP",
|
|
"description": "VIP Badge",
|
|
"extra_field": "should_fail", # This should cause validation to fail
|
|
}
|
|
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
ChatBadgeVersionSchema.model_validate(data)
|
|
|
|
# Check that the error is about the extra field
|
|
assert "extra_field" in str(exc_info.value)
|