from datetime import timedelta import pytest from django.utils import timezone from rest_framework import serializers from accounts.models import InviteCode, InviteCodeUsage, User from accounts.serializers import RegisterSerializer def registration_data(code="VALID-CODE", username="math_user"): return { "invite_code": code, "username": username, "password": "StrongPass_2026", "nickname": "数学少年", "track": User.Track.STANDARD, } @pytest.mark.django_db def test_register_serializer_有效邀请码创建用户并原子消费(): invite = InviteCode.objects.create(code="VALID-CODE", max_uses=1) serializer = RegisterSerializer( data=registration_data(), context={"ip_address": "127.0.0.1"}, ) assert serializer.is_valid(), serializer.errors user = serializer.save() invite.refresh_from_db() assert invite.used_count == 1 assert user.check_password("StrongPass_2026") usage = InviteCodeUsage.objects.get(user=user) assert usage.invite_code == invite assert usage.ip_address == "127.0.0.1" @pytest.mark.django_db def test_register_serializer_过期邀请码拒绝创建用户(): InviteCode.objects.create( code="EXPIRED", max_uses=1, expires_at=timezone.now() - timedelta(seconds=1), ) serializer = RegisterSerializer(data=registration_data(code="EXPIRED")) assert serializer.is_valid(), serializer.errors with pytest.raises(serializers.ValidationError, match="已过期或已用完"): serializer.save() assert User.objects.count() == 0 @pytest.mark.django_db def test_register_serializer_用户名大小写重复时校验失败(): User.objects.create_user( username="Math_User", password="StrongPass_2026", nickname="已有用户", ) serializer = RegisterSerializer(data=registration_data(username="math_user")) assert not serializer.is_valid() assert "用户名已存在" in str(serializer.errors["username"]) @pytest.mark.django_db def test_register_serializer_游客迁移字段类型错误时拒绝(): InviteCode.objects.create(code="VALID-CODE", max_uses=1) data = registration_data() data["visitor_data"] = {"favorites": None} serializer = RegisterSerializer(data=data) assert not serializer.is_valid() assert "favorites 必须是数组" in str(serializer.errors["visitor_data"])