~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_ui.py

local_concurrency can be overridden from command-line

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
18
18
"""
19
19
 
20
20
import os
 
21
from StringIO import StringIO
21
22
import re
 
23
import sys
22
24
import time
23
25
 
24
 
from StringIO import StringIO
25
 
 
26
26
from bzrlib import (
27
27
    errors,
28
 
    remote,
29
 
    repository,
30
28
    tests,
31
29
    ui as _mod_ui,
32
30
    )
33
31
from bzrlib.symbol_versioning import (
34
32
    deprecated_in,
35
33
    )
36
 
from bzrlib.tests import test_progress
37
 
from bzrlib.ui import text as _mod_ui_text
 
34
from bzrlib.tests import (
 
35
    TestCase,
 
36
    TestUIFactory,
 
37
    StringIOWrapper,
 
38
    )
 
39
from bzrlib.tests.test_progress import (
 
40
    _NonTTYStringIO,
 
41
    _TTYStringIO,
 
42
    )
 
43
from bzrlib.ui import (
 
44
    CannedInputUIFactory,
 
45
    SilentUIFactory,
 
46
    UIFactory,
 
47
    make_ui_for_terminal,
 
48
    )
 
49
from bzrlib.ui.text import (
 
50
    NullProgressView,
 
51
    TextProgressView,
 
52
    TextUIFactory,
 
53
    )
38
54
 
39
55
 
40
56
class TestTextUIFactory(tests.TestCase):
84
100
            pb.finished()
85
101
 
86
102
    def test_progress_note(self):
87
 
        stderr = tests.StringIOWrapper()
88
 
        stdout = tests.StringIOWrapper()
89
 
        ui_factory = _mod_ui_text.TextUIFactory(stdin=tests.StringIOWrapper(''),
90
 
                                                stderr=stderr,
91
 
                                                stdout=stdout)
 
103
        stderr = StringIO()
 
104
        stdout = StringIO()
 
105
        ui_factory = TextUIFactory(stdin=StringIO(''),
 
106
            stderr=stderr,
 
107
            stdout=stdout)
92
108
        pb = ui_factory.nested_progress_bar()
93
109
        try:
94
110
            result = self.applyDeprecated(deprecated_in((2, 1, 0)),
104
120
            pb.finished()
105
121
 
106
122
    def test_progress_note_clears(self):
107
 
        stderr = test_progress._TTYStringIO()
108
 
        stdout = test_progress._TTYStringIO()
 
123
        stderr = _TTYStringIO()
 
124
        stdout = _TTYStringIO()
109
125
        # so that we get a TextProgressBar
110
126
        os.environ['TERM'] = 'xterm'
111
 
        ui_factory = _mod_ui_text.TextUIFactory(
112
 
            stdin=tests.StringIOWrapper(''),
 
127
        ui_factory = TextUIFactory(
 
128
            stdin=StringIO(''),
113
129
            stdout=stdout, stderr=stderr)
114
130
        self.assertIsInstance(ui_factory._progress_view,
115
 
                              _mod_ui_text.TextProgressView)
 
131
            TextProgressView)
116
132
        pb = ui_factory.nested_progress_bar()
117
133
        try:
118
134
            # Create a progress update that isn't throttled
128
144
        finally:
129
145
            pb.finished()
130
146
 
 
147
    def test_progress_nested(self):
 
148
        # test factory based nested and popping.
 
149
        ui = TextUIFactory(None, None, None)
 
150
        pb1 = ui.nested_progress_bar()
 
151
        pb2 = ui.nested_progress_bar()
 
152
        # You do get a warning if the outermost progress bar wasn't finished
 
153
        # first - it's not clear if this is really useful or if it should just
 
154
        # become orphaned -- mbp 20090120
 
155
        warnings, _ = self.callCatchWarnings(pb1.finished)
 
156
        if len(warnings) != 1:
 
157
            self.fail("unexpected warnings: %r" % (warnings,))
 
158
        pb2.finished()
 
159
        pb1.finished()
 
160
 
131
161
    def test_text_ui_get_boolean(self):
132
 
        stdin = tests.StringIOWrapper("y\n" # True
133
 
                                      "n\n" # False
134
 
                                      "yes with garbage\nY\n" # True
135
 
                                      "not an answer\nno\n" # False
136
 
                                      "I'm sure!\nyes\n" # True
137
 
                                      "NO\n" # False
138
 
                                      "foo\n")
139
 
        stdout = tests.StringIOWrapper()
140
 
        stderr = tests.StringIOWrapper()
141
 
        factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
 
162
        stdin = StringIO("y\n" # True
 
163
                         "n\n" # False
 
164
                         "yes with garbage\nY\n" # True
 
165
                         "not an answer\nno\n" # False
 
166
                         "I'm sure!\nyes\n" # True
 
167
                         "NO\n" # False
 
168
                         "foo\n")
 
169
        stdout = StringIO()
 
170
        stderr = StringIO()
 
171
        factory = TextUIFactory(stdin, stdout, stderr)
142
172
        self.assertEqual(True, factory.get_boolean(""))
143
173
        self.assertEqual(False, factory.get_boolean(""))
144
174
        self.assertEqual(True, factory.get_boolean(""))
149
179
        # stdin should be empty
150
180
        self.assertEqual('', factory.stdin.readline())
151
181
 
152
 
    def test_text_ui_get_integer(self):
153
 
        stdin = tests.StringIOWrapper(
154
 
            "1\n"
155
 
            "  -2  \n"
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(""))
163
 
 
164
182
    def test_text_factory_prompt(self):
165
183
        # see <https://launchpad.net/bugs/365891>
166
 
        StringIO = tests.StringIOWrapper
167
 
        factory = _mod_ui_text.TextUIFactory(StringIO(), StringIO(), StringIO())
 
184
        factory = TextUIFactory(StringIO(), StringIO(), StringIO())
168
185
        factory.prompt('foo %2e')
169
186
        self.assertEqual('', factory.stdout.getvalue())
170
187
        self.assertEqual('foo %2e', factory.stderr.getvalue())
171
188
 
172
189
    def test_text_factory_prompts_and_clears(self):
173
190
        # a get_boolean call should clear the pb before prompting
174
 
        out = test_progress._TTYStringIO()
 
191
        out = _TTYStringIO()
175
192
        os.environ['TERM'] = 'xterm'
176
 
        factory = _mod_ui_text.TextUIFactory(
177
 
            stdin=tests.StringIOWrapper("yada\ny\n"),
178
 
            stdout=out, stderr=out)
 
193
        factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
179
194
        pb = factory.nested_progress_bar()
180
195
        pb.show_bar = False
181
196
        pb.show_spinner = False
195
210
        self.assertEqual('', factory.stdin.readline())
196
211
 
197
212
    def test_text_tick_after_update(self):
198
 
        ui_factory = _mod_ui_text.TextUIFactory(stdout=tests.StringIOWrapper(),
199
 
                                                stderr=tests.StringIOWrapper())
 
213
        ui_factory = TextUIFactory(stdout=StringIO(), stderr=StringIO())
200
214
        pb = ui_factory.nested_progress_bar()
201
215
        try:
202
216
            pb.update('task', 0, 3)
207
221
            pb.finished()
208
222
 
209
223
    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()
 
224
        factory = TextUIFactory(None, None, None)
 
225
        factory.stdin = StringIO("someuser\n\n")
 
226
        factory.stdout = StringIO()
 
227
        factory.stderr = StringIO()
214
228
        factory.stdout.encoding = "utf8"
215
229
        # there is no output from the base factory
216
230
        self.assertEqual("someuser",
238
252
        finally:
239
253
            pb.finished()
240
254
 
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)
251
 
 
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
255
 
        err = StringIO()
256
 
        out = StringIO()
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",
267
 
            err.getvalue())
268
 
        # and now with it suppressed please
269
 
        err = StringIO()
270
 
        out = StringIO()
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())
277
 
 
278
 
 
279
 
class TestTextUIOutputStream(tests.TestCase):
280
 
    """Tests for output stream that synchronizes with progress bar."""
281
 
 
282
 
    def test_output_clears_terminal(self):
283
 
        stdout = tests.StringIOWrapper()
284
 
        stderr = tests.StringIOWrapper()
285
 
        clear_calls = []
286
 
 
287
 
        uif =  _mod_ui_text.TextUIFactory(None, stdout, stderr)
288
 
        uif.clear_term = lambda: clear_calls.append('clear')
289
 
 
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"])
294
 
 
295
 
        self.assertEqual(stdout.getvalue(),
296
 
            "Hello world!\n"
297
 
            "there's more...\n"
298
 
            "1\n2\n3\n")
299
 
        self.assertEqual(['clear', 'clear', 'clear'],
300
 
            clear_calls)
301
 
 
302
 
        stream.flush()
303
 
 
304
255
 
305
256
class UITests(tests.TestCase):
306
257
 
307
258
    def test_progress_construction(self):
308
259
        """TextUIFactory constructs the right progress view.
309
260
        """
310
 
        TTYStringIO = test_progress._TTYStringIO
311
 
        FileStringIO = tests.StringIOWrapper
312
261
        for (file_class, term, pb, expected_pb_class) in (
313
262
            # on an xterm, either use them or not as the user requests,
314
263
            # 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),
 
264
            (_TTYStringIO, 'xterm', 'none', NullProgressView),
 
265
            (_TTYStringIO, 'xterm', 'text', TextProgressView),
 
266
            (_TTYStringIO, 'xterm', None, TextProgressView),
318
267
            # on a dumb terminal, again if there's explicit configuration do
319
268
            # 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),
 
269
            (_TTYStringIO, 'dumb', 'none', NullProgressView),
 
270
            (_TTYStringIO, 'dumb', 'text', TextProgressView),
 
271
            (_TTYStringIO, 'dumb', None, NullProgressView),
323
272
            # 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),
 
273
            (StringIO, 'xterm', None, NullProgressView),
 
274
            (StringIO, 'dumb', None, NullProgressView),
326
275
            # however, it can still be forced on
327
 
            (FileStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
 
276
            (StringIO, 'dumb', 'text', TextProgressView),
328
277
            ):
329
278
            os.environ['TERM'] = term
330
279
            if pb is None:
335
284
            stdin = file_class('')
336
285
            stderr = file_class()
337
286
            stdout = file_class()
338
 
            uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
339
 
            self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
 
287
            uif = make_ui_for_terminal(stdin, stdout, stderr)
 
288
            self.assertIsInstance(uif, TextUIFactory,
340
289
                "TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
341
290
            self.assertIsInstance(uif.make_progress_view(),
342
291
                expected_pb_class,
344
293
 
345
294
    def test_text_ui_non_terminal(self):
346
295
        """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()
 
296
        stdin = _NonTTYStringIO('')
 
297
        stderr = _NonTTYStringIO()
 
298
        stdout = _NonTTYStringIO()
350
299
        for term_type in ['dumb', None, 'xterm']:
351
300
            if term_type is None:
352
301
                del os.environ['TERM']
353
302
            else:
354
303
                os.environ['TERM'] = term_type
355
 
            uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
356
 
            self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
 
304
            uif = make_ui_for_terminal(stdin, stdout, stderr)
 
305
            self.assertIsInstance(uif, TextUIFactory,
357
306
                'TERM=%r' % (term_type,))
358
307
 
359
308
 
360
 
class SilentUITests(tests.TestCase):
 
309
class SilentUITests(TestCase):
361
310
 
362
311
    def test_silent_factory_get_password(self):
363
312
        # A silent factory that can't do user interaction can't get a
364
313
        # password.  Possibly it should raise a more specific error but it
365
314
        # can't succeed.
366
 
        ui = _mod_ui.SilentUIFactory()
367
 
        stdout = tests.StringIOWrapper()
 
315
        ui = SilentUIFactory()
 
316
        stdout = StringIO()
368
317
        self.assertRaises(
369
318
            NotImplementedError,
370
319
            self.apply_redirected,
373
322
        self.assertEqual('', stdout.getvalue())
374
323
 
375
324
    def test_silent_ui_getbool(self):
376
 
        factory = _mod_ui.SilentUIFactory()
377
 
        stdout = tests.StringIOWrapper()
 
325
        factory = SilentUIFactory()
 
326
        stdout = StringIO()
378
327
        self.assertRaises(
379
328
            NotImplementedError,
380
329
            self.apply_redirected,
381
330
            None, stdout, stdout, factory.get_boolean, "foo")
382
331
 
383
332
 
384
 
class TestUIFactoryTests(tests.TestCase):
 
333
class TestUIFactoryTests(TestCase):
385
334
 
386
335
    def test_test_ui_factory_progress(self):
387
336
        # there's no output; we just want to make sure this doesn't crash -
388
337
        # see https://bugs.edge.launchpad.net/bzr/+bug/408201
389
 
        ui = tests.TestUIFactory()
 
338
        ui = TestUIFactory()
390
339
        pb = ui.nested_progress_bar()
391
340
        pb.update('hello')
392
341
        pb.tick()
393
342
        pb.finished()
394
343
 
395
344
 
396
 
class CannedInputUIFactoryTests(tests.TestCase):
397
 
 
 
345
class CannedInputUIFactoryTests(TestCase):
 
346
    
398
347
    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',
404
 
                                          host='example.com'))
405
 
        self.assertEqual(42, uif.get_integer('And all that jazz ?'))
 
348
        uif = CannedInputUIFactory([True, 'mbp', 'password'])
 
349
        self.assertEqual(uif.get_boolean('Extra cheese?'), True)
 
350
        self.assertEqual(uif.get_username('Enter your user name'), 'mbp')
 
351
        self.assertEqual(uif.get_password('Password for %(host)s', host='example.com'),
 
352
            'password')
406
353
 
407
354
 
408
355
class TestBoolFromString(tests.TestCase):