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

"""Tests for view_utils."""

import json

import yaml
from django.template.defaultfilters import filesizeformat

from debusine.db.models import FileInArtifact, FileStore
from debusine.test.django import TestCase
from debusine.web.views import view_utils


class ReadFileTests(TestCase):
    """Tests for read_file() function."""

    def create_file_in_backend(
        self,
        *,
        contents: bytes = b"sample-data",
        path: str = "/usr/bin/test",
        complete: bool = True,
    ) -> FileInArtifact:
        """
        Create a FileInArtifact and add it into the backend.

        This is intended for read_file() tests, where the file must exist in
        the backend.
        """
        artifact, _ = self.playground.create_artifact()
        file_backend = FileStore.default().get_backend_object()

        file = self.playground.create_file_in_backend(
            backend=file_backend,
            contents=contents,
        )

        file_in_artifact = FileInArtifact(
            file=file,
            artifact=artifact,
            path=path,
            complete=complete,
        )

        return file_in_artifact

    def test_read_file(self) -> None:
        file_in_artifact = self.create_file_in_backend(contents=b"The contents")

        self.assertEqual(
            view_utils.read_file(file_in_artifact, max_file_size=1024),
            b"The contents",
        )

    def test_read_file_too_big_error(self) -> None:
        max_file_size = 10
        file_in_artifact = self.create_file_in_backend(
            contents=b"a" * (max_file_size + 1), complete=True
        )

        with self.assertRaises(view_utils.TooBigFileInArtifactError) as error:
            view_utils.read_file(file_in_artifact, max_file_size=max_file_size)

        self.assertEqual(
            error.exception.to_html(),
            f'File too big to display '
            f'(size: {filesizeformat(file_in_artifact.file.size)} '
            f'maximum size: {filesizeformat(max_file_size)}). '
            f'<a href="{file_in_artifact.get_absolute_url_download()}">Download'
            '</a> or '
            f'<a href="{file_in_artifact.get_absolute_url_raw()}">view</a> '
            'it raw.',
        )

    def test_read_file_incomplete_error(self) -> None:
        file_in_artifact = self.create_file_in_backend(complete=False)

        with self.assertRaises(
            view_utils.IncompleteFileInArtifactError
        ) as error:
            view_utils.read_file(file_in_artifact, max_file_size=1024)

        self.assertEqual(
            error.exception.to_html(),
            'File "/usr/bin/test" has not completed uploading.',
        )


class TestViewUtils(TestCase):
    """Tests for view_utils functions."""

    CONTENTS_XPATH = 'string(//div[@class="formatted-content"]/pre)'

    def test_as_yaml_round_trip(self) -> None:
        for value in (
            {"package": "hello", "version": "1.0.0"},
            "hello",
            4242,
            42.42,
            True,
            False,
            None,
            [1, "a", 42.42],
        ):
            with self.subTest(value=value, type=type(value).__name__):
                html = view_utils.highlight_as_yaml(value)

                tree = self.assertHTMLValid(html)
                output = tree.xpath(self.CONTENTS_XPATH)

                self.assertEqual(yaml.safe_load(output), value)

    def test_as_json(self) -> None:
        value = {"package": "hello"}

        html = view_utils.highlight_as_json(value)
        tree = self.assertHTMLValid(html)

        output = tree.xpath(self.CONTENTS_XPATH)
        self.assertEqual(json.loads(output), value)

    def test_syntax_highlight(self) -> None:
        value = "some text"

        html = view_utils.syntax_highlight("text", value)
        tree = self.assertHTMLValid(html)

        output = self.get_node_text_normalized(tree)
        self.assertEqual(output, value)
