#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""Unit tests for stubs.py."""


from __future__ import print_function
import unittest

from test import stubs


class StubOsTest(unittest.TestCase):

    def test_isolated_environ_1(self):
        """Make sure changes to os.environ won't bleed between tests.

        If os.environ is shared, this or test_isolated_environ_2() will fail.
        """
        os = stubs.StubOs()
        os.environ['foo'] = 'bar'
        self.assertEqual({'foo': 'bar'}, os.environ)

    def test_isolated_environ_2(self):
        os = stubs.StubOs()
        os.environ['abc'] = 'def'
        self.assertEqual({'abc': 'def'}, os.environ)


class StubSubprocessTest(unittest.TestCase):

    def setUp(self):
        self.stub_subprocess = stubs.StubSubprocess()

    def test_call(self):
        """Tests a basic call() subprocess."""
        command = self.stub_subprocess.AddCommand()
        self.stub_subprocess.call(['echo', 'foo'])
        command.AssertCallWas(['echo', 'foo'])

    def test_popen(self):
        """Tests a basic Popen + communicate() subprocess."""
        command = self.stub_subprocess.AddCommand()
        self.stub_subprocess.Popen(['echo', 'foo']).communicate()
        command.AssertCallWas(['echo', 'foo'])

    def test_exit_code(self):
        """Tests returning a non-zero exit code."""
        self.stub_subprocess.AddCommand(ret_code=1)
        self.assertEqual(1, self.stub_subprocess.call(['echo', 'foo']))

    def test_output(self):
        """Tests returning stdout, stderr, and and exit code."""
        self.stub_subprocess.AddCommand(ret_out='foo', ret_err='bar',
                                        ret_code=5)
        popen = self.stub_subprocess.Popen(['echo', 'foo'])
        # Not piped, shouldn't return the string values.
        self.assertEqual((None, None), popen.communicate())
        self.assertEqual(5, popen.returncode)

        self.stub_subprocess.AddCommand(ret_out='baz', ret_err='bip',
                                        ret_code=6)
        popen = self.stub_subprocess.Popen(
            ['a command'], stdout=self.stub_subprocess.PIPE,
            stderr=self.stub_subprocess.PIPE)
        # Piped, should return the string values.
        self.assertEqual(('baz', 'bip'), popen.communicate())
        self.assertEqual(6, popen.returncode)


    def test_specified_command(self):
        """Tests specifying the command args at creation."""
        self.stub_subprocess.AddCommand(['echo', 'foo'])
        self.stub_subprocess.call(['echo', 'foo'])

    def test_underspecified_command(self):
        """Tests underspecifying the command args at creation."""
        full_command = ['repo', 'sync', '-c', '-j20', '--prune', '-q']

        # Any command subset should pass even in the wrong order. This lets a
        # test check only that the args it cares about are present.
        for partial in (['repo', 'sync'], ['repo', '-j20'], ['-q', 'sync'], []):
            command = self.stub_subprocess.AddCommand(partial)
            self.stub_subprocess.Popen(full_command).communicate()

            command.AssertCallWas(full_command)
            command.AssertCallContained(partial)

    def test_kwargs(self):
        """Tests additional kwargs passed to a subprocess."""
        command = self.stub_subprocess.AddCommand()
        self.stub_subprocess.call(['echo', 'foo'],
                                  stdout=self.stub_subprocess.PIPE,
                                  cwd='/path/to/foo', env={'bar': 'baz'})

        command.AssertCallWas(['echo', 'foo'], stdout=self.stub_subprocess.PIPE,
                              cwd='/path/to/foo', env={'bar': 'baz'})
        command.AssertCallContained(['echo', 'foo'], cwd='/path/to/foo')
        command.AssertCallContained(env={'bar': 'baz'})

        # Try a few assert failures to make sure we check kwargs properly.
        with self.assertRaises(stubs.CommandError):
            command.AssertCallWas(['echo', 'foo'])
        with self.assertRaises(stubs.CommandError):
            command.AssertCallContained(stderr=self.stub_subprocess.PIPE)
        with self.assertRaises(stubs.CommandError):
            command.AssertCallContained(env={'not_bar': 'baz'})

    def test_unexpected_subprocess_failure(self):
        """Tests failure when an unexpected subprocess is run."""
        with self.assertRaises(stubs.CommandError):
            self.stub_subprocess.call(['echo', 'foo'])

    def test_wrong_command_failure(self):
        """Tests failure when command args don't match."""
        self.stub_subprocess.AddCommand(['echo', 'foo'])

        with self.assertRaises(stubs.CommandError):
            self.stub_subprocess.call(['echo', 'bar'])

    def test_not_run_failure(self):
        """Tests failure when a command was created but not run."""
        command = self.stub_subprocess.AddCommand()
        self.stub_subprocess.Popen(['echo', 'foo'])
        with self.assertRaises(stubs.CommandError):
            command.AssertCallWas(['echo', 'foo'])


class StubSubprocessFileTest(unittest.TestCase):

    def setUp(self):
        self.stub_os = stubs.StubOs()
        self.stub_open = stubs.StubOpen(self.stub_os)
        self.stub_subprocess = stubs.StubSubprocess(self.stub_os,
                                                    self.stub_open)

    def test_input_name(self):
        """Tests requiring an input file by argument name."""
        self.stub_subprocess.AddFileCommand(['my_command'], in_args=['--in'])
        with self.assertRaises(stubs.CommandError):
            self.stub_subprocess.call(['my_command', '--in', 'foo.txt'])

        self.stub_subprocess.AddFileCommand(['my_command'], in_args=['--in'])
        self.stub_open.open('foo.txt', 'w')
        self.stub_subprocess.call(['my_command', '--in', 'foo.txt'])

    def test_output_name(self):
        """Tests creating an output file by argument name."""
        self.stub_subprocess.AddFileCommand(['my_command'], out_args=['--out'])
        self.assertFalse(self.stub_os.path.exists('foo.txt'))

        self.stub_subprocess.call(['my_command', '--out', 'foo.txt'])
        self.assertTrue(self.stub_os.path.exists('foo.txt'))

    def test_input_position(self):
        """Tests requiring an input file by argument position."""
        self.stub_subprocess.AddFileCommand(['cat'], pos_in=[1, 2])
        with self.assertRaises(stubs.CommandError):
            self.stub_subprocess.call(['cat', 'foo.txt', 'bar.txt'])

        self.stub_subprocess.AddFileCommand(['cat'], pos_in=[1, 2])
        self.stub_open.open('foo.txt', 'w')
        self.stub_open.open('bar.txt', 'w')
        self.stub_subprocess.call(['cat', 'foo.txt', 'bar.txt'])

    def test_output_position(self):
        """Tests creating an output file by argument position."""
        self.stub_subprocess.AddFileCommand(['touch'], pos_out=[1, 2])
        self.assertFalse(self.stub_os.path.exists('foo.txt'))
        self.assertFalse(self.stub_os.path.exists('bar.txt'))

        self.stub_subprocess.call(['touch', 'foo.txt', 'bar.txt'])
        self.assertTrue(self.stub_os.path.exists('foo.txt'))
        self.assertTrue(self.stub_os.path.exists('bar.txt'))
