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(""))
127
def test_text_ui_get_boolean(self):
128
stdin = tests.StringIOWrapper("y\n" # True
130
"yes with garbage\nY\n" # True
131
"not an answer\nno\n" # False
132
"I'm sure!\nyes\n" # True
135
stdout = tests.StringIOWrapper()
136
stderr = tests.StringIOWrapper()
137
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
138
self.assertEqual(True, factory.get_boolean(""))
139
self.assertEqual(False, factory.get_boolean(""))
140
self.assertEqual(True, factory.get_boolean(""))
141
self.assertEqual(False, factory.get_boolean(""))
142
self.assertEqual(True, factory.get_boolean(""))
200
143
self.assertEqual(False, factory.get_boolean(""))
201
144
self.assertEqual("foo\n", factory.stdin.read())
202
145
# stdin should be empty
203
146
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)
148
def test_text_ui_get_integer(self):
149
stdin = tests.StringIOWrapper(
152
"hmmm\nwhat else ?\nCome on\nok 42\n4.24\n42\n")
153
stdout = tests.StringIOWrapper()
154
stderr = tests.StringIOWrapper()
155
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
156
self.assertEqual(1, factory.get_integer(""))
157
self.assertEqual(-2, factory.get_integer(""))
158
self.assertEqual(42, factory.get_integer(""))
160
def test_text_factory_prompt(self):
161
# see <https://launchpad.net/bugs/365891>
162
StringIO = tests.StringIOWrapper
163
factory = _mod_ui_text.TextUIFactory(StringIO(), StringIO(), StringIO())
164
factory.prompt('foo %2e')
165
self.assertEqual('', factory.stdout.getvalue())
166
self.assertEqual('foo %2e', factory.stderr.getvalue())
224
168
def test_text_factory_prompts_and_clears(self):
225
169
# a get_boolean call should clear the pb before prompting
227
factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
170
out = test_progress._TTYStringIO()
171
os.environ['TERM'] = 'xterm'
172
factory = _mod_ui_text.TextUIFactory(
173
stdin=tests.StringIOWrapper("yada\ny\n"),
174
stdout=out, stderr=out)
228
175
pb = factory.nested_progress_bar()
229
176
pb.show_bar = False
230
177
pb.show_spinner = False
258
class TestTextProgressView(TestCase):
259
"""Tests for text display of progress bars.
261
# XXX: These might be a bit easier to write if the rendering and
262
# state-maintaining parts of TextProgressView were more separate, and if
263
# the progress task called back directly to its own view not to the ui
264
# factory. -- mbp 20090312
266
def _make_factory(self):
268
uif = TextUIFactory(stderr=out)
269
uif._progress_view._width = 80
272
def test_render_progress_easy(self):
273
"""Just one task and one quarter done"""
274
out, uif = self._make_factory()
275
task = uif.nested_progress_bar()
276
task.update('reticulating splines', 5, 20)
278
'\r[####/ ] reticulating splines 5/20 \r'
281
def test_render_progress_nested(self):
282
"""Tasks proportionally contribute to overall progress"""
283
out, uif = self._make_factory()
284
task = uif.nested_progress_bar()
285
task.update('reticulating splines', 0, 2)
286
task2 = uif.nested_progress_bar()
287
task2.update('stage2', 1, 2)
288
# so we're in the first half of the main task, and half way through
291
r'[####\ ] reticulating splines:stage2 1/2'
292
, uif._progress_view._render_line())
293
# if the nested task is complete, then we're all the way through the
294
# first half of the overall work
295
task2.update('stage2', 2, 2)
297
r'[#########| ] reticulating splines:stage2 2/2'
298
, uif._progress_view._render_line())
300
def test_render_progress_sub_nested(self):
301
"""Intermediate tasks don't mess up calculation."""
302
out, uif = self._make_factory()
303
task_a = uif.nested_progress_bar()
304
task_a.update('a', 0, 2)
305
task_b = uif.nested_progress_bar()
307
task_c = uif.nested_progress_bar()
308
task_c.update('c', 1, 2)
309
# the top-level task is in its first half; the middle one has no
310
# progress indication, just a label; and the bottom one is half done,
311
# so the overall fraction is 1/4
313
r'[####| ] a:b:c 1/2'
314
, uif._progress_view._render_line())
205
def test_text_ui_getusername(self):
206
factory = _mod_ui_text.TextUIFactory(None, None, None)
207
factory.stdin = tests.StringIOWrapper("someuser\n\n")
208
factory.stdout = tests.StringIOWrapper()
209
factory.stderr = tests.StringIOWrapper()
210
factory.stdout.encoding = "utf8"
211
# there is no output from the base factory
212
self.assertEqual("someuser",
213
factory.get_username('Hello %(host)s', host='some'))
214
self.assertEquals("Hello some: ", factory.stderr.getvalue())
215
self.assertEquals('', factory.stdout.getvalue())
216
self.assertEqual("", factory.get_username("Gebruiker"))
217
# stdin should be empty
218
self.assertEqual('', factory.stdin.readline())
220
def test_text_ui_getusername_utf8(self):
221
ui = tests.TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
222
stdout=tests.StringIOWrapper(),
223
stderr=tests.StringIOWrapper())
224
ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = "utf8"
225
pb = ui.nested_progress_bar()
227
# there is no output from the base factory
228
username = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
229
ui.get_username, u'Hello\u1234 %(host)s', host=u'some\u1234')
230
self.assertEquals(u"someuser\u1234", username.decode('utf8'))
231
self.assertEquals(u"Hello\u1234 some\u1234: ",
232
ui.stderr.getvalue().decode("utf8"))
233
self.assertEquals('', ui.stdout.getvalue())
237
def test_quietness(self):
238
os.environ['BZR_PROGRESS_BAR'] = 'text'
239
ui_factory = _mod_ui_text.TextUIFactory(None,
240
test_progress._TTYStringIO(),
241
test_progress._TTYStringIO())
242
self.assertIsInstance(ui_factory._progress_view,
243
_mod_ui_text.TextProgressView)
244
ui_factory.be_quiet(True)
245
self.assertIsInstance(ui_factory._progress_view,
246
_mod_ui_text.NullProgressView)
249
class TestTextUIOutputStream(tests.TestCase):
250
"""Tests for output stream that synchronizes with progress bar."""
252
def test_output_clears_terminal(self):
253
stdout = tests.StringIOWrapper()
254
stderr = tests.StringIOWrapper()
257
uif = _mod_ui_text.TextUIFactory(None, stdout, stderr)
258
uif.clear_term = lambda: clear_calls.append('clear')
260
stream = _mod_ui_text.TextUIOutputStream(uif, uif.stdout)
261
stream.write("Hello world!\n")
262
stream.write("there's more...\n")
263
stream.writelines(["1\n", "2\n", "3\n"])
265
self.assertEqual(stdout.getvalue(),
269
self.assertEqual(['clear', 'clear', 'clear'],
275
class UITests(tests.TestCase):
277
def test_progress_construction(self):
278
"""TextUIFactory constructs the right progress view.
280
TTYStringIO = test_progress._TTYStringIO
281
FileStringIO = tests.StringIOWrapper
282
for (file_class, term, pb, expected_pb_class) in (
283
# on an xterm, either use them or not as the user requests,
284
# otherwise default on
285
(TTYStringIO, 'xterm', 'none', _mod_ui_text.NullProgressView),
286
(TTYStringIO, 'xterm', 'text', _mod_ui_text.TextProgressView),
287
(TTYStringIO, 'xterm', None, _mod_ui_text.TextProgressView),
288
# on a dumb terminal, again if there's explicit configuration do
289
# it, otherwise default off
290
(TTYStringIO, 'dumb', 'none', _mod_ui_text.NullProgressView),
291
(TTYStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
292
(TTYStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
293
# on a non-tty terminal, it's null regardless of $TERM
294
(FileStringIO, 'xterm', None, _mod_ui_text.NullProgressView),
295
(FileStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
296
# however, it can still be forced on
297
(FileStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
299
os.environ['TERM'] = term
301
if 'BZR_PROGRESS_BAR' in os.environ:
302
del os.environ['BZR_PROGRESS_BAR']
304
os.environ['BZR_PROGRESS_BAR'] = pb
305
stdin = file_class('')
306
stderr = file_class()
307
stdout = file_class()
308
uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
309
self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
310
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
311
self.assertIsInstance(uif.make_progress_view(),
313
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
315
def test_text_ui_non_terminal(self):
316
"""Even on non-ttys, make_ui_for_terminal gives a text ui."""
317
stdin = test_progress._NonTTYStringIO('')
318
stderr = test_progress._NonTTYStringIO()
319
stdout = test_progress._NonTTYStringIO()
320
for term_type in ['dumb', None, 'xterm']:
321
if term_type is None:
322
del os.environ['TERM']
324
os.environ['TERM'] = term_type
325
uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
326
self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
327
'TERM=%r' % (term_type,))
330
class SilentUITests(tests.TestCase):
332
def test_silent_factory_get_password(self):
333
# A silent factory that can't do user interaction can't get a
334
# password. Possibly it should raise a more specific error but it
336
ui = _mod_ui.SilentUIFactory()
337
stdout = tests.StringIOWrapper()
340
self.apply_redirected,
341
None, stdout, stdout, ui.get_password)
342
# and it didn't write anything out either
343
self.assertEqual('', stdout.getvalue())
345
def test_silent_ui_getbool(self):
346
factory = _mod_ui.SilentUIFactory()
347
stdout = tests.StringIOWrapper()
350
self.apply_redirected,
351
None, stdout, stdout, factory.get_boolean, "foo")
354
class TestUIFactoryTests(tests.TestCase):
356
def test_test_ui_factory_progress(self):
357
# there's no output; we just want to make sure this doesn't crash -
358
# see https://bugs.edge.launchpad.net/bzr/+bug/408201
359
ui = tests.TestUIFactory()
360
pb = ui.nested_progress_bar()
366
class CannedInputUIFactoryTests(tests.TestCase):
368
def test_canned_input_get_input(self):
369
uif = _mod_ui.CannedInputUIFactory([True, 'mbp', 'password', 42])
370
self.assertEqual(True, uif.get_boolean('Extra cheese?'))
371
self.assertEqual('mbp', uif.get_username('Enter your user name'))
372
self.assertEqual('password',
373
uif.get_password('Password for %(host)s',
375
self.assertEqual(42, uif.get_integer('And all that jazz ?'))
378
class TestBoolFromString(tests.TestCase):
380
def assertIsTrue(self, s, accepted_values=None):
381
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
382
self.assertEquals(True, res)
384
def assertIsFalse(self, s, accepted_values=None):
385
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
386
self.assertEquals(False, res)
388
def assertIsNone(self, s, accepted_values=None):
389
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
390
self.assertIs(None, res)
392
def test_know_valid_values(self):
393
self.assertIsTrue('true')
394
self.assertIsFalse('false')
395
self.assertIsTrue('1')
396
self.assertIsFalse('0')
397
self.assertIsTrue('on')
398
self.assertIsFalse('off')
399
self.assertIsTrue('yes')
400
self.assertIsFalse('no')
401
self.assertIsTrue('y')
402
self.assertIsFalse('n')
403
# Also try some case variations
404
self.assertIsTrue('True')
405
self.assertIsFalse('False')
406
self.assertIsTrue('On')
407
self.assertIsFalse('Off')
408
self.assertIsTrue('ON')
409
self.assertIsFalse('OFF')
410
self.assertIsTrue('oN')
411
self.assertIsFalse('oFf')
413
def test_invalid_values(self):
414
self.assertIsNone(None)
415
self.assertIsNone('doubt')
416
self.assertIsNone('frue')
417
self.assertIsNone('talse')
418
self.assertIsNone('42')
420
def test_provided_values(self):
421
av = dict(y=True, n=False, yes=True, no=False)
422
self.assertIsTrue('y', av)
423
self.assertIsTrue('Y', av)
424
self.assertIsTrue('Yes', av)
425
self.assertIsFalse('n', av)
426
self.assertIsFalse('N', av)
427
self.assertIsFalse('No', av)
428
self.assertIsNone('1', av)
429
self.assertIsNone('0', av)
430
self.assertIsNone('on', av)
431
self.assertIsNone('off', av)