#
# Copyright (c) 2009 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 testr."""

import doctest
import os.path
import subprocess
import sys

from testresources import TestResource
from testtools.matchers import (
    DocTestMatches,
)

from testrepository.tests import ResourcedTestCase
from testrepository.tests.stubpackage import StubPackageResource


class StubbedTestr(object):
    """Testr executable with replaced testrepository package for testing."""

    def __init__(self, testrpath):
        self.execpath = testrpath

    def execute(self, args):
        # sys.executable is used so that this works on windows.
        proc = subprocess.Popen(
            [sys.executable, self.execpath] + args,
            env={"PYTHONPATH": self.stubpackage.base},
            stdout=subprocess.PIPE,
            stdin=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            universal_newlines=True,
        )
        out, err = proc.communicate()
        return proc.returncode, out


class StubbedTestrResource(TestResource):
    resources = [
        (
            "stubpackage",
            StubPackageResource(
                "testrepository",
                [
                    (
                        "commands.py",
                        r"""import sys
def run_argv(argv, stdin, stdout, stderr):
    sys.stdout.write("%s %s %s\n" % (sys.stdin is stdin, sys.stdout is stdout,
        sys.stderr is stderr))
    sys.stdout.write("%s\n" % argv)
    return len(argv) - 1
""",
                    )
                ],
            ),
        )
    ]

    def make(self, dependency_resources):
        stub = dependency_resources["stubpackage"]
        path = os.path.join(os.path.dirname(__file__), "..", "..", "testr")
        # Make a copy of the testr script as running in place uses the current
        # library, not the stub library.
        execpath = os.path.join(stub.base, "testr")
        source = open(path, "rb")
        try:
            testr_contents = source.read()
        finally:
            source.close()
        target = open(execpath, "wb")
        try:
            target.write(testr_contents)
        finally:
            target.close()
        return StubbedTestr(execpath)


class TestExecuted(ResourcedTestCase):
    """Tests that execute testr. These tests are (moderately) expensive!."""

    resources = [("testr", StubbedTestrResource())]

    def test_runs_and_returns_run_argv_some_args(self):
        status, output = self.testr.execute(["foo bar", "baz"])
        self.assertEqual(2, status)
        self.assertThat(
            output,
            DocTestMatches(
                """True True True
[..., 'foo bar', 'baz']\n""",
                doctest.ELLIPSIS,
            ),
        )

    def test_runs_and_returns_run_argv_no_args(self):
        status, output = self.testr.execute([])
        self.assertThat(
            output,
            DocTestMatches(
                """True True True
[...]\n""",
                doctest.ELLIPSIS,
            ),
        )
        self.assertEqual(0, status)
