| #!/usr/bin/env python3.8 |
| # Copyright 2020 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import errno |
| import os |
| import shutil |
| import subprocess |
| import sys |
| import tempfile |
| import unittest |
| from io import StringIO |
| |
| import test_env |
| from lib.host import Host |
| from host_fake import FakeHost |
| from test_case import TestCaseWithIO |
| """ Test the real and fake implementations of the Host. |
| |
| The structure of these tests is organized into 5 classes: |
| |
| NonHermeticTestCase HostTestCase HermeticTestCase |
| ^ ^ ^ ^ |
| | | | | |
| +-HostTest-+ +-FakeHostTest-+ |
| |
| NonHermeticTestCase is a TestCase that provides real-system utility functions. |
| HermeticTestCase is a TestCase that provides faked utility functions. |
| HostTestCase defines a set of tests without a TestCase. |
| HostTest creates tests for Host. |
| FakeHostTest creates tests for FakeHost. |
| """ |
| |
| |
| class NonHermeticTestCase(TestCaseWithIO): |
| """TestCase that provides real-system utility functions.""" |
| |
| # Unit test "constructor" and "destructor" |
| |
| def setUp(self): |
| super(NonHermeticTestCase, self).setUp() |
| self._host = Host() |
| self._host.fd_out = self._stdout |
| self._host.fd_err = self._stderr |
| self._temp_dir = tempfile.mkdtemp() |
| |
| def tearDown(self): |
| shutil.rmtree(self._temp_dir) |
| self._temp_dir = None |
| super(NonHermeticTestCase, self).tearDown() |
| |
| # Unit test context |
| |
| @property |
| def host(self): |
| return self._host |
| |
| @property |
| def temp_dir(self): |
| return self._temp_dir |
| |
| # Unit test utilities |
| |
| def isfile(self, pathname): |
| return os.path.isfile(pathname) |
| |
| def isdir(self, pathname): |
| return os.path.isdir(pathname) |
| |
| def mkdir(self, pathname): |
| os.makedirs(pathname) |
| |
| def readfile(self, pathname): |
| with open(pathname) as opened: |
| return opened.read().strip() |
| |
| def writefile(self, pathname, contents=None): |
| with open(pathname, 'w') as opened: |
| if contents: |
| opened.write(contents) |
| |
| |
| class HermeticTestCase(TestCaseWithIO): |
| """TestCase that provides faked utility functions.""" |
| |
| # Unit test "constructor" |
| |
| def setUp(self): |
| super(HermeticTestCase, self).setUp() |
| self._host = FakeHost() |
| self._host.fd_out = self._stdout |
| self._host.fd_err = self._stderr |
| |
| process = self.host.create_process(['false']) |
| process.succeeds = False |
| |
| process = self.host.create_process(['echo foo']) |
| process.schedule(start=0, output='foo') |
| |
| # Unit test context |
| |
| @property |
| def host(self): |
| return self._host |
| |
| @property |
| def temp_dir(self): |
| return 'temp_dir' |
| |
| # Unit test utilities |
| |
| def isfile(self, pathname): |
| return self.host.isfile(pathname) |
| |
| def isdir(self, pathname): |
| return self.host.isdir(pathname) |
| |
| def mkdir(self, pathname): |
| self.host.mkdir(pathname) |
| |
| def readfile(self, pathname): |
| return self.host.readfile(pathname) |
| |
| def writefile(self, pathname, contents=None): |
| with self.host.open(pathname, 'w') as opened: |
| if contents: |
| opened.write(contents) |
| |
| |
| class HostTestCase(object): |
| """Defines a set of tests without a TestCase.""" |
| |
| def test_trace(self): |
| sys.stdout = self._stdout |
| original = self.host.tracing |
| try: |
| # Tracing can be enabled |
| self.host.tracing = True |
| self.host.trace('Check one...') |
| self.assertOut(['+ Check one...']) |
| |
| # It can be disabled again |
| self.host.tracing = False |
| self.host.trace('Check two...') |
| self.assertOut([]) |
| finally: |
| sys.stdout = sys.__stdout__ |
| self.host.tracing = original |
| |
| def test_echo(self): |
| self.host.echo('Hello world') |
| self.assertOut(['Hello world']) |
| |
| def test_error(self): |
| with self.assertRaises(SystemExit): |
| self.host.error('Hello world') |
| self.assertErr(['ERROR: Hello world']) |
| |
| def test_choose(self): |
| prompt = 'Pick your favorite animal' |
| choices = ['cat', 'dog', 'bear'] |
| |
| self.set_input('3') |
| choice = self.host.choose(prompt, choices) |
| self.assertEqual(choice, 'bear') |
| |
| self.set_input('0') |
| with self.assertRaises(SystemExit): |
| self.host.choose(prompt, choices) |
| |
| def test_isdir(self): |
| pathname = os.path.join(self.temp_dir, 'test_isdir') |
| self.assertFalse(self.host.isdir(pathname)) |
| self.mkdir(pathname) |
| self.assertTrue(self.host.isdir(pathname)) |
| |
| def test_isfile(self): |
| pathname = os.path.join(self.temp_dir, 'test_isfile') |
| self.assertFalse(self.host.isfile(pathname)) |
| self.writefile(pathname) |
| self.assertTrue(self.host.isfile(pathname)) |
| |
| def test_glob(self): |
| foo = os.path.join(self.temp_dir, 'foo') |
| bar = os.path.join(self.temp_dir, 'bar') |
| self.writefile(foo) |
| self.writefile(bar) |
| files = self.host.glob(os.path.join(self.temp_dir, '*')) |
| self.assertIn(foo, files) |
| self.assertIn(bar, files) |
| |
| def test_open(self): |
| pathname = os.path.join(self.temp_dir, 'test_open') |
| with self.assertRaises(SystemExit): |
| opened = self.host.open(pathname) |
| self.assertErr(['ERROR: Failed to open {}.'.format(pathname)]) |
| |
| opened = self.host.open(pathname, missing_ok=True) |
| self.assertFalse(opened) |
| |
| with self.host.open(pathname, mode='w') as opened: |
| pass |
| |
| with self.host.open(pathname) as opened: |
| pass |
| |
| def test_readfile(self): |
| pathname = os.path.join(self.temp_dir, 'test_readfile') |
| with self.assertRaises(SystemExit): |
| self.host.readfile(pathname) |
| self.assertErr(['ERROR: Failed to open {}.'.format(pathname)]) |
| |
| self.assertFalse(self.host.readfile(pathname, missing_ok=True)) |
| self.writefile(pathname, 'data') |
| self.assertEqual(self.host.readfile(pathname), 'data') |
| |
| def test_touch(self): |
| pathname = os.path.join(self.temp_dir, 'test_touch') |
| self.assertFalse(self.isfile(pathname)) |
| self.host.touch(pathname) |
| self.assertTrue(self.isfile(pathname)) |
| |
| def test_mkdir(self): |
| pathname = os.path.join(self.temp_dir, 'test', 'mkdir') |
| self.assertFalse(self.isdir(pathname)) |
| self.host.mkdir(pathname) |
| self.assertTrue(self.isdir(pathname)) |
| |
| def test_link(self): |
| link = os.path.join(self.temp_dir, 'test_link') |
| |
| foo = os.path.join(self.temp_dir, 'foo') |
| self.writefile(foo, 'foo') |
| |
| bar = os.path.join(self.temp_dir, 'bar') |
| self.writefile(bar, 'bar') |
| |
| self.host.link(foo, link) |
| self.writefile(link, 'baz') |
| self.assertEqual(self.readfile(foo), 'baz') |
| self.assertEqual(self.readfile(bar), 'bar') |
| |
| self.host.link(bar, link) |
| self.writefile(link, 'qux') |
| self.assertEqual(self.readfile(foo), 'baz') |
| self.assertEqual(self.readfile(bar), 'qux') |
| |
| def test_remove(self): |
| pathname = os.path.join(self.temp_dir, 'test_remove') |
| self.mkdir(pathname) |
| self.assertTrue(self.isdir(pathname)) |
| self.host.remove(pathname) |
| self.assertFalse(self.isdir(pathname)) |
| |
| self.writefile(pathname) |
| self.assertTrue(self.isfile(pathname)) |
| self.host.remove(pathname) |
| self.assertFalse(self.isfile(pathname)) |
| |
| def test_temp_dir(self): |
| with self.host.temp_dir() as temp_dir: |
| self.assertTrue(self.isdir(temp_dir.pathname)) |
| |
| def test_create_process(self): |
| self.host.create_process(['true']).call() |
| with self.assertRaises(subprocess.CalledProcessError): |
| self.host.create_process(['false']).check_call() |
| output = self.host.create_process(['echo', 'foo']).check_output() |
| self.assertEqual(output, 'foo\n') |
| |
| |
| class HostTest(NonHermeticTestCase, HostTestCase): |
| """Creates tests for Host.""" |
| pass |
| |
| |
| class FakeHostTest(HermeticTestCase, HostTestCase): |
| """Creates tests for FakeHost.""" |
| pass |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |