#
# Copyright (c) 2010 Testrepository Contributors
#
# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
# license at the users choice. A copy of both licenses are available in the
# project source as Apache-2.0 and BSD. You may not use this file except in
# compliance with one of these two licences.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
# license you chose for the specific language governing permissions and
# limitations under that license.

"""Tests for the list_tests command."""

from io import BytesIO
import os.path
from subprocess import PIPE

import subunit
from testtools.matchers import MatchesException

from testrepository.commands import list_tests
from testrepository.ui.model import UI
from testrepository.repository import memory
from testrepository.tests import ResourcedTestCase
from testrepository.tests.stubpackage import TempDirResource


class TestCommand(ResourcedTestCase):
    resources = [("tempdir", TempDirResource())]

    def get_test_ui_and_cmd(self, options=(), args=()):
        self.dirty()
        ui = UI(options=options, args=args)
        ui.here = self.tempdir
        cmd = list_tests.list_tests(ui)
        ui.set_command(cmd)
        return ui, cmd

    def dirty(self):
        # Ugly: TODO - improve testresources to make this go away.
        dict(self.resources)["tempdir"]._dirty = True

    def config_path(self):
        return os.path.join(self.tempdir, ".testr.conf")

    def set_config(self, text):
        with open(self.config_path(), "wt") as stream:
            stream.write(text)

    def setup_repo(self, cmd, ui):
        repo = cmd.repository_factory.initialise(ui.here)
        inserter = repo.get_inserter()
        inserter.startTestRun()
        inserter.status(test_id="passing", test_status="success")
        inserter.status(test_id="failing", test_status="fail")
        inserter.stopTestRun()

    def test_no_config_file_errors(self):
        ui, cmd = self.get_test_ui_and_cmd()
        self.assertEqual(3, cmd.execute())
        self.assertEqual(1, len(ui.outputs))
        self.assertEqual("error", ui.outputs[0][0])
        self.assertThat(
            ui.outputs[0][1], MatchesException(ValueError("No .testr.conf config file"))
        )

    def test_calls_list_tests(self):
        ui, cmd = self.get_test_ui_and_cmd(args=("--", "bar", "quux"))
        cmd.repository_factory = memory.RepositoryFactory()
        buffer = BytesIO()
        stream = subunit.StreamResultToBytes(buffer)
        stream.status(test_id="returned", test_status="exists")
        stream.status(test_id="values", test_status="exists")
        subunit_bytes = buffer.getvalue()
        ui.proc_outputs = [subunit_bytes]
        self.setup_repo(cmd, ui)
        self.set_config(
            "[DEFAULT]\ntest_command=foo $LISTOPT $IDOPTION\n"
            "test_id_option=--load-list $IDFILE\n"
            "test_list_option=--list\n"
        )
        self.assertEqual(0, cmd.execute())
        expected_cmd = "foo --list  bar quux"
        self.assertEqual(
            [
                ("values", [("running", expected_cmd)]),
                (
                    "popen",
                    (expected_cmd,),
                    {"shell": True, "stdout": PIPE, "stdin": PIPE},
                ),
                ("communicate",),
                ("stream", b"returned\nvalues\n"),
            ],
            ui.outputs,
        )

    def test_filters_use_filtered_list(self):
        ui, cmd = self.get_test_ui_and_cmd(args=("returned", "--", "bar", "quux"))
        cmd.repository_factory = memory.RepositoryFactory()
        buffer = BytesIO()
        stream = subunit.StreamResultToBytes(buffer)
        stream.status(test_id="returned", test_status="exists")
        stream.status(test_id="values", test_status="exists")
        subunit_bytes = buffer.getvalue()
        ui.proc_outputs = [subunit_bytes]
        self.setup_repo(cmd, ui)
        self.set_config(
            "[DEFAULT]\ntest_command=foo $LISTOPT $IDOPTION\n"
            "test_id_option=--load-list $IDFILE\n"
            "test_list_option=--list\n"
        )
        retcode = cmd.execute()
        expected_cmd = "foo --list  bar quux"
        self.assertEqual(
            [
                ("values", [("running", expected_cmd)]),
                (
                    "popen",
                    (expected_cmd,),
                    {"shell": True, "stdout": PIPE, "stdin": PIPE},
                ),
                ("communicate",),
                ("stream", b"returned\n"),
            ],
            ui.outputs,
        )
        self.assertEqual(0, retcode)
