150
def test_progress_nested(self):
151
# test factory based nested and popping.
152
ui = TextUIFactory(None, None, None)
153
pb1 = ui.nested_progress_bar()
154
pb2 = ui.nested_progress_bar()
155
# You do get a warning if the outermost progress bar wasn't finished
156
# first - it's not clear if this is really useful or if it should just
157
# become orphaned -- mbp 20090120
158
warnings, _ = self.callCatchWarnings(pb1.finished)
159
if len(warnings) != 1:
160
self.fail("unexpected warnings: %r" % (warnings,))
164
def test_progress_stack(self):
165
# test the progress bar stack which the default text factory
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(""))
148
def test_text_ui_get_boolean(self):
149
stdin = tests.StringIOWrapper("y\n" # True
151
"yes with garbage\nY\n" # True
152
"not an answer\nno\n" # False
153
"I'm sure!\nyes\n" # True
156
stdout = tests.StringIOWrapper()
157
stderr = tests.StringIOWrapper()
158
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
159
self.assertEqual(True, factory.get_boolean(""))
160
self.assertEqual(False, factory.get_boolean(""))
161
self.assertEqual(True, factory.get_boolean(""))
162
self.assertEqual(False, factory.get_boolean(""))
163
self.assertEqual(True, factory.get_boolean(""))
200
164
self.assertEqual(False, factory.get_boolean(""))
201
165
self.assertEqual("foo\n", factory.stdin.read())
202
166
# stdin should be empty
203
167
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)
169
def test_text_ui_get_integer(self):
170
stdin = tests.StringIOWrapper(
173
"hmmm\nwhat else ?\nCome on\nok 42\n4.24\n42\n")
174
stdout = tests.StringIOWrapper()
175
stderr = tests.StringIOWrapper()
176
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
177
self.assertEqual(1, factory.get_integer(""))
178
self.assertEqual(-2, factory.get_integer(""))
179
self.assertEqual(42, factory.get_integer(""))
181
def test_text_factory_prompt(self):
182
# see <https://launchpad.net/bugs/365891>
183
StringIO = tests.StringIOWrapper
184
factory = _mod_ui_text.TextUIFactory(StringIO(), StringIO(), StringIO())
185
factory.prompt('foo %2e')
186
self.assertEqual('', factory.stdout.getvalue())
187
self.assertEqual('foo %2e', factory.stderr.getvalue())
224
189
def test_text_factory_prompts_and_clears(self):
225
190
# a get_boolean call should clear the pb before prompting
227
factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
191
out = test_progress._TTYStringIO()
192
os.environ['TERM'] = 'xterm'
193
factory = _mod_ui_text.TextUIFactory(
194
stdin=tests.StringIOWrapper("yada\ny\n"),
195
stdout=out, stderr=out)
228
196
pb = factory.nested_progress_bar()
229
197
pb.show_bar = False
230
198
pb.show_spinner = False
257
def test_silent_ui_getusername(self):
258
factory = SilentUIFactory()
259
factory.stdin = StringIO("someuser\n\n")
260
factory.stdout = StringIO()
261
self.assertEquals(None,
262
factory.get_username(u'Hello\u1234 %(host)s', host=u'some\u1234'))
263
self.assertEquals("", factory.stdout.getvalue())
264
self.assertEquals("someuser\n\n", factory.stdin.getvalue())
266
226
def test_text_ui_getusername(self):
267
factory = TextUIFactory(None, None, None)
268
factory.stdin = StringIO("someuser\n\n")
269
factory.stdout = StringIO()
227
factory = _mod_ui_text.TextUIFactory(None, None, None)
228
factory.stdin = tests.StringIOWrapper("someuser\n\n")
229
factory.stdout = tests.StringIOWrapper()
230
factory.stderr = tests.StringIOWrapper()
270
231
factory.stdout.encoding = "utf8"
271
232
# there is no output from the base factory
272
self.assertEqual("someuser",
273
factory.get_username('Hello %(host)s', host='some'))
274
self.assertEquals("Hello some: ", factory.stdout.getvalue())
233
self.assertEqual("someuser",
234
factory.get_username('Hello %(host)s', host='some'))
235
self.assertEquals("Hello some: ", factory.stderr.getvalue())
236
self.assertEquals('', factory.stdout.getvalue())
275
237
self.assertEqual("", factory.get_username("Gebruiker"))
276
238
# stdin should be empty
277
239
self.assertEqual('', factory.stdin.readline())
279
241
def test_text_ui_getusername_utf8(self):
280
ui = TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
281
stdout=StringIOWrapper())
282
ui.stdin.encoding = "utf8"
283
ui.stdout.encoding = ui.stdin.encoding
242
ui = tests.TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
243
stdout=tests.StringIOWrapper(),
244
stderr=tests.StringIOWrapper())
245
ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = "utf8"
284
246
pb = ui.nested_progress_bar()
286
248
# there is no output from the base factory
287
username = self.apply_redirected(ui.stdin, ui.stdout, ui.stdout,
249
username = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
288
250
ui.get_username, u'Hello\u1234 %(host)s', host=u'some\u1234')
289
251
self.assertEquals(u"someuser\u1234", username.decode('utf8'))
290
self.assertEquals(u"Hello\u1234 some\u1234: ",
291
ui.stdout.getvalue().decode("utf8"))
252
self.assertEquals(u"Hello\u1234 some\u1234: ",
253
ui.stderr.getvalue().decode("utf8"))
254
self.assertEquals('', ui.stdout.getvalue())
296
class TestTextProgressView(TestCase):
297
"""Tests for text display of progress bars.
299
# XXX: These might be a bit easier to write if the rendering and
300
# state-maintaining parts of TextProgressView were more separate, and if
301
# the progress task called back directly to its own view not to the ui
302
# factory. -- mbp 20090312
304
def _make_factory(self):
306
uif = TextUIFactory(stderr=out)
307
uif._progress_view._width = 80
310
def test_render_progress_easy(self):
311
"""Just one task and one quarter done"""
312
out, uif = self._make_factory()
313
task = uif.nested_progress_bar()
314
task.update('reticulating splines', 5, 20)
316
'\r[####/ ] reticulating splines 5/20 \r'
319
def test_render_progress_nested(self):
320
"""Tasks proportionally contribute to overall progress"""
321
out, uif = self._make_factory()
322
task = uif.nested_progress_bar()
323
task.update('reticulating splines', 0, 2)
324
task2 = uif.nested_progress_bar()
325
task2.update('stage2', 1, 2)
326
# so we're in the first half of the main task, and half way through
329
r'[####\ ] reticulating splines:stage2 1/2'
330
, uif._progress_view._render_line())
331
# if the nested task is complete, then we're all the way through the
332
# first half of the overall work
333
task2.update('stage2', 2, 2)
335
r'[#########| ] reticulating splines:stage2 2/2'
336
, uif._progress_view._render_line())
338
def test_render_progress_sub_nested(self):
339
"""Intermediate tasks don't mess up calculation."""
340
out, uif = self._make_factory()
341
task_a = uif.nested_progress_bar()
342
task_a.update('a', 0, 2)
343
task_b = uif.nested_progress_bar()
345
task_c = uif.nested_progress_bar()
346
task_c.update('c', 1, 2)
347
# the top-level task is in its first half; the middle one has no
348
# progress indication, just a label; and the bottom one is half done,
349
# so the overall fraction is 1/4
351
r'[####| ] a:b:c 1/2'
352
, uif._progress_view._render_line())
258
def test_quietness(self):
259
os.environ['BZR_PROGRESS_BAR'] = 'text'
260
ui_factory = _mod_ui_text.TextUIFactory(None,
261
test_progress._TTYStringIO(),
262
test_progress._TTYStringIO())
263
self.assertIsInstance(ui_factory._progress_view,
264
_mod_ui_text.TextProgressView)
265
ui_factory.be_quiet(True)
266
self.assertIsInstance(ui_factory._progress_view,
267
_mod_ui_text.NullProgressView)
269
def test_text_ui_show_user_warning(self):
270
from bzrlib.repofmt.groupcompress_repo import RepositoryFormat2a
271
from bzrlib.repofmt.pack_repo import RepositoryFormatKnitPack5
274
ui = tests.TextUIFactory(stdin=None, stdout=out, stderr=err)
275
remote_fmt = remote.RemoteRepositoryFormat()
276
remote_fmt._network_name = RepositoryFormatKnitPack5().network_name()
277
ui.show_user_warning('cross_format_fetch', from_format=RepositoryFormat2a(),
278
to_format=remote_fmt)
279
self.assertEquals('', out.getvalue())
280
self.assertEquals("Doing on-the-fly conversion from RepositoryFormat2a() to "
281
"RemoteRepositoryFormat(_network_name='Bazaar RepositoryFormatKnitPack5 "
282
"(bzr 1.6)\\n').\nThis may take some time. Upgrade the repositories to "
283
"the same format for better performance.\n",
285
# and now with it suppressed please
288
ui = tests.TextUIFactory(stdin=None, stdout=out, stderr=err)
289
ui.suppressed_warnings.add('cross_format_fetch')
290
ui.show_user_warning('cross_format_fetch', from_format=RepositoryFormat2a(),
291
to_format=remote_fmt)
292
self.assertEquals('', out.getvalue())
293
self.assertEquals('', err.getvalue())
296
class TestTextUIOutputStream(tests.TestCase):
297
"""Tests for output stream that synchronizes with progress bar."""
299
def test_output_clears_terminal(self):
300
stdout = tests.StringIOWrapper()
301
stderr = tests.StringIOWrapper()
304
uif = _mod_ui_text.TextUIFactory(None, stdout, stderr)
305
uif.clear_term = lambda: clear_calls.append('clear')
307
stream = _mod_ui_text.TextUIOutputStream(uif, uif.stdout)
308
stream.write("Hello world!\n")
309
stream.write("there's more...\n")
310
stream.writelines(["1\n", "2\n", "3\n"])
312
self.assertEqual(stdout.getvalue(),
316
self.assertEqual(['clear', 'clear', 'clear'],
322
class UITests(tests.TestCase):
324
def test_progress_construction(self):
325
"""TextUIFactory constructs the right progress view.
327
TTYStringIO = test_progress._TTYStringIO
328
FileStringIO = tests.StringIOWrapper
329
for (file_class, term, pb, expected_pb_class) in (
330
# on an xterm, either use them or not as the user requests,
331
# otherwise default on
332
(TTYStringIO, 'xterm', 'none', _mod_ui_text.NullProgressView),
333
(TTYStringIO, 'xterm', 'text', _mod_ui_text.TextProgressView),
334
(TTYStringIO, 'xterm', None, _mod_ui_text.TextProgressView),
335
# on a dumb terminal, again if there's explicit configuration do
336
# it, otherwise default off
337
(TTYStringIO, 'dumb', 'none', _mod_ui_text.NullProgressView),
338
(TTYStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
339
(TTYStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
340
# on a non-tty terminal, it's null regardless of $TERM
341
(FileStringIO, 'xterm', None, _mod_ui_text.NullProgressView),
342
(FileStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
343
# however, it can still be forced on
344
(FileStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
346
os.environ['TERM'] = term
348
if 'BZR_PROGRESS_BAR' in os.environ:
349
del os.environ['BZR_PROGRESS_BAR']
351
os.environ['BZR_PROGRESS_BAR'] = pb
352
stdin = file_class('')
353
stderr = file_class()
354
stdout = file_class()
355
uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
356
self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
357
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
358
self.assertIsInstance(uif.make_progress_view(),
360
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
362
def test_text_ui_non_terminal(self):
363
"""Even on non-ttys, make_ui_for_terminal gives a text ui."""
364
stdin = test_progress._NonTTYStringIO('')
365
stderr = test_progress._NonTTYStringIO()
366
stdout = test_progress._NonTTYStringIO()
367
for term_type in ['dumb', None, 'xterm']:
368
if term_type is None:
369
del os.environ['TERM']
371
os.environ['TERM'] = term_type
372
uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
373
self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
374
'TERM=%r' % (term_type,))
377
class SilentUITests(tests.TestCase):
379
def test_silent_factory_get_password(self):
380
# A silent factory that can't do user interaction can't get a
381
# password. Possibly it should raise a more specific error but it
383
ui = _mod_ui.SilentUIFactory()
384
stdout = tests.StringIOWrapper()
387
self.apply_redirected,
388
None, stdout, stdout, ui.get_password)
389
# and it didn't write anything out either
390
self.assertEqual('', stdout.getvalue())
392
def test_silent_ui_getbool(self):
393
factory = _mod_ui.SilentUIFactory()
394
stdout = tests.StringIOWrapper()
397
self.apply_redirected,
398
None, stdout, stdout, factory.get_boolean, "foo")
401
class TestUIFactoryTests(tests.TestCase):
403
def test_test_ui_factory_progress(self):
404
# there's no output; we just want to make sure this doesn't crash -
405
# see https://bugs.launchpad.net/bzr/+bug/408201
406
ui = tests.TestUIFactory()
407
pb = ui.nested_progress_bar()
413
class CannedInputUIFactoryTests(tests.TestCase):
415
def test_canned_input_get_input(self):
416
uif = _mod_ui.CannedInputUIFactory([True, 'mbp', 'password', 42])
417
self.assertEqual(True, uif.get_boolean('Extra cheese?'))
418
self.assertEqual('mbp', uif.get_username('Enter your user name'))
419
self.assertEqual('password',
420
uif.get_password('Password for %(host)s',
422
self.assertEqual(42, uif.get_integer('And all that jazz ?'))
425
class TestBoolFromString(tests.TestCase):
427
def assertIsTrue(self, s, accepted_values=None):
428
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
429
self.assertEquals(True, res)
431
def assertIsFalse(self, s, accepted_values=None):
432
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
433
self.assertEquals(False, res)
435
def assertIsNone(self, s, accepted_values=None):
436
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
437
self.assertIs(None, res)
439
def test_know_valid_values(self):
440
self.assertIsTrue('true')
441
self.assertIsFalse('false')
442
self.assertIsTrue('1')
443
self.assertIsFalse('0')
444
self.assertIsTrue('on')
445
self.assertIsFalse('off')
446
self.assertIsTrue('yes')
447
self.assertIsFalse('no')
448
self.assertIsTrue('y')
449
self.assertIsFalse('n')
450
# Also try some case variations
451
self.assertIsTrue('True')
452
self.assertIsFalse('False')
453
self.assertIsTrue('On')
454
self.assertIsFalse('Off')
455
self.assertIsTrue('ON')
456
self.assertIsFalse('OFF')
457
self.assertIsTrue('oN')
458
self.assertIsFalse('oFf')
460
def test_invalid_values(self):
461
self.assertIsNone(None)
462
self.assertIsNone('doubt')
463
self.assertIsNone('frue')
464
self.assertIsNone('talse')
465
self.assertIsNone('42')
467
def test_provided_values(self):
468
av = dict(y=True, n=False, yes=True, no=False)
469
self.assertIsTrue('y', av)
470
self.assertIsTrue('Y', av)
471
self.assertIsTrue('Yes', av)
472
self.assertIsFalse('n', av)
473
self.assertIsFalse('N', av)
474
self.assertIsFalse('No', av)
475
self.assertIsNone('1', av)
476
self.assertIsNone('0', av)
477
self.assertIsNone('on', av)
478
self.assertIsNone('off', av)