13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
"""Tests for the bzrlib ui
21
24
from StringIO import StringIO
26
import bzrlib.errors as errors
27
from bzrlib.progress import (
32
34
from bzrlib.symbol_versioning import (
35
37
from bzrlib.tests import (
40
from bzrlib.tests.test_progress import _TTYStringIO
41
from bzrlib.ui import (
45
from bzrlib.ui.text import TextUIFactory
48
class UITests(TestCase):
50
def test_silent_factory(self):
51
ui = SilentUIFactory()
53
self.assertEqual(None,
54
self.apply_redirected(None, stdout, stdout,
56
self.assertEqual('', stdout.getvalue())
57
self.assertEqual(None,
58
self.apply_redirected(None, stdout, stdout,
60
u'Hello\u1234 %(user)s',
62
self.assertEqual('', stdout.getvalue())
41
from bzrlib.ui import text as _mod_ui_text
44
class TestUIConfiguration(tests.TestCaseWithTransport):
46
def test_output_encoding_configuration(self):
47
enc = fixtures.generate_unicode_encodings().next()
48
config.GlobalConfig().set_user_option('output_encoding',
50
ui = tests.TestUIFactory(stdin=None,
51
stdout=tests.StringIOWrapper(),
52
stderr=tests.StringIOWrapper())
53
os = ui.make_output_stream()
54
self.assertEquals(os.encoding, enc)
57
class TestTextUIFactory(tests.TestCase):
64
59
def test_text_factory_ascii_password(self):
65
ui = TestUIFactory(stdin='secret\n', stdout=StringIOWrapper())
60
ui = tests.TestUIFactory(stdin='secret\n',
61
stdout=tests.StringIOWrapper(),
62
stderr=tests.StringIOWrapper())
66
63
pb = ui.nested_progress_bar()
68
65
self.assertEqual('secret',
69
66
self.apply_redirected(ui.stdin, ui.stdout,
72
69
# ': ' is appended to prompt
73
self.assertEqual(': ', ui.stdout.getvalue())
70
self.assertEqual(': ', ui.stderr.getvalue())
71
self.assertEqual('', ui.stdout.readline())
74
72
# stdin should be empty
75
73
self.assertEqual('', ui.stdin.readline())
145
def test_progress_nested(self):
146
# test factory based nested and popping.
147
ui = TextUIFactory(None, None, None)
148
pb1 = ui.nested_progress_bar()
149
pb2 = ui.nested_progress_bar()
150
# You do get a warning if the outermost progress bar wasn't finished
151
# first - it's not clear if this is really useful or if it should just
152
# become orphaned -- mbp 20090120
153
warnings, _ = self.callCatchWarnings(pb1.finished)
154
if len(warnings) != 1:
155
self.fail("unexpected warnings: %r" % (warnings,))
159
def test_progress_stack(self):
160
# test the progress bar stack which the default text factory
164
# make a stack, which accepts parameters like a pb.
165
stack = self.applyDeprecated(
166
deprecated_in((1, 12, 0)),
168
to_file=stderr, to_messages_file=stdout)
170
self.assertFalse(getattr(stack, 'note', False))
171
pb1 = stack.get_nested()
172
pb2 = stack.get_nested()
173
warnings, _ = self.callCatchWarnings(pb1.finished)
174
self.assertEqual(len(warnings), 1)
177
# the text ui factory never actually removes the stack once its setup.
178
# we need to be able to nest again correctly from here.
179
pb1 = stack.get_nested()
180
pb2 = stack.get_nested()
181
warnings, _ = self.callCatchWarnings(pb1.finished)
182
self.assertEqual(len(warnings), 1)
186
def assert_get_bool_acceptance_of_user_input(self, factory):
187
factory.stdin = StringIO("y\nyes with garbage\n"
188
"yes\nn\nnot an answer\n"
190
factory.stdout = StringIO()
191
# there is no output from the base factory
192
self.assertEqual(True, factory.get_boolean(""))
193
self.assertEqual(True, factory.get_boolean(""))
194
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(""))
195
164
self.assertEqual(False, factory.get_boolean(""))
196
165
self.assertEqual("foo\n", factory.stdin.read())
197
166
# stdin should be empty
198
167
self.assertEqual('', factory.stdin.readline())
200
def test_silent_ui_getbool(self):
201
factory = SilentUIFactory()
202
self.assert_get_bool_acceptance_of_user_input(factory)
204
def test_silent_factory_prompts_silently(self):
205
factory = SilentUIFactory()
207
factory.stdin = StringIO("y\n")
208
self.assertEqual(True,
209
self.apply_redirected(None, stdout, stdout,
210
factory.get_boolean, "foo"))
211
self.assertEqual("", stdout.getvalue())
212
# stdin should be empty
213
self.assertEqual('', factory.stdin.readline())
215
def test_text_ui_getbool(self):
216
factory = TextUIFactory(None, None, None)
217
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())
219
189
def test_text_factory_prompts_and_clears(self):
220
190
# a get_boolean call should clear the pb before prompting
222
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)
223
196
pb = factory.nested_progress_bar()
224
197
pb.show_bar = False
225
198
pb.show_spinner = False
237
210
r"what do you want\? \[y/n\]: what do you want\? \[y/n\]: ")
238
211
# stdin should have been totally consumed
239
212
self.assertEqual('', factory.stdin.readline())
214
def test_text_tick_after_update(self):
215
ui_factory = _mod_ui_text.TextUIFactory(stdout=tests.StringIOWrapper(),
216
stderr=tests.StringIOWrapper())
217
pb = ui_factory.nested_progress_bar()
219
pb.update('task', 0, 3)
220
# Reset the clock, so that it actually tries to repaint itself
221
ui_factory._progress_view._last_repaint = time.time() - 1.0
226
def test_text_ui_getusername(self):
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()
231
factory.stdout.encoding = "utf8"
232
# there is no output from the base factory
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())
237
self.assertEqual("", factory.get_username("Gebruiker"))
238
# stdin should be empty
239
self.assertEqual('', factory.stdin.readline())
241
def test_text_ui_getusername_utf8(self):
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"
246
pb = ui.nested_progress_bar()
248
# there is no output from the base factory
249
username = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
250
ui.get_username, u'Hello\u1234 %(host)s', host=u'some\u1234')
251
self.assertEquals(u"someuser\u1234", username.decode('utf8'))
252
self.assertEquals(u"Hello\u1234 some\u1234: ",
253
ui.stderr.getvalue().decode("utf8"))
254
self.assertEquals('', ui.stdout.getvalue())
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)