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
33
from bzrlib.symbol_versioning import (
35
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())
36
from bzrlib.tests import test_progress
37
from bzrlib.ui import text as _mod_ui_text
40
class TestTextUIFactory(tests.TestCase):
64
42
def test_text_factory_ascii_password(self):
65
ui = TestUIFactory(stdin='secret\n', stdout=StringIOWrapper())
43
ui = tests.TestUIFactory(stdin='secret\n',
44
stdout=tests.StringIOWrapper(),
45
stderr=tests.StringIOWrapper())
66
46
pb = ui.nested_progress_bar()
68
48
self.assertEqual('secret',
69
49
self.apply_redirected(ui.stdin, ui.stdout,
72
52
# ': ' is appended to prompt
73
self.assertEqual(': ', ui.stdout.getvalue())
53
self.assertEqual(': ', ui.stderr.getvalue())
54
self.assertEqual('', ui.stdout.readline())
74
55
# stdin should be empty
75
56
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(""))
131
def test_text_ui_get_boolean(self):
132
stdin = tests.StringIOWrapper("y\n" # True
134
"yes with garbage\nY\n" # True
135
"not an answer\nno\n" # False
136
"I'm sure!\nyes\n" # True
139
stdout = tests.StringIOWrapper()
140
stderr = tests.StringIOWrapper()
141
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
142
self.assertEqual(True, factory.get_boolean(""))
143
self.assertEqual(False, factory.get_boolean(""))
144
self.assertEqual(True, factory.get_boolean(""))
145
self.assertEqual(False, factory.get_boolean(""))
146
self.assertEqual(True, factory.get_boolean(""))
195
147
self.assertEqual(False, factory.get_boolean(""))
196
148
self.assertEqual("foo\n", factory.stdin.read())
197
149
# stdin should be empty
198
150
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)
152
def test_text_ui_get_integer(self):
153
stdin = tests.StringIOWrapper(
156
"hmmm\nwhat else ?\nCome on\nok 42\n4.24\n42\n")
157
stdout = tests.StringIOWrapper()
158
stderr = tests.StringIOWrapper()
159
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
160
self.assertEqual(1, factory.get_integer(""))
161
self.assertEqual(-2, factory.get_integer(""))
162
self.assertEqual(42, factory.get_integer(""))
164
def test_text_factory_prompt(self):
165
# see <https://launchpad.net/bugs/365891>
166
StringIO = tests.StringIOWrapper
167
factory = _mod_ui_text.TextUIFactory(StringIO(), StringIO(), StringIO())
168
factory.prompt('foo %2e')
169
self.assertEqual('', factory.stdout.getvalue())
170
self.assertEqual('foo %2e', factory.stderr.getvalue())
219
172
def test_text_factory_prompts_and_clears(self):
220
173
# a get_boolean call should clear the pb before prompting
222
factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
174
out = test_progress._TTYStringIO()
175
os.environ['TERM'] = 'xterm'
176
factory = _mod_ui_text.TextUIFactory(
177
stdin=tests.StringIOWrapper("yada\ny\n"),
178
stdout=out, stderr=out)
223
179
pb = factory.nested_progress_bar()
224
180
pb.show_bar = False
225
181
pb.show_spinner = False
237
193
r"what do you want\? \[y/n\]: what do you want\? \[y/n\]: ")
238
194
# stdin should have been totally consumed
239
195
self.assertEqual('', factory.stdin.readline())
197
def test_text_tick_after_update(self):
198
ui_factory = _mod_ui_text.TextUIFactory(stdout=tests.StringIOWrapper(),
199
stderr=tests.StringIOWrapper())
200
pb = ui_factory.nested_progress_bar()
202
pb.update('task', 0, 3)
203
# Reset the clock, so that it actually tries to repaint itself
204
ui_factory._progress_view._last_repaint = time.time() - 1.0
209
def test_text_ui_getusername(self):
210
factory = _mod_ui_text.TextUIFactory(None, None, None)
211
factory.stdin = tests.StringIOWrapper("someuser\n\n")
212
factory.stdout = tests.StringIOWrapper()
213
factory.stderr = tests.StringIOWrapper()
214
factory.stdout.encoding = "utf8"
215
# there is no output from the base factory
216
self.assertEqual("someuser",
217
factory.get_username('Hello %(host)s', host='some'))
218
self.assertEquals("Hello some: ", factory.stderr.getvalue())
219
self.assertEquals('', factory.stdout.getvalue())
220
self.assertEqual("", factory.get_username("Gebruiker"))
221
# stdin should be empty
222
self.assertEqual('', factory.stdin.readline())
224
def test_text_ui_getusername_utf8(self):
225
ui = tests.TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
226
stdout=tests.StringIOWrapper(),
227
stderr=tests.StringIOWrapper())
228
ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = "utf8"
229
pb = ui.nested_progress_bar()
231
# there is no output from the base factory
232
username = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
233
ui.get_username, u'Hello\u1234 %(host)s', host=u'some\u1234')
234
self.assertEquals(u"someuser\u1234", username.decode('utf8'))
235
self.assertEquals(u"Hello\u1234 some\u1234: ",
236
ui.stderr.getvalue().decode("utf8"))
237
self.assertEquals('', ui.stdout.getvalue())
241
def test_quietness(self):
242
os.environ['BZR_PROGRESS_BAR'] = 'text'
243
ui_factory = _mod_ui_text.TextUIFactory(None,
244
test_progress._TTYStringIO(),
245
test_progress._TTYStringIO())
246
self.assertIsInstance(ui_factory._progress_view,
247
_mod_ui_text.TextProgressView)
248
ui_factory.be_quiet(True)
249
self.assertIsInstance(ui_factory._progress_view,
250
_mod_ui_text.NullProgressView)
252
def test_text_ui_show_user_warning(self):
253
from bzrlib.repofmt.groupcompress_repo import RepositoryFormat2a
254
from bzrlib.repofmt.pack_repo import RepositoryFormatKnitPack5
257
ui = tests.TextUIFactory(stdin=None, stdout=out, stderr=err)
258
remote_fmt = remote.RemoteRepositoryFormat()
259
remote_fmt._network_name = RepositoryFormatKnitPack5().network_name()
260
ui.show_user_warning('cross_format_fetch', from_format=RepositoryFormat2a(),
261
to_format=remote_fmt)
262
self.assertEquals('', out.getvalue())
263
self.assertEquals("Doing on-the-fly conversion from RepositoryFormat2a() to "
264
"RemoteRepositoryFormat(_network_name='Bazaar RepositoryFormatKnitPack5 "
265
"(bzr 1.6)\\n').\nThis may take some time. Upgrade the repositories to "
266
"the same format for better performance.\n",
268
# and now with it suppressed please
271
ui = tests.TextUIFactory(stdin=None, stdout=out, stderr=err)
272
ui.suppressed_warnings.add('cross_format_fetch')
273
ui.show_user_warning('cross_format_fetch', from_format=RepositoryFormat2a(),
274
to_format=remote_fmt)
275
self.assertEquals('', out.getvalue())
276
self.assertEquals('', err.getvalue())
279
class TestTextUIOutputStream(tests.TestCase):
280
"""Tests for output stream that synchronizes with progress bar."""
282
def test_output_clears_terminal(self):
283
stdout = tests.StringIOWrapper()
284
stderr = tests.StringIOWrapper()
287
uif = _mod_ui_text.TextUIFactory(None, stdout, stderr)
288
uif.clear_term = lambda: clear_calls.append('clear')
290
stream = _mod_ui_text.TextUIOutputStream(uif, uif.stdout)
291
stream.write("Hello world!\n")
292
stream.write("there's more...\n")
293
stream.writelines(["1\n", "2\n", "3\n"])
295
self.assertEqual(stdout.getvalue(),
299
self.assertEqual(['clear', 'clear', 'clear'],
305
class UITests(tests.TestCase):
307
def test_progress_construction(self):
308
"""TextUIFactory constructs the right progress view.
310
TTYStringIO = test_progress._TTYStringIO
311
FileStringIO = tests.StringIOWrapper
312
for (file_class, term, pb, expected_pb_class) in (
313
# on an xterm, either use them or not as the user requests,
314
# otherwise default on
315
(TTYStringIO, 'xterm', 'none', _mod_ui_text.NullProgressView),
316
(TTYStringIO, 'xterm', 'text', _mod_ui_text.TextProgressView),
317
(TTYStringIO, 'xterm', None, _mod_ui_text.TextProgressView),
318
# on a dumb terminal, again if there's explicit configuration do
319
# it, otherwise default off
320
(TTYStringIO, 'dumb', 'none', _mod_ui_text.NullProgressView),
321
(TTYStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
322
(TTYStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
323
# on a non-tty terminal, it's null regardless of $TERM
324
(FileStringIO, 'xterm', None, _mod_ui_text.NullProgressView),
325
(FileStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
326
# however, it can still be forced on
327
(FileStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
329
os.environ['TERM'] = term
331
if 'BZR_PROGRESS_BAR' in os.environ:
332
del os.environ['BZR_PROGRESS_BAR']
334
os.environ['BZR_PROGRESS_BAR'] = pb
335
stdin = file_class('')
336
stderr = file_class()
337
stdout = file_class()
338
uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
339
self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
340
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
341
self.assertIsInstance(uif.make_progress_view(),
343
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
345
def test_text_ui_non_terminal(self):
346
"""Even on non-ttys, make_ui_for_terminal gives a text ui."""
347
stdin = test_progress._NonTTYStringIO('')
348
stderr = test_progress._NonTTYStringIO()
349
stdout = test_progress._NonTTYStringIO()
350
for term_type in ['dumb', None, 'xterm']:
351
if term_type is None:
352
del os.environ['TERM']
354
os.environ['TERM'] = term_type
355
uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
356
self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
357
'TERM=%r' % (term_type,))
360
class SilentUITests(tests.TestCase):
362
def test_silent_factory_get_password(self):
363
# A silent factory that can't do user interaction can't get a
364
# password. Possibly it should raise a more specific error but it
366
ui = _mod_ui.SilentUIFactory()
367
stdout = tests.StringIOWrapper()
370
self.apply_redirected,
371
None, stdout, stdout, ui.get_password)
372
# and it didn't write anything out either
373
self.assertEqual('', stdout.getvalue())
375
def test_silent_ui_getbool(self):
376
factory = _mod_ui.SilentUIFactory()
377
stdout = tests.StringIOWrapper()
380
self.apply_redirected,
381
None, stdout, stdout, factory.get_boolean, "foo")
384
class TestUIFactoryTests(tests.TestCase):
386
def test_test_ui_factory_progress(self):
387
# there's no output; we just want to make sure this doesn't crash -
388
# see https://bugs.launchpad.net/bzr/+bug/408201
389
ui = tests.TestUIFactory()
390
pb = ui.nested_progress_bar()
396
class CannedInputUIFactoryTests(tests.TestCase):
398
def test_canned_input_get_input(self):
399
uif = _mod_ui.CannedInputUIFactory([True, 'mbp', 'password', 42])
400
self.assertEqual(True, uif.get_boolean('Extra cheese?'))
401
self.assertEqual('mbp', uif.get_username('Enter your user name'))
402
self.assertEqual('password',
403
uif.get_password('Password for %(host)s',
405
self.assertEqual(42, uif.get_integer('And all that jazz ?'))
408
class TestBoolFromString(tests.TestCase):
410
def assertIsTrue(self, s, accepted_values=None):
411
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
412
self.assertEquals(True, res)
414
def assertIsFalse(self, s, accepted_values=None):
415
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
416
self.assertEquals(False, res)
418
def assertIsNone(self, s, accepted_values=None):
419
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
420
self.assertIs(None, res)
422
def test_know_valid_values(self):
423
self.assertIsTrue('true')
424
self.assertIsFalse('false')
425
self.assertIsTrue('1')
426
self.assertIsFalse('0')
427
self.assertIsTrue('on')
428
self.assertIsFalse('off')
429
self.assertIsTrue('yes')
430
self.assertIsFalse('no')
431
self.assertIsTrue('y')
432
self.assertIsFalse('n')
433
# Also try some case variations
434
self.assertIsTrue('True')
435
self.assertIsFalse('False')
436
self.assertIsTrue('On')
437
self.assertIsFalse('Off')
438
self.assertIsTrue('ON')
439
self.assertIsFalse('OFF')
440
self.assertIsTrue('oN')
441
self.assertIsFalse('oFf')
443
def test_invalid_values(self):
444
self.assertIsNone(None)
445
self.assertIsNone('doubt')
446
self.assertIsNone('frue')
447
self.assertIsNone('talse')
448
self.assertIsNone('42')
450
def test_provided_values(self):
451
av = dict(y=True, n=False, yes=True, no=False)
452
self.assertIsTrue('y', av)
453
self.assertIsTrue('Y', av)
454
self.assertIsTrue('Yes', av)
455
self.assertIsFalse('n', av)
456
self.assertIsFalse('N', av)
457
self.assertIsFalse('No', av)
458
self.assertIsNone('1', av)
459
self.assertIsNone('0', av)
460
self.assertIsNone('on', av)
461
self.assertIsNone('off', av)