87
80
We can't predict what encoding users will have for stdin, so we force
88
81
it to utf8 to test that we transport the password correctly.
90
ui = TestUIFactory(stdin=u'baz\u1234'.encode('utf8'),
91
stdout=StringIOWrapper())
92
ui.stdin.encoding = 'utf8'
93
ui.stdout.encoding = ui.stdin.encoding
83
ui = tests.TestUIFactory(stdin=u'baz\u1234'.encode('utf8'),
84
stdout=tests.StringIOWrapper(),
85
stderr=tests.StringIOWrapper())
86
ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = 'utf8'
94
87
pb = ui.nested_progress_bar()
96
password = self.apply_redirected(ui.stdin, ui.stdout, ui.stdout,
89
password = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
98
91
u'Hello \u1234 %(user)s',
99
92
user=u'some\u1234')
100
93
# We use StringIO objects, we need to decode them
101
94
self.assertEqual(u'baz\u1234', password.decode('utf8'))
102
95
self.assertEqual(u'Hello \u1234 some\u1234: ',
103
ui.stdout.getvalue().decode('utf8'))
104
# stdin should be empty
96
ui.stderr.getvalue().decode('utf8'))
97
# stdin and stdout should be empty
105
98
self.assertEqual('', ui.stdin.readline())
99
self.assertEqual('', ui.stdout.readline())
103
def test_progress_construction(self):
104
"""TextUIFactory constructs the right progress view.
106
for (file_class, term, pb, expected_pb_class) in (
107
# on an xterm, either use them or not as the user requests,
108
# otherwise default on
109
(_TTYStringIO, 'xterm', 'none', NullProgressView),
110
(_TTYStringIO, 'xterm', 'text', TextProgressView),
111
(_TTYStringIO, 'xterm', None, TextProgressView),
112
# on a dumb terminal, again if there's explicit configuration do
113
# it, otherwise default off
114
(_TTYStringIO, 'dumb', 'none', NullProgressView),
115
(_TTYStringIO, 'dumb', 'text', TextProgressView),
116
(_TTYStringIO, 'dumb', None, NullProgressView),
117
# on a non-tty terminal, it's null regardless of $TERM
118
(StringIO, 'xterm', None, NullProgressView),
119
(StringIO, 'dumb', None, NullProgressView),
120
# however, it can still be forced on
121
(StringIO, 'dumb', 'text', TextProgressView),
123
os.environ['TERM'] = term
125
if 'BZR_PROGRESS_BAR' in os.environ:
126
del os.environ['BZR_PROGRESS_BAR']
128
os.environ['BZR_PROGRESS_BAR'] = pb
129
stdin = file_class('')
130
stderr = file_class()
131
stdout = file_class()
132
uif = make_ui_for_terminal(stdin, stdout, stderr)
133
self.assertIsInstance(uif, TextUIFactory,
134
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
135
self.assertIsInstance(uif.make_progress_view(),
137
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
139
def test_text_ui_non_terminal(self):
140
"""Even on non-ttys, make_ui_for_terminal gives a text ui."""
141
stdin = _NonTTYStringIO('')
142
stderr = _NonTTYStringIO()
143
stdout = _NonTTYStringIO()
144
for term_type in ['dumb', None, 'xterm']:
145
if term_type is None:
146
del os.environ['TERM']
148
os.environ['TERM'] = term_type
149
uif = make_ui_for_terminal(stdin, stdout, stderr)
150
self.assertIsInstance(uif, TextUIFactory,
151
'TERM=%r' % (term_type,))
109
153
def test_progress_note(self):
110
154
stderr = StringIO()
111
155
stdout = StringIO()
164
def test_progress_stack(self):
165
# test the progress bar stack which the default text factory
209
def test_text_ui_get_boolean(self):
210
stdin = StringIO("y\n" # True
212
"yes with garbage\nY\n" # True
213
"not an answer\nno\n" # False
214
"I'm sure!\nyes\n" # True
167
218
stderr = StringIO()
169
# make a stack, which accepts parameters like a pb.
170
stack = self.applyDeprecated(
171
deprecated_in((1, 12, 0)),
173
to_file=stderr, to_messages_file=stdout)
175
self.assertFalse(getattr(stack, 'note', False))
176
pb1 = stack.get_nested()
177
pb2 = stack.get_nested()
178
warnings, _ = self.callCatchWarnings(pb1.finished)
179
self.assertEqual(len(warnings), 1)
182
# the text ui factory never actually removes the stack once its setup.
183
# we need to be able to nest again correctly from here.
184
pb1 = stack.get_nested()
185
pb2 = stack.get_nested()
186
warnings, _ = self.callCatchWarnings(pb1.finished)
187
self.assertEqual(len(warnings), 1)
191
def assert_get_bool_acceptance_of_user_input(self, factory):
192
factory.stdin = StringIO("y\nyes with garbage\n"
193
"yes\nn\nnot an answer\n"
195
factory.stdout = StringIO()
196
# there is no output from the base factory
197
self.assertEqual(True, factory.get_boolean(""))
198
self.assertEqual(True, factory.get_boolean(""))
199
self.assertEqual(False, factory.get_boolean(""))
219
factory = TextUIFactory(stdin, stdout, stderr)
220
self.assertEqual(True, factory.get_boolean(""))
221
self.assertEqual(False, factory.get_boolean(""))
222
self.assertEqual(True, factory.get_boolean(""))
223
self.assertEqual(False, factory.get_boolean(""))
224
self.assertEqual(True, factory.get_boolean(""))
200
225
self.assertEqual(False, factory.get_boolean(""))
201
226
self.assertEqual("foo\n", factory.stdin.read())
202
227
# stdin should be empty
203
228
self.assertEqual('', factory.stdin.readline())
205
def test_silent_ui_getbool(self):
206
factory = SilentUIFactory()
207
self.assert_get_bool_acceptance_of_user_input(factory)
209
def test_silent_factory_prompts_silently(self):
210
factory = SilentUIFactory()
212
factory.stdin = StringIO("y\n")
213
self.assertEqual(True,
214
self.apply_redirected(None, stdout, stdout,
215
factory.get_boolean, "foo"))
216
self.assertEqual("", stdout.getvalue())
217
# stdin should be empty
218
self.assertEqual('', factory.stdin.readline())
220
def test_text_ui_getbool(self):
221
factory = TextUIFactory(None, None, None)
222
self.assert_get_bool_acceptance_of_user_input(factory)
224
230
def test_text_factory_prompt(self):
225
231
# see <https://launchpad.net/bugs/365891>
226
factory = TextUIFactory(None, StringIO(), StringIO())
232
factory = TextUIFactory(StringIO(), StringIO(), StringIO())
227
233
factory.prompt('foo %2e')
234
self.assertEqual('', factory.stdout.getvalue())
235
self.assertEqual('foo %2e', factory.stderr.getvalue())
229
237
def test_text_factory_prompts_and_clears(self):
230
238
# a get_boolean call should clear the pb before prompting
231
239
out = _TTYStringIO()
240
os.environ['TERM'] = 'xterm'
232
241
factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
233
242
pb = factory.nested_progress_bar()
234
243
pb.show_bar = False
262
def test_silent_ui_getusername(self):
263
factory = SilentUIFactory()
264
factory.stdin = StringIO("someuser\n\n")
265
factory.stdout = StringIO()
266
self.assertEquals(None,
267
factory.get_username(u'Hello\u1234 %(host)s', host=u'some\u1234'))
268
self.assertEquals("", factory.stdout.getvalue())
269
self.assertEquals("someuser\n\n", factory.stdin.getvalue())
271
271
def test_text_ui_getusername(self):
272
272
factory = TextUIFactory(None, None, None)
273
273
factory.stdin = StringIO("someuser\n\n")
274
274
factory.stdout = StringIO()
275
factory.stderr = StringIO()
275
276
factory.stdout.encoding = "utf8"
276
277
# there is no output from the base factory
277
self.assertEqual("someuser",
278
factory.get_username('Hello %(host)s', host='some'))
279
self.assertEquals("Hello some: ", factory.stdout.getvalue())
278
self.assertEqual("someuser",
279
factory.get_username('Hello %(host)s', host='some'))
280
self.assertEquals("Hello some: ", factory.stderr.getvalue())
281
self.assertEquals('', factory.stdout.getvalue())
280
282
self.assertEqual("", factory.get_username("Gebruiker"))
281
283
# stdin should be empty
282
284
self.assertEqual('', factory.stdin.readline())
284
286
def test_text_ui_getusername_utf8(self):
285
ui = TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
286
stdout=StringIOWrapper())
287
ui.stdin.encoding = "utf8"
288
ui.stdout.encoding = ui.stdin.encoding
287
ui = tests.TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
288
stdout=tests.StringIOWrapper(),
289
stderr=tests.StringIOWrapper())
290
ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = "utf8"
289
291
pb = ui.nested_progress_bar()
291
293
# there is no output from the base factory
292
username = self.apply_redirected(ui.stdin, ui.stdout, ui.stdout,
294
username = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
293
295
ui.get_username, u'Hello\u1234 %(host)s', host=u'some\u1234')
294
296
self.assertEquals(u"someuser\u1234", username.decode('utf8'))
295
self.assertEquals(u"Hello\u1234 some\u1234: ",
296
ui.stdout.getvalue().decode("utf8"))
297
self.assertEquals(u"Hello\u1234 some\u1234: ",
298
ui.stderr.getvalue().decode("utf8"))
299
self.assertEquals('', ui.stdout.getvalue())
301
class TestTextProgressView(TestCase):
302
"""Tests for text display of progress bars.
304
# XXX: These might be a bit easier to write if the rendering and
305
# state-maintaining parts of TextProgressView were more separate, and if
306
# the progress task called back directly to its own view not to the ui
307
# factory. -- mbp 20090312
304
class CLIUITests(TestCase):
306
def test_cli_factory_deprecated(self):
307
uif = self.applyDeprecated(deprecated_in((1, 18, 0)),
309
StringIO(), StringIO(), StringIO())
310
self.assertIsInstance(uif, UIFactory)
313
class SilentUITests(TestCase):
315
def test_silent_factory_get_password(self):
316
# A silent factory that can't do user interaction can't get a
317
# password. Possibly it should raise a more specific error but it
319
ui = SilentUIFactory()
323
self.apply_redirected,
324
None, stdout, stdout, ui.get_password)
325
# and it didn't write anything out either
326
self.assertEqual('', stdout.getvalue())
328
def test_silent_ui_getbool(self):
329
factory = SilentUIFactory()
333
self.apply_redirected,
334
None, stdout, stdout, factory.get_boolean, "foo")
337
class TestUIFactoryTests(TestCase):
339
def test_test_ui_factory_progress(self):
340
# there's no output; we just want to make sure this doesn't crash -
341
# see https://bugs.edge.launchpad.net/bzr/+bug/408201
343
pb = ui.nested_progress_bar()
349
class CannedInputUIFactoryTests(TestCase):
309
def _make_factory(self):
311
uif = TextUIFactory(stderr=out)
312
uif._progress_view._width = 80
315
def test_render_progress_easy(self):
316
"""Just one task and one quarter done"""
317
out, uif = self._make_factory()
318
task = uif.nested_progress_bar()
319
task.update('reticulating splines', 5, 20)
321
'\r[####/ ] reticulating splines 5/20 \r'
324
def test_render_progress_nested(self):
325
"""Tasks proportionally contribute to overall progress"""
326
out, uif = self._make_factory()
327
task = uif.nested_progress_bar()
328
task.update('reticulating splines', 0, 2)
329
task2 = uif.nested_progress_bar()
330
task2.update('stage2', 1, 2)
331
# so we're in the first half of the main task, and half way through
334
r'[####\ ] reticulating splines:stage2 1/2'
335
, uif._progress_view._render_line())
336
# if the nested task is complete, then we're all the way through the
337
# first half of the overall work
338
task2.update('stage2', 2, 2)
340
r'[#########| ] reticulating splines:stage2 2/2'
341
, uif._progress_view._render_line())
343
def test_render_progress_sub_nested(self):
344
"""Intermediate tasks don't mess up calculation."""
345
out, uif = self._make_factory()
346
task_a = uif.nested_progress_bar()
347
task_a.update('a', 0, 2)
348
task_b = uif.nested_progress_bar()
350
task_c = uif.nested_progress_bar()
351
task_c.update('c', 1, 2)
352
# the top-level task is in its first half; the middle one has no
353
# progress indication, just a label; and the bottom one is half done,
354
# so the overall fraction is 1/4
356
r'[####| ] a:b:c 1/2'
357
, uif._progress_view._render_line())
351
def test_canned_input_get_input(self):
352
uif = CannedInputUIFactory([True, 'mbp', 'password'])
353
self.assertEqual(uif.get_boolean('Extra cheese?'), True)
354
self.assertEqual(uif.get_username('Enter your user name'), 'mbp')
355
self.assertEqual(uif.get_password('Password for %(host)s', host='example.com'),
359
class TestBoolFromString(tests.TestCase):
361
def assertIsTrue(self, s, accepted_values=None):
362
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
363
self.assertEquals(True, res)
365
def assertIsFalse(self, s, accepted_values=None):
366
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
367
self.assertEquals(False, res)
369
def assertIsNone(self, s, accepted_values=None):
370
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
371
self.assertIs(None, res)
373
def test_know_valid_values(self):
374
self.assertIsTrue('true')
375
self.assertIsFalse('false')
376
self.assertIsTrue('1')
377
self.assertIsFalse('0')
378
self.assertIsTrue('on')
379
self.assertIsFalse('off')
380
self.assertIsTrue('yes')
381
self.assertIsFalse('no')
382
self.assertIsTrue('y')
383
self.assertIsFalse('n')
384
# Also try some case variations
385
self.assertIsTrue('True')
386
self.assertIsFalse('False')
387
self.assertIsTrue('On')
388
self.assertIsFalse('Off')
389
self.assertIsTrue('ON')
390
self.assertIsFalse('OFF')
391
self.assertIsTrue('oN')
392
self.assertIsFalse('oFf')
394
def test_invalid_values(self):
395
self.assertIsNone(None)
396
self.assertIsNone('doubt')
397
self.assertIsNone('frue')
398
self.assertIsNone('talse')
399
self.assertIsNone('42')
401
def test_provided_values(self):
402
av = dict(y=True, n=False, yes=True, no=False)
403
self.assertIsTrue('y', av)
404
self.assertIsTrue('Y', av)
405
self.assertIsTrue('Yes', av)
406
self.assertIsFalse('n', av)
407
self.assertIsFalse('N', av)
408
self.assertIsFalse('No', av)
409
self.assertIsNone('1', av)
410
self.assertIsNone('0', av)
411
self.assertIsNone('on', av)
412
self.assertIsNone('off', av)