17
17
"""Tests for the bzrlib ui
22
24
from StringIO import StringIO
24
from testtools.matchers import *
26
26
from bzrlib import (
34
from bzrlib.symbol_versioning import (
32
37
from bzrlib.tests import (
35
41
from bzrlib.ui import text as _mod_ui_text
36
from bzrlib.tests.testui import (
37
ProgressRecordingUIFactory,
41
class TTYStringIO(StringIO):
42
"""A helper class which makes a StringIO look like a terminal"""
48
class NonTTYStringIO(StringIO):
49
"""Helper that implements isatty() but returns False"""
55
44
class TestUIConfiguration(tests.TestCaseWithTransport):
57
46
def test_output_encoding_configuration(self):
58
47
enc = fixtures.generate_unicode_encodings().next()
59
config.GlobalStack().set('output_encoding', enc)
48
config.GlobalConfig().set_user_option('output_encoding',
60
50
ui = tests.TestUIFactory(stdin=None,
61
51
stdout=tests.StringIOWrapper(),
62
52
stderr=tests.StringIOWrapper())
63
output = ui.make_output_stream()
64
self.assertEqual(output.encoding, enc)
53
os = ui.make_output_stream()
54
self.assertEquals(os.encoding, enc)
67
57
class TestTextUIFactory(tests.TestCase):
69
def make_test_ui_factory(self, stdin_contents):
70
ui = tests.TestUIFactory(stdin=stdin_contents,
71
stdout=tests.StringIOWrapper(),
72
stderr=tests.StringIOWrapper())
75
def test_text_factory_confirm(self):
76
# turns into reading a regular boolean
77
ui = self.make_test_ui_factory('n\n')
78
self.assertEqual(ui.confirm_action(u'Should %(thing)s pass?',
79
'bzrlib.tests.test_ui.confirmation',
83
59
def test_text_factory_ascii_password(self):
84
ui = self.make_test_ui_factory('secret\n')
60
ui = tests.TestUIFactory(stdin='secret\n',
61
stdout=tests.StringIOWrapper(),
62
stderr=tests.StringIOWrapper())
85
63
pb = ui.nested_progress_bar()
87
65
self.assertEqual('secret',
99
77
def test_text_factory_utf8_password(self):
100
"""Test an utf8 password."""
101
ui = _mod_ui_text.TextUIFactory(None, None, None)
102
ui.stdin = tests.StringIOWrapper(u'baz\u1234'.encode('utf8'))
103
ui.stdout = tests.StringIOWrapper()
104
ui.stderr = tests.StringIOWrapper()
78
"""Test an utf8 password.
80
We can't predict what encoding users will have for stdin, so we force
81
it to utf8 to test that we transport the password correctly.
83
ui = tests.TestUIFactory(stdin=u'baz\u1234'.encode('utf8'),
84
stdout=tests.StringIOWrapper(),
85
stderr=tests.StringIOWrapper())
105
86
ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = 'utf8'
106
password = ui.get_password(u'Hello \u1234 %(user)s', user=u'some\u1234')
107
self.assertEqual(u'baz\u1234', password)
108
self.assertEqual(u'Hello \u1234 some\u1234: ',
109
ui.stderr.getvalue().decode('utf8'))
110
# stdin and stdout should be empty
111
self.assertEqual('', ui.stdin.readline())
112
self.assertEqual('', ui.stdout.getvalue())
87
pb = ui.nested_progress_bar()
89
password = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
91
u'Hello \u1234 %(user)s',
93
# We use StringIO objects, we need to decode them
94
self.assertEqual(u'baz\u1234', password.decode('utf8'))
95
self.assertEqual(u'Hello \u1234 some\u1234: ',
96
ui.stderr.getvalue().decode('utf8'))
97
# stdin and stdout should be empty
98
self.assertEqual('', ui.stdin.readline())
99
self.assertEqual('', ui.stdout.readline())
114
103
def test_text_ui_get_boolean(self):
115
104
stdin = tests.StringIOWrapper("y\n" # True
119
106
"yes with garbage\nY\n" # True
120
107
"not an answer\nno\n" # False
121
108
"I'm sure!\nyes\n" # True
124
111
stdout = tests.StringIOWrapper()
125
112
stderr = tests.StringIOWrapper()
126
113
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
127
self.assertEqual(True, factory.get_boolean(u""))
128
self.assertEqual(False, factory.get_boolean(u""))
129
self.assertEqual(True, factory.get_boolean(u""))
130
self.assertEqual(False, factory.get_boolean(u""))
131
self.assertEqual(True, factory.get_boolean(u""))
132
self.assertEqual(False, factory.get_boolean(u""))
133
self.assertEqual(True, factory.get_boolean(u""))
134
self.assertEqual(False, factory.get_boolean(u""))
135
self.assertEqual("foo\n", factory.stdin.read())
136
# stdin should be empty
137
self.assertEqual('', factory.stdin.readline())
138
# return false on EOF
139
self.assertEqual(False, factory.get_boolean(u""))
141
def test_text_ui_choose_bad_parameters(self):
142
stdin = tests.StringIOWrapper()
143
stdout = tests.StringIOWrapper()
144
stderr = tests.StringIOWrapper()
145
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
146
# invalid default index
147
self.assertRaises(ValueError, factory.choose, u"", u"&Yes\n&No", 3)
149
self.assertRaises(ValueError, factory.choose, u"", u"&choice\n&ChOiCe")
150
# duplicated shortcut
151
self.assertRaises(ValueError, factory.choose, u"", u"&choice1\nchoi&ce2")
153
def test_text_ui_choose_prompt(self):
154
stdin = tests.StringIOWrapper()
155
stdout = tests.StringIOWrapper()
156
stderr = tests.StringIOWrapper()
157
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
158
# choices with explicit shortcuts
159
factory.choose(u"prompt", u"&yes\n&No\nmore &info")
160
self.assertEqual("prompt ([y]es, [N]o, more [i]nfo): \n", factory.stderr.getvalue())
161
# automatic shortcuts
162
factory.stderr.truncate(0)
163
factory.choose(u"prompt", u"yes\nNo\nmore info")
164
self.assertEqual("prompt ([y]es, [N]o, [m]ore info): \n", factory.stderr.getvalue())
166
def test_text_ui_choose_return_values(self):
167
choose = lambda: factory.choose(u"", u"&Yes\n&No\nMaybe\nmore &info", 3)
168
stdin = tests.StringIOWrapper("y\n" # 0
172
"b\na\nd \n" # bad shortcuts, all ignored
173
"yes with garbage\nY\n" # 0
174
"not an answer\nno\n" # 1
175
"info\nmore info\n" # 3
178
stdout = tests.StringIOWrapper()
179
stderr = tests.StringIOWrapper()
180
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
181
self.assertEqual(0, choose())
182
self.assertEqual(1, choose())
183
self.assertEqual(3, choose())
184
self.assertEqual(1, choose())
185
self.assertEqual(0, choose())
186
self.assertEqual(1, choose())
187
self.assertEqual(3, choose())
188
self.assertEqual(2, choose())
189
self.assertEqual("foo\n", factory.stdin.read())
190
# stdin should be empty
191
self.assertEqual('', factory.stdin.readline())
193
self.assertEqual(None, choose())
195
def test_text_ui_choose_no_default(self):
196
stdin = tests.StringIOWrapper(" \n" # no default, invalid!
199
stdout = tests.StringIOWrapper()
200
stderr = tests.StringIOWrapper()
201
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
202
self.assertEqual(0, factory.choose(u"", u"&Yes\n&No"))
203
self.assertEqual("foo\n", factory.stdin.read())
114
self.assertEqual(True, factory.get_boolean(""))
115
self.assertEqual(False, factory.get_boolean(""))
116
self.assertEqual(True, factory.get_boolean(""))
117
self.assertEqual(False, factory.get_boolean(""))
118
self.assertEqual(True, factory.get_boolean(""))
119
self.assertEqual(False, factory.get_boolean(""))
120
self.assertEqual("foo\n", factory.stdin.read())
121
# stdin should be empty
122
self.assertEqual('', factory.stdin.readline())
205
124
def test_text_ui_get_integer(self):
206
125
stdin = tests.StringIOWrapper(
210
129
stdout = tests.StringIOWrapper()
211
130
stderr = tests.StringIOWrapper()
212
131
factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
213
self.assertEqual(1, factory.get_integer(u""))
214
self.assertEqual(-2, factory.get_integer(u""))
215
self.assertEqual(42, factory.get_integer(u""))
132
self.assertEqual(1, factory.get_integer(""))
133
self.assertEqual(-2, factory.get_integer(""))
134
self.assertEqual(42, factory.get_integer(""))
217
136
def test_text_factory_prompt(self):
218
137
# see <https://launchpad.net/bugs/365891>
219
138
StringIO = tests.StringIOWrapper
220
139
factory = _mod_ui_text.TextUIFactory(StringIO(), StringIO(), StringIO())
221
factory.prompt(u'foo %2e')
140
factory.prompt('foo %2e')
222
141
self.assertEqual('', factory.stdout.getvalue())
223
142
self.assertEqual('foo %2e', factory.stderr.getvalue())
225
144
def test_text_factory_prompts_and_clears(self):
226
145
# a get_boolean call should clear the pb before prompting
228
self.overrideEnv('TERM', 'xterm')
146
out = test_progress._TTYStringIO()
147
os.environ['TERM'] = 'xterm'
229
148
factory = _mod_ui_text.TextUIFactory(
230
149
stdin=tests.StringIOWrapper("yada\ny\n"),
231
150
stdout=out, stderr=out)
263
182
def test_text_ui_getusername(self):
264
ui = _mod_ui_text.TextUIFactory(None, None, None)
265
ui.stdin = tests.StringIOWrapper('someuser\n\n')
266
ui.stdout = tests.StringIOWrapper()
267
ui.stderr = tests.StringIOWrapper()
268
ui.stdout.encoding = 'utf8'
269
self.assertEqual('someuser',
270
ui.get_username(u'Hello %(host)s', host='some'))
271
self.assertEqual('Hello some: ', ui.stderr.getvalue())
272
self.assertEqual('', ui.stdout.getvalue())
273
self.assertEqual('', ui.get_username(u"Gebruiker"))
183
factory = _mod_ui_text.TextUIFactory(None, None, None)
184
factory.stdin = tests.StringIOWrapper("someuser\n\n")
185
factory.stdout = tests.StringIOWrapper()
186
factory.stderr = tests.StringIOWrapper()
187
factory.stdout.encoding = "utf8"
188
# there is no output from the base factory
189
self.assertEqual("someuser",
190
factory.get_username('Hello %(host)s', host='some'))
191
self.assertEquals("Hello some: ", factory.stderr.getvalue())
192
self.assertEquals('', factory.stdout.getvalue())
193
self.assertEqual("", factory.get_username("Gebruiker"))
274
194
# stdin should be empty
275
self.assertEqual('', ui.stdin.readline())
195
self.assertEqual('', factory.stdin.readline())
277
197
def test_text_ui_getusername_utf8(self):
278
ui = _mod_ui_text.TextUIFactory(None, None, None)
279
ui.stdin = tests.StringIOWrapper(u'someuser\u1234'.encode('utf8'))
280
ui.stdout = tests.StringIOWrapper()
281
ui.stderr = tests.StringIOWrapper()
198
ui = tests.TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
199
stdout=tests.StringIOWrapper(),
200
stderr=tests.StringIOWrapper())
282
201
ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = "utf8"
283
username = ui.get_username(u'Hello %(host)s', host=u'some\u1234')
284
self.assertEqual(u"someuser\u1234", username)
285
self.assertEqual(u"Hello some\u1234: ",
286
ui.stderr.getvalue().decode("utf8"))
287
self.assertEqual('', ui.stdout.getvalue())
202
pb = ui.nested_progress_bar()
204
# there is no output from the base factory
205
username = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
206
ui.get_username, u'Hello\u1234 %(host)s', host=u'some\u1234')
207
self.assertEquals(u"someuser\u1234", username.decode('utf8'))
208
self.assertEquals(u"Hello\u1234 some\u1234: ",
209
ui.stderr.getvalue().decode("utf8"))
210
self.assertEquals('', ui.stdout.getvalue())
289
214
def test_quietness(self):
290
self.overrideEnv('BZR_PROGRESS_BAR', 'text')
215
os.environ['BZR_PROGRESS_BAR'] = 'text'
291
216
ui_factory = _mod_ui_text.TextUIFactory(None,
217
test_progress._TTYStringIO(),
218
test_progress._TTYStringIO())
294
219
self.assertIsInstance(ui_factory._progress_view,
295
220
_mod_ui_text.TextProgressView)
296
221
ui_factory.be_quiet(True)
388
318
def test_text_ui_non_terminal(self):
389
319
"""Even on non-ttys, make_ui_for_terminal gives a text ui."""
390
stdin = NonTTYStringIO('')
391
stderr = NonTTYStringIO()
392
stdout = NonTTYStringIO()
320
stdin = test_progress._NonTTYStringIO('')
321
stderr = test_progress._NonTTYStringIO()
322
stdout = test_progress._NonTTYStringIO()
393
323
for term_type in ['dumb', None, 'xterm']:
394
self.overrideEnv('TERM', term_type)
324
if term_type is None:
325
del os.environ['TERM']
327
os.environ['TERM'] = term_type
395
328
uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
396
329
self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
397
330
'TERM=%r' % (term_type,))
438
371
def test_canned_input_get_input(self):
439
372
uif = _mod_ui.CannedInputUIFactory([True, 'mbp', 'password', 42])
440
self.assertEqual(True, uif.get_boolean(u'Extra cheese?'))
441
self.assertEqual('mbp', uif.get_username(u'Enter your user name'))
373
self.assertEqual(True, uif.get_boolean('Extra cheese?'))
374
self.assertEqual('mbp', uif.get_username('Enter your user name'))
442
375
self.assertEqual('password',
443
uif.get_password(u'Password for %(host)s',
376
uif.get_password('Password for %(host)s',
444
377
host='example.com'))
445
self.assertEqual(42, uif.get_integer(u'And all that jazz ?'))
378
self.assertEqual(42, uif.get_integer('And all that jazz ?'))
448
381
class TestBoolFromString(tests.TestCase):
450
383
def assertIsTrue(self, s, accepted_values=None):
451
384
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
452
self.assertEqual(True, res)
385
self.assertEquals(True, res)
454
387
def assertIsFalse(self, s, accepted_values=None):
455
388
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
456
self.assertEqual(False, res)
389
self.assertEquals(False, res)
458
391
def assertIsNone(self, s, accepted_values=None):
459
392
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
499
432
self.assertIsNone('0', av)
500
433
self.assertIsNone('on', av)
501
434
self.assertIsNone('off', av)
504
class TestConfirmationUserInterfacePolicy(tests.TestCase):
506
def test_confirm_action_default(self):
507
base_ui = _mod_ui.NoninteractiveUIFactory()
508
for answer in [True, False]:
510
_mod_ui.ConfirmationUserInterfacePolicy(base_ui, answer, {})
511
.confirm_action("Do something?",
512
"bzrlib.tests.do_something", {}),
515
def test_confirm_action_specific(self):
516
base_ui = _mod_ui.NoninteractiveUIFactory()
517
for default_answer in [True, False]:
518
for specific_answer in [True, False]:
519
for conf_id in ['given_id', 'other_id']:
520
wrapper = _mod_ui.ConfirmationUserInterfacePolicy(
521
base_ui, default_answer, dict(given_id=specific_answer))
522
result = wrapper.confirm_action("Do something?", conf_id, {})
523
if conf_id == 'given_id':
524
self.assertEqual(result, specific_answer)
526
self.assertEqual(result, default_answer)
529
base_ui = _mod_ui.NoninteractiveUIFactory()
530
wrapper = _mod_ui.ConfirmationUserInterfacePolicy(
531
base_ui, True, dict(a=2))
532
self.assertThat(repr(wrapper),
533
Equals("ConfirmationUserInterfacePolicy("
534
"NoninteractiveUIFactory(), True, {'a': 2})"))
537
class TestProgressRecordingUI(tests.TestCase):
538
"""Test test-oriented UIFactory that records progress updates"""
540
def test_nested_ignore_depth_beyond_one(self):
541
# we only want to capture the first level out progress, not
542
# want sub-components might do. So we have nested bars ignored.
543
factory = ProgressRecordingUIFactory()
544
pb1 = factory.nested_progress_bar()
545
pb1.update('foo', 0, 1)
546
pb2 = factory.nested_progress_bar()
547
pb2.update('foo', 0, 1)
550
self.assertEqual([("update", 0, 1, 'foo')], factory._calls)