# Copyright (C) 2023 Canonical Ltd.
# Author: Benjamin Drung <benjamin.drung@canonical.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.

"""Unit tests for apport.sandboxutils."""

import os
import tempfile
import unittest
import unittest.mock
from unittest.mock import MagicMock

from apport.package_info import PackageInfo
from apport.report import Report
from apport.sandboxutils import _move_base_files_first, make_sandbox


class TestSandboxutils(unittest.TestCase):
    """Unit tests for apport.sandboxutils."""

    @staticmethod
    def _get_sample_report() -> Report:
        report = Report()
        report["Architecture"] = "amd64"
        report["DistroRelease"] = "Ubuntu 22.04"
        report["ExecutablePath"] = "/bin/bash"
        report["Signal"] = "11"
        return report

    @unittest.mock.patch("apport.sandboxutils.packaging", spec=PackageInfo)
    def test_make_sandbox(self, packaging_mock: MagicMock) -> None:
        """make_sandbox() for a sample report."""
        packaging_mock.install_packages.return_value = "obsolete\n"
        report = self._get_sample_report()
        sandbox, cache, outdated_msg = make_sandbox(report, "system")
        self.assertTrue(os.path.exists(sandbox), f"'{sandbox}' does not exist")
        self.assertTrue(os.path.exists(cache), f"'{cache}' does not exist")
        self.assertEqual(outdated_msg, "obsolete\nobsolete\n")
        self.assertEqual(packaging_mock.install_packages.call_count, 2)

    @unittest.mock.patch("apport.sandboxutils.packaging", spec=PackageInfo)
    def test_make_sandbox_install_packages_failure(
        self, packaging_mock: MagicMock
    ) -> None:
        """make_sandbox() where packaging.install_packages fails."""
        packaging_mock.install_packages.side_effect = SystemError("100% fail")
        with self.assertRaises(SystemExit):
            make_sandbox(self._get_sample_report(), "system")
        packaging_mock.install_packages.assert_called_once()

    @unittest.mock.patch("apport.sandboxutils.packaging", spec=PackageInfo)
    def test_make_sandbox_with_sandbox_dir(self, packaging_mock: MagicMock) -> None:
        """make_sandbox() with sandbox_dir set."""
        packaging_mock.install_packages.return_value = "obsolete\n"
        with tempfile.TemporaryDirectory(dir="/var/tmp") as tmpdir:
            config_dir = os.path.join(tmpdir, "config")
            cache_dir = os.path.join(tmpdir, "cache")
            sandbox_dir = os.path.join(tmpdir, "sandbox")
            sandbox, cache, outdated_msg = make_sandbox(
                self._get_sample_report(),
                config_dir,
                cache_dir=cache_dir,
                sandbox_dir=sandbox_dir,
            )
            self.assertEqual(sandbox, sandbox_dir)
            self.assertEqual(cache, cache_dir)
        self.assertEqual(outdated_msg, "obsolete\nobsolete\n")
        self.assertEqual(packaging_mock.install_packages.call_count, 2)

    def test_move_base_files_first_existing(self) -> None:
        """_move_base_files_first() with base-files in list."""
        pkgs: list[tuple[str, None | str]] = [
            ("chaos-marmosets", "0.1.2-2"),
            ("base-files", "13ubuntu9"),
            ("libc6", "2.39-0ubuntu8.2"),
        ]
        _move_base_files_first(pkgs)
        self.assertEqual(
            pkgs,
            [
                ("base-files", "13ubuntu9"),
                ("chaos-marmosets", "0.1.2-2"),
                ("libc6", "2.39-0ubuntu8.2"),
            ],
        )

    def test_move_base_files_first_missing(self) -> None:
        """_move_base_files_first() without base-files in list."""
        pkgs: list[tuple[str, None | str]] = [
            ("chaos-marmosets", "0.1.2-2"),
            ("libc6", "2.39-0ubuntu8.2"),
        ]
        _move_base_files_first(pkgs)
        self.assertEqual(
            pkgs, [("chaos-marmosets", "0.1.2-2"), ("libc6", "2.39-0ubuntu8.2")]
        )
