From c548b7b44cb6108d3f20453d9b3db8f8f7e48b19 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 23 Apr 2017 10:16:30 -0400 Subject: [PATCH] covert test suite to use testrepository Drop the use of nose in favor of testrepository. Set up the gitignore rules for the output files. Add coverage reporting to test jobs. Update tox.ini so the default environments make sense so it is possible to just run "tox" for local development. Change-Id: Ieeffdde3bb8a1869af01f5be2bc682a1a834ba13 Signed-off-by: Doug Hellmann --- .gitignore | 3 + .testr.conf | 7 + cliff/tests/base.py | 29 + cliff/tests/test_app.py | 828 ++++++++++---------- cliff/tests/test_columns.py | 19 +- cliff/tests/test_command.py | 81 +- cliff/tests/test_commandmanager.py | 212 +++--- cliff/tests/test_complete.py | 248 +++--- cliff/tests/test_formatters_csv.py | 119 +-- cliff/tests/test_formatters_json.py | 194 ++--- cliff/tests/test_formatters_shell.py | 136 ++-- cliff/tests/test_formatters_table.py | 1036 ++++++++++++++------------ cliff/tests/test_formatters_value.py | 82 +- cliff/tests/test_formatters_yaml.py | 142 ++-- cliff/tests/test_help.py | 286 ++++--- cliff/tests/test_interactive.py | 94 ++- cliff/tests/test_lister.py | 53 +- cliff/tests/test_show.py | 68 +- cliff/tests/test_sphinxext.py | 157 ++-- cliff/tests/test_utils.py | 94 ++- test-requirements.txt | 8 +- tox.ini | 6 +- 22 files changed, 2016 insertions(+), 1886 deletions(-) create mode 100644 .testr.conf create mode 100644 cliff/tests/base.py diff --git a/.gitignore b/.gitignore index ba52b1e9..28420f97 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ ChangeLog # Editors *~ .*.swp +/.testrepository/ +/cover/ +.coverage.* \ No newline at end of file diff --git a/.testr.conf b/.testr.conf new file mode 100644 index 00000000..faf55cfd --- /dev/null +++ b/.testr.conf @@ -0,0 +1,7 @@ +[DEFAULT] +test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ + OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ + OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ + ${PYTHON:-python} -m subunit.run discover -t ./ ./cliff $LISTOPT $IDOPTION +test_id_option=--load-list $IDFILE +test_list_option=--list diff --git a/cliff/tests/base.py b/cliff/tests/base.py new file mode 100644 index 00000000..7afce023 --- /dev/null +++ b/cliff/tests/base.py @@ -0,0 +1,29 @@ +# -*- encoding: utf-8 -*- +# +# 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. + +import testtools + +import fixtures + + +class TestBase(testtools.TestCase): + + def setUp(self): + super(TestBase, self).setUp() + self._stdout_fixture = fixtures.StringStream('stdout') + self.stdout = self.useFixture(self._stdout_fixture).stream + self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.stdout)) + self._stderr_fixture = fixtures.StringStream('stderr') + self.stderr = self.useFixture(self._stderr_fixture).stream + self.useFixture(fixtures.MonkeyPatch('sys.stderr', self.stderr)) diff --git a/cliff/tests/test_app.py b/cliff/tests/test_app.py index 26149a23..4430d772 100644 --- a/cliff/tests/test_app.py +++ b/cliff/tests/test_app.py @@ -13,20 +13,21 @@ # under the License. import argparse +import codecs +import locale try: from StringIO import StringIO except ImportError: from io import StringIO +import sys -import codecs -import locale import mock import six -import sys from cliff import app as application from cliff import command as c_cmd from cliff import commandmanager +from cliff.tests import base from cliff.tests import utils as test_utils from cliff import utils @@ -59,440 +60,441 @@ def make_app(**kwargs): return app, command -def test_no_args_triggers_interactive_mode(): - app, command = make_app() - app.interact = mock.MagicMock(name='inspect') - app.run([]) - app.interact.assert_called_once_with() +class TestInteractiveMode(base.TestBase): + + def test_no_args_triggers_interactive_mode(self): + app, command = make_app() + app.interact = mock.MagicMock(name='inspect') + app.run([]) + app.interact.assert_called_once_with() + + def test_interactive_mode_cmdloop(self): + app, command = make_app() + app.interactive_app_factory = mock.MagicMock( + name='interactive_app_factory' + ) + self.assertIs(None, app.interpreter) + app.run([]) + self.assertIsNot(None, app.interpreter) + cmdloop = app.interactive_app_factory.return_value.cmdloop + cmdloop.assert_called_once_with() -def test_interactive_mode_cmdloop(): - app, command = make_app() - app.interactive_app_factory = mock.MagicMock( - name='interactive_app_factory' - ) - assert app.interpreter is None - app.run([]) - assert app.interpreter is not None - app.interactive_app_factory.return_value.cmdloop.assert_called_once_with() +class TestInitAndCleanup(base.TestBase): + + def test_initialize_app(self): + app, command = make_app() + app.initialize_app = mock.MagicMock(name='initialize_app') + app.run(['mock']) + app.initialize_app.assert_called_once_with(['mock']) + + def test_prepare_to_run_command(self): + app, command = make_app() + app.prepare_to_run_command = mock.MagicMock( + name='prepare_to_run_command', + ) + app.run(['mock']) + app.prepare_to_run_command.assert_called_once_with(command()) + + def test_clean_up_success(self): + app, command = make_app() + app.clean_up = mock.MagicMock(name='clean_up') + app.run(['mock']) + app.clean_up.assert_called_once_with(command.return_value, 0, None) + + def test_clean_up_error(self): + app, command = make_app() + + app.clean_up = mock.MagicMock(name='clean_up') + app.run(['error']) + + app.clean_up.assert_called_once_with(mock.ANY, mock.ANY, mock.ANY) + call_args = app.clean_up.call_args_list[0] + self.assertEqual(mock.call(mock.ANY, 1, mock.ANY), call_args) + args, kwargs = call_args + self.assertIsInstance(args[2], RuntimeError) + self.assertEqual(('test exception',), args[2].args) + + def test_clean_up_error_debug(self): + app, command = make_app() + + app.clean_up = mock.MagicMock(name='clean_up') + try: + app.run(['--debug', 'error']) + except RuntimeError as err: + self.assertIs(err, app.clean_up.call_args_list[0][0][2]) + else: + self.fail('Should have had an exception') + + self.assertTrue(app.clean_up.called) + call_args = app.clean_up.call_args_list[0] + self.assertEqual(mock.call(mock.ANY, 1, mock.ANY), call_args) + args, kwargs = call_args + self.assertIsInstance(args[2], RuntimeError) + self.assertEqual(('test exception',), args[2].args) + + def test_error_handling_clean_up_raises_exception(self): + app, command = make_app() + + app.clean_up = mock.MagicMock( + name='clean_up', + side_effect=RuntimeError('within clean_up'), + ) + app.run(['error']) + + self.assertTrue(app.clean_up.called) + call_args = app.clean_up.call_args_list[0] + self.assertEqual(mock.call(mock.ANY, 1, mock.ANY), call_args) + args, kwargs = call_args + self.assertIsInstance(args[2], RuntimeError) + self.assertEqual(('test exception',), args[2].args) + + def test_error_handling_clean_up_raises_exception_debug(self): + app, command = make_app() + + app.clean_up = mock.MagicMock( + name='clean_up', + side_effect=RuntimeError('within clean_up'), + ) + try: + app.run(['--debug', 'error']) + except RuntimeError as err: + if not hasattr(err, '__context__'): + # The exception passed to clean_up is not the exception + # caused *by* clean_up. This test is only valid in python + # 2 because under v3 the original exception is re-raised + # with the new one as a __context__ attribute. + self.assertIsNot(err, app.clean_up.call_args_list[0][0][2]) + else: + self.fail('Should have had an exception') + + self.assertTrue(app.clean_up.called) + call_args = app.clean_up.call_args_list[0] + self.assertEqual(mock.call(mock.ANY, 1, mock.ANY), call_args) + args, kwargs = call_args + self.assertIsInstance(args[2], RuntimeError) + self.assertEqual(('test exception',), args[2].args) + + def test_normal_clean_up_raises_exception(self): + app, command = make_app() + + app.clean_up = mock.MagicMock( + name='clean_up', + side_effect=RuntimeError('within clean_up'), + ) + app.run(['mock']) + + self.assertTrue(app.clean_up.called) + call_args = app.clean_up.call_args_list[0] + self.assertEqual(mock.call(mock.ANY, 0, None), call_args) + + def test_normal_clean_up_raises_exception_debug(self): + app, command = make_app() + + app.clean_up = mock.MagicMock( + name='clean_up', + side_effect=RuntimeError('within clean_up'), + ) + app.run(['--debug', 'mock']) + + self.assertTrue(app.clean_up.called) + call_args = app.clean_up.call_args_list[0] + self.assertEqual(mock.call(mock.ANY, 0, None), call_args) -def test_initialize_app(): - app, command = make_app() - app.initialize_app = mock.MagicMock(name='initialize_app') - app.run(['mock']) - app.initialize_app.assert_called_once_with(['mock']) +class TestOptionParser(base.TestBase): + def test_conflicting_option_should_throw(self): + class MyApp(application.App): + def __init__(self): + super(MyApp, self).__init__( + description='testing', + version='0.1', + command_manager=commandmanager.CommandManager('tests'), + ) -def test_prepare_to_run_command(): - app, command = make_app() - app.prepare_to_run_command = mock.MagicMock(name='prepare_to_run_command') - app.run(['mock']) - app.prepare_to_run_command.assert_called_once_with(command()) + def build_option_parser(self, description, version): + parser = super(MyApp, self).build_option_parser(description, + version) + parser.add_argument( + '-h', '--help', + default=self, # tricky + help="Show help message and exit.", + ) + self.assertRaises( + argparse.ArgumentError, + MyApp, + ) -def test_clean_up_success(): - app, command = make_app() - app.clean_up = mock.MagicMock(name='clean_up') - app.run(['mock']) - app.clean_up.assert_called_once_with(command.return_value, 0, None) + def test_conflicting_option_custom_arguments_should_not_throw(self): + class MyApp(application.App): + def __init__(self): + super(MyApp, self).__init__( + description='testing', + version='0.1', + command_manager=commandmanager.CommandManager('tests'), + ) + def build_option_parser(self, description, version): + argparse_kwargs = {'conflict_handler': 'resolve'} + parser = super(MyApp, self).build_option_parser( + description, + version, + argparse_kwargs=argparse_kwargs) + parser.add_argument( + '-h', '--help', + default=self, # tricky + help="Show help message and exit.", + ) -def test_clean_up_error(): - app, command = make_app() - - app.clean_up = mock.MagicMock(name='clean_up') - app.run(['error']) - - app.clean_up.assert_called_once_with(mock.ANY, mock.ANY, mock.ANY) - call_args = app.clean_up.call_args_list[0] - assert call_args == mock.call(mock.ANY, 1, mock.ANY) - args, kwargs = call_args - assert isinstance(args[2], RuntimeError) - assert args[2].args == ('test exception',) - - -def test_clean_up_error_debug(): - app, command = make_app() - - app.clean_up = mock.MagicMock(name='clean_up') - try: - app.run(['--debug', 'error']) - except RuntimeError as err: - assert app.clean_up.call_args_list[0][0][2] is err - else: - assert False, 'Should have had an exception' - - assert app.clean_up.called - call_args = app.clean_up.call_args_list[0] - assert call_args == mock.call(mock.ANY, 1, mock.ANY) - args, kwargs = call_args - assert isinstance(args[2], RuntimeError) - assert args[2].args == ('test exception',) - - -def test_error_handling_clean_up_raises_exception(): - app, command = make_app() - - app.clean_up = mock.MagicMock( - name='clean_up', - side_effect=RuntimeError('within clean_up'), - ) - app.run(['error']) - - assert app.clean_up.called - call_args = app.clean_up.call_args_list[0] - assert call_args == mock.call(mock.ANY, 1, mock.ANY) - args, kwargs = call_args - assert isinstance(args[2], RuntimeError) - assert args[2].args == ('test exception',) - - -def test_error_handling_clean_up_raises_exception_debug(): - app, command = make_app() - - app.clean_up = mock.MagicMock( - name='clean_up', - side_effect=RuntimeError('within clean_up'), - ) - try: - app.run(['--debug', 'error']) - except RuntimeError as err: - if not hasattr(err, '__context__'): - # The exception passed to clean_up is not the exception - # caused *by* clean_up. This test is only valid in python - # 2 because under v3 the original exception is re-raised - # with the new one as a __context__ attribute. - assert app.clean_up.call_args_list[0][0][2] is not err - else: - assert False, 'Should have had an exception' - - assert app.clean_up.called - call_args = app.clean_up.call_args_list[0] - assert call_args == mock.call(mock.ANY, 1, mock.ANY) - args, kwargs = call_args - assert isinstance(args[2], RuntimeError) - assert args[2].args == ('test exception',) - - -def test_normal_clean_up_raises_exception(): - app, command = make_app() - - app.clean_up = mock.MagicMock( - name='clean_up', - side_effect=RuntimeError('within clean_up'), - ) - app.run(['mock']) - - assert app.clean_up.called - call_args = app.clean_up.call_args_list[0] - assert call_args == mock.call(mock.ANY, 0, None) - - -def test_normal_clean_up_raises_exception_debug(): - app, command = make_app() - - app.clean_up = mock.MagicMock( - name='clean_up', - side_effect=RuntimeError('within clean_up'), - ) - app.run(['--debug', 'mock']) - - assert app.clean_up.called - call_args = app.clean_up.call_args_list[0] - assert call_args == mock.call(mock.ANY, 0, None) - - -def test_build_option_parser_conflicting_option_should_throw(): - class MyApp(application.App): - def __init__(self): - super(MyApp, self).__init__( - description='testing', - version='0.1', - command_manager=commandmanager.CommandManager('tests'), - ) - - def build_option_parser(self, description, version): - parser = super(MyApp, self).build_option_parser(description, - version) - parser.add_argument( - '-h', '--help', - default=self, # tricky - help="Show help message and exit.", - ) - - # TODO: tests should really use unittest2. - try: MyApp() - except argparse.ArgumentError: - pass - else: - raise Exception('Exception was not thrown') + + def test_option_parser_abbrev_issue(self): + class MyCommand(c_cmd.Command): + def get_parser(self, prog_name): + parser = super(MyCommand, self).get_parser(prog_name) + parser.add_argument("--end") + return parser + + def take_action(self, parsed_args): + assert(parsed_args.end == '123') + + class MyCommandManager(commandmanager.CommandManager): + def load_commands(self, namespace): + self.add_command("mycommand", MyCommand) + + class MyApp(application.App): + def __init__(self): + super(MyApp, self).__init__( + description='testing', + version='0.1', + command_manager=MyCommandManager(None), + ) + + def build_option_parser(self, description, version): + parser = super(MyApp, self).build_option_parser( + description, + version, + argparse_kwargs={'allow_abbrev': False}) + parser.add_argument('--endpoint') + return parser + + app = MyApp() + # NOTE(jd) --debug is necessary so assert in take_action() + # raises correctly here + app.run(['--debug', 'mycommand', '--end', '123']) -def test_option_parser_conflicting_option_custom_arguments_should_not_throw(): - class MyApp(application.App): - def __init__(self): - super(MyApp, self).__init__( - description='testing', - version='0.1', - command_manager=commandmanager.CommandManager('tests'), +class TestHelpHandling(base.TestBase): + + def _test_help(self, deferred_help): + app, _ = make_app(deferred_help=deferred_help) + with mock.patch.object(app, 'initialize_app') as init: + with mock.patch('cliff.help.HelpAction.__call__', + side_effect=SystemExit(0)) as helper: + self.assertRaises( + SystemExit, + app.run, + ['--help'], + ) + self.assertTrue(helper.called) + self.assertEqual(deferred_help, init.called) + + def test_help(self): + self._test_help(False) + + def test_deferred_help(self): + self._test_help(True) + + def test_subcommand_help(self): + app, _ = make_app(deferred_help=False) + + # Help is called immediately + with mock.patch('cliff.help.HelpAction.__call__') as helper: + app.run(['show', 'files', '--help']) + + self.assertTrue(helper.called) + + def test_subcommand_deferred_help(self): + app, _ = make_app(deferred_help=True) + + # Show that provide_help_if_requested() did not show help and exit + with mock.patch.object(app, 'run_subcommand') as helper: + app.run(['show', 'files', '--help']) + + helper.assert_called_once_with(['help', 'show', 'files']) + + +class TestCommandLookup(base.TestBase): + + def test_unknown_cmd(self): + app, command = make_app() + self.assertEqual(2, app.run(['hell'])) + + def test_unknown_cmd_debug(self): + app, command = make_app() + try: + self.assertEqual(2, app.run(['--debug', 'hell'])) + except ValueError as err: + self.assertIn("['hell']", str(err)) + + def test_list_matching_commands(self): + stdout = StringIO() + app = application.App('testing', '1', + test_utils.TestCommandManager( + test_utils.TEST_NAMESPACE), + stdout=stdout) + app.NAME = 'test' + try: + self.assertEqual(2, app.run(['t'])) + except SystemExit: + pass + output = stdout.getvalue() + self.assertIn("test: 't' is not a test command. See 'test --help'.", + output) + self.assertIn('Did you mean one of these?', output) + self.assertIn('three word command\n two words\n', output) + + def test_fuzzy_no_commands(self): + cmd_mgr = commandmanager.CommandManager('cliff.fuzzy') + app = application.App('test', '1.0', cmd_mgr) + cmd_mgr.commands = {} + matches = app.get_fuzzy_matches('foo') + self.assertEqual([], matches) + + def test_fuzzy_common_prefix(self): + # searched string is a prefix of all commands + cmd_mgr = commandmanager.CommandManager('cliff.fuzzy') + app = application.App('test', '1.0', cmd_mgr) + cmd_mgr.commands = {} + cmd_mgr.add_command('user list', test_utils.TestCommand) + cmd_mgr.add_command('user show', test_utils.TestCommand) + matches = app.get_fuzzy_matches('user') + self.assertEqual(['user list', 'user show'], matches) + + def test_fuzzy_same_distance(self): + # searched string has the same distance to all commands + cmd_mgr = commandmanager.CommandManager('cliff.fuzzy') + app = application.App('test', '1.0', cmd_mgr) + cmd_mgr.add_command('user', test_utils.TestCommand) + for cmd in cmd_mgr.commands.keys(): + self.assertEqual( + 8, + utils.damerau_levenshtein('node', cmd, utils.COST), ) + matches = app.get_fuzzy_matches('node') + self.assertEqual(['complete', 'help', 'user'], matches) - def build_option_parser(self, description, version): - argparse_kwargs = {'conflict_handler': 'resolve'} - parser = super(MyApp, self).build_option_parser( - description, - version, - argparse_kwargs=argparse_kwargs) - parser.add_argument( - '-h', '--help', - default=self, # tricky - help="Show help message and exit.", - ) - - MyApp() + def test_fuzzy_no_prefix(self): + # search by distance, no common prefix with any command + cmd_mgr = commandmanager.CommandManager('cliff.fuzzy') + app = application.App('test', '1.0', cmd_mgr) + cmd_mgr.add_command('user', test_utils.TestCommand) + matches = app.get_fuzzy_matches('uesr') + self.assertEqual(['user'], matches) -def test_option_parser_abbrev_issue(): - class MyCommand(c_cmd.Command): - def get_parser(self, prog_name): - parser = super(MyCommand, self).get_parser(prog_name) - parser.add_argument("--end") - return parser +class TestVerboseMode(base.TestBase): - def take_action(self, parsed_args): - assert(parsed_args.end == '123') - - class MyCommandManager(commandmanager.CommandManager): - def load_commands(self, namespace): - self.add_command("mycommand", MyCommand) - - class MyApp(application.App): - def __init__(self): - super(MyApp, self).__init__( - description='testing', - version='0.1', - command_manager=MyCommandManager(None), - ) - - def build_option_parser(self, description, version): - parser = super(MyApp, self).build_option_parser( - description, - version, - argparse_kwargs={'allow_abbrev': False}) - parser.add_argument('--endpoint') - return parser - - app = MyApp() - # NOTE(jd) --debug is necessary so assert in take_action() raises correctly - # here - app.run(['--debug', 'mycommand', '--end', '123']) + def test_verbose(self): + app, command = make_app() + app.clean_up = mock.MagicMock(name='clean_up') + app.run(['--verbose', 'mock']) + app.clean_up.assert_called_once_with(command.return_value, 0, None) + app.clean_up.reset_mock() + app.run(['--quiet', 'mock']) + app.clean_up.assert_called_once_with(command.return_value, 0, None) + self.assertRaises( + SystemExit, + app.run, + ['--verbose', '--quiet', 'mock'], + ) -def _test_help(deferred_help): - app, _ = make_app(deferred_help=deferred_help) - with mock.patch.object(app, 'initialize_app') as init: - with mock.patch('cliff.help.HelpAction.__call__', - side_effect=SystemExit(0)) as helper: +class TestIO(base.TestBase): + + def test_io_streams(self): + cmd_mgr = commandmanager.CommandManager('cliff.tests') + io = mock.Mock() + + if six.PY2: + stdin_save = sys.stdin + stdout_save = sys.stdout + stderr_save = sys.stderr + encoding = locale.getpreferredencoding() or 'utf-8' + + app = application.App('no io streams', 1, cmd_mgr) + self.assertIsInstance(app.stdin, codecs.StreamReader) + self.assertIsInstance(app.stdout, codecs.StreamWriter) + self.assertIsInstance(app.stderr, codecs.StreamWriter) + + app = application.App('with stdin io stream', 1, cmd_mgr, stdin=io) + self.assertIs(io, app.stdin) + self.assertIsInstance(app.stdout, codecs.StreamWriter) + self.assertIsInstance(app.stderr, codecs.StreamWriter) + + app = application.App('with stdout io stream', 1, cmd_mgr, + stdout=io) + self.assertIsInstance(app.stdin, codecs.StreamReader) + self.assertIs(io, app.stdout) + self.assertIsInstance(app.stderr, codecs.StreamWriter) + + app = application.App('with stderr io stream', 1, cmd_mgr, + stderr=io) + self.assertIsInstance(app.stdin, codecs.StreamReader) + self.assertIsInstance(app.stdout, codecs.StreamWriter) + self.assertIs(io, app.stderr) + try: - app.run(['--help']) - except SystemExit: - pass - else: - raise Exception('Exception was not thrown') - assert helper.called - assert init.called == deferred_help + sys.stdin = codecs.getreader(encoding)(sys.stdin) + app = application.App( + 'with wrapped sys.stdin io stream', 1, cmd_mgr) + self.assertIs(sys.stdin, app.stdin) + self.assertIsInstance(app.stdout, codecs.StreamWriter) + self.assertIsInstance(app.stderr, codecs.StreamWriter) + finally: + sys.stdin = stdin_save + try: + sys.stdout = codecs.getwriter(encoding)(sys.stdout) + app = application.App('with wrapped stdout io stream', 1, + cmd_mgr) + self.assertIsInstance(app.stdin, codecs.StreamReader) + self.assertIs(sys.stdout, app.stdout) + self.assertIsInstance(app.stderr, codecs.StreamWriter) + finally: + sys.stdout = stdout_save -def test_help(): - _test_help(False) + try: + sys.stderr = codecs.getwriter(encoding)(sys.stderr) + app = application.App('with wrapped stderr io stream', 1, + cmd_mgr) + self.assertIsInstance(app.stdin, codecs.StreamReader) + self.assertIsInstance(app.stdout, codecs.StreamWriter) + self.assertIs(sys.stderr, app.stderr) + finally: + sys.stderr = stderr_save + else: + app = application.App('no io streams', 1, cmd_mgr) + self.assertIs(sys.stdin, app.stdin) + self.assertIs(sys.stdout, app.stdout) + self.assertIs(sys.stderr, app.stderr) -def test_deferred_help(): - _test_help(True) + app = application.App('with stdin io stream', 1, cmd_mgr, stdin=io) + self.assertIs(io, app.stdin) + self.assertIs(sys.stdout, app.stdout) + self.assertIs(sys.stderr, app.stderr) + app = application.App('with stdout io stream', 1, cmd_mgr, + stdout=io) + self.assertIs(sys.stdin, app.stdin) + self.assertIs(io, app.stdout) + self.assertIs(sys.stderr, app.stderr) -def test_subcommand_help(): - app, _ = make_app(deferred_help=False) - - # Help is called immediately - with mock.patch('cliff.help.HelpAction.__call__') as helper: - app.run(['show', 'files', '--help']) - - assert helper.called - - -def test_subcommand_deferred_help(): - app, _ = make_app(deferred_help=True) - - # Show that provide_help_if_requested() did not show help and exit - with mock.patch.object(app, 'run_subcommand') as helper: - app.run(['show', 'files', '--help']) - - helper.assert_called_once_with(['help', 'show', 'files']) - - -def test_unknown_cmd(): - app, command = make_app() - assert app.run(['hell']) == 2 - - -def test_unknown_cmd_debug(): - app, command = make_app() - try: - app.run(['--debug', 'hell']) == 2 - except ValueError as err: - assert "['hell']" in ('%s' % err) - - -def test_list_matching_commands(): - stdout = StringIO() - app = application.App('testing', '1', - test_utils.TestCommandManager( - test_utils.TEST_NAMESPACE), - stdout=stdout) - app.NAME = 'test' - try: - assert app.run(['t']) == 2 - except SystemExit: - pass - output = stdout.getvalue() - assert "test: 't' is not a test command. See 'test --help'." in output - assert 'Did you mean one of these?' in output - assert 'three word command\n two words\n' in output - - -def test_fuzzy_no_commands(): - cmd_mgr = commandmanager.CommandManager('cliff.fuzzy') - app = application.App('test', '1.0', cmd_mgr) - cmd_mgr.commands = {} - matches = app.get_fuzzy_matches('foo') - assert matches == [] - - -def test_fuzzy_common_prefix(): - # searched string is a prefix of all commands - cmd_mgr = commandmanager.CommandManager('cliff.fuzzy') - app = application.App('test', '1.0', cmd_mgr) - cmd_mgr.commands = {} - cmd_mgr.add_command('user list', test_utils.TestCommand) - cmd_mgr.add_command('user show', test_utils.TestCommand) - matches = app.get_fuzzy_matches('user') - assert matches == ['user list', 'user show'] - - -def test_fuzzy_same_distance(): - # searched string has the same distance to all commands - cmd_mgr = commandmanager.CommandManager('cliff.fuzzy') - app = application.App('test', '1.0', cmd_mgr) - cmd_mgr.add_command('user', test_utils.TestCommand) - for cmd in cmd_mgr.commands.keys(): - assert utils.damerau_levenshtein('node', cmd, utils.COST) == 8 - matches = app.get_fuzzy_matches('node') - assert matches == ['complete', 'help', 'user'] - - -def test_fuzzy_no_prefix(): - # search by distance, no common prefix with any command - cmd_mgr = commandmanager.CommandManager('cliff.fuzzy') - app = application.App('test', '1.0', cmd_mgr) - cmd_mgr.add_command('user', test_utils.TestCommand) - matches = app.get_fuzzy_matches('uesr') - assert matches == ['user'] - - -def test_verbose(): - app, command = make_app() - app.clean_up = mock.MagicMock(name='clean_up') - app.run(['--verbose', 'mock']) - app.clean_up.assert_called_once_with(command.return_value, 0, None) - app.clean_up.reset_mock() - app.run(['--quiet', 'mock']) - app.clean_up.assert_called_once_with(command.return_value, 0, None) - try: - app.run(['--verbose', '--quiet', 'mock']) - except SystemExit: - pass - else: - raise Exception('Exception was not thrown') - - -def test_io_streams(): - cmd_mgr = commandmanager.CommandManager('cliff.tests') - io = mock.Mock() - - if six.PY2: - stdin_save = sys.stdin - stdout_save = sys.stdout - stderr_save = sys.stderr - encoding = locale.getpreferredencoding() or 'utf-8' - - app = application.App('no io streams', 1, cmd_mgr) - assert isinstance(app.stdin, codecs.StreamReader) - assert isinstance(app.stdout, codecs.StreamWriter) - assert isinstance(app.stderr, codecs.StreamWriter) - - app = application.App('with stdin io stream', 1, cmd_mgr, stdin=io) - assert app.stdin is io - assert isinstance(app.stdout, codecs.StreamWriter) - assert isinstance(app.stderr, codecs.StreamWriter) - - app = application.App('with stdout io stream', 1, cmd_mgr, stdout=io) - assert isinstance(app.stdin, codecs.StreamReader) - assert app.stdout is io - assert isinstance(app.stderr, codecs.StreamWriter) - - app = application.App('with stderr io stream', 1, cmd_mgr, stderr=io) - assert isinstance(app.stdin, codecs.StreamReader) - assert isinstance(app.stdout, codecs.StreamWriter) - assert app.stderr is io - - try: - sys.stdin = codecs.getreader(encoding)(sys.stdin) - app = application.App( - 'with wrapped sys.stdin io stream', 1, cmd_mgr) - assert app.stdin is sys.stdin - assert isinstance(app.stdout, codecs.StreamWriter) - assert isinstance(app.stderr, codecs.StreamWriter) - finally: - sys.stdin = stdin_save - - try: - sys.stdout = codecs.getwriter(encoding)(sys.stdout) - app = application.App('with wrapped stdout io stream', 1, cmd_mgr) - assert isinstance(app.stdin, codecs.StreamReader) - assert app.stdout is sys.stdout - assert isinstance(app.stderr, codecs.StreamWriter) - finally: - sys.stdout = stdout_save - - try: - sys.stderr = codecs.getwriter(encoding)(sys.stderr) - app = application.App('with wrapped stderr io stream', 1, cmd_mgr) - assert isinstance(app.stdin, codecs.StreamReader) - assert isinstance(app.stdout, codecs.StreamWriter) - assert app.stderr is sys.stderr - finally: - sys.stderr = stderr_save - - else: - app = application.App('no io streams', 1, cmd_mgr) - assert app.stdin is sys.stdin - assert app.stdout is sys.stdout - assert app.stderr is sys.stderr - - app = application.App('with stdin io stream', 1, cmd_mgr, stdin=io) - assert app.stdin is io - assert app.stdout is sys.stdout - assert app.stderr is sys.stderr - - app = application.App('with stdout io stream', 1, cmd_mgr, stdout=io) - assert app.stdin is sys.stdin - assert app.stdout is io - assert app.stderr is sys.stderr - - app = application.App('with stderr io stream', 1, cmd_mgr, stderr=io) - assert app.stdin is sys.stdin - assert app.stdout is sys.stdout - assert app.stderr is io + app = application.App('with stderr io stream', 1, cmd_mgr, + stderr=io) + self.assertIs(sys.stdin, app.stdin) + self.assertIs(sys.stdout, app.stdout) + self.assertIs(io, app.stderr) diff --git a/cliff/tests/test_columns.py b/cliff/tests/test_columns.py index d7bb2b00..fef1128c 100644 --- a/cliff/tests/test_columns.py +++ b/cliff/tests/test_columns.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import unittest + from cliff import columns @@ -19,12 +21,15 @@ class FauxColumn(columns.FormattableColumn): return u'I made this string myself: {}'.format(self._value) -def test_faux_column_machine(): - c = FauxColumn(['list', 'of', 'values']) - assert c.machine_readable() == ['list', 'of', 'values'] +class TestColumns(unittest.TestCase): + def test_faux_column_machine(self): + c = FauxColumn(['list', 'of', 'values']) + self.assertEqual(['list', 'of', 'values'], c.machine_readable()) -def test_faux_column_human(): - c = FauxColumn(['list', 'of', 'values']) - assert c.human_readable() == \ - u"I made this string myself: ['list', 'of', 'values']" + def test_faux_column_human(self): + c = FauxColumn(['list', 'of', 'values']) + self.assertEqual( + u"I made this string myself: ['list', 'of', 'values']", + c.human_readable(), + ) diff --git a/cliff/tests/test_command.py b/cliff/tests/test_command.py index 55bb61ce..4bc03aab 100644 --- a/cliff/tests/test_command.py +++ b/cliff/tests/test_command.py @@ -11,6 +11,7 @@ # under the License. from cliff import command +from cliff.tests import base class TestCommand(command.Command): @@ -51,47 +52,44 @@ class TestCommandNoDocstring(command.Command): return 42 -def test_get_description_docstring(): - cmd = TestCommand(None, None) - desc = cmd.get_description() - assert desc == "Description of command.\n " +class TestDescription(base.TestBase): + + def test_get_description_docstring(self): + cmd = TestCommand(None, None) + desc = cmd.get_description() + assert desc == "Description of command.\n " + + def test_get_description_attribute(self): + cmd = TestCommand(None, None) + # Artificially inject a value for _description to verify that it + # overrides the docstring. + cmd._description = 'this is not the default' + desc = cmd.get_description() + assert desc == 'this is not the default' + + def test_get_description_default(self): + cmd = TestCommandNoDocstring(None, None) + desc = cmd.get_description() + assert desc == '' -def test_get_description_attribute(): - cmd = TestCommand(None, None) - # Artificially inject a value for _description to verify that it - # overrides the docstring. - cmd._description = 'this is not the default' - desc = cmd.get_description() - assert desc == 'this is not the default' +class TestBasicValues(base.TestBase): + + def test_get_parser(self): + cmd = TestCommand(None, None) + parser = cmd.get_parser('NAME') + assert parser.prog == 'NAME' + + def test_get_name(self): + cmd = TestCommand(None, None, cmd_name='object action') + assert cmd.cmd_name == 'object action' + + def test_run_return(self): + cmd = TestCommand(None, None, cmd_name='object action') + assert cmd.run(None) == 42 -def test_get_description_default(): - cmd = TestCommandNoDocstring(None, None) - desc = cmd.get_description() - assert desc == '' - - -def test_get_parser(): - cmd = TestCommand(None, None) - parser = cmd.get_parser('NAME') - assert parser.prog == 'NAME' - - -def test_get_name(): - cmd = TestCommand(None, None, cmd_name='object action') - assert cmd.cmd_name == 'object action' - - -def test_run_return(): - cmd = TestCommand(None, None, cmd_name='object action') - assert cmd.run(None) == 42 - - -def test_smart_help_formatter(): - cmd = TestCommand(None, None) - parser = cmd.get_parser('NAME') - expected_help_message = """ +expected_help_message = """ long_help_argument Create a NIC on the server. Specify option multiple times to create multiple NICs. Either net-id or port-id must be provided, but not @@ -108,4 +106,11 @@ def test_smart_help_formatter(): regular_help_argument The quick brown fox jumps over the lazy dog. """ - assert expected_help_message in parser.format_help() + + +class TestHelp(base.TestBase): + + def test_smart_help_formatter(self): + cmd = TestCommand(None, None) + parser = cmd.get_parser('NAME') + self.assertIn(expected_help_message, parser.format_help()) diff --git a/cliff/tests/test_commandmanager.py b/cliff/tests/test_commandmanager.py index 7f5ce0c9..e4ba225b 100644 --- a/cliff/tests/test_commandmanager.py +++ b/cliff/tests/test_commandmanager.py @@ -11,122 +11,142 @@ # under the License. import mock +import testscenarios from cliff import commandmanager +from cliff.tests import base from cliff.tests import utils -def test_lookup_and_find(): - def check(mgr, argv): - cmd, name, remaining = mgr.find_command(argv) - assert cmd - assert name == ' '.join(argv) - assert not remaining - mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) - for expected in [['one'], - ['two', 'words'], - ['three', 'word', 'command'], - ]: - yield check, mgr, expected - return +load_tests = testscenarios.load_tests_apply_scenarios -def test_lookup_with_remainder(): - def check(mgr, argv): - cmd, name, remaining = mgr.find_command(argv) - assert cmd - assert remaining == ['--opt'] - mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) - for expected in [['one', '--opt'], - ['two', 'words', '--opt'], - ['three', 'word', 'command', '--opt'], - ]: - yield check, mgr, expected - return +class TestLookupAndFind(base.TestBase): + + scenarios = [ + ('one-word', {'argv': ['one']}), + ('two-words', {'argv': ['two', 'words']}), + ('three-words', {'argv': ['three', 'word', 'command']}), + ] + + def test(self): + mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) + cmd, name, remaining = mgr.find_command(self.argv) + self.assertTrue(cmd) + self.assertEqual(' '.join(self.argv), name) + self.assertFalse(remaining) -def test_find_invalid_command(): - mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) +class TestLookupWithRemainder(base.TestBase): - def check_one(argv): + scenarios = [ + ('one', {'argv': ['one', '--opt']}), + ('two', {'argv': ['two', 'words', '--opt']}), + ('three', {'argv': ['three', 'word', 'command', '--opt']}), + ] + + def test(self): + mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) + cmd, name, remaining = mgr.find_command(self.argv) + self.assertTrue(cmd) + self.assertEqual(['--opt'], remaining) + + +class TestFindInvalidCommand(base.TestBase): + + scenarios = [ + ('no-such-command', {'argv': ['a', '-b']}), + ('no-command-given', {'argv': ['-b']}), + ] + + def test(self): + mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) try: - mgr.find_command(argv) + mgr.find_command(self.argv) except ValueError as err: # make sure err include 'a' when ['a', '-b'] - assert argv[0] in ('%s' % err) - assert '-b' in ('%s' % err) + self.assertIn(self.argv[0], str(err)) + self.assertIn('-b', str(err)) else: - assert False, 'expected a failure' - for argv in [['a', '-b'], - ['-b'], - ]: - yield check_one, argv + self.fail('expected a failure') -def test_find_unknown_command(): - mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) - try: - mgr.find_command(['a', 'b']) - except ValueError as err: - assert "['a', 'b']" in ('%s' % err) - else: - assert False, 'expected a failure' +class TestFindUnknownCommand(base.TestBase): + + def test(self): + mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) + try: + mgr.find_command(['a', 'b']) + except ValueError as err: + self.assertIn("['a', 'b']", str(err)) + else: + self.fail('expected a failure') -def test_add_command(): - mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) - mock_cmd = mock.Mock() - mgr.add_command('mock', mock_cmd) - found_cmd, name, args = mgr.find_command(['mock']) - assert found_cmd is mock_cmd +class TestDynamicCommands(base.TestBase): + + def test_add(self): + mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) + mock_cmd = mock.Mock() + mgr.add_command('mock', mock_cmd) + found_cmd, name, args = mgr.find_command(['mock']) + self.assertIs(mock_cmd, found_cmd) + + def test_intersected_commands(self): + def foo(arg): + pass + + def foo_bar(): + pass + + mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) + mgr.add_command('foo', foo) + mgr.add_command('foo bar', foo_bar) + + self.assertIs(foo_bar, mgr.find_command(['foo', 'bar'])[0]) + self.assertIs( + foo, + mgr.find_command(['foo', 'arg0'])[0], + ) -def test_intersected_commands(): - def foo(arg): - pass +class TestLoad(base.TestBase): - def foo_bar(): - pass + def test_load_commands(self): + testcmd = mock.Mock(name='testcmd') + testcmd.name.replace.return_value = 'test' + mock_pkg_resources = mock.Mock(return_value=[testcmd]) + with mock.patch('pkg_resources.iter_entry_points', + mock_pkg_resources) as iter_entry_points: + mgr = commandmanager.CommandManager('test') + iter_entry_points.assert_called_once_with('test') + names = [n for n, v in mgr] + self.assertEqual(['test'], names) - mgr = utils.TestCommandManager(utils.TEST_NAMESPACE) - mgr.add_command('foo', foo) - mgr.add_command('foo bar', foo_bar) + def test_load_commands_keep_underscores(self): + testcmd = mock.Mock() + testcmd.name = 'test_cmd' + mock_pkg_resources = mock.Mock(return_value=[testcmd]) + with mock.patch('pkg_resources.iter_entry_points', + mock_pkg_resources) as iter_entry_points: + mgr = commandmanager.CommandManager( + 'test', + convert_underscores=False, + ) + iter_entry_points.assert_called_once_with('test') + names = [n for n, v in mgr] + self.assertEqual(['test_cmd'], names) - assert mgr.find_command(['foo', 'bar'])[0] is foo_bar - assert mgr.find_command(['foo', 'arg0'])[0] is foo - - -def test_load_commands(): - testcmd = mock.Mock(name='testcmd') - testcmd.name.replace.return_value = 'test' - mock_pkg_resources = mock.Mock(return_value=[testcmd]) - with mock.patch('pkg_resources.iter_entry_points', - mock_pkg_resources) as iter_entry_points: - mgr = commandmanager.CommandManager('test') - iter_entry_points.assert_called_once_with('test') - names = [n for n, v in mgr] - assert names == ['test'] - - -def test_load_commands_keep_underscores(): - testcmd = mock.Mock() - testcmd.name = 'test_cmd' - mock_pkg_resources = mock.Mock(return_value=[testcmd]) - with mock.patch('pkg_resources.iter_entry_points', - mock_pkg_resources) as iter_entry_points: - mgr = commandmanager.CommandManager('test', convert_underscores=False) - iter_entry_points.assert_called_once_with('test') - names = [n for n, v in mgr] - assert names == ['test_cmd'] - - -def test_load_commands_replace_underscores(): - testcmd = mock.Mock() - testcmd.name = 'test_cmd' - mock_pkg_resources = mock.Mock(return_value=[testcmd]) - with mock.patch('pkg_resources.iter_entry_points', - mock_pkg_resources) as iter_entry_points: - mgr = commandmanager.CommandManager('test', convert_underscores=True) - iter_entry_points.assert_called_once_with('test') - names = [n for n, v in mgr] - assert names == ['test cmd'] + def test_load_commands_replace_underscores(self): + testcmd = mock.Mock() + testcmd.name = 'test_cmd' + mock_pkg_resources = mock.Mock(return_value=[testcmd]) + with mock.patch('pkg_resources.iter_entry_points', + mock_pkg_resources) as iter_entry_points: + mgr = commandmanager.CommandManager( + 'test', + convert_underscores=True, + ) + iter_entry_points.assert_called_once_with('test') + names = [n for n, v in mgr] + self.assertEqual(['test cmd'], names) diff --git a/cliff/tests/test_complete.py b/cliff/tests/test_complete.py index b1523ec6..a4f8dc40 100644 --- a/cliff/tests/test_complete.py +++ b/cliff/tests/test_complete.py @@ -18,50 +18,52 @@ import mock from cliff import app as application from cliff import commandmanager from cliff import complete +from cliff.tests import base -def test_complete_dictionary(): - sot = complete.CompleteDictionary() - sot.add_command("image delete".split(), - [mock.Mock(option_strings=["1"])]) - sot.add_command("image list".split(), - [mock.Mock(option_strings=["2"])]) - sot.add_command("image create".split(), - [mock.Mock(option_strings=["3"])]) - sot.add_command("volume type create".split(), - [mock.Mock(option_strings=["4"])]) - sot.add_command("volume type delete".split(), - [mock.Mock(option_strings=["5"])]) - assert "image volume" == sot.get_commands() - result = sot.get_data() - assert "image" == result[0][0] - assert "create delete list" == result[0][1] - assert "image_create" == result[1][0] - assert "3" == result[1][1] - assert "image_delete" == result[2][0] - assert "1" == result[2][1] - assert "image_list" == result[3][0] - assert "2" == result[3][1] +class TestCompletion(base.TestBase): + def test_dictionary(self): + sot = complete.CompleteDictionary() + sot.add_command("image delete".split(), + [mock.Mock(option_strings=["1"])]) + sot.add_command("image list".split(), + [mock.Mock(option_strings=["2"])]) + sot.add_command("image create".split(), + [mock.Mock(option_strings=["3"])]) + sot.add_command("volume type create".split(), + [mock.Mock(option_strings=["4"])]) + sot.add_command("volume type delete".split(), + [mock.Mock(option_strings=["5"])]) + self.assertEqual("image volume", sot.get_commands()) + result = sot.get_data() + self.assertEqual("image", result[0][0]) + self.assertEqual("create delete list", result[0][1]) + self.assertEqual("image_create", result[1][0]) + self.assertEqual("3", result[1][1]) + self.assertEqual("image_delete", result[2][0]) + self.assertEqual("1", result[2][1]) + self.assertEqual("image_list", result[3][0]) + self.assertEqual("2", result[3][1]) -def test_complete_dictionary_subcmd(): - sot = complete.CompleteDictionary() - sot.add_command("image delete".split(), - [mock.Mock(option_strings=["1"])]) - sot.add_command("image list".split(), - [mock.Mock(option_strings=["2"])]) - sot.add_command("image list better".split(), - [mock.Mock(option_strings=["3"])]) - assert "image" == sot.get_commands() - result = sot.get_data() - assert "image" == result[0][0] - assert "delete list list_better" == result[0][1] - assert "image_delete" == result[1][0] - assert "1" == result[1][1] - assert "image_list" == result[2][0] - assert "2 better" == result[2][1] - assert "image_list_better" == result[3][0] - assert "3" == result[3][1] + def test_complete_dictionary_subcmd(self): + sot = complete.CompleteDictionary() + sot.add_command("image delete".split(), + [mock.Mock(option_strings=["1"])]) + sot.add_command("image list".split(), + [mock.Mock(option_strings=["2"])]) + sot.add_command("image list better".split(), + [mock.Mock(option_strings=["3"])]) + self.assertEqual("image", sot.get_commands()) + result = sot.get_data() + self.assertEqual("image", result[0][0]) + self.assertEqual("delete list list_better", result[0][1]) + self.assertEqual("image_delete", result[1][0]) + self.assertEqual("1", result[1][1]) + self.assertEqual("image_list", result[2][0]) + self.assertEqual("2 better", result[2][1]) + self.assertEqual("image_list_better", result[3][0]) + self.assertEqual("3", result[3][1]) class FakeStdout: @@ -78,96 +80,92 @@ class FakeStdout: return result -def given_cmdo_data(): - cmdo = "image server" - data = [("image", "create"), - ("image_create", "--eolus"), - ("server", "meta ssh"), - ("server_meta_delete", "--wilson"), - ("server_ssh", "--sunlight")] - return cmdo, data +class TestCompletionAlternatives(base.TestBase): + + def given_cmdo_data(self): + cmdo = "image server" + data = [("image", "create"), + ("image_create", "--eolus"), + ("server", "meta ssh"), + ("server_meta_delete", "--wilson"), + ("server_ssh", "--sunlight")] + return cmdo, data + + def then_data(self, content): + self.assertIn(" cmds='image server'\n", content) + self.assertIn(" cmds_image='create'\n", content) + self.assertIn(" cmds_image_create='--eolus'\n", content) + self.assertIn(" cmds_server='meta ssh'\n", content) + self.assertIn(" cmds_server_meta_delete='--wilson'\n", content) + self.assertIn(" cmds_server_ssh='--sunlight'\n", content) + + def test_complete_no_code(self): + output = FakeStdout() + sot = complete.CompleteNoCode("doesNotMatter", output) + sot.write(*self.given_cmdo_data()) + self.then_data(output.content) + + def test_complete_bash(self): + output = FakeStdout() + sot = complete.CompleteBash("openstack", output) + sot.write(*self.given_cmdo_data()) + self.then_data(output.content) + self.assertIn("_openstack()\n", output.content[0]) + self.assertIn("complete -F _openstack openstack\n", output.content[-1]) + + def test_complete_command_parser(self): + sot = complete.CompleteCommand(mock.Mock(), mock.Mock()) + parser = sot.get_parser('nothing') + self.assertEqual("nothing", parser.prog) + self.assertEqual("print bash completion command\n ", + parser.description) -def then_data(content): - assert " cmds='image server'\n" in content - assert " cmds_image='create'\n" in content - assert " cmds_image_create='--eolus'\n" in content - assert " cmds_server='meta ssh'\n" in content - assert " cmds_server_meta_delete='--wilson'\n" in content - assert " cmds_server_ssh='--sunlight'\n" in content +class TestCompletionAction(base.TestBase): + def given_complete_command(self): + cmd_mgr = commandmanager.CommandManager('cliff.tests') + app = application.App('testing', '1', cmd_mgr, stdout=FakeStdout()) + sot = complete.CompleteCommand(app, mock.Mock()) + cmd_mgr.add_command('complete', complete.CompleteCommand) + return sot, app, cmd_mgr -def test_complete_no_code(): - output = FakeStdout() - sot = complete.CompleteNoCode("doesNotMatter", output) - sot.write(*given_cmdo_data()) - then_data(output.content) + def then_actions_equal(self, actions): + optstr = ' '.join(opt for action in actions + for opt in action.option_strings) + self.assertEqual('-h --help --name --shell', optstr) + def test_complete_command_get_actions(self): + sot, app, cmd_mgr = self.given_complete_command() + app.interactive_mode = False + actions = sot.get_actions(["complete"]) + self.then_actions_equal(actions) -def test_complete_bash(): - output = FakeStdout() - sot = complete.CompleteBash("openstack", output) - sot.write(*given_cmdo_data()) - then_data(output.content) - assert "_openstack()\n" in output.content[0] - assert "complete -F _openstack openstack\n" in output.content[-1] + def test_complete_command_get_actions_interactive(self): + sot, app, cmd_mgr = self.given_complete_command() + app.interactive_mode = True + actions = sot.get_actions(["complete"]) + self.then_actions_equal(actions) + def test_complete_command_take_action(self): + sot, app, cmd_mgr = self.given_complete_command() + parsed_args = mock.Mock() + parsed_args.name = "test_take" + parsed_args.shell = "bash" + content = app.stdout.content + self.assertEqual(0, sot.take_action(parsed_args)) + self.assertIn("_test_take()\n", content[0]) + self.assertIn("complete -F _test_take test_take\n", content[-1]) + self.assertIn(" cmds='complete help'\n", content) + self.assertIn(" cmds_complete='-h --help --name --shell'\n", content) + self.assertIn(" cmds_help='-h --help'\n", content) -def test_complete_command_parser(): - sot = complete.CompleteCommand(mock.Mock(), mock.Mock()) - parser = sot.get_parser('nothing') - assert "nothing" == parser.prog - assert "print bash completion command\n " == parser.description - - -def given_complete_command(): - cmd_mgr = commandmanager.CommandManager('cliff.tests') - app = application.App('testing', '1', cmd_mgr, stdout=FakeStdout()) - sot = complete.CompleteCommand(app, mock.Mock()) - cmd_mgr.add_command('complete', complete.CompleteCommand) - return sot, app, cmd_mgr - - -def then_actions_equal(actions): - optstr = ' '.join(opt for action in actions - for opt in action.option_strings) - assert '-h --help --name --shell' == optstr - - -def test_complete_command_get_actions(): - sot, app, cmd_mgr = given_complete_command() - app.interactive_mode = False - actions = sot.get_actions(["complete"]) - then_actions_equal(actions) - - -def test_complete_command_get_actions_interactive(): - sot, app, cmd_mgr = given_complete_command() - app.interactive_mode = True - actions = sot.get_actions(["complete"]) - then_actions_equal(actions) - - -def test_complete_command_take_action(): - sot, app, cmd_mgr = given_complete_command() - parsed_args = mock.Mock() - parsed_args.name = "test_take" - parsed_args.shell = "bash" - content = app.stdout.content - assert 0 == sot.take_action(parsed_args) - assert "_test_take()\n" in content[0] - assert "complete -F _test_take test_take\n" in content[-1] - assert " cmds='complete help'\n" in content - assert " cmds_complete='-h --help --name --shell'\n" in content - assert " cmds_help='-h --help'\n" in content - - -def test_complete_command_remove_dashes(): - sot, app, cmd_mgr = given_complete_command() - parsed_args = mock.Mock() - parsed_args.name = "test-take" - parsed_args.shell = "bash" - content = app.stdout.content - assert 0 == sot.take_action(parsed_args) - assert "_test_take()\n" in content[0] - assert "complete -F _test_take test-take\n" in content[-1] + def test_complete_command_remove_dashes(self): + sot, app, cmd_mgr = self.given_complete_command() + parsed_args = mock.Mock() + parsed_args.name = "test-take" + parsed_args.shell = "bash" + content = app.stdout.content + self.assertEqual(0, sot.take_action(parsed_args)) + self.assertIn("_test_take()\n", content[0]) + self.assertIn("complete -F _test_take test-take\n", content[-1]) diff --git a/cliff/tests/test_formatters_csv.py b/cliff/tests/test_formatters_csv.py index 27c6f84c..001f1694 100644 --- a/cliff/tests/test_formatters_csv.py +++ b/cliff/tests/test_formatters_csv.py @@ -13,73 +13,74 @@ # License for the specific language governing permissions and limitations # under the License. -import mock import argparse +import unittest + +import mock import six from cliff.formatters import commaseparated from cliff.tests import test_columns -def test_commaseparated_list_formatter(): - sf = commaseparated.CSVLister() - c = ('a', 'b', 'c') - d1 = ('A', 'B', 'C') - d2 = ('D', 'E', 'F') - data = [d1, d2] - expected = 'a,b,c\nA,B,C\nD,E,F\n' - output = six.StringIO() - parsed_args = mock.Mock() - parsed_args.quote_mode = 'none' - sf.emit_list(c, data, output, parsed_args) - actual = output.getvalue() - assert expected == actual +class TestCSVFormatter(unittest.TestCase): + def test_commaseparated_list_formatter(self): + sf = commaseparated.CSVLister() + c = ('a', 'b', 'c') + d1 = ('A', 'B', 'C') + d2 = ('D', 'E', 'F') + data = [d1, d2] + expected = 'a,b,c\nA,B,C\nD,E,F\n' + output = six.StringIO() + parsed_args = mock.Mock() + parsed_args.quote_mode = 'none' + sf.emit_list(c, data, output, parsed_args) + actual = output.getvalue() + self.assertEqual(expected, actual) -def test_commaseparated_list_formatter_quoted(): - sf = commaseparated.CSVLister() - c = ('a', 'b', 'c') - d1 = ('A', 'B', 'C') - d2 = ('D', 'E', 'F') - data = [d1, d2] - expected = '"a","b","c"\n"A","B","C"\n"D","E","F"\n' - output = six.StringIO() - # Parse arguments as if passed on the command-line - parser = argparse.ArgumentParser(description='Testing...') - sf.add_argument_group(parser) - parsed_args = parser.parse_args(['--quote', 'all']) - sf.emit_list(c, data, output, parsed_args) - actual = output.getvalue() - assert expected == actual + def test_commaseparated_list_formatter_quoted(self): + sf = commaseparated.CSVLister() + c = ('a', 'b', 'c') + d1 = ('A', 'B', 'C') + d2 = ('D', 'E', 'F') + data = [d1, d2] + expected = '"a","b","c"\n"A","B","C"\n"D","E","F"\n' + output = six.StringIO() + # Parse arguments as if passed on the command-line + parser = argparse.ArgumentParser(description='Testing...') + sf.add_argument_group(parser) + parsed_args = parser.parse_args(['--quote', 'all']) + sf.emit_list(c, data, output, parsed_args) + actual = output.getvalue() + self.assertEqual(expected, actual) + def test_commaseparated_list_formatter_formattable_column(self): + sf = commaseparated.CSVLister() + c = ('a', 'b', 'c') + d1 = ('A', 'B', test_columns.FauxColumn(['the', 'value'])) + data = [d1] + expected = 'a,b,c\nA,B,[\'the\'\\, \'value\']\n' + output = six.StringIO() + parsed_args = mock.Mock() + parsed_args.quote_mode = 'none' + sf.emit_list(c, data, output, parsed_args) + actual = output.getvalue() + self.assertEqual(expected, actual) -def test_commaseparated_list_formatter_formattable_column(): - sf = commaseparated.CSVLister() - c = ('a', 'b', 'c') - d1 = ('A', 'B', test_columns.FauxColumn(['the', 'value'])) - data = [d1] - expected = 'a,b,c\nA,B,[\'the\'\\, \'value\']\n' - output = six.StringIO() - parsed_args = mock.Mock() - parsed_args.quote_mode = 'none' - sf.emit_list(c, data, output, parsed_args) - actual = output.getvalue() - assert expected == actual - - -def test_commaseparated_list_formatter_unicode(): - sf = commaseparated.CSVLister() - c = (u'a', u'b', u'c') - d1 = (u'A', u'B', u'C') - happy = u'高兴' - d2 = (u'D', u'E', happy) - data = [d1, d2] - expected = u'a,b,c\nA,B,C\nD,E,%s\n' % happy - output = six.StringIO() - parsed_args = mock.Mock() - parsed_args.quote_mode = 'none' - sf.emit_list(c, data, output, parsed_args) - actual = output.getvalue() - if six.PY2: - actual = actual.decode('utf-8') - assert expected == actual + def test_commaseparated_list_formatter_unicode(self): + sf = commaseparated.CSVLister() + c = (u'a', u'b', u'c') + d1 = (u'A', u'B', u'C') + happy = u'高兴' + d2 = (u'D', u'E', happy) + data = [d1, d2] + expected = u'a,b,c\nA,B,C\nD,E,%s\n' % happy + output = six.StringIO() + parsed_args = mock.Mock() + parsed_args.quote_mode = 'none' + sf.emit_list(c, data, output, parsed_args) + actual = output.getvalue() + if six.PY2: + actual = actual.decode('utf-8') + self.assertEqual(expected, actual) diff --git a/cliff/tests/test_formatters_json.py b/cliff/tests/test_formatters_json.py index eb7397df..2f3a6e94 100644 --- a/cliff/tests/test_formatters_json.py +++ b/cliff/tests/test_formatters_json.py @@ -13,117 +13,117 @@ # under the License. import json -import six from cliff.formatters import json_format +from cliff.tests import base from cliff.tests import test_columns import mock +import six -def test_json_format_one(): - sf = json_format.JSONFormatter() - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', '"escape me"') - expected = { - 'a': 'A', - 'b': 'B', - 'c': 'C', - 'd': '"escape me"' - } - args = mock.Mock() - sf.add_argument_group(args) +class TestJSONFormatter(base.TestBase): - args.noindent = True - output = six.StringIO() - sf.emit_one(c, d, output, args) - value = output.getvalue() - print(len(value.splitlines())) - assert 1 == len(value.splitlines()) - actual = json.loads(value) - assert expected == actual + def test_one(self): + sf = json_format.JSONFormatter() + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', '"escape me"') + expected = { + 'a': 'A', + 'b': 'B', + 'c': 'C', + 'd': '"escape me"' + } + args = mock.Mock() + sf.add_argument_group(args) - args.noindent = False - output = six.StringIO() - sf.emit_one(c, d, output, args) - value = output.getvalue() - assert 6 == len(value.splitlines()) - actual = json.loads(value) - assert expected == actual + args.noindent = True + output = six.StringIO() + sf.emit_one(c, d, output, args) + value = output.getvalue() + print(len(value.splitlines())) + self.assertEqual(1, len(value.splitlines())) + actual = json.loads(value) + self.assertEqual(expected, actual) + args.noindent = False + output = six.StringIO() + sf.emit_one(c, d, output, args) + value = output.getvalue() + self.assertEqual(6, len(value.splitlines())) + actual = json.loads(value) + self.assertEqual(expected, actual) -def test_json_format_formattablecolumn_one(): - sf = json_format.JSONFormatter() - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value'])) - expected = { - 'a': 'A', - 'b': 'B', - 'c': 'C', - 'd': ['the', 'value'], - } - args = mock.Mock() - sf.add_argument_group(args) + def test_formattablecolumn_one(self): + sf = json_format.JSONFormatter() + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value'])) + expected = { + 'a': 'A', + 'b': 'B', + 'c': 'C', + 'd': ['the', 'value'], + } + args = mock.Mock() + sf.add_argument_group(args) - args.noindent = True - output = six.StringIO() - sf.emit_one(c, d, output, args) - value = output.getvalue() - print(len(value.splitlines())) - assert 1 == len(value.splitlines()) - actual = json.loads(value) - assert expected == actual + args.noindent = True + output = six.StringIO() + sf.emit_one(c, d, output, args) + value = output.getvalue() + print(len(value.splitlines())) + self.assertEqual(1, len(value.splitlines())) + actual = json.loads(value) + self.assertEqual(expected, actual) + def test_list(self): + sf = json_format.JSONFormatter() + c = ('a', 'b', 'c') + d = ( + ('A1', 'B1', 'C1'), + ('A2', 'B2', 'C2'), + ('A3', 'B3', 'C3') + ) + expected = [ + {'a': 'A1', 'b': 'B1', 'c': 'C1'}, + {'a': 'A2', 'b': 'B2', 'c': 'C2'}, + {'a': 'A3', 'b': 'B3', 'c': 'C3'} + ] + args = mock.Mock() + sf.add_argument_group(args) -def test_json_format_list(): - sf = json_format.JSONFormatter() - c = ('a', 'b', 'c') - d = ( - ('A1', 'B1', 'C1'), - ('A2', 'B2', 'C2'), - ('A3', 'B3', 'C3') - ) - expected = [ - {'a': 'A1', 'b': 'B1', 'c': 'C1'}, - {'a': 'A2', 'b': 'B2', 'c': 'C2'}, - {'a': 'A3', 'b': 'B3', 'c': 'C3'} - ] - args = mock.Mock() - sf.add_argument_group(args) + args.noindent = True + output = six.StringIO() + sf.emit_list(c, d, output, args) + value = output.getvalue() + self.assertEqual(1, len(value.splitlines())) + actual = json.loads(value) + self.assertEqual(expected, actual) - args.noindent = True - output = six.StringIO() - sf.emit_list(c, d, output, args) - value = output.getvalue() - assert 1 == len(value.splitlines()) - actual = json.loads(value) - assert expected == actual + args.noindent = False + output = six.StringIO() + sf.emit_list(c, d, output, args) + value = output.getvalue() + self.assertEqual(17, len(value.splitlines())) + actual = json.loads(value) + self.assertEqual(expected, actual) - args.noindent = False - output = six.StringIO() - sf.emit_list(c, d, output, args) - value = output.getvalue() - assert 17 == len(value.splitlines()) - actual = json.loads(value) - assert expected == actual + def test_formattablecolumn_list(self): + sf = json_format.JSONFormatter() + c = ('a', 'b', 'c') + d = ( + ('A1', 'B1', test_columns.FauxColumn(['the', 'value'])), + ) + expected = [ + {'a': 'A1', 'b': 'B1', 'c': ['the', 'value']}, + ] + args = mock.Mock() + sf.add_argument_group(args) - -def test_json_format_formattablecolumn_list(): - sf = json_format.JSONFormatter() - c = ('a', 'b', 'c') - d = ( - ('A1', 'B1', test_columns.FauxColumn(['the', 'value'])), - ) - expected = [ - {'a': 'A1', 'b': 'B1', 'c': ['the', 'value']}, - ] - args = mock.Mock() - sf.add_argument_group(args) - - args.noindent = True - output = six.StringIO() - sf.emit_list(c, d, output, args) - value = output.getvalue() - assert 1 == len(value.splitlines()) - actual = json.loads(value) - assert expected == actual + args.noindent = True + output = six.StringIO() + sf.emit_list(c, d, output, args) + value = output.getvalue() + self.assertEqual(1, len(value.splitlines())) + actual = json.loads(value) + self.assertEqual(expected, actual) diff --git a/cliff/tests/test_formatters_shell.py b/cliff/tests/test_formatters_shell.py index 7689f73a..a6929a37 100644 --- a/cliff/tests/test_formatters_shell.py +++ b/cliff/tests/test_formatters_shell.py @@ -16,81 +16,81 @@ import argparse import six from cliff.formatters import shell +from cliff.tests import base from cliff.tests import test_columns import mock -def test_shell_formatter(): - sf = shell.ShellFormatter() - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', '"escape me"') - expected = 'a="A"\nb="B"\nd="\\"escape me\\""\n' - output = six.StringIO() - args = mock.Mock() - args.variables = ['a', 'b', 'd'] - args.prefix = '' - sf.emit_one(c, d, output, args) - actual = output.getvalue() - assert expected == actual +class TestShellFormatter(base.TestBase): + def test(self): + sf = shell.ShellFormatter() + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', '"escape me"') + expected = 'a="A"\nb="B"\nd="\\"escape me\\""\n' + output = six.StringIO() + args = mock.Mock() + args.variables = ['a', 'b', 'd'] + args.prefix = '' + sf.emit_one(c, d, output, args) + actual = output.getvalue() + self.assertEqual(expected, actual) -def test_shell_formatter_args(): - sf = shell.ShellFormatter() - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', '"escape me"') - expected = 'Xd="\\"escape me\\""\n' - output = six.StringIO() - # Parse arguments as if passed on the command-line - parser = argparse.ArgumentParser(description='Testing...') - sf.add_argument_group(parser) - parsed_args = parser.parse_args(['--variable', 'd', '--prefix', 'X']) - sf.emit_one(c, d, output, parsed_args) - actual = output.getvalue() - assert expected == actual + def test_args(self): + sf = shell.ShellFormatter() + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', '"escape me"') + expected = 'Xd="\\"escape me\\""\n' + output = six.StringIO() + # Parse arguments as if passed on the command-line + parser = argparse.ArgumentParser(description='Testing...') + sf.add_argument_group(parser) + parsed_args = parser.parse_args(['--variable', 'd', '--prefix', 'X']) + sf.emit_one(c, d, output, parsed_args) + actual = output.getvalue() + self.assertEqual(expected, actual) + def test_formattable_column(self): + sf = shell.ShellFormatter() + c = ('a', 'b', 'c') + d = ('A', 'B', test_columns.FauxColumn(['the', 'value'])) + expected = '\n'.join([ + 'a="A"', + 'b="B"', + 'c="[\'the\', \'value\']"\n', + ]) + output = six.StringIO() + args = mock.Mock() + args.variables = ['a', 'b', 'c'] + args.prefix = '' + sf.emit_one(c, d, output, args) + actual = output.getvalue() + self.assertEqual(expected, actual) -def test_shell_formatter_formattable_column(): - sf = shell.ShellFormatter() - c = ('a', 'b', 'c') - d = ('A', 'B', test_columns.FauxColumn(['the', 'value'])) - expected = '\n'.join([ - 'a="A"', - 'b="B"', - 'c="[\'the\', \'value\']"\n', - ]) - output = six.StringIO() - args = mock.Mock() - args.variables = ['a', 'b', 'c'] - args.prefix = '' - sf.emit_one(c, d, output, args) - actual = output.getvalue() - assert expected == actual + def test_non_string_values(self): + sf = shell.ShellFormatter() + c = ('a', 'b', 'c', 'd', 'e') + d = (True, False, 100, '"esc"', six.text_type('"esc"')) + expected = ('a="True"\nb="False"\nc="100"\n' + 'd="\\"esc\\""\ne="\\"esc\\""\n') + output = six.StringIO() + args = mock.Mock() + args.variables = ['a', 'b', 'c', 'd', 'e'] + args.prefix = '' + sf.emit_one(c, d, output, args) + actual = output.getvalue() + self.assertEqual(expected, actual) - -def test_shell_formatter_with_non_string_values(): - sf = shell.ShellFormatter() - c = ('a', 'b', 'c', 'd', 'e') - d = (True, False, 100, '"esc"', six.text_type('"esc"')) - expected = 'a="True"\nb="False"\nc="100"\nd="\\"esc\\""\ne="\\"esc\\""\n' - output = six.StringIO() - args = mock.Mock() - args.variables = ['a', 'b', 'c', 'd', 'e'] - args.prefix = '' - sf.emit_one(c, d, output, args) - actual = output.getvalue() - assert expected == actual - - -def test_shell_formatter_with_non_bash_friendly_values(): - sf = shell.ShellFormatter() - c = ('a', 'foo-bar', 'provider:network_type') - d = (True, 'baz', 'vxlan') - expected = 'a="True"\nfoo_bar="baz"\nprovider_network_type="vxlan"\n' - output = six.StringIO() - args = mock.Mock() - args.variables = ['a', 'foo-bar', 'provider:network_type'] - args.prefix = '' - sf.emit_one(c, d, output, args) - actual = output.getvalue() - assert expected == actual + def test_non_bash_friendly_values(self): + sf = shell.ShellFormatter() + c = ('a', 'foo-bar', 'provider:network_type') + d = (True, 'baz', 'vxlan') + expected = 'a="True"\nfoo_bar="baz"\nprovider_network_type="vxlan"\n' + output = six.StringIO() + args = mock.Mock() + args.variables = ['a', 'foo-bar', 'provider:network_type'] + args.prefix = '' + sf.emit_one(c, d, output, args) + actual = output.getvalue() + self.assertEqual(expected, actual) diff --git a/cliff/tests/test_formatters_table.py b/cliff/tests/test_formatters_table.py index 7e8cf97a..e1b2f09a 100644 --- a/cliff/tests/test_formatters_table.py +++ b/cliff/tests/test_formatters_table.py @@ -12,12 +12,15 @@ # License for the specific language governing permissions and limitations # under the License. +import argparse +import os +import textwrap + import mock from six import StringIO -import os -import argparse from cliff.formatters import table +from cliff.tests import base from cliff.tests import test_columns @@ -61,487 +64,548 @@ def _table_tester_helper(tags, data, extra_args=None): return output.getvalue() -@mock.patch('cliff.utils.terminal_width') -def test_table_formatter(tw): - tw.return_value = 80 - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', 'test\rcarriage\r\nreturn') - expected = '''\ -+-------+---------------+ -| Field | Value | -+-------+---------------+ -| a | A | -| b | B | -| c | C | -| d | test carriage | -| | return | -+-------+---------------+ -''' - assert expected == _table_tester_helper(c, d) - - -# Multi-line output when width is restricted to 42 columns -expected_ml_val = '''\ -+-------+--------------------------------+ -| Field | Value | -+-------+--------------------------------+ -| a | A | -| b | B | -| c | C | -| d | dddddddddddddddddddddddddddddd | -| | dddddddddddddddddddddddddddddd | -| | ddddddddddddddddd | -+-------+--------------------------------+ -''' - -# Multi-line output when width is restricted to 80 columns -expected_ml_80_val = '''\ -+-------+----------------------------------------------------------------------+ -| Field | Value | -+-------+----------------------------------------------------------------------+ -| a | A | -| b | B | -| c | C | -| d | dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd | -| | ddddddddd | -+-------+----------------------------------------------------------------------+ -''' # noqa - -# Single-line output, for when no line length restriction apply -expected_sl_val = '''\ -+-------+-------------------------------------------------------------------------------+ -| Field | Value | -+-------+-------------------------------------------------------------------------------+ -| a | A | -| b | B | -| c | C | -| d | ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd | -+-------+-------------------------------------------------------------------------------+ -''' # noqa - - -@mock.patch('cliff.utils.terminal_width') -def test_table_formatter_no_cli_param(tw): - tw.return_value = 80 - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', 'd' * 77) - assert expected_ml_80_val == _table_tester_helper(c, d, extra_args=args()) - - -@mock.patch('cliff.utils.terminal_width') -def test_table_formatter_cli_param(tw): - tw.return_value = 80 - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', 'd' * 77) - assert (expected_ml_val == - _table_tester_helper(c, d, extra_args=['--max-width', '42'])) - - -@mock.patch('cliff.utils.terminal_width') -def test_table_formatter_no_cli_param_unlimited_tw(tw): - tw.return_value = 0 - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', 'd' * 77) - # output should not be wrapped to multiple lines - assert expected_sl_val == _table_tester_helper(c, d, extra_args=args()) - - -@mock.patch('cliff.utils.terminal_width') -def test_table_formatter_cli_param_unlimited_tw(tw): - tw.return_value = 0 - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', 'd' * 77) - assert (expected_ml_val == - _table_tester_helper(c, d, extra_args=['--max-width', '42'])) - - -@mock.patch('cliff.utils.terminal_width') -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '666'}) -def test_table_formatter_cli_param_envvar_big(tw): - tw.return_value = 80 - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', 'd' * 77) - assert (expected_ml_val == - _table_tester_helper(c, d, extra_args=['--max-width', '42'])) - - -@mock.patch('cliff.utils.terminal_width') -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '23'}) -def test_table_formatter_cli_param_envvar_tiny(tw): - tw.return_value = 80 - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', 'd' * 77) - assert (expected_ml_val == - _table_tester_helper(c, d, extra_args=['--max-width', '42'])) - - -@mock.patch('cliff.utils.terminal_width') -def test_table_formatter_max_width(tw): - tw.return_value = 80 - c = ('field_name', 'a_really_long_field_name') - d = ('the value', 'a value significantly longer than the field') - expected = '''\ -+--------------------------+---------------------------------------------+ -| Field | Value | -+--------------------------+---------------------------------------------+ -| field_name | the value | -| a_really_long_field_name | a value significantly longer than the field | -+--------------------------+---------------------------------------------+ -''' - assert expected == _table_tester_helper(c, d) - - # resize value column - tw.return_value = 70 - expected = '''\ -+--------------------------+-----------------------------------------+ -| Field | Value | -+--------------------------+-----------------------------------------+ -| field_name | the value | -| a_really_long_field_name | a value significantly longer than the | -| | field | -+--------------------------+-----------------------------------------+ -''' - assert expected == _table_tester_helper(c, d) - - # resize both columns - tw.return_value = 50 - expected = '''\ -+-----------------------+------------------------+ -| Field | Value | -+-----------------------+------------------------+ -| field_name | the value | -| a_really_long_field_n | a value significantly | -| ame | longer than the field | -+-----------------------+------------------------+ -''' - assert expected == _table_tester_helper(c, d) - - # resize all columns limited by min_width=16 - tw.return_value = 10 - expected = '''\ -+------------------+------------------+ -| Field | Value | -+------------------+------------------+ -| field_name | the value | -| a_really_long_fi | a value | -| eld_name | significantly | -| | longer than the | -| | field | -+------------------+------------------+ -''' - assert expected == _table_tester_helper(c, d) - - -@mock.patch('cliff.utils.terminal_width') -def test_table_list_formatter(tw): - tw.return_value = 80 - c = ('a', 'b', 'c') - d1 = ('A', 'B', 'C') - d2 = ('D', 'E', 'test\rcarriage\r\nreturn') - data = [d1, d2] - expected = '''\ -+---+---+---------------+ -| a | b | c | -+---+---+---------------+ -| A | B | C | -| D | E | test carriage | -| | | return | -+---+---+---------------+ -''' - assert expected == _table_tester_helper(c, data) - - -@mock.patch('cliff.utils.terminal_width') -def test_table_formatter_formattable_column(tw): - tw.return_value = 0 - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value'])) - expected = '''\ -+-------+---------------------------------------------+ -| Field | Value | -+-------+---------------------------------------------+ -| a | A | -| b | B | -| c | C | -| d | I made this string myself: ['the', 'value'] | -+-------+---------------------------------------------+ -''' - assert expected == _table_tester_helper(c, d) - - -_col_names = ('one', 'two', 'three') -_col_data = [( - 'one one one one one', - 'two two two two', - 'three three')] - -_expected_mv = { - 80: '''\ -+---------------------+-----------------+-------------+ -| one | two | three | -+---------------------+-----------------+-------------+ -| one one one one one | two two two two | three three | -+---------------------+-----------------+-------------+ -''', - - 50: '''\ -+----------------+-----------------+-------------+ -| one | two | three | -+----------------+-----------------+-------------+ -| one one one | two two two two | three three | -| one one | | | -+----------------+-----------------+-------------+ -''', - - 47: '''\ -+---------------+---------------+-------------+ -| one | two | three | -+---------------+---------------+-------------+ -| one one one | two two two | three three | -| one one | two | | -+---------------+---------------+-------------+ -''', - - 45: '''\ -+--------------+--------------+-------------+ -| one | two | three | -+--------------+--------------+-------------+ -| one one one | two two two | three three | -| one one | two | | -+--------------+--------------+-------------+ -''', - - 40: '''\ -+------------+------------+------------+ -| one | two | three | -+------------+------------+------------+ -| one one | two two | three | -| one one | two two | three | -| one | | | -+------------+------------+------------+ -''', - - 10: '''\ -+----------+----------+----------+ -| one | two | three | -+----------+----------+----------+ -| one one | two two | three | -| one one | two two | three | -| one | | | -+----------+----------+----------+ -''', -} - - -@mock.patch('cliff.utils.terminal_width') -def test_table_list_formatter_formattable_column(tw): - tw.return_value = 80 - c = ('a', 'b', 'c') - d1 = ('A', 'B', test_columns.FauxColumn(['the', 'value'])) - data = [d1] - expected = '''\ -+---+---+---------------------------------------------+ -| a | b | c | -+---+---+---------------------------------------------+ -| A | B | I made this string myself: ['the', 'value'] | -+---+---+---------------------------------------------+ -''' - assert expected == _table_tester_helper(c, data) - - -@mock.patch('cliff.utils.terminal_width') -def test_table_list_formatter_max_width(tw): - # no resize - l = tw.return_value = 80 - assert _expected_mv[l] == _table_tester_helper(_col_names, _col_data) - - # resize 1 column - l = tw.return_value = 50 - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[l] == actual - assert len(actual.splitlines()[0]) == l - - # resize 2 columns - l = tw.return_value = 45 - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[l] == actual - assert len(actual.splitlines()[0]) == l - - # resize all columns - l = tw.return_value = 40 - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[l] == actual - assert len(actual.splitlines()[0]) == l - - # resize all columns limited by min_width=8 - l = tw.return_value = 10 - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[l] == actual - # 3 columns each 8 wide, plus table spacing and borders - expected_width = 11 * 3 + 1 - assert len(actual.splitlines()[0]) == expected_width - - -# Force a wide terminal by overriding its width with envvar -@mock.patch('cliff.utils.terminal_width') -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '666'}) -def test_table_list_formatter_max_width_and_envvar_max(tw): - # no resize - tw.return_value = 80 - assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data) - - # resize 1 column - tw.return_value = 50 - assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data) - - # resize 2 columns - tw.return_value = 45 - assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data) - - # resize all columns - tw.return_value = 40 - assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data) - - # resize all columns limited by min_width=8 - tw.return_value = 10 - assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data) - - -# Force a narrow terminal by overriding its width with envvar -@mock.patch('cliff.utils.terminal_width') -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '47'}) -def test_table_list_formatter_max_width_and_envvar_mid(tw): - # no resize - tw.return_value = 80 - assert _expected_mv[47] == _table_tester_helper(_col_names, _col_data) - - # resize 1 column - tw.return_value = 50 - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[47] == actual - assert len(actual.splitlines()[0]) == 47 - - # resize 2 columns - tw.return_value = 45 - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[47] == actual - assert len(actual.splitlines()[0]) == 47 - - # resize all columns - tw.return_value = 40 - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[47] == actual - assert len(actual.splitlines()[0]) == 47 - - # resize all columns limited by min_width=8 - tw.return_value = 10 - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[47] == actual - assert len(actual.splitlines()[0]) == 47 - - -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '80'}) -def test_table_list_formatter_env_maxwidth_noresize(): - # no resize - assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data) - - -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '50'}) -def test_table_list_formatter_env_maxwidth_resize_one(): - # resize 1 column - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[50] == actual - assert len(actual.splitlines()[0]) == 50 - - -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '45'}) -def test_table_list_formatter_env_maxwidth_resize_two(): - # resize 2 columns - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[45] == actual - assert len(actual.splitlines()[0]) == 45 - - -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '40'}) -def test_table_list_formatter_env_maxwidth_resize_all(): - # resize all columns - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[40] == actual - assert len(actual.splitlines()[0]) == 40 - - -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '8'}) -def test_table_list_formatter_env_maxwidth_resize_all_tiny(): - # resize all columns limited by min_width=8 - actual = _table_tester_helper(_col_names, _col_data) - assert _expected_mv[10] == actual - # 3 columns each 8 wide, plus table spacing and borders - expected_width = 11 * 3 + 1 - assert len(actual.splitlines()[0]) == expected_width - - -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '42'}) -def test_table_list_formatter_env_maxwidth_args_big(): - assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data, - extra_args=args(666)) - - -@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '42'}) -def test_table_list_formatter_env_maxwidth_args_tiny(): - assert _expected_mv[40] == _table_tester_helper(_col_names, _col_data, - extra_args=args(40)) - - -@mock.patch('cliff.utils.terminal_width') -def test_table_list_formatter_empty(tw): - tw.return_value = 80 - c = ('a', 'b', 'c') - data = [] - expected = '\n' - assert expected == _table_tester_helper(c, data) - - -@mock.patch('cliff.utils.terminal_width') -def test_table_list_formatter_empty_table(tw): - tw.return_value = 80 - c = ('a', 'b', 'c') - data = [] - expected = '''\ -+---+---+---+ -| a | b | c | -+---+---+---+ -+---+---+---+ -''' - assert expected == _table_tester_helper(c, data, - extra_args=['--print-empty']) - - -def test_field_widths(): - tf = table.TableFormatter - assert { - 'a': 1, - 'b': 2, - 'c': 3, - 'd': 10 - } == tf._field_widths( - ('a', 'b', 'c', 'd'), - '+---+----+-----+------------+') - - -def test_field_widths_zero(): - tf = table.TableFormatter - assert { - 'a': 0, - 'b': 0, - 'c': 0 - } == tf._field_widths( - ('a', 'b', 'c'), - '+--+-++') - - -def test_width_info(): - tf = table.TableFormatter - assert (49, 4) == (tf._width_info(80, 10)) - assert (76, 76) == (tf._width_info(80, 1)) - assert (79, 0) == (tf._width_info(80, 0)) - assert (0, 0) == (tf._width_info(0, 80)) +class TestTableFormatter(base.TestBase): + + @mock.patch('cliff.utils.terminal_width') + def test(self, tw): + tw.return_value = 80 + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', 'test\rcarriage\r\nreturn') + expected = textwrap.dedent('''\ + +-------+---------------+ + | Field | Value | + +-------+---------------+ + | a | A | + | b | B | + | c | C | + | d | test carriage | + | | return | + +-------+---------------+ + ''') + self.assertEqual(expected, _table_tester_helper(c, d)) + + +class TestTerminalWidth(base.TestBase): + + # Multi-line output when width is restricted to 42 columns + expected_ml_val = textwrap.dedent('''\ + +-------+--------------------------------+ + | Field | Value | + +-------+--------------------------------+ + | a | A | + | b | B | + | c | C | + | d | dddddddddddddddddddddddddddddd | + | | dddddddddddddddddddddddddddddd | + | | ddddddddddddddddd | + +-------+--------------------------------+ + ''') + + # Multi-line output when width is restricted to 80 columns + expected_ml_80_val = textwrap.dedent('''\ + +-------+----------------------------------------------------------------------+ + | Field | Value | + +-------+----------------------------------------------------------------------+ + | a | A | + | b | B | + | c | C | + | d | dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd | + | | ddddddddd | + +-------+----------------------------------------------------------------------+ + ''') # noqa + + # Single-line output, for when no line length restriction apply + expected_sl_val = textwrap.dedent('''\ + +-------+-------------------------------------------------------------------------------+ + | Field | Value | + +-------+-------------------------------------------------------------------------------+ + | a | A | + | b | B | + | c | C | + | d | ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd | + +-------+-------------------------------------------------------------------------------+ + ''') # noqa + + @mock.patch('cliff.utils.terminal_width') + def test_table_formatter_no_cli_param(self, tw): + tw.return_value = 80 + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', 'd' * 77) + self.assertEqual( + self.expected_ml_80_val, + _table_tester_helper(c, d, extra_args=args()), + ) + + @mock.patch('cliff.utils.terminal_width') + def test_table_formatter_cli_param(self, tw): + tw.return_value = 80 + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', 'd' * 77) + self.assertEqual( + self.expected_ml_val, + _table_tester_helper(c, d, extra_args=['--max-width', '42']), + ) + + @mock.patch('cliff.utils.terminal_width') + def test_table_formatter_no_cli_param_unlimited_tw(self, tw): + tw.return_value = 0 + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', 'd' * 77) + # output should not be wrapped to multiple lines + self.assertEqual( + self.expected_sl_val, + _table_tester_helper(c, d, extra_args=args()), + ) + + @mock.patch('cliff.utils.terminal_width') + def test_table_formatter_cli_param_unlimited_tw(self, tw): + tw.return_value = 0 + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', 'd' * 77) + self.assertEqual( + self.expected_ml_val, + _table_tester_helper(c, d, extra_args=['--max-width', '42']), + ) + + @mock.patch('cliff.utils.terminal_width') + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '666'}) + def test_table_formatter_cli_param_envvar_big(self, tw): + tw.return_value = 80 + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', 'd' * 77) + self.assertEqual( + self.expected_ml_val, + _table_tester_helper(c, d, extra_args=['--max-width', '42']), + ) + + @mock.patch('cliff.utils.terminal_width') + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '23'}) + def test_table_formatter_cli_param_envvar_tiny(self, tw): + tw.return_value = 80 + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', 'd' * 77) + self.assertEqual( + self.expected_ml_val, + _table_tester_helper(c, d, extra_args=['--max-width', '42']), + ) + + +class TestMaxWidth(base.TestBase): + + expected_80 = textwrap.dedent('''\ + +--------------------------+---------------------------------------------+ + | Field | Value | + +--------------------------+---------------------------------------------+ + | field_name | the value | + | a_really_long_field_name | a value significantly longer than the field | + +--------------------------+---------------------------------------------+ + ''') + + @mock.patch('cliff.utils.terminal_width') + def test_80(self, tw): + tw.return_value = 80 + c = ('field_name', 'a_really_long_field_name') + d = ('the value', 'a value significantly longer than the field') + self.assertEqual(self.expected_80, _table_tester_helper(c, d)) + + @mock.patch('cliff.utils.terminal_width') + def test_70(self, tw): + # resize value column + tw.return_value = 70 + c = ('field_name', 'a_really_long_field_name') + d = ('the value', 'a value significantly longer than the field') + expected = textwrap.dedent('''\ + +--------------------------+-----------------------------------------+ + | Field | Value | + +--------------------------+-----------------------------------------+ + | field_name | the value | + | a_really_long_field_name | a value significantly longer than the | + | | field | + +--------------------------+-----------------------------------------+ + ''') + self.assertEqual(expected, _table_tester_helper(c, d)) + + @mock.patch('cliff.utils.terminal_width') + def test_50(self, tw): + # resize both columns + tw.return_value = 50 + c = ('field_name', 'a_really_long_field_name') + d = ('the value', 'a value significantly longer than the field') + expected = textwrap.dedent('''\ + +-----------------------+------------------------+ + | Field | Value | + +-----------------------+------------------------+ + | field_name | the value | + | a_really_long_field_n | a value significantly | + | ame | longer than the field | + +-----------------------+------------------------+ + ''') + self.assertEqual(expected, _table_tester_helper(c, d)) + + @mock.patch('cliff.utils.terminal_width') + def test_10(self, tw): + # resize all columns limited by min_width=16 + tw.return_value = 10 + c = ('field_name', 'a_really_long_field_name') + d = ('the value', 'a value significantly longer than the field') + expected = textwrap.dedent('''\ + +------------------+------------------+ + | Field | Value | + +------------------+------------------+ + | field_name | the value | + | a_really_long_fi | a value | + | eld_name | significantly | + | | longer than the | + | | field | + +------------------+------------------+ + ''') + self.assertEqual(expected, _table_tester_helper(c, d)) + + +class TestListFormatter(base.TestBase): + + _col_names = ('one', 'two', 'three') + _col_data = [( + 'one one one one one', + 'two two two two', + 'three three')] + + _expected_mv = { + 80: textwrap.dedent('''\ + +---------------------+-----------------+-------------+ + | one | two | three | + +---------------------+-----------------+-------------+ + | one one one one one | two two two two | three three | + +---------------------+-----------------+-------------+ + '''), + + 50: textwrap.dedent('''\ + +----------------+-----------------+-------------+ + | one | two | three | + +----------------+-----------------+-------------+ + | one one one | two two two two | three three | + | one one | | | + +----------------+-----------------+-------------+ + '''), + + 47: textwrap.dedent('''\ + +---------------+---------------+-------------+ + | one | two | three | + +---------------+---------------+-------------+ + | one one one | two two two | three three | + | one one | two | | + +---------------+---------------+-------------+ + '''), + + 45: textwrap.dedent('''\ + +--------------+--------------+-------------+ + | one | two | three | + +--------------+--------------+-------------+ + | one one one | two two two | three three | + | one one | two | | + +--------------+--------------+-------------+ + '''), + + 40: textwrap.dedent('''\ + +------------+------------+------------+ + | one | two | three | + +------------+------------+------------+ + | one one | two two | three | + | one one | two two | three | + | one | | | + +------------+------------+------------+ + '''), + + 10: textwrap.dedent('''\ + +----------+----------+----------+ + | one | two | three | + +----------+----------+----------+ + | one one | two two | three | + | one one | two two | three | + | one | | | + +----------+----------+----------+ + '''), + } + + @mock.patch('cliff.utils.terminal_width') + def test_table_list_formatter(self, tw): + tw.return_value = 80 + c = ('a', 'b', 'c') + d1 = ('A', 'B', 'C') + d2 = ('D', 'E', 'test\rcarriage\r\nreturn') + data = [d1, d2] + expected = textwrap.dedent('''\ + +---+---+---------------+ + | a | b | c | + +---+---+---------------+ + | A | B | C | + | D | E | test carriage | + | | | return | + +---+---+---------------+ + ''') + self.assertEqual(expected, _table_tester_helper(c, data)) + + @mock.patch('cliff.utils.terminal_width') + def test_table_formatter_formattable_column(self, tw): + tw.return_value = 0 + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value'])) + expected = textwrap.dedent('''\ + +-------+---------------------------------------------+ + | Field | Value | + +-------+---------------------------------------------+ + | a | A | + | b | B | + | c | C | + | d | I made this string myself: ['the', 'value'] | + +-------+---------------------------------------------+ + ''') + self.assertEqual(expected, _table_tester_helper(c, d)) + + @mock.patch('cliff.utils.terminal_width') + def test_formattable_column(self, tw): + tw.return_value = 80 + c = ('a', 'b', 'c') + d1 = ('A', 'B', test_columns.FauxColumn(['the', 'value'])) + data = [d1] + expected = textwrap.dedent('''\ + +---+---+---------------------------------------------+ + | a | b | c | + +---+---+---------------------------------------------+ + | A | B | I made this string myself: ['the', 'value'] | + +---+---+---------------------------------------------+ + ''') + self.assertEqual(expected, _table_tester_helper(c, data)) + + @mock.patch('cliff.utils.terminal_width') + def test_max_width_80(self, tw): + # no resize + l = tw.return_value = 80 + self.assertEqual( + self._expected_mv[l], + _table_tester_helper(self._col_names, self._col_data), + ) + + @mock.patch('cliff.utils.terminal_width') + def test_max_width_50(self, tw): + # resize 1 column + l = tw.return_value = 50 + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[l], actual) + self.assertEqual(l, len(actual.splitlines()[0])) + + @mock.patch('cliff.utils.terminal_width') + def test_max_width_45(self, tw): + # resize 2 columns + l = tw.return_value = 45 + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[l], actual) + self.assertEqual(l, len(actual.splitlines()[0])) + + @mock.patch('cliff.utils.terminal_width') + def test_max_width_40(self, tw): + # resize all columns + l = tw.return_value = 40 + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[l], actual) + self.assertEqual(l, len(actual.splitlines()[0])) + + @mock.patch('cliff.utils.terminal_width') + def test_max_width_10(self, tw): + # resize all columns limited by min_width=8 + l = tw.return_value = 10 + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[l], actual) + # 3 columns each 8 wide, plus table spacing and borders + expected_width = 11 * 3 + 1 + self.assertEqual(expected_width, len(actual.splitlines()[0])) + + # Force a wide terminal by overriding its width with envvar + @mock.patch('cliff.utils.terminal_width') + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '666'}) + def test_max_width_and_envvar_max(self, tw): + # no resize + tw.return_value = 80 + self.assertEqual( + self._expected_mv[80], + _table_tester_helper(self._col_names, self._col_data), + ) + + # resize 1 column + tw.return_value = 50 + self.assertEqual( + self._expected_mv[80], + _table_tester_helper(self._col_names, self._col_data), + ) + + # resize 2 columns + tw.return_value = 45 + self.assertEqual( + self._expected_mv[80], + _table_tester_helper(self._col_names, self._col_data), + ) + + # resize all columns + tw.return_value = 40 + self.assertEqual( + self._expected_mv[80], + _table_tester_helper(self._col_names, self._col_data), + ) + + # resize all columns limited by min_width=8 + tw.return_value = 10 + self.assertEqual( + self._expected_mv[80], + _table_tester_helper(self._col_names, self._col_data), + ) + + # Force a narrow terminal by overriding its width with envvar + @mock.patch('cliff.utils.terminal_width') + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '47'}) + def test_max_width_and_envvar_mid(self, tw): + # no resize + tw.return_value = 80 + self.assertEqual( + self._expected_mv[47], + _table_tester_helper(self._col_names, self._col_data), + ) + + # resize 1 column + tw.return_value = 50 + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[47], actual) + self.assertEqual(47, len(actual.splitlines()[0])) + + # resize 2 columns + tw.return_value = 45 + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[47], actual) + self.assertEqual(47, len(actual.splitlines()[0])) + + # resize all columns + tw.return_value = 40 + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[47], actual) + self.assertEqual(47, len(actual.splitlines()[0])) + + # resize all columns limited by min_width=8 + tw.return_value = 10 + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[47], actual) + self.assertEqual(47, len(actual.splitlines()[0])) + + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '80'}) + def test_env_maxwidth_noresize(self): + # no resize + self.assertEqual( + self._expected_mv[80], + _table_tester_helper(self._col_names, self._col_data), + ) + + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '50'}) + def test_env_maxwidth_resize_one(self): + # resize 1 column + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[50], actual) + self.assertEqual(50, len(actual.splitlines()[0])) + + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '45'}) + def test_env_maxwidth_resize_two(self): + # resize 2 columns + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[45], actual) + self.assertEqual(45, len(actual.splitlines()[0])) + + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '40'}) + def test_env_maxwidth_resize_all(self): + # resize all columns + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[40], actual) + self.assertEqual(40, len(actual.splitlines()[0])) + + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '8'}) + def test_env_maxwidth_resize_all_tiny(self): + # resize all columns limited by min_width=8 + actual = _table_tester_helper(self._col_names, self._col_data) + self.assertEqual(self._expected_mv[10], actual) + # 3 columns each 8 wide, plus table spacing and borders + expected_width = 11 * 3 + 1 + self.assertEqual(expected_width, len(actual.splitlines()[0])) + + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '42'}) + def test_env_maxwidth_args_big(self): + self.assertEqual( + self._expected_mv[80], + _table_tester_helper(self._col_names, self._col_data, + extra_args=args(666)), + ) + + @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '42'}) + def test_env_maxwidth_args_tiny(self): + self.assertEqual( + self._expected_mv[40], + _table_tester_helper(self._col_names, self._col_data, + extra_args=args(40)), + ) + + @mock.patch('cliff.utils.terminal_width') + def test_empty(self, tw): + tw.return_value = 80 + c = ('a', 'b', 'c') + data = [] + expected = '\n' + self.assertEqual(expected, _table_tester_helper(c, data)) + + @mock.patch('cliff.utils.terminal_width') + def test_empty_table(self, tw): + tw.return_value = 80 + c = ('a', 'b', 'c') + data = [] + expected = textwrap.dedent('''\ + +---+---+---+ + | a | b | c | + +---+---+---+ + +---+---+---+ + ''') + self.assertEqual( + expected, + _table_tester_helper(c, data, + extra_args=['--print-empty']), + ) + + +class TestFieldWidths(base.TestBase): + + def test(self): + tf = table.TableFormatter + self.assertEqual( + { + 'a': 1, + 'b': 2, + 'c': 3, + 'd': 10 + }, + tf._field_widths( + ('a', 'b', 'c', 'd'), + '+---+----+-----+------------+'), + ) + + def test_zero(self): + tf = table.TableFormatter + self.assertEqual( + { + 'a': 0, + 'b': 0, + 'c': 0 + }, + tf._field_widths( + ('a', 'b', 'c'), + '+--+-++'), + ) + + def test_info(self): + tf = table.TableFormatter + self.assertEqual((49, 4), (tf._width_info(80, 10))) + self.assertEqual((76, 76), (tf._width_info(80, 1))) + self.assertEqual((79, 0), (tf._width_info(80, 0))) + self.assertEqual((0, 0), (tf._width_info(0, 80))) diff --git a/cliff/tests/test_formatters_value.py b/cliff/tests/test_formatters_value.py index f704b08c..6053dd31 100644 --- a/cliff/tests/test_formatters_value.py +++ b/cliff/tests/test_formatters_value.py @@ -15,51 +15,51 @@ import six from cliff.formatters import value +from cliff.tests import base from cliff.tests import test_columns -def test_value_formatter(): - sf = value.ValueFormatter() - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', '"no escape me"') - expected = 'A\nB\nC\n"no escape me"\n' - output = six.StringIO() - sf.emit_one(c, d, output, None) - actual = output.getvalue() - assert expected == actual +class TestValueFormatter(base.TestBase): + def test(self): + sf = value.ValueFormatter() + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', '"no escape me"') + expected = 'A\nB\nC\n"no escape me"\n' + output = six.StringIO() + sf.emit_one(c, d, output, None) + actual = output.getvalue() + self.assertEqual(expected, actual) -def test_value_formatter_formattable_column(): - sf = value.ValueFormatter() - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value'])) - expected = "A\nB\nC\n['the', 'value']\n" - output = six.StringIO() - sf.emit_one(c, d, output, None) - actual = output.getvalue() - assert expected == actual + def test_formattable_column(self): + sf = value.ValueFormatter() + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value'])) + expected = "A\nB\nC\n['the', 'value']\n" + output = six.StringIO() + sf.emit_one(c, d, output, None) + actual = output.getvalue() + self.assertEqual(expected, actual) + def test_list_formatter(self): + sf = value.ValueFormatter() + c = ('a', 'b', 'c') + d1 = ('A', 'B', 'C') + d2 = ('D', 'E', 'F') + data = [d1, d2] + expected = 'A B C\nD E F\n' + output = six.StringIO() + sf.emit_list(c, data, output, None) + actual = output.getvalue() + self.assertEqual(expected, actual) -def test_value_list_formatter(): - sf = value.ValueFormatter() - c = ('a', 'b', 'c') - d1 = ('A', 'B', 'C') - d2 = ('D', 'E', 'F') - data = [d1, d2] - expected = 'A B C\nD E F\n' - output = six.StringIO() - sf.emit_list(c, data, output, None) - actual = output.getvalue() - assert expected == actual - - -def test_value_list_formatter_formattable_column(): - sf = value.ValueFormatter() - c = ('a', 'b', 'c') - d1 = ('A', 'B', test_columns.FauxColumn(['the', 'value'])) - data = [d1] - expected = "A B ['the', 'value']\n" - output = six.StringIO() - sf.emit_list(c, data, output, None) - actual = output.getvalue() - assert expected == actual + def test_list_formatter_formattable_column(self): + sf = value.ValueFormatter() + c = ('a', 'b', 'c') + d1 = ('A', 'B', test_columns.FauxColumn(['the', 'value'])) + data = [d1] + expected = "A B ['the', 'value']\n" + output = six.StringIO() + sf.emit_list(c, data, output, None) + actual = output.getvalue() + self.assertEqual(expected, actual) diff --git a/cliff/tests/test_formatters_yaml.py b/cliff/tests/test_formatters_yaml.py index 61db5d85..b6147d85 100644 --- a/cliff/tests/test_formatters_yaml.py +++ b/cliff/tests/test_formatters_yaml.py @@ -16,85 +16,85 @@ import six import yaml from cliff.formatters import yaml_format +from cliff.tests import base from cliff.tests import test_columns import mock -def test_yaml_format_one(): - sf = yaml_format.YAMLFormatter() - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', '"escape me"') - expected = { - 'a': 'A', - 'b': 'B', - 'c': 'C', - 'd': '"escape me"' - } - output = six.StringIO() - args = mock.Mock() - sf.emit_one(c, d, output, args) - actual = yaml.safe_load(output.getvalue()) - assert expected == actual +class TestYAMLFormatter(base.TestBase): + def test_format_one(self): + sf = yaml_format.YAMLFormatter() + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', '"escape me"') + expected = { + 'a': 'A', + 'b': 'B', + 'c': 'C', + 'd': '"escape me"' + } + output = six.StringIO() + args = mock.Mock() + sf.emit_one(c, d, output, args) + actual = yaml.safe_load(output.getvalue()) + self.assertEqual(expected, actual) -def test_yaml_format_formattablecolumn_one(): - sf = yaml_format.YAMLFormatter() - c = ('a', 'b', 'c', 'd') - d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value'])) - expected = { - 'a': 'A', - 'b': 'B', - 'c': 'C', - 'd': ['the', 'value'], - } - args = mock.Mock() - sf.add_argument_group(args) + def test_formattablecolumn_one(self): + sf = yaml_format.YAMLFormatter() + c = ('a', 'b', 'c', 'd') + d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value'])) + expected = { + 'a': 'A', + 'b': 'B', + 'c': 'C', + 'd': ['the', 'value'], + } + args = mock.Mock() + sf.add_argument_group(args) - args.noindent = True - output = six.StringIO() - sf.emit_one(c, d, output, args) - value = output.getvalue() - print(len(value.splitlines())) - actual = yaml.safe_load(output.getvalue()) - assert expected == actual + args.noindent = True + output = six.StringIO() + sf.emit_one(c, d, output, args) + value = output.getvalue() + print(len(value.splitlines())) + actual = yaml.safe_load(output.getvalue()) + self.assertEqual(expected, actual) + def test_list(self): + sf = yaml_format.YAMLFormatter() + c = ('a', 'b', 'c') + d = ( + ('A1', 'B1', 'C1'), + ('A2', 'B2', 'C2'), + ('A3', 'B3', 'C3') + ) + expected = [ + {'a': 'A1', 'b': 'B1', 'c': 'C1'}, + {'a': 'A2', 'b': 'B2', 'c': 'C2'}, + {'a': 'A3', 'b': 'B3', 'c': 'C3'} + ] + output = six.StringIO() + args = mock.Mock() + sf.add_argument_group(args) + sf.emit_list(c, d, output, args) + actual = yaml.safe_load(output.getvalue()) + self.assertEqual(expected, actual) -def test_yaml_format_list(): - sf = yaml_format.YAMLFormatter() - c = ('a', 'b', 'c') - d = ( - ('A1', 'B1', 'C1'), - ('A2', 'B2', 'C2'), - ('A3', 'B3', 'C3') - ) - expected = [ - {'a': 'A1', 'b': 'B1', 'c': 'C1'}, - {'a': 'A2', 'b': 'B2', 'c': 'C2'}, - {'a': 'A3', 'b': 'B3', 'c': 'C3'} - ] - output = six.StringIO() - args = mock.Mock() - sf.add_argument_group(args) - sf.emit_list(c, d, output, args) - actual = yaml.safe_load(output.getvalue()) - assert expected == actual + def test_formattablecolumn_list(self): + sf = yaml_format.YAMLFormatter() + c = ('a', 'b', 'c') + d = ( + ('A1', 'B1', test_columns.FauxColumn(['the', 'value'])), + ) + expected = [ + {'a': 'A1', 'b': 'B1', 'c': ['the', 'value']}, + ] + args = mock.Mock() + sf.add_argument_group(args) - -def test_yaml_format_formattablecolumn_list(): - sf = yaml_format.YAMLFormatter() - c = ('a', 'b', 'c') - d = ( - ('A1', 'B1', test_columns.FauxColumn(['the', 'value'])), - ) - expected = [ - {'a': 'A1', 'b': 'B1', 'c': ['the', 'value']}, - ] - args = mock.Mock() - sf.add_argument_group(args) - - args.noindent = True - output = six.StringIO() - sf.emit_list(c, d, output, args) - actual = yaml.safe_load(output.getvalue()) - assert expected == actual + args.noindent = True + output = six.StringIO() + sf.emit_list(c, d, output, args) + actual = yaml.safe_load(output.getvalue()) + self.assertEqual(expected, actual) diff --git a/cliff/tests/test_help.py b/cliff/tests/test_help.py index 23659a27..8b66fbed 100644 --- a/cliff/tests/test_help.py +++ b/cliff/tests/test_help.py @@ -22,159 +22,153 @@ import mock from cliff import app as application from cliff import commandmanager from cliff import help +from cliff.tests import base from cliff.tests import utils -def test_show_help_for_command(): - # FIXME(dhellmann): Are commands tied too closely to the app? Or - # do commands know too much about apps by using them to get to the - # command manager? - stdout = StringIO() - app = application.App('testing', '1', - utils.TestCommandManager(utils.TEST_NAMESPACE), - stdout=stdout) - app.NAME = 'test' - help_cmd = help.HelpCommand(app, mock.Mock()) - parser = help_cmd.get_parser('test') - parsed_args = parser.parse_args(['one']) - try: - help_cmd.run(parsed_args) - except SystemExit: - pass - assert stdout.getvalue() == 'TestParser' +class TestHelp(base.TestBase): + def test_show_help_for_command(self): + # FIXME(dhellmann): Are commands tied too closely to the app? Or + # do commands know too much about apps by using them to get to the + # command manager? + stdout = StringIO() + app = application.App('testing', '1', + utils.TestCommandManager(utils.TEST_NAMESPACE), + stdout=stdout) + app.NAME = 'test' + help_cmd = help.HelpCommand(app, mock.Mock()) + parser = help_cmd.get_parser('test') + parsed_args = parser.parse_args(['one']) + try: + help_cmd.run(parsed_args) + except SystemExit: + pass + self.assertEqual('TestParser', stdout.getvalue()) -def test_list_matching_commands(): - # FIXME(dhellmann): Are commands tied too closely to the app? Or - # do commands know too much about apps by using them to get to the - # command manager? - stdout = StringIO() - app = application.App('testing', '1', - utils.TestCommandManager(utils.TEST_NAMESPACE), - stdout=stdout) - app.NAME = 'test' - help_cmd = help.HelpCommand(app, mock.Mock()) - parser = help_cmd.get_parser('test') - parsed_args = parser.parse_args(['t']) - try: - help_cmd.run(parsed_args) - except SystemExit: - pass - help_output = stdout.getvalue() - assert 'Command "t" matches:' in help_output - assert 'three word command\n two words\n' in help_output + def test_list_matching_commands(self): + # FIXME(dhellmann): Are commands tied too closely to the app? Or + # do commands know too much about apps by using them to get to the + # command manager? + stdout = StringIO() + app = application.App('testing', '1', + utils.TestCommandManager(utils.TEST_NAMESPACE), + stdout=stdout) + app.NAME = 'test' + help_cmd = help.HelpCommand(app, mock.Mock()) + parser = help_cmd.get_parser('test') + parsed_args = parser.parse_args(['t']) + try: + help_cmd.run(parsed_args) + except SystemExit: + pass + help_output = stdout.getvalue() + self.assertIn('Command "t" matches:', help_output) + self.assertIn('three word command\n two words\n', help_output) + def test_list_matching_commands_no_match(self): + # FIXME(dhellmann): Are commands tied too closely to the app? Or + # do commands know too much about apps by using them to get to the + # command manager? + stdout = StringIO() + app = application.App('testing', '1', + utils.TestCommandManager(utils.TEST_NAMESPACE), + stdout=stdout) + app.NAME = 'test' + help_cmd = help.HelpCommand(app, mock.Mock()) + parser = help_cmd.get_parser('test') + parsed_args = parser.parse_args(['z']) + self.assertRaises( + ValueError, + help_cmd.run, + parsed_args, + ) -def test_list_matching_commands_no_match(): - # FIXME(dhellmann): Are commands tied too closely to the app? Or - # do commands know too much about apps by using them to get to the - # command manager? - stdout = StringIO() - app = application.App('testing', '1', - utils.TestCommandManager(utils.TEST_NAMESPACE), - stdout=stdout) - app.NAME = 'test' - help_cmd = help.HelpCommand(app, mock.Mock()) - parser = help_cmd.get_parser('test') - parsed_args = parser.parse_args(['z']) - try: - help_cmd.run(parsed_args) - except SystemExit: - pass - except ValueError: - pass - else: - assert False, 'Should have seen a ValueError' + def test_show_help_for_help(self): + # FIXME(dhellmann): Are commands tied too closely to the app? Or + # do commands know too much about apps by using them to get to the + # command manager? + stdout = StringIO() + app = application.App('testing', '1', + utils.TestCommandManager(utils.TEST_NAMESPACE), + stdout=stdout) + app.NAME = 'test' + app.options = mock.Mock() + help_cmd = help.HelpCommand(app, mock.Mock()) + parser = help_cmd.get_parser('test') + parsed_args = parser.parse_args([]) + try: + help_cmd.run(parsed_args) + except SystemExit: + pass + help_text = stdout.getvalue() + basecommand = os.path.split(sys.argv[0])[1] + self.assertIn('usage: %s [--version]' % basecommand, help_text) + self.assertIn('optional arguments:\n --version', help_text) + expected = ( + ' one Test command.\n' + ' three word command Test command.\n' + ) + self.assertIn(expected, help_text) + def test_list_deprecated_commands(self): + # FIXME(dhellmann): Are commands tied too closely to the app? Or + # do commands know too much about apps by using them to get to the + # command manager? + stdout = StringIO() + app = application.App('testing', '1', + utils.TestCommandManager(utils.TEST_NAMESPACE), + stdout=stdout) + app.NAME = 'test' + try: + app.run(['--help']) + except SystemExit: + pass + help_output = stdout.getvalue() + self.assertIn('two words', help_output) + self.assertIn('three word command', help_output) + self.assertNotIn('old cmd', help_output) -def test_show_help_for_help(): - # FIXME(dhellmann): Are commands tied too closely to the app? Or - # do commands know too much about apps by using them to get to the - # command manager? - stdout = StringIO() - app = application.App('testing', '1', - utils.TestCommandManager(utils.TEST_NAMESPACE), - stdout=stdout) - app.NAME = 'test' - app.options = mock.Mock() - help_cmd = help.HelpCommand(app, mock.Mock()) - parser = help_cmd.get_parser('test') - parsed_args = parser.parse_args([]) - try: - help_cmd.run(parsed_args) - except SystemExit: - pass - help_text = stdout.getvalue() - basecommand = os.path.split(sys.argv[0])[1] - assert 'usage: %s [--version]' % basecommand in help_text - assert 'optional arguments:\n --version' in help_text - expected = ( - ' one Test command.\n' - ' three word command Test command.\n' - ) - assert expected in help_text + @mock.patch.object(commandmanager.EntryPointWrapper, 'load', + side_effect=Exception('Could not load EntryPoint')) + def test_show_help_with_ep_load_fail(self, mock_load): + stdout = StringIO() + app = application.App('testing', '1', + utils.TestCommandManager(utils.TEST_NAMESPACE), + stdout=stdout) + app.NAME = 'test' + app.options = mock.Mock() + app.options.debug = False + help_cmd = help.HelpCommand(app, mock.Mock()) + parser = help_cmd.get_parser('test') + parsed_args = parser.parse_args([]) + try: + help_cmd.run(parsed_args) + except SystemExit: + pass + help_output = stdout.getvalue() + self.assertIn('Commands:', help_output) + self.assertIn('Could not load', help_output) + self.assertNotIn('Exception: Could not load EntryPoint', help_output) - -def test_list_deprecated_commands(): - # FIXME(dhellmann): Are commands tied too closely to the app? Or - # do commands know too much about apps by using them to get to the - # command manager? - stdout = StringIO() - app = application.App('testing', '1', - utils.TestCommandManager(utils.TEST_NAMESPACE), - stdout=stdout) - app.NAME = 'test' - try: - app.run(['--help']) - except SystemExit: - pass - help_output = stdout.getvalue() - assert 'two words' in help_output - assert 'three word command' in help_output - assert 'old cmd' not in help_output - - -@mock.patch.object(commandmanager.EntryPointWrapper, 'load', - side_effect=Exception('Could not load EntryPoint')) -def test_show_help_with_ep_load_fail(mock_load): - stdout = StringIO() - app = application.App('testing', '1', - utils.TestCommandManager(utils.TEST_NAMESPACE), - stdout=stdout) - app.NAME = 'test' - app.options = mock.Mock() - app.options.debug = False - help_cmd = help.HelpCommand(app, mock.Mock()) - parser = help_cmd.get_parser('test') - parsed_args = parser.parse_args([]) - try: - help_cmd.run(parsed_args) - except SystemExit: - pass - help_output = stdout.getvalue() - assert 'Commands:' in help_output - assert 'Could not load' in help_output - assert 'Exception: Could not load EntryPoint' not in help_output - - -@mock.patch.object(commandmanager.EntryPointWrapper, 'load', - side_effect=Exception('Could not load EntryPoint')) -def test_show_help_print_exc_with_ep_load_fail(mock_load): - stdout = StringIO() - app = application.App('testing', '1', - utils.TestCommandManager(utils.TEST_NAMESPACE), - stdout=stdout) - app.NAME = 'test' - app.options = mock.Mock() - app.options.debug = True - help_cmd = help.HelpCommand(app, mock.Mock()) - parser = help_cmd.get_parser('test') - parsed_args = parser.parse_args([]) - try: - help_cmd.run(parsed_args) - except SystemExit: - pass - help_output = stdout.getvalue() - assert 'Commands:' in help_output - assert 'Could not load' in help_output - assert 'Exception: Could not load EntryPoint' in help_output + @mock.patch.object(commandmanager.EntryPointWrapper, 'load', + side_effect=Exception('Could not load EntryPoint')) + def test_show_help_print_exc_with_ep_load_fail(self, mock_load): + stdout = StringIO() + app = application.App('testing', '1', + utils.TestCommandManager(utils.TEST_NAMESPACE), + stdout=stdout) + app.NAME = 'test' + app.options = mock.Mock() + app.options.debug = True + help_cmd = help.HelpCommand(app, mock.Mock()) + parser = help_cmd.get_parser('test') + parsed_args = parser.parse_args([]) + try: + help_cmd.run(parsed_args) + except SystemExit: + pass + help_output = stdout.getvalue() + self.assertIn('Commands:', help_output) + self.assertIn('Could not load', help_output) + self.assertIn('Exception: Could not load EntryPoint', help_output) diff --git a/cliff/tests/test_interactive.py b/cliff/tests/test_interactive.py index c18e7b3a..8dfb5e9d 100644 --- a/cliff/tests/test_interactive.py +++ b/cliff/tests/test_interactive.py @@ -15,69 +15,65 @@ import cmd2 from cliff.interactive import InteractiveApp +from cliff.tests import base class FakeApp(object): NAME = 'Fake' -def make_interactive_app(*command_names): - fake_command_manager = [(x, None) for x in command_names] - return InteractiveApp(FakeApp, fake_command_manager, - stdin=None, stdout=None) +class TestInteractive(base.TestBase): + def make_interactive_app(self, *command_names): + fake_command_manager = [(x, None) for x in command_names] + return InteractiveApp(FakeApp, fake_command_manager, + stdin=None, stdout=None) -def _test_completenames(expecteds, prefix): - app = make_interactive_app('hips', 'hippo', 'nonmatching') - assert set(app.completenames(prefix)) == set(expecteds) + def _test_completenames(self, expecteds, prefix): + app = self.make_interactive_app('hips', 'hippo', 'nonmatching') + self.assertEqual(set(app.completenames(prefix)), set(expecteds)) + def test_cmd2_completenames(self): + # cmd2.Cmd define do_help method + self._test_completenames(['help'], 'he') -def test_cmd2_completenames(): - # cmd2.Cmd define do_help method - _test_completenames(['help'], 'he') + def test_cliff_completenames(self): + self._test_completenames(['hips', 'hippo'], 'hip') + def test_no_completenames(self): + self._test_completenames([], 'taz') -def test_cliff_completenames(): - _test_completenames(['hips', 'hippo'], 'hip') + def test_both_completenames(self): + # cmd2.Cmd define do_history method + # NOTE(dtroyer): Before release 0.7.0 do_hi was also defined so we need + # to account for that in the list of possible responses. + # Remove this check after cmd2 0.7.0 is the minimum + # requirement. + if hasattr(cmd2.Cmd, "do_hi"): + self._test_completenames(['hi', 'history', 'hips', 'hippo'], 'hi') + else: + self._test_completenames(['history', 'hips', 'hippo'], 'hi') + def _test_completedefault(self, expecteds, line, begidx): + command_names = set(['show file', 'show folder', 'show long', + 'list all']) + app = self.make_interactive_app(*command_names) + observeds = app.completedefault(None, line, begidx, None) + self.assertEqual(set(expecteds), set(observeds)) + self.assertTrue( + set([line[:begidx] + x for x in observeds]) <= command_names + ) -def test_no_completenames(): - _test_completenames([], 'taz') + def test_empty_text_completedefault(self): + # line = 'show ' + begidx = 5 implies text = '' + self._test_completedefault(['file', 'folder', ' long'], 'show ', 5) + def test_nonempty_text_completedefault2(self): + # line = 'show f' + begidx = 6 implies text = 'f' + self._test_completedefault(['file', 'folder'], 'show f', 5) -def test_both_completenames(): - # cmd2.Cmd define do_history method - # NOTE(dtroyer): Before release 0.7.0 do_hi was also defined so we need - # to account for that in the list of possible responses. - # Remove this check after cmd2 0.7.0 is the minimum - # requirement. - if hasattr(cmd2.Cmd, "do_hi"): - _test_completenames(['hi', 'history', 'hips', 'hippo'], 'hi') - else: - _test_completenames(['history', 'hips', 'hippo'], 'hi') + def test_long_completedefault(self): + self._test_completedefault(['long'], 'show ', 6) - -def _test_completedefault(expecteds, line, begidx): - command_names = set(['show file', 'show folder', 'show long', 'list all']) - app = make_interactive_app(*command_names) - observeds = app.completedefault(None, line, begidx, None) - assert set(observeds) == set(expecteds) - assert set([line[:begidx] + x for x in observeds]) <= command_names - - -def test_empty_text_completedefault(): - # line = 'show ' + begidx = 5 implies text = '' - _test_completedefault(['file', 'folder', ' long'], 'show ', 5) - - -def test_nonempty_text_completedefault2(): - # line = 'show f' + begidx = 6 implies text = 'f' - _test_completedefault(['file', 'folder'], 'show f', 5) - - -def test_long_completedefault(): - _test_completedefault(['long'], 'show ', 6) - - -def test_no_completedefault(): - _test_completedefault([], 'taz ', 4) + def test_no_completedefault(self): + self._test_completedefault([], 'taz ', 4) diff --git a/cliff/tests/test_lister.py b/cliff/tests/test_lister.py index f2e4a0d7..9434ce63 100644 --- a/cliff/tests/test_lister.py +++ b/cliff/tests/test_lister.py @@ -15,6 +15,7 @@ import weakref from cliff import lister +from cliff.tests import base import mock @@ -43,33 +44,33 @@ class ExerciseLister(lister.Lister): ) -def test_formatter_args(): - app = mock.Mock() - test_lister = ExerciseLister(app, []) +class TestLister(base.TestBase): - parsed_args = mock.Mock() - parsed_args.columns = ('Col1', 'Col2') - parsed_args.formatter = 'test' + def test_formatter_args(self): + app = mock.Mock() + test_lister = ExerciseLister(app, []) - test_lister.run(parsed_args) - f = test_lister._formatter_plugins['test'] - assert len(f.args) == 1 - args = f.args[0] - assert args[0] == list(parsed_args.columns) - data = list(args[1]) - assert data == [['a', 'A'], ['b', 'B']] + parsed_args = mock.Mock() + parsed_args.columns = ('Col1', 'Col2') + parsed_args.formatter = 'test' + test_lister.run(parsed_args) + f = test_lister._formatter_plugins['test'] + self.assertEqual(1, len(f.args)) + args = f.args[0] + self.assertEqual(list(parsed_args.columns), args[0]) + data = list(args[1]) + self.assertEqual([['a', 'A'], ['b', 'B']], data) -def test_no_exist_column(): - test_lister = ExerciseLister(mock.Mock(), []) - parsed_args = mock.Mock() - parsed_args.columns = ('no_exist_column',) - parsed_args.formatter = 'test' - with mock.patch.object(test_lister, 'take_action') as mock_take_action: - mock_take_action.return_value = (('Col1', 'Col2', 'Col3'), []) - try: - test_lister.run(parsed_args) - except ValueError: - pass - else: - assert False, 'Should have had an exception' + def test_no_exist_column(self): + test_lister = ExerciseLister(mock.Mock(), []) + parsed_args = mock.Mock() + parsed_args.columns = ('no_exist_column',) + parsed_args.formatter = 'test' + with mock.patch.object(test_lister, 'take_action') as mock_take_action: + mock_take_action.return_value = (('Col1', 'Col2', 'Col3'), []) + self.assertRaises( + ValueError, + test_lister.run, + parsed_args, + ) diff --git a/cliff/tests/test_show.py b/cliff/tests/test_show.py index 9e46c54e..ab185e29 100644 --- a/cliff/tests/test_show.py +++ b/cliff/tests/test_show.py @@ -15,6 +15,7 @@ import weakref from cliff import show +from cliff.tests import base import mock @@ -43,42 +44,41 @@ class ExerciseShowOne(show.ShowOne): ) -def test_formatter_args(): - app = mock.Mock() - test_show = ExerciseShowOne(app, []) +class TestShow(base.TestBase): - parsed_args = mock.Mock() - parsed_args.columns = ('Col1', 'Col2') - parsed_args.formatter = 'test' + def test_formatter_args(self): + app = mock.Mock() + test_show = ExerciseShowOne(app, []) - test_show.run(parsed_args) - f = test_show._formatter_plugins['test'] - assert len(f.args) == 1 - args = f.args[0] - assert args[0] == list(parsed_args.columns) - data = list(args[1]) - assert data == [('a', 'A'), ('b', 'B')] + parsed_args = mock.Mock() + parsed_args.columns = ('Col1', 'Col2') + parsed_args.formatter = 'test' + test_show.run(parsed_args) + f = test_show._formatter_plugins['test'] + self.assertEqual(1, len(f.args)) + args = f.args[0] + self.assertEqual(list(parsed_args.columns), args[0]) + data = list(args[1]) + self.assertEqual([('a', 'A'), ('b', 'B')], data) -def test_dict2columns(): - app = mock.Mock() - test_show = ExerciseShowOne(app, []) - d = {'a': 'A', 'b': 'B', 'c': 'C'} - expected = [('a', 'b', 'c'), ('A', 'B', 'C')] - actual = list(test_show.dict2columns(d)) - assert expected == actual + def test_dict2columns(self): + app = mock.Mock() + test_show = ExerciseShowOne(app, []) + d = {'a': 'A', 'b': 'B', 'c': 'C'} + expected = [('a', 'b', 'c'), ('A', 'B', 'C')] + actual = list(test_show.dict2columns(d)) + self.assertEqual(expected, actual) - -def test_no_exist_column(): - test_show = ExerciseShowOne(mock.Mock(), []) - parsed_args = mock.Mock() - parsed_args.columns = ('no_exist_column',) - parsed_args.formatter = 'test' - with mock.patch.object(test_show, 'take_action') as mock_take_action: - mock_take_action.return_value = (('Col1', 'Col2', 'Col3'), []) - try: - test_show.run(parsed_args) - except ValueError: - pass - else: - assert False, 'Should have had an exception' + def test_no_exist_column(self): + test_show = ExerciseShowOne(mock.Mock(), []) + parsed_args = mock.Mock() + parsed_args.columns = ('no_exist_column',) + parsed_args.formatter = 'test' + with mock.patch.object(test_show, 'take_action') as mock_take_action: + mock_take_action.return_value = (('Col1', 'Col2', 'Col3'), []) + self.assertRaises( + ValueError, + test_show.run, + parsed_args, + ) diff --git a/cliff/tests/test_sphinxext.py b/cliff/tests/test_sphinxext.py index fe271fad..2720d22e 100644 --- a/cliff/tests/test_sphinxext.py +++ b/cliff/tests/test_sphinxext.py @@ -15,92 +15,91 @@ import argparse import textwrap -from nose.tools import assert_equals - from cliff import sphinxext +from cliff.tests import base -def test_empty_help(): - """Handle positional and optional actions without help messages.""" - parser = argparse.ArgumentParser(prog='hello-world', add_help=False) - parser.add_argument('name', action='store') - parser.add_argument('--language', dest='lang') +class TestSphinxExtension(base.TestBase): - output = '\n'.join(sphinxext._format_parser(parser)) - assert_equals(textwrap.dedent(""" - .. program:: hello-world - .. code-block:: shell + def test_empty_help(self): + """Handle positional and optional actions without help messages.""" + parser = argparse.ArgumentParser(prog='hello-world', add_help=False) + parser.add_argument('name', action='store') + parser.add_argument('--language', dest='lang') - hello-world [--language LANG] name + output = '\n'.join(sphinxext._format_parser(parser)) + self.assertEqual(textwrap.dedent(""" + .. program:: hello-world + .. code-block:: shell - .. option:: --language + hello-world [--language LANG] name - .. option:: name - """).lstrip(), output) + .. option:: --language + + .. option:: name + """).lstrip(), output) + + def test_nonempty_help(self): + """Handle positional and optional actions with help messages.""" + parser = argparse.ArgumentParser(prog='hello-world', add_help=False) + parser.add_argument('name', help='user name') + parser.add_argument('--language', dest='lang', + help='greeting language') + + output = '\n'.join(sphinxext._format_parser(parser)) + self.assertEqual(textwrap.dedent(""" + .. program:: hello-world + .. code-block:: shell + + hello-world [--language LANG] name + + .. option:: --language + + greeting language + + .. option:: name + + user name + """).lstrip(), output) + + def test_flag(self): + """Handle a boolean argparse action.""" + parser = argparse.ArgumentParser(prog='hello-world', add_help=False) + parser.add_argument('name', help='user name') + parser.add_argument('--translate', action='store_true', + help='translate to local language') + + output = '\n'.join(sphinxext._format_parser(parser)) + self.assertEqual(textwrap.dedent(""" + .. program:: hello-world + .. code-block:: shell + + hello-world [--translate] name + + .. option:: --translate + + translate to local language + + .. option:: name + + user name + """).lstrip(), output) + + def test_supressed(self): + """Handle a supressed action.""" + parser = argparse.ArgumentParser(prog='hello-world', add_help=False) + parser.add_argument('name', help='user name') + parser.add_argument('--variable', help=argparse.SUPPRESS) + + output = '\n'.join(sphinxext._format_parser(parser)) + self.assertEqual(textwrap.dedent(""" + .. program:: hello-world + .. code-block:: shell + + hello-world name -def test_nonempty_help(): - """Handle positional and optional actions with help messages.""" - parser = argparse.ArgumentParser(prog='hello-world', add_help=False) - parser.add_argument('name', help='user name') - parser.add_argument('--language', dest='lang', help='greeting language') + .. option:: name - output = '\n'.join(sphinxext._format_parser(parser)) - assert_equals(textwrap.dedent(""" - .. program:: hello-world - .. code-block:: shell - - hello-world [--language LANG] name - - .. option:: --language - - greeting language - - .. option:: name - - user name - """).lstrip(), output) - - -def test_flag(): - """Handle a boolean argparse action.""" - parser = argparse.ArgumentParser(prog='hello-world', add_help=False) - parser.add_argument('name', help='user name') - parser.add_argument('--translate', action='store_true', - help='translate to local language') - - output = '\n'.join(sphinxext._format_parser(parser)) - assert_equals(textwrap.dedent(""" - .. program:: hello-world - .. code-block:: shell - - hello-world [--translate] name - - .. option:: --translate - - translate to local language - - .. option:: name - - user name - """).lstrip(), output) - - -def test_supressed(): - """Handle a supressed action.""" - parser = argparse.ArgumentParser(prog='hello-world', add_help=False) - parser.add_argument('name', help='user name') - parser.add_argument('--variable', help=argparse.SUPPRESS) - - output = '\n'.join(sphinxext._format_parser(parser)) - assert_equals(textwrap.dedent(""" - .. program:: hello-world - .. code-block:: shell - - hello-world name - - - .. option:: name - - user name - """).lstrip(), output) + user name + """).lstrip(), output) diff --git a/cliff/tests/test_utils.py b/cliff/tests/test_utils.py index 23c46c42..9d6b1f68 100644 --- a/cliff/tests/test_utils.py +++ b/cliff/tests/test_utils.py @@ -15,65 +15,63 @@ import os import struct import sys +import unittest import mock -import nose from cliff import utils +from cliff.tests import base -def test_utils_terminal_width(): - width = utils.terminal_width(sys.stdout) - # Results are specific to the execution environment, so only assert - # that no error is raised. - assert width is None or isinstance(width, int) +class TestTerminalWidth(base.TestBase): + def test(self): + width = utils.terminal_width(sys.stdout) + # Results are specific to the execution environment, so only assert + # that no error is raised. + if width is not None: + self.assertIsInstance(width, int) -@mock.patch('cliff.utils.os') -def test_utils_terminal_width_get_terminal_size(mock_os): - if not hasattr(os, 'get_terminal_size'): - raise nose.SkipTest('only needed for python 3.3 onwards') - ts = os.terminal_size((10, 5)) - mock_os.get_terminal_size.return_value = ts - width = utils.terminal_width(sys.stdout) - assert width == 10 + @unittest.skipIf(not hasattr(os, 'get_terminal_size'), + 'only needed for python 3.3 onwards') + @mock.patch('cliff.utils.os') + def test_get_terminal_size(self, mock_os): + ts = os.terminal_size((10, 5)) + mock_os.get_terminal_size.return_value = ts + width = utils.terminal_width(sys.stdout) + self.assertEqual(10, width) + mock_os.get_terminal_size.side_effect = OSError() + width = utils.terminal_width(sys.stdout) + self.assertIs(None, width) - mock_os.get_terminal_size.side_effect = OSError() - width = utils.terminal_width(sys.stdout) - assert width is None + @unittest.skipIf(hasattr(os, 'get_terminal_size'), + 'only needed for python 3.2 and before') + @mock.patch('fcntl.ioctl') + def test_ioctl(self, mock_ioctl): + mock_ioctl.return_value = struct.pack('hhhh', 57, 101, 0, 0) + width = utils.terminal_width(sys.stdout) + self.assertEqual(101, width) + mock_ioctl.side_effect = IOError() + width = utils.terminal_width(sys.stdout) + self.assertIs(None, width) + @unittest.skipIf(hasattr(os, 'get_terminal_size'), + 'only needed for python 3.2 and before') + @mock.patch('cliff.utils.ctypes') + @mock.patch('sys.platform', 'win32') + def test_windows(self, mock_ctypes): + mock_ctypes.create_string_buffer.return_value.raw = struct.pack( + 'hhhhHhhhhhh', 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + mock_ctypes.windll.kernel32.GetStdHandle.return_value = -11 + mock_ctypes.windll.kernel32.GetConsoleScreenBufferInfo.return_value = 1 -@mock.patch('fcntl.ioctl') -def test_utils_terminal_width_ioctl(mock_ioctl): - if hasattr(os, 'get_terminal_size'): - raise nose.SkipTest('only needed for python 3.2 and before') - mock_ioctl.return_value = struct.pack('hhhh', 57, 101, 0, 0) - width = utils.terminal_width(sys.stdout) - assert width == 101 + width = utils.terminal_width(sys.stdout) + self.assertEqual(101, width) - mock_ioctl.side_effect = IOError() - width = utils.terminal_width(sys.stdout) - assert width is None + mock_ctypes.windll.kernel32.GetConsoleScreenBufferInfo.return_value = 0 + width = utils.terminal_width(sys.stdout) + self.assertIs(None, width) -@mock.patch('cliff.utils.ctypes') -@mock.patch('sys.platform', 'win32') -def test_utils_terminal_width_windows(mock_ctypes): - if hasattr(os, 'get_terminal_size'): - raise nose.SkipTest('only needed for python 3.2 and before') - - mock_ctypes.create_string_buffer.return_value.raw = struct.pack( - 'hhhhHhhhhhh', 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) - mock_ctypes.windll.kernel32.GetStdHandle.return_value = -11 - mock_ctypes.windll.kernel32.GetConsoleScreenBufferInfo.return_value = 1 - - width = utils.terminal_width(sys.stdout) - assert width == 101 - - mock_ctypes.windll.kernel32.GetConsoleScreenBufferInfo.return_value = 0 - - width = utils.terminal_width(sys.stdout) - assert width is None - - width = utils.terminal_width('foo') - assert width is None + width = utils.terminal_width('foo') + self.assertIs(None, width) diff --git a/test-requirements.txt b/test-requirements.txt index a80bfd6b..ee616290 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,9 +1,15 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -nose # LGPL + +python-subunit>=0.0.18 # Apache-2.0/BSD +testrepository>=0.0.18 # Apache-2.0/BSD +testtools>=1.4.0 # MIT mock>=2.0 # BSD +testscenarios>=0.4 # Apache-2.0/BSD + coverage>=4.0 # Apache-2.0 + # this is required for the docs build jobs sphinx>=1.5.1 # BSD oslosphinx>=4.7.0 # Apache-2.0 diff --git a/tox.ini b/tox.ini index 5740170f..470da53f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py35,py27,pypy,pep8 +envlist = py35,py27,pep8 [testenv] setenv = @@ -11,7 +11,9 @@ passenv = ZUUL_CACHE_DIR distribute = False install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} -commands = nosetests -d --with-coverage --cover-inclusive --cover-package cliff [] +commands = + python setup.py test --coverage --coverage-package-name=cliff --slowest --testr-args='{posargs}' + coverage report --show-missing deps = -r{toxinidir}/test-requirements.txt [testenv:pep8]