# Copyright 2024 The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.

"""Unit tests for the scopes models."""
from django.core.exceptions import ValidationError
from django.db import IntegrityError, transaction
from django.test import TestCase

from debusine.db.models import Scope
from debusine.db.models.scopes import is_valid_scope_name


class ScopeTests(TestCase):
    """Tests for the Scope class."""

    def test_create(self) -> None:
        """Test basic behavior."""
        scope = Scope.objects.create(name="test")
        self.assertEqual(scope.name, "test")
        self.assertEqual(str(scope), "test")

    def test_unique(self) -> None:
        """Check that scopes are unique by name."""
        Scope.objects.create(name="test")
        with transaction.atomic():
            with self.assertRaisesRegex(
                IntegrityError,
                "duplicate key value violates unique constraint"
                ' "db_scope_name_key"',
            ):
                Scope.objects.create(name="test")
        Scope.objects.create(name="test1")

    def test_fallback(self) -> None:
        """The fallback scope for migrations exists."""
        scope = Scope.objects.get(name="debusine")
        self.assertEqual(scope.name, "debusine")

    def test_is_valid_scope_name(self) -> None:
        """Test is_valid_scope_name."""
        valid_names = (
            "debian",
            "debian-lts",
            "debusine",
            "c",
            "c++",
            "foo_bar",
            "foo.bar",
            "foo+bar",
            "tail_",
            "c--",
        )
        invalid_names = (
            "api",
            "admin",
            "user",
            "+tag",
            "-tag",
            ".profile",
            "_reserved",
        )

        for name in valid_names:
            with self.subTest(name=name):
                self.assertTrue(is_valid_scope_name(name))

        for name in invalid_names:
            with self.subTest(name=name):
                self.assertFalse(is_valid_scope_name(name))

    def test_scope_name_validation(self) -> None:
        """Test validation for scope names."""
        Scope(name="foo").full_clean()
        Scope(name="foo_").full_clean()
        with self.assertRaises(ValidationError) as exc:
            Scope(name="_foo").full_clean()
        self.assertEqual(
            exc.exception.message_dict,
            {'name': ["'_foo' is not a valid scope name"]},
        )
