# Copyright 2023 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.

"""Test of the signon authentication middleware for external providers."""

from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ImproperlyConfigured, MiddlewareNotUsed
from django.http import HttpRequest, HttpResponse
from django.test import RequestFactory, TestCase, override_settings

from debusine.server.signon import providers
from debusine.server.signon.middleware import SignonMiddleware
from debusine.server.signon.signon import Signon


def mock_get_response(request: HttpRequest) -> HttpResponse:  # noqa: U100
    """Mock version of get_response to use for testing middlewares."""
    return HttpResponse()


class TestMiddleware(TestCase):
    """Test SignonMiddleware."""

    def setUp(self):
        """Provide a mock unauthenticated request for tests."""
        super().setUp()
        self.factory = RequestFactory()
        self.request = self.factory.get("/")

    @override_settings(
        SIGNON_PROVIDERS=[
            providers.Provider(
                name="debsso",
                label="sso.debian.org",
            ),
            providers.Provider(name="salsa", label="Salsa"),
        ]
    )
    def test_no_authentication_middleware(self):
        """Enforce that AuthenticationMiddleware is required."""
        mw = SignonMiddleware(get_response=mock_get_response)
        with self.assertRaises(ImproperlyConfigured):
            mw(self.request)

    @override_settings(SIGNON_PROVIDERS=[])
    def test_no_providers(self):
        """Skip middleware if there are no providers."""
        with self.assertRaises(MiddlewareNotUsed):
            SignonMiddleware(get_response=mock_get_response)

    @override_settings(
        SIGNON_PROVIDERS=[
            providers.Provider(
                name="debsso",
                label="sso.debian.org",
            ),
            providers.Provider(name="salsa", label="Salsa"),
        ]
    )
    def test_all_fine(self):
        """Test the case where all requirements are met."""
        self.request.user = AnonymousUser()
        self.assertFalse(hasattr(self.request, "signon"))

        mw = SignonMiddleware(get_response=mock_get_response)
        mw(self.request)

        self.assertTrue(hasattr(self.request, "signon"))
        self.assertIsInstance(self.request.signon, Signon)
