1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
# coding=utf-8
"""
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, Cmd2TestCase
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
class DemoApp(Cmd):
@options([make_option('-n', '--name', action="store", help="your name"),
])
def do_hello(self, arg, opts):
"""Says hello."""
if opts.name:
self.stdout.write('Hello {}\n'.format(opts.name))
else:
self.stdout.write('Hello Nobody\n')
@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
@pytest.fixture
def _demo_app():
c = DemoApp()
c.stdout = StdOut()
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)
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 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 maxrepeats 5
-------------------------[6]
say -ps --repeat=5 goodnight, Gracie
(Cmd) run 4
OODNIGHT, GRACIEGAY
OODNIGHT, GRACIEGAY
OODNIGHT, GRACIEGAY
OODNIGHT, GRACIEGAY
OODNIGHT, GRACIEGAY
(Cmd) set prompt "---> "
prompt - was: (Cmd)
now: --->
"""
for cmd, expected in _get_transcript_blocks(transcript):
out = run_cmd(app, cmd)
assert out == expected
class TestMyAppCase(Cmd2TestCase):
CmdApp = CmdLineApp
CmdApp.testfiles = ['tests/transcript.txt']
def test_optparser(_cmdline_app, capsys):
run_cmd(_cmdline_app, 'say -h')
out, err = capsys.readouterr()
expected = _normalize("""
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""")
# NOTE: For some reason this extra cast to str is required for Python 2.7 but not 3.x
assert _normalize(str(out)) == expected
def test_optparser_nosuchoption(_cmdline_app, capsys):
run_cmd(_cmdline_app, 'say -a')
out, err = capsys.readouterr()
expected = _normalize("""
no such option: -a
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""")
assert _normalize(str(out)) == expected
def test_comment_stripping(_cmdline_app):
out = run_cmd(_cmdline_app, 'speak it was /* not */ delicious! # Yuck!')
expected = _normalize("""it was delicious!""")
assert out == expected
def test_optarser_correct_args_with_quotes_and_midline_options(_cmdline_app):
out = run_cmd(_cmdline_app, "speak 'This is a' -s test of the emergency broadcast system!")
expected = _normalize("""THIS IS A TEST OF THE EMERGENCY BROADCAST SYSTEM!""")
assert out == expected
def test_optarser_options_with_spaces_in_quotes(_demo_app):
out = run_cmd(_demo_app, "hello foo -n 'Bugs Bunny' bar baz")
expected = _normalize("""Hello Bugs Bunny""")
assert out == expected
|