From e5104784c66b68d5fc23644d0863612d5e25e891 Mon Sep 17 00:00:00 2001 From: Thomas Scholtes Date: Sat, 12 Apr 2014 16:49:54 +0200 Subject: [PATCH] Add captureStdout helper and mocks to some tests --- test/helper.py | 19 ++++++++ test/test_config_command.py | 91 ++++++++++++++++------------------- test/test_ui.py | 94 ++++++++++++++++++------------------- 3 files changed, 105 insertions(+), 99 deletions(-) diff --git a/test/helper.py b/test/helper.py index 4850841c0..e3e16199f 100644 --- a/test/helper.py +++ b/test/helper.py @@ -48,6 +48,25 @@ def controlStdin(input=None): sys.stdin = org +@contextmanager +def captureStdout(): + """Save stdout in a StringIO. + + >>> with captureStdout() as output: + ... print('spam') + ... + >>> output.getvalue() + 'spam' + """ + org = sys.stdout + sys.stdout = StringIO() + sys.stdout.encoding = 'utf8' + try: + yield sys.stdout + finally: + sys.stdout = org + + class TestHelper(object): """Helper mixin for high-level cli and plugin tests. diff --git a/test/test_config_command.py b/test/test_config_command.py index 72e7bc05f..acb0e90ce 100644 --- a/test/test_config_command.py +++ b/test/test_config_command.py @@ -1,21 +1,21 @@ import os import yaml +from mock import patch +from tempfile import mkdtemp +from shutil import rmtree from beets import ui from beets import config -from beets.library import Library import _common from _common import unittest -from helper import TestHelper +from helper import TestHelper, captureStdout -class ConfigCommandTest(_common.TestCase, TestHelper): +class ConfigCommandTest(unittest.TestCase, TestHelper): def setUp(self): - super(ConfigCommandTest, self).setUp() - self.io.install() - + self.temp_dir = mkdtemp() if 'EDITOR' in os.environ: del os.environ['EDITOR'] @@ -33,89 +33,78 @@ class ConfigCommandTest(_common.TestCase, TestHelper): config._materialized = False def tearDown(self): - super(ConfigCommandTest, self).tearDown() - self.execlp_restore() + rmtree(self.temp_dir) def test_show_user_config(self): - self.run_command('config') - output = yaml.load(self.io.getoutput()) + with captureStdout() as output: + self.run_command('config') + output = yaml.load(output.getvalue()) self.assertEqual(output['option'], 'value') def test_show_user_config_with_defaults(self): - self.run_command('config', '-d') - output = yaml.load(self.io.getoutput()) + with captureStdout() as output: + self.run_command('config', '-d') + output = yaml.load(output.getvalue()) self.assertEqual(output['option'], 'value') self.assertEqual(output['library'], 'lib') self.assertEqual(output['import']['timid'], False) def test_show_user_config_with_cli(self): - self.run_command('--config', self.cli_config_path, 'config') - output = yaml.load(self.io.getoutput()) + with captureStdout() as output: + self.run_command('--config', self.cli_config_path, 'config') + output = yaml.load(output.getvalue()) self.assertEqual(output['library'], 'lib') self.assertEqual(output['option'], 'cli overwrite') def test_config_paths(self): - self.run_command('config', '-p') - paths = self.io.getoutput().split('\n') + with captureStdout() as output: + self.run_command('config', '-p') + paths = output.getvalue().split('\n') self.assertEqual(len(paths), 2) self.assertEqual(paths[0], self.config_path) def test_config_paths_with_cli(self): - self.run_command('--config', self.cli_config_path, 'config', '-p') - paths = self.io.getoutput().split('\n') + with captureStdout() as output: + self.run_command('--config', self.cli_config_path, 'config', '-p') + paths = output.getvalue().split('\n') self.assertEqual(len(paths), 3) self.assertEqual(paths[0], self.cli_config_path) def test_edit_config_with_editor_env(self): - self.execlp_stub() os.environ['EDITOR'] = 'myeditor' - - self.run_command('config', '-e') - self.assertEqual(self._execlp_call, ['myeditor', self.config_path]) + with patch('os.execlp') as execlp: + self.run_command('config', '-e') + execlp.assert_called_once_with( + 'myeditor', 'myeditor', self.config_path) def test_edit_config_with_open(self): - self.execlp_stub() - with _common.system_mock('Darwin'): - self.run_command('config', '-e') - self.assertEqual(self._execlp_call, ['open', '-n', self.config_path]) - + with patch('os.execlp') as execlp: + self.run_command('config', '-e') + execlp.assert_called_once_with( + 'open', 'open', '-n', self.config_path) def test_edit_config_with_xdg_open(self): - self.execlp_stub() - with _common.system_mock('Linux'): - self.run_command('config', '-e') - self.assertEqual(self._execlp_call, ['xdg-open', self.config_path]) + with patch('os.execlp') as execlp: + self.run_command('config', '-e') + execlp.assert_called_once_with( + 'xdg-open', 'xdg-open', self.config_path) def test_edit_config_with_windows_exec(self): - self.execlp_stub() - with _common.system_mock('Windows'): - self.run_command('config', '-e') - self.assertEqual(self._execlp_call, [self.config_path]) + with patch('os.execlp') as execlp: + self.run_command('config', '-e') + execlp.assert_called_once_with(self.config_path, self.config_path) def test_config_editor_not_found(self): - def raise_os_error(*args): - raise OSError - os.execlp = raise_os_error with self.assertRaises(ui.UserError) as user_error: - self.run_command('config', '-e') + with patch('os.execlp') as execlp: + execlp.side_effect = OSError() + self.run_command('config', '-e') self.assertIn('Could not edit configuration', str(user_error.exception.args[0])) - def execlp_stub(self): - self._execlp_call = None - def _execlp_stub(file, *args): - self._execlp_call = [file] + list(args[1:]) - - self._orig_execlp = os.execlp - os.execlp = _execlp_stub - - def execlp_restore(self): - if hasattr(self, '_orig_execlp'): - os.execlp = self._orig_execlp - def suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/test/test_ui.py b/test/test_ui.py index ce72debd0..3b8a8aabb 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -21,6 +21,8 @@ import subprocess import _common from _common import unittest +from helper import captureStdout + from beets import library from beets import ui from beets.ui import commands @@ -33,85 +35,81 @@ from beets import plugins from beets.util.confit import ConfigError -class ListTest(_common.TestCase): +class ListTest(unittest.TestCase): def setUp(self): - super(ListTest, self).setUp() - self.io.install() - self.lib = library.Library(':memory:') - i = _common.item() - i.path = 'xxx/yyy' - self.lib.add(i) - self.lib.add_album([i]) - self.item = i + self.item = _common.item() + self.item.path = 'xxx/yyy' + self.lib.add(self.item) + self.lib.add_album([self.item]) def _run_list(self, query='', album=False, path=False, fmt=None): commands.list_items(self.lib, query, album, fmt) def test_list_outputs_item(self): - self._run_list() - out = self.io.getoutput() - self.assertTrue(u'the title' in out) + with captureStdout() as stdout: + self._run_list() + self.assertIn(u'the title', stdout.getvalue()) def test_list_unicode_query(self): self.item.title = u'na\xefve' self.item.store() self.lib._connection().commit() - self._run_list([u'na\xefve']) - out = self.io.getoutput() - self.assertTrue(u'na\xefve' in out.decode(self.io.stdout.encoding)) + with captureStdout() as stdout: + self._run_list([u'na\xefve']) + out = stdout.getvalue() + self.assertTrue(u'na\xefve' in out.decode(stdout.encoding)) def test_list_item_path(self): - self._run_list(fmt='$path') - out = self.io.getoutput() - self.assertEqual(out.strip(), u'xxx/yyy') + with captureStdout() as stdout: + self._run_list(fmt='$path') + self.assertEqual(stdout.getvalue().strip(), u'xxx/yyy') def test_list_album_outputs_something(self): - self._run_list(album=True) - out = self.io.getoutput() - self.assertGreater(len(out), 0) + with captureStdout() as stdout: + self._run_list(album=True) + self.assertGreater(len(stdout.getvalue()), 0) def test_list_album_path(self): - self._run_list(album=True, fmt='$path') - out = self.io.getoutput() - self.assertEqual(out.strip(), u'xxx') + with captureStdout() as stdout: + self._run_list(album=True, fmt='$path') + self.assertEqual(stdout.getvalue().strip(), u'xxx') def test_list_album_omits_title(self): - self._run_list(album=True) - out = self.io.getoutput() - self.assertTrue(u'the title' not in out) + with captureStdout() as stdout: + self._run_list(album=True) + self.assertNotIn(u'the title', stdout.getvalue()) def test_list_uses_track_artist(self): - self._run_list() - out = self.io.getoutput() - self.assertTrue(u'the artist' in out) - self.assertTrue(u'the album artist' not in out) + with captureStdout() as stdout: + self._run_list() + self.assertIn(u'the artist', stdout.getvalue()) + self.assertNotIn(u'the album artist', stdout.getvalue()) def test_list_album_uses_album_artist(self): - self._run_list(album=True) - out = self.io.getoutput() - self.assertTrue(u'the artist' not in out) - self.assertTrue(u'the album artist' in out) + with captureStdout() as stdout: + self._run_list(album=True) + self.assertNotIn(u'the artist', stdout.getvalue()) + self.assertIn(u'the album artist', stdout.getvalue()) def test_list_item_format_artist(self): - self._run_list(fmt='$artist') - out = self.io.getoutput() - self.assertTrue(u'the artist' in out) + with captureStdout() as stdout: + self._run_list(fmt='$artist') + self.assertIn(u'the artist', stdout.getvalue()) def test_list_item_format_multiple(self): - self._run_list(fmt='$artist - $album - $year') - out = self.io.getoutput() - self.assertTrue(u'1' in out) - self.assertTrue(u'the album' in out) - self.assertTrue(u'the artist' in out) - self.assertEqual(u'the artist - the album - 0001', out.strip()) + with captureStdout() as stdout: + self._run_list(fmt='$artist - $album - $year') + self.assertEqual(u'the artist - the album - 0001', + stdout.getvalue().strip()) def test_list_album_format(self): - self._run_list(album=True, fmt='$genre') - out = self.io.getoutput() - self.assertTrue(u'the genre' in out) - self.assertTrue(u'the album' not in out) + with captureStdout() as stdout: + self._run_list(album=True, fmt='$genre') + self.assertIn(u'the genre', stdout.getvalue()) + self.assertNotIn(u'the album', stdout.getvalue()) + class RemoveTest(_common.TestCase): def setUp(self):