# Copyright 2010-2026 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

from portage.tests import TestCase
from portage.tests.resolver.ResolverPlayground import (
    ResolverPlayground,
    ResolverPlaygroundTestCase,
)


class BacktrackingTestCase(TestCase):
    def testBacktracking(self):
        ebuilds = {
            "dev-libs/A-1": {},
            "dev-libs/A-2": {},
            "dev-libs/B-1": {"DEPEND": "dev-libs/A"},
        }

        test_cases = (
            ResolverPlaygroundTestCase(
                ["=dev-libs/A-1", "dev-libs/B"],
                all_permutations=True,
                mergelist=["dev-libs/A-1", "dev-libs/B-1"],
                success=True,
            ),
        )

        playground = ResolverPlayground(ebuilds=ebuilds)

        try:
            for test_case in test_cases:
                playground.run_TestCase(test_case)
                self.assertEqual(test_case.test_success, True, test_case.fail_msg)
        finally:
            playground.cleanup()

    def testBacktrackNotNeeded(self):
        ebuilds = {
            "dev-libs/A-1": {},
            "dev-libs/A-2": {},
            "dev-libs/B-1": {},
            "dev-libs/B-2": {},
            "dev-libs/C-1": {"DEPEND": "dev-libs/A dev-libs/B"},
            "dev-libs/D-1": {"DEPEND": "=dev-libs/A-1 =dev-libs/B-1"},
        }

        test_cases = (
            ResolverPlaygroundTestCase(
                ["dev-libs/C", "dev-libs/D"],
                all_permutations=True,
                options={"--backtrack": 1},
                mergelist=[
                    "dev-libs/A-1",
                    "dev-libs/B-1",
                    "dev-libs/C-1",
                    "dev-libs/D-1",
                ],
                ignore_mergelist_order=True,
                success=True,
            ),
        )

        playground = ResolverPlayground(ebuilds=ebuilds)

        try:
            for test_case in test_cases:
                playground.run_TestCase(test_case)
                self.assertEqual(test_case.test_success, True, test_case.fail_msg)
        finally:
            playground.cleanup()

    def testBacktrackWithoutUpdates(self):
        """
        If --update is not given we might have to mask the old installed version later.
        """

        ebuilds = {
            "dev-libs/A-1": {"DEPEND": "dev-libs/Z"},
            "dev-libs/B-1": {"DEPEND": ">=dev-libs/Z-2"},
            "dev-libs/Z-1": {},
            "dev-libs/Z-2": {},
        }

        installed = {
            "dev-libs/Z-1": {"USE": ""},
        }

        test_cases = (
            ResolverPlaygroundTestCase(
                ["dev-libs/B", "dev-libs/A"],
                all_permutations=True,
                mergelist=[
                    "dev-libs/Z-2",
                    "dev-libs/B-1",
                    "dev-libs/A-1",
                ],
                ignore_mergelist_order=True,
                success=True,
            ),
        )

        playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)

        try:
            for test_case in test_cases:
                playground.run_TestCase(test_case)
                self.assertEqual(test_case.test_success, True, test_case.fail_msg)
        finally:
            playground.cleanup()

    def testBacktrackMissedUpdates(self):
        """
        An update is missed due to a dependency on an older version.
        """

        ebuilds = {
            "dev-libs/A-1": {},
            "dev-libs/A-2": {},
            "dev-libs/B-1": {"RDEPEND": "<=dev-libs/A-1"},
        }

        installed = {
            "dev-libs/A-1": {"USE": ""},
            "dev-libs/B-1": {"USE": "", "RDEPEND": "<=dev-libs/A-1"},
        }

        options = {"--update": True, "--deep": True, "--selective": True}

        test_cases = (
            ResolverPlaygroundTestCase(
                ["dev-libs/A", "dev-libs/B"],
                options=options,
                all_permutations=True,
                mergelist=[],
                success=True,
            ),
        )

        playground = ResolverPlayground(ebuilds=ebuilds, installed=installed)

        try:
            for test_case in test_cases:
                playground.run_TestCase(test_case)
                self.assertEqual(test_case.test_success, True, test_case.fail_msg)
        finally:
            playground.cleanup()

    def testBacktrackNoWrongRebuilds(self):
        """
        Ensure we remove backtrack masks if the reason for the mask gets masked itself.
        """

        ebuilds = {
            "dev-libs/A-1": {},
            "dev-libs/A-2": {},
            "dev-libs/B-1": {"RDEPEND": "dev-libs/D"},
            "dev-libs/C-1": {},
            "dev-libs/C-2": {"RDEPEND": ">=dev-libs/A-2"},
            "dev-libs/D-1": {"RDEPEND": "<dev-libs/A-2"},
        }

        installed = {
            "dev-libs/A-1": {},
            "dev-libs/B-1": {"RDEPEND": "dev-libs/D"},
            "dev-libs/C-1": {},
            "dev-libs/D-1": {"RDEPEND": "<dev-libs/A-2"},
        }

        world = ["dev-libs/B", "dev-libs/C"]

        options = {
            "--backtrack": 6,
            "--deep": True,
            "--selective": True,
            "--update": True,
        }

        test_cases = (
            ResolverPlaygroundTestCase(
                ["@world"], options=options, mergelist=[], success=True
            ),
        )

        playground = ResolverPlayground(
            ebuilds=ebuilds, installed=installed, world=world
        )

        try:
            for test_case in test_cases:
                playground.run_TestCase(test_case)
                self.assertEqual(test_case.test_success, True, test_case.fail_msg)
        finally:
            playground.cleanup()

    def testBacktrackInconsistentForcedRebuildWithBlocker(self):

        ebuilds = {
            "dev-libs/boost-1.88.0": {"EAPI": 8, "SLOT": "0/1.88"},
            "dev-libs/boost-1.89.0": {"EAPI": 8, "SLOT": "0/1.89"},
            "x11-libs/qwt-6.3.0": {"EAPI": 8},
            "x11-libs/qwt-6.2.0": {"EAPI": 8, "IUSE": "+qt5"},
            "net-wireless/gnuradio-3.10.12": {
                "EAPI": 8,
                "SLOT": "0/3.10.12.0",
                "RDEPEND": "x11-libs/qwt[qt5(-)]",
            },
            "net-wireless/gr-iqbal-0.38.3": {
                "EAPI": 8,
                "RDEPEND": "net-wireless/gnuradio:= dev-libs/boost:=",
            },
            "dev-libs/A-1": {"EAPI": 8, "RDEPEND": "dev-libs/boost:="},
            "dev-libs/B-1": {"EAPI": 8, "RDEPEND": "dev-libs/boost:="},
            "dev-libs/C-1": {"EAPI": 8, "RDEPEND": "dev-libs/boost:="},
            "dev-libs/D-1": {"EAPI": 8, "RDEPEND": "dev-libs/boost:="},
        }

        installed = {
            "dev-libs/boost-1.89.0": {"EAPI": 8, "SLOT": "0/1.89"},
            "x11-libs/qwt-6.2.0": {"EAPI": 8, "IUSE": "+qt5", "USE": "qt5"},
            "net-wireless/gnuradio-3.10.12": {
                "EAPI": 8,
                "SLOT": "0/3.10.12.0",
                "RDEPEND": "x11-libs/qwt[qt5(-)]",
            },
            "net-wireless/gr-iqbal-0.38.3": {
                "EAPI": 8,
                "RDEPEND": "net-wireless/gnuradio:0/3.10.12.0= dev-libs/boost:0/1.88=",
            },
            "dev-libs/A-1": {"EAPI": 8, "RDEPEND": "dev-libs/boost:0/1.89="},
            "dev-libs/B-1": {"EAPI": 8, "RDEPEND": "dev-libs/boost:0/1.89="},
            "dev-libs/C-1": {"EAPI": 8, "RDEPEND": "dev-libs/boost:0/1.89="},
            "dev-libs/D-1": {"EAPI": 8, "RDEPEND": "dev-libs/boost:0/1.89="},
        }

        world = [
            "net-wireless/gr-iqbal",
            "dev-libs/A",
            "dev-libs/B",
            "dev-libs/C",
            "dev-libs/D",
        ]

        options = {
            "--update": True,
            "--deep": True,
            "--reinstall": "changed-use",
        }

        test_cases = (
            ResolverPlaygroundTestCase(
                ["@world"],
                options=options,
                mergelist=["net-wireless/gr-iqbal-0.38.3"],
                success=True,
            ),
        )

        playground = ResolverPlayground(
            ebuilds=ebuilds, installed=installed, world=world, debug=False
        )

        try:
            for test_case in test_cases:
                playground.run_TestCase(test_case)
                self.assertEqual(test_case.test_success, True, test_case.fail_msg)
        finally:
            playground.cleanup()
