from git import InvalidGitRepositoryError
from ploneintranet.fastest import Policy
from ploneintranet.fastest import repo
from ploneintranet.fastest import run
from ploneintranet.fastest import run_multi
from ploneintranet.fastest import RunAllTestsException
from ploneintranet.fastest import RunNoTestsException
from ploneintranet.fastest import spec
from ploneintranet.fastest import Strategy
from ploneintranet.fastest import whatchanged

import os
import unittest


class TestFastest(unittest.TestCase):
    # These tests fail on Gitlab-CI, because the source checkout there is shallow
    # and does not contain the deep history this suite depends on.
    # "Hide" this suite on level 2 which is not run by default.
    level = 2

    def setUp(self):
        try:
            repo()
        except InvalidGitRepositoryError:
            self.skipTest("Not in a git repo (egg release?)")

        self.ws_strategy = Strategy("workspace")
        self.ws_strategy.packages = ["ploneintranet.workspace"]
        self.ws_strategy.tests = ["workspace", "shoppingcart"]
        self.ws_strategy.triggers = [
            "src/ploneintranet/workspace",
            "workspace.robot",
            "case.robot",
        ]
        self.mb_strategy = Strategy("microblog")
        self.mb_strategy.packages = [
            "ploneintranet.microblog",
            "ploneintranet.activitystream",
        ]
        self.mb_strategy.tests = ["posting", "content_discussion"]
        self.mb_strategy.triggers = [
            "src/ploneintranet/microblog",
            "src/ploneintranet/activitystream",
        ]

    def test_whatchanged_nobase(self):
        newest = "e0995692edab70ec5aa7121a9a476b673bce3626"
        with self.assertRaises(RunAllTestsException):
            whatchanged(newest, verbose=False)

    def test_whatchanged(self):
        newest = "e0995692edab70ec5aa7121a9a476b673bce3626"
        since = "05a5fb0d1e2d7f1dbc86708eebef926d5e7715bb"
        changed = whatchanged(newest, since, verbose=False)
        expect = {
            "src/ploneintranet/activitystream/browser/statusupdate.py",
            "news/3864.changed",
        }
        self.assertEqual(changed, expect)

    def test_whatchanged_runall(self):
        newest = since = "ad00f110"
        with self.assertRaises(RunAllTestsException):
            whatchanged(newest, since, verbose=False)

    def test_whatchanged_ci_skip_runno(self):
        newest = "bbc10d977d07"
        since = "f7af272f10e4"
        with self.assertRaises(RunNoTestsException):
            whatchanged(newest, since, verbose=False)

    def test_whatchanged_ci_skip_skips(self):
        # this is only ever simple when no merge commits are involved
        newest = "fd22bdade7be3e35782345dab70e2b54a61dfbf4"
        since = "ac98296aa073b0e2de9ab1d5f4f2a27a12c848b6"
        changed = whatchanged(newest, since, verbose=False)
        to_skip = {"src/ploneintranet/fastest/policy.cfg"}
        for skipped in to_skip:
            self.assertTrue(skipped not in changed)
        expect = {
            "src/ploneintranet/core/locales/de/LC_MESSAGES/ploneintranet.po",
            "src/ploneintranet/core/locales/ploneintranet.pot",
        }
        self.assertEqual(changed, expect)

    def test_strategy_nomatch(self):
        changed = {
            "src/ploneintranet/layout/browser/passwordpanel.py",
            "src/ploneintranet/layout/browser/templates/personal-menu.pt",
            "src/ploneintranet/layout/viewlets/personalbar.py",
        }
        packages, tests = self.ws_strategy(changed, verbose=False)
        self.assertEqual((set(), set()), (packages, tests))

    def test_strategy_matchall(self):
        changed = {
            "src/ploneintranet/workspace/workspacefolder.py",
            "src/ploneintranet/workspace/browser/configure.zcml",
        }
        packages, tests = self.ws_strategy(changed, verbose=False)
        self.assertEqual(
            ({"ploneintranet.workspace"}, {"workspace", "shoppingcart"}),
            (packages, tests),
        )

    def test_strategy_matchall_2(self):
        changed = {
            "src/ploneintranet/suite/tests/acceptance/workspace.robot",
            "src/ploneintranet/suite/tests/acceptance/case.robot",
        }
        packages, tests = self.ws_strategy(changed, verbose=False)
        self.assertEqual(
            ({"ploneintranet.workspace"}, {"workspace", "shoppingcart"}),
            (packages, tests),
        )

    def test_policy_ws(self):
        policy = Policy()
        policy.add(self.ws_strategy, self.mb_strategy)
        changed = {
            "src/ploneintranet/workspace/workspacefolder.py",
            "src/ploneintranet/workspace/browser/configure.zcml",
        }
        packages, tests = policy(changed, verbose=False)
        self.assertEqual(
            ({"ploneintranet.workspace"}, {"workspace", "shoppingcart"}),
            (packages, tests),
        )

    def test_policy_both(self):
        policy = Policy()
        policy.add(self.ws_strategy, self.mb_strategy)
        changed = {
            "src/ploneintranet/workspace/workspacefolder.py",
            "src/ploneintranet/microblog/browser/__init__.py",
        }
        packages, tests = policy(changed, verbose=False)
        self.assertEqual(
            (
                {
                    "ploneintranet.workspace",
                    "ploneintranet.microblog",
                    "ploneintranet.activitystream",
                },
                {"workspace", "shoppingcart", "posting", "content_discussion"},
            ),
            (packages, tests),
        )

    def test_policy_read_config(self):
        policy = Policy()
        filepath = os.path.join(os.path.dirname(__file__), "testconfig.cfg")
        policy.read_config(filepath)
        self.assertEqual(
            {"workspace", "microblog"}, {x.name for x in policy.strategies}
        )

    def test_policy_both_read_config(self):
        filepath = os.path.join(os.path.dirname(__file__), "testconfig.cfg")
        policy = Policy(filepath)
        changed = {
            "src/ploneintranet/workspace/workspacefolder.py",
            "src/ploneintranet/microblog/browser/__init__.py",
        }
        packages, tests = policy(changed, verbose=False)
        self.assertEqual(
            (
                {
                    "ploneintranet.workspace",
                    "ploneintranet.microblog",
                    "ploneintranet.activitystream",
                },
                {"workspace", "shoppingcart", "posting", "content_discussion"},
            ),
            (packages, tests),
        )

    def test_policy_mismatch(self):
        policy = Policy()
        policy.add(self.ws_strategy, self.mb_strategy)
        changed = {
            "src/ploneintranet/workspace/workspacefolder.py",
            "src/ploneintranet/microblog/browser/__init__.py",
            "src/ploneintranet/no/such/thing",
        }
        packages, tests = policy(changed, verbose=False)
        self.assertEqual((set(), set()), (packages, tests))

    def test_wildcard(self):
        policy = Policy()
        policy.add(self.ws_strategy, self.mb_strategy)
        strategy = Strategy("wildcard")
        strategy.wildcard = True
        strategy.triggers = "setup.py"
        policy.add(strategy)
        changed = {
            "src/ploneintranet/workspace/workspacefolder.py",
            "src/ploneintranet/microblog/browser/__init__.py",
            "setup.py",
        }
        packages, tests = policy(changed, verbose=False)
        self.assertEqual((set(), set()), (packages, tests))

    def test_spec(self):
        self.assertEqual("-s bar -s foo", spec("-s", {"foo", "bar"}))

    def test_run(self):
        testspec = "-s ploneintranet.fastest -t noop"
        self.assertEqual(0, run(testspec, verbose=False))

    def test_run_multi(self):
        testspec = [
            "-s ploneintranet.fastest -t noop",
            "-s ploneintranet.fastest -t noop",
        ]
        self.assertEqual(0, run_multi(testspec, verbose=False))

    def test_noop(self):
        # avoid a test_run infinite recursion loop
        self.assertTrue(True)


if __name__ == "__main__":
    import unittest

    unittest.main()
