diff options
author | Federico Ceratto <federico.ceratto@gmail.com> | 2016-02-23 23:55:58 +0000 |
---|---|---|
committer | Federico Ceratto <federico.ceratto@gmail.com> | 2016-02-23 23:55:58 +0000 |
commit | 24e841d5e002442115e3d7a045742fbd8a05477f (patch) | |
tree | 45e47959e46168def43e5eda4c83dd0a9da70071 | |
parent | d37d349a1a0319f9735af9ffdf6bd976f6f41ee9 (diff) | |
download | cmd2-git-24e841d5e002442115e3d7a045742fbd8a05477f.tar.gz |
Add unit tests
-rw-r--r-- | tests/conftest.py | 45 | ||||
-rw-r--r-- | tests/test_cmd2.py | 187 | ||||
-rw-r--r-- | tests/test_transcript.py | 167 | ||||
-rw-r--r-- | tox.ini | 7 |
4 files changed, 405 insertions, 1 deletions
diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..55700914 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,45 @@ +# +# Cmd2 unit/functional testing +# +# Copyright 2016 Federico Ceratto <federico.ceratto@gmail.com> +# Released under MIT license, see LICENSE file + +from pytest import fixture + +import cmd2 + + +class StdOut(object): + def __init__(self): + self.clear() + + def write(self, s): + self.buffer += s + + def read(self): + raise NotImplementedError + + def clear(self): + self.buffer = '' + + +def _normalize(block): + # normalize a block of text to perform comparison + assert isinstance(block, str) + block = block.strip('\n') + return [line.rstrip() for line in block.splitlines()] + + +def run_cmd(app, cmd): + app.stdout.clear() + app.onecmd_plus_hooks(cmd) + out = app.stdout.buffer + app.stdout.clear() + return _normalize(out) + + +@fixture +def base_app(): + c = cmd2.Cmd() + c.stdout = StdOut() + return c diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py new file mode 100644 index 00000000..8435ac1a --- /dev/null +++ b/tests/test_cmd2.py @@ -0,0 +1,187 @@ +# +# Cmd2 unit/functional testing +# +# Copyright 2016 Federico Ceratto <federico.ceratto@gmail.com> +# Released under MIT license, see LICENSE file + +import mock +import pytest + +from conftest import run_cmd, _normalize +import cmd2 + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + + +def test_ver(): + assert cmd2.__version__ == '0.6.9a' + + +def test_base_help(base_app): + out = run_cmd(base_app, 'help') + expected = _normalize(""" +Documented commands (type help <topic>): +======================================== +_load ed history list py save shortcuts +_relative_load edit l load r set show +cmdenvironment hi li pause run shell + +Undocumented commands: +====================== +EOF eof exit help q quit +""") + assert out == expected + + +def test_base_help_history(base_app): + out = run_cmd(base_app, 'help history') + expected = _normalize(""" +history [arg]: lists past commands issued + + | no arg: list all + | arg is integer: list one history item, by index + | arg is string: string search + | arg is /enclosed in forward-slashes/: regular expression search + +Usage: history [options] (limit on which commands to include) + +Options: + -h, --help show this help message and exit + -s, --script Script format; no separation lines +""") + assert out == expected + + +def test_base_shortcuts(base_app): + out = run_cmd(base_app, 'shortcuts') + expected = _normalize(""" +Single-key shortcuts for other commands: +!: shell +?: help +@: load +@@: _relative_load +""") + assert out == expected + + +def notest_base_(base_app): + out = run_cmd(base_app, 'shortcuts') + expected = _normalize(""" +""") + assert out == expected + + +def test_base_show(base_app): + out = run_cmd(base_app, 'show') + expected = _normalize(""" +abbrev: True +case_insensitive: True +colors: True +continuation_prompt: > +debug: False +default_file_name: command.txt +echo: False +feedback_to_output: False +prompt: (Cmd) +quiet: False +timing: False +""") + # ignore "editor: vi" (could be others) + out = [l for l in out if not l.startswith('editor: ')] + assert out == expected + + +def test_base_set(base_app): + out = run_cmd(base_app, 'set quiet True') + expected = _normalize(""" +quiet - was: False +now: True +""") + assert out == expected + + out = run_cmd(base_app, 'show quiet') + assert out == ['quiet: True'] + + +def test_base_set_not_supported(base_app): + out = run_cmd(base_app, 'set qqq True') + assert out == [] + # TODO: check stderr + + +def test_base_shell(base_app, monkeypatch): + m = mock.Mock() + monkeypatch.setattr("os.system", m) + out = run_cmd(base_app, 'shell echo a') + assert out == [] + assert m.called + m.assert_called_with('echo a') + + +def test_base_py(base_app): + out = run_cmd(base_app, 'py qqq=3') + assert out == [] + out = run_cmd(base_app, 'py print qqq') + assert out == [] + # TODO: check stderr + + +def test_base_error(base_app): + out = run_cmd(base_app, 'meow') + assert out == ["*** Unknown syntax: meow"] + + +def test_base_history(base_app): + run_cmd(base_app, 'help') + run_cmd(base_app, 'shortcuts') + out = run_cmd(base_app, 'history') + expected = _normalize(""" +-------------------------[1] +help +-------------------------[2] +shortcuts +""") + assert out == expected + + out = run_cmd(base_app, 'history he') + expected = _normalize(""" +-------------------------[1] +help +""") + assert out == expected + + out = run_cmd(base_app, 'history sh') + expected = _normalize(""" +-------------------------[2] +shortcuts +""") + assert out == expected + + +def test_base_list(base_app): + run_cmd(base_app, 'help') + run_cmd(base_app, 'shortcuts') + out = run_cmd(base_app, 'list') + expected = _normalize(""" +-------------------------[2] +shortcuts +""") + assert out == expected + + +@pytest.mark.xfail +def test_base_load(base_app): + base_app.read_file_or_url = mock.Mock( + return_value=StringIO('set quiet True\n') + ) + out = run_cmd(base_app, 'load myfname') + expected = _normalize(""" +quiet - was: False +now: True +""") + assert out == expected + + diff --git a/tests/test_transcript.py b/tests/test_transcript.py new file mode 100644 index 00000000..06cf50b6 --- /dev/null +++ b/tests/test_transcript.py @@ -0,0 +1,167 @@ +# +# Cmd2 functional testing based on transcript +# +# Copyright 2016 Federico Ceratto <federico.ceratto@gmail.com> +# Released under MIT license, see LICENSE file + +import pytest + +from cmd2 import Cmd, make_option, options +from conftest import run_cmd, StdOut, _normalize + + +class CmdLineApp(Cmd): + multilineCommands = ['orate'] + maxrepeats = 3 + redirector = '->' + + opts = [ + make_option('-p', '--piglatin', action="store_true", help="atinLay"), + make_option('-s', '--shout', action="store_true", + help="N00B EMULATION MODE"), + make_option('-r', '--repeat', type="int", help="output [n] times") + ] + + @options(opts, arg_desc='(text to say)') + def do_speak(self, arg, opts=None): + """Repeats what you tell me to.""" + arg = ''.join(arg) + if opts.piglatin: + arg = '%s%say' % (arg[1:].rstrip(), arg[0]) + if opts.shout: + arg = arg.upper() + repetitions = opts.repeat or 1 + for i in range(min(repetitions, self.maxrepeats)): + self.stdout.write(arg) + self.stdout.write('\n') + # self.stdout.write is better than "print", because Cmd can be + # initialized with a non-standard output destination + + do_say = do_speak # now "say" is a synonym for "speak" + do_orate = do_speak # another synonym, but this one takes multi-line input + + +@pytest.fixture +def _cmdline_app(): + c = CmdLineApp() + c.stdout = StdOut() + #c.shortcuts.update({'&': 'speak', 'h': 'hello'}) + c.settable.append('maxrepeats Max number of `--repeat`s allowed') + return c + + +def _get_transcript_blocks(transcript): + cmd = None + expected = '' + for line in transcript.splitlines(): + if line.startswith('(Cmd) '): + if cmd is not None: + yield cmd, _normalize(expected) + + cmd = line[6:] + expected = '' + else: + expected += line + '\n' + yield cmd, _normalize(expected) + + +@pytest.mark.xfail +def test_base_with_transcript(_cmdline_app): + app = _cmdline_app + transcript = """ +(Cmd) help + +Documented commands (type help <topic>): +======================================== +_load ed history list pause run set show +_relative_load edit l load py save shell speak +cmdenvironment hi li orate r say shortcuts + +Undocumented commands: +====================== +EOF eof exit help q quit + +(Cmd) help say +Repeats what you tell me to. +Usage: speak [options] (text to say) + +Options: + -h, --help show this help message and exit + -p, --piglatin atinLay + -s, --shout N00B EMULATION MODE + -r REPEAT, --repeat=REPEAT + output [n] times + +(Cmd) say goodnight, Gracie +goodnight, Gracie +(Cmd) say -ps --repeat=5 goodnight, Gracie +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +(Cmd) set +abbrev: True +case_insensitive: True +colors: True +continuation_prompt: > +debug: False +default_file_name: command.txt +echo: False +editor: /\w*/ +feedback_to_output: False +maxrepeats: 3 +prompt: (Cmd) +quiet: False +timing: False +(Cmd) set maxrepeats 5 +maxrepeats - was: 3 +now: 5 +(Cmd) say -ps --repeat=5 goodnight, Gracie +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +(Cmd) hi +-------------------------[1] +help +-------------------------[2] +help say +-------------------------[3] +say goodnight, Gracie +-------------------------[4] +say -ps --repeat=5 goodnight, Gracie +-------------------------[5] +set +-------------------------[6] +set maxrepeats 5 +-------------------------[7] +say -ps --repeat=5 goodnight, Gracie +(Cmd) run 4 +say -ps --repeat=5 goodnight, Gracie +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +OODNIGHT, GRACIEGAY +(Cmd) orate Four score and +> seven releases ago +> our BDFL +> +Four score and +seven releases ago +our BDFL +(Cmd) & look, a shortcut! +look, a shortcut! +(Cmd) say put this in a file > myfile.txt +(Cmd) say < myfile.txt +put this in a file +(Cmd) set prompt "---> " +prompt - was: (Cmd) +now: ---> +---> say goodbye +goodbye +""" + + for cmd, expected in _get_transcript_blocks(transcript): + out = run_cmd(app, 'help') + assert out == expected @@ -2,7 +2,12 @@ envlist = py27,py34,py35,jython,pypy [testenv] -deps=pyparsing +deps = + mock + pyparsing + pytest commands= + py.test -v --basetemp={envtmpdir} {posargs} {envpython} cmd2.py {envpython} example/example.py --test example/exampleSession.txt + |