79
80
We can't predict what encoding users will have for stdin, so we force
80
81
it to utf8 to test that we transport the password correctly.
82
ui = TestUIFactory(stdin=u'baz\u1234'.encode('utf8'),
83
stdout=StringIOWrapper())
84
ui.stdin.encoding = 'utf8'
85
ui.stdout.encoding = ui.stdin.encoding
83
ui = tests.TestUIFactory(stdin=u'baz\u1234'.encode('utf8'),
84
stdout=tests.StringIOWrapper(),
85
stderr=tests.StringIOWrapper())
86
ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = 'utf8'
86
87
pb = ui.nested_progress_bar()
88
password = self.apply_redirected(ui.stdin, ui.stdout, ui.stdout,
89
password = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
90
91
u'Hello \u1234 %(user)s',
91
92
user=u'some\u1234')
92
93
# We use StringIO objects, we need to decode them
93
94
self.assertEqual(u'baz\u1234', password.decode('utf8'))
94
95
self.assertEqual(u'Hello \u1234 some\u1234: ',
95
ui.stdout.getvalue().decode('utf8'))
96
# stdin should be empty
96
ui.stderr.getvalue().decode('utf8'))
97
# stdin and stdout should be empty
97
98
self.assertEqual('', ui.stdin.readline())
99
self.assertEqual('', ui.stdout.readline())
103
def test_progress_construction(self):
104
"""TextUIFactory constructs the right progress view.
106
for (file_class, term, pb, expected_pb_class) in (
107
# on an xterm, either use them or not as the user requests,
108
# otherwise default on
109
(_TTYStringIO, 'xterm', 'none', NullProgressView),
110
(_TTYStringIO, 'xterm', 'text', TextProgressView),
111
(_TTYStringIO, 'xterm', None, TextProgressView),
112
# on a dumb terminal, again if there's explicit configuration do
113
# it, otherwise default off
114
(_TTYStringIO, 'dumb', 'none', NullProgressView),
115
(_TTYStringIO, 'dumb', 'text', TextProgressView),
116
(_TTYStringIO, 'dumb', None, NullProgressView),
117
# on a non-tty terminal, it's null regardless of $TERM
118
(StringIO, 'xterm', None, NullProgressView),
119
(StringIO, 'dumb', None, NullProgressView),
120
# however, it can still be forced on
121
(StringIO, 'dumb', 'text', TextProgressView),
123
os.environ['TERM'] = term
125
if 'BZR_PROGRESS_BAR' in os.environ:
126
del os.environ['BZR_PROGRESS_BAR']
128
os.environ['BZR_PROGRESS_BAR'] = pb
129
stdin = file_class('')
130
stderr = file_class()
131
stdout = file_class()
132
uif = make_ui_for_terminal(stdin, stdout, stderr)
133
self.assertIsInstance(uif, TextUIFactory,
134
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
135
self.assertIsInstance(uif.make_progress_view(),
137
"TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
139
def test_text_ui_non_terminal(self):
140
"""Even on non-ttys, make_ui_for_terminal gives a text ui."""
141
stdin = _NonTTYStringIO('')
142
stderr = _NonTTYStringIO()
143
stdout = _NonTTYStringIO()
144
for term_type in ['dumb', None, 'xterm']:
145
if term_type is None:
146
del os.environ['TERM']
148
os.environ['TERM'] = term_type
149
uif = make_ui_for_terminal(stdin, stdout, stderr)
150
self.assertIsInstance(uif, TextUIFactory,
151
'TERM=%r' % (term_type,))
101
153
def test_progress_note(self):
102
154
stderr = StringIO()
103
155
stdout = StringIO()
104
ui_factory = TextUIFactory(bar_type=TTYProgressBar)
156
ui_factory = TextUIFactory(stdin=StringIO(''),
105
159
pb = ui_factory.nested_progress_bar()
107
pb.to_messages_file = stdout
108
ui_factory._progress_bar_stack.bottom().to_file = stderr
109
161
result = pb.note('t')
110
162
self.assertEqual(None, result)
111
163
self.assertEqual("t\n", stdout.getvalue())
143
195
def test_progress_nested(self):
144
196
# test factory based nested and popping.
197
ui = TextUIFactory(None, None, None)
146
198
pb1 = ui.nested_progress_bar()
147
199
pb2 = ui.nested_progress_bar()
148
self.assertRaises(errors.MissingProgressBarFinish, pb1.finished)
200
# You do get a warning if the outermost progress bar wasn't finished
201
# first - it's not clear if this is really useful or if it should just
202
# become orphaned -- mbp 20090120
203
warnings, _ = self.callCatchWarnings(pb1.finished)
204
if len(warnings) != 1:
205
self.fail("unexpected warnings: %r" % (warnings,))
152
def test_progress_stack(self):
153
# test the progress bar stack which the default text factory
209
def test_text_ui_get_boolean(self):
210
stdin = StringIO("y\n" # True
212
"yes with garbage\nY\n" # True
213
"not an answer\nno\n" # False
214
"I'm sure!\nyes\n" # True
155
218
stderr = StringIO()
157
# make a stack, which accepts parameters like a pb.
158
stack = ProgressBarStack(to_file=stderr, to_messages_file=stdout)
160
self.assertFalse(getattr(stack, 'note', False))
161
pb1 = stack.get_nested()
162
pb2 = stack.get_nested()
163
self.assertRaises(errors.MissingProgressBarFinish, pb1.finished)
166
# the text ui factory never actually removes the stack once its setup.
167
# we need to be able to nest again correctly from here.
168
pb1 = stack.get_nested()
169
pb2 = stack.get_nested()
170
self.assertRaises(errors.MissingProgressBarFinish, pb1.finished)
174
def test_text_factory_setting_progress_bar(self):
175
# we should be able to choose the progress bar type used.
176
factory = TextUIFactory(bar_type=DotsProgressBar)
177
bar = factory.nested_progress_bar()
179
self.assertIsInstance(bar, DotsProgressBar)
181
def test_cli_stdin_is_default_stdin(self):
182
factory = CLIUIFactory()
183
self.assertEqual(sys.stdin, factory.stdin)
185
def assert_get_bool_acceptance_of_user_input(self, factory):
186
factory.stdin = StringIO("y\nyes with garbage\n"
187
"yes\nn\nnot an answer\n"
189
factory.stdout = StringIO()
190
# there is no output from the base factory
191
self.assertEqual(True, factory.get_boolean(""))
192
self.assertEqual(True, factory.get_boolean(""))
193
self.assertEqual(False, factory.get_boolean(""))
219
factory = TextUIFactory(stdin, stdout, stderr)
220
self.assertEqual(True, factory.get_boolean(""))
221
self.assertEqual(False, factory.get_boolean(""))
222
self.assertEqual(True, factory.get_boolean(""))
223
self.assertEqual(False, factory.get_boolean(""))
224
self.assertEqual(True, factory.get_boolean(""))
194
225
self.assertEqual(False, factory.get_boolean(""))
195
226
self.assertEqual("foo\n", factory.stdin.read())
196
227
# stdin should be empty
197
228
self.assertEqual('', factory.stdin.readline())
199
def test_silent_ui_getbool(self):
200
factory = SilentUIFactory()
201
self.assert_get_bool_acceptance_of_user_input(factory)
203
def test_silent_factory_prompts_silently(self):
204
factory = SilentUIFactory()
206
factory.stdin = StringIO("y\n")
207
self.assertEqual(True,
208
self.apply_redirected(None, stdout, stdout,
209
factory.get_boolean, "foo"))
210
self.assertEqual("", stdout.getvalue())
211
# stdin should be empty
212
self.assertEqual('', factory.stdin.readline())
214
def test_text_ui_getbool(self):
215
factory = TextUIFactory()
216
self.assert_get_bool_acceptance_of_user_input(factory)
230
def test_text_factory_prompt(self):
231
# see <https://launchpad.net/bugs/365891>
232
factory = TextUIFactory(StringIO(), StringIO(), StringIO())
233
factory.prompt('foo %2e')
234
self.assertEqual('', factory.stdout.getvalue())
235
self.assertEqual('foo %2e', factory.stderr.getvalue())
218
237
def test_text_factory_prompts_and_clears(self):
219
238
# a get_boolean call should clear the pb before prompting
220
factory = TextUIFactory(bar_type=DotsProgressBar)
221
factory.stdout = _TTYStringIO()
222
factory.stdin = StringIO("yada\ny\n")
223
pb = self.apply_redirected(factory.stdin, factory.stdout,
224
factory.stdout, factory.nested_progress_bar)
226
self.apply_redirected(factory.stdin, factory.stdout,
227
factory.stdout, pb.update, "foo", 0, 1)
240
os.environ['TERM'] = 'xterm'
241
factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
242
pb = factory.nested_progress_bar()
244
pb.show_spinner = False
245
pb.show_count = False
246
pb.update("foo", 0, 1)
228
247
self.assertEqual(True,
229
248
self.apply_redirected(None, factory.stdout,
231
250
factory.get_boolean,
232
251
"what do you want"))
233
output = factory.stdout.getvalue()
234
self.assertEqual("foo: .\n"
235
"what do you want? [y/n]: what do you want? [y/n]: ",
236
factory.stdout.getvalue())
252
output = out.getvalue()
253
self.assertContainsRe(factory.stdout.getvalue(),
255
self.assertContainsRe(factory.stdout.getvalue(),
256
r"what do you want\? \[y/n\]: what do you want\? \[y/n\]: ")
257
# stdin should have been totally consumed
258
self.assertEqual('', factory.stdin.readline())
260
def test_text_tick_after_update(self):
261
ui_factory = TextUIFactory(stdout=StringIO(), stderr=StringIO())
262
pb = ui_factory.nested_progress_bar()
264
pb.update('task', 0, 3)
265
# Reset the clock, so that it actually tries to repaint itself
266
ui_factory._progress_view._last_repaint = time.time() - 1.0
271
def test_text_ui_getusername(self):
272
factory = TextUIFactory(None, None, None)
273
factory.stdin = StringIO("someuser\n\n")
274
factory.stdout = StringIO()
275
factory.stderr = StringIO()
276
factory.stdout.encoding = "utf8"
277
# there is no output from the base factory
278
self.assertEqual("someuser",
279
factory.get_username('Hello %(host)s', host='some'))
280
self.assertEquals("Hello some: ", factory.stderr.getvalue())
281
self.assertEquals('', factory.stdout.getvalue())
282
self.assertEqual("", factory.get_username("Gebruiker"))
237
283
# stdin should be empty
238
284
self.assertEqual('', factory.stdin.readline())
286
def test_text_ui_getusername_utf8(self):
287
ui = tests.TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
288
stdout=tests.StringIOWrapper(),
289
stderr=tests.StringIOWrapper())
290
ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = "utf8"
291
pb = ui.nested_progress_bar()
293
# there is no output from the base factory
294
username = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
295
ui.get_username, u'Hello\u1234 %(host)s', host=u'some\u1234')
296
self.assertEquals(u"someuser\u1234", username.decode('utf8'))
297
self.assertEquals(u"Hello\u1234 some\u1234: ",
298
ui.stderr.getvalue().decode("utf8"))
299
self.assertEquals('', ui.stdout.getvalue())
304
class CLIUITests(TestCase):
306
def test_cli_factory_deprecated(self):
307
uif = self.applyDeprecated(deprecated_in((1, 18, 0)),
309
StringIO(), StringIO(), StringIO())
310
self.assertIsInstance(uif, UIFactory)
313
class SilentUITests(TestCase):
315
def test_silent_factory_get_password(self):
316
# A silent factory that can't do user interaction can't get a
317
# password. Possibly it should raise a more specific error but it
319
ui = SilentUIFactory()
323
self.apply_redirected,
324
None, stdout, stdout, ui.get_password)
325
# and it didn't write anything out either
326
self.assertEqual('', stdout.getvalue())
328
def test_silent_ui_getbool(self):
329
factory = SilentUIFactory()
333
self.apply_redirected,
334
None, stdout, stdout, factory.get_boolean, "foo")
337
class TestUIFactoryTests(TestCase):
339
def test_test_ui_factory_progress(self):
340
# there's no output; we just want to make sure this doesn't crash -
341
# see https://bugs.edge.launchpad.net/bzr/+bug/408201
343
pb = ui.nested_progress_bar()
349
class CannedInputUIFactoryTests(TestCase):
351
def test_canned_input_get_input(self):
352
uif = CannedInputUIFactory([True, 'mbp', 'password'])
353
self.assertEqual(uif.get_boolean('Extra cheese?'), True)
354
self.assertEqual(uif.get_username('Enter your user name'), 'mbp')
355
self.assertEqual(uif.get_password('Password for %(host)s', host='example.com'),
359
class TestBoolFromString(tests.TestCase):
361
def assertIsTrue(self, s, accepted_values=None):
362
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
363
self.assertEquals(True, res)
365
def assertIsFalse(self, s, accepted_values=None):
366
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
367
self.assertEquals(False, res)
369
def assertIsNone(self, s, accepted_values=None):
370
res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
371
self.assertIs(None, res)
373
def test_know_valid_values(self):
374
self.assertIsTrue('true')
375
self.assertIsFalse('false')
376
self.assertIsTrue('1')
377
self.assertIsFalse('0')
378
self.assertIsTrue('on')
379
self.assertIsFalse('off')
380
self.assertIsTrue('yes')
381
self.assertIsFalse('no')
382
self.assertIsTrue('y')
383
self.assertIsFalse('n')
384
# Also try some case variations
385
self.assertIsTrue('True')
386
self.assertIsFalse('False')
387
self.assertIsTrue('On')
388
self.assertIsFalse('Off')
389
self.assertIsTrue('ON')
390
self.assertIsFalse('OFF')
391
self.assertIsTrue('oN')
392
self.assertIsFalse('oFf')
394
def test_invalid_values(self):
395
self.assertIsNone(None)
396
self.assertIsNone('doubt')
397
self.assertIsNone('frue')
398
self.assertIsNone('talse')
399
self.assertIsNone('42')
401
def test_provided_values(self):
402
av = dict(y=True, n=False, yes=True, no=False)
403
self.assertIsTrue('y', av)
404
self.assertIsTrue('Y', av)
405
self.assertIsTrue('Yes', av)
406
self.assertIsFalse('n', av)
407
self.assertIsFalse('N', av)
408
self.assertIsFalse('No', av)
409
self.assertIsNone('1', av)
410
self.assertIsNone('0', av)
411
self.assertIsNone('on', av)
412
self.assertIsNone('off', av)