~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_ui.py

  • Committer: INADA Naoki
  • Date: 2010-03-03 12:14:16 UTC
  • mfrom: (4634.171.4 fix-523746-2)
  • mto: This revision was merged to the branch mainline in revision 5892.
  • Revision ID: inada-n@klab.jp-20100303121416-uemvz4l5y1ilclv6
merge #523746 fix from lp:~songofacandy/bzr/fix-523746-2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
22
21
import re
23
 
import sys
24
22
import time
25
23
 
26
24
from bzrlib import (
31
29
from bzrlib.symbol_versioning import (
32
30
    deprecated_in,
33
31
    )
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
 
    CLIUIFactory,
46
 
    SilentUIFactory,
47
 
    UIFactory,
48
 
    make_ui_for_terminal,
49
 
    )
50
 
from bzrlib.ui.text import (
51
 
    NullProgressView,
52
 
    TextProgressView,
53
 
    TextUIFactory,
54
 
    )
55
 
 
56
 
 
57
 
class UITests(tests.TestCase):
 
32
from bzrlib.tests import test_progress
 
33
from bzrlib.ui import text as _mod_ui_text
 
34
 
 
35
 
 
36
class TestTextUIFactory(tests.TestCase):
58
37
 
59
38
    def test_text_factory_ascii_password(self):
60
39
        ui = tests.TestUIFactory(stdin='secret\n',
100
79
        finally:
101
80
            pb.finished()
102
81
 
103
 
    def test_progress_construction(self):
104
 
        """TextUIFactory constructs the right progress view.
105
 
        """
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),
122
 
            ):
123
 
            os.environ['TERM'] = term
124
 
            if pb is None:
125
 
                if 'BZR_PROGRESS_BAR' in os.environ:
126
 
                    del os.environ['BZR_PROGRESS_BAR']
127
 
            else:
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(),
136
 
                expected_pb_class,
137
 
                "TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
138
 
 
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']
147
 
            else:
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,))
152
 
 
153
82
    def test_progress_note(self):
154
 
        stderr = StringIO()
155
 
        stdout = StringIO()
156
 
        ui_factory = TextUIFactory(stdin=StringIO(''),
157
 
            stderr=stderr,
158
 
            stdout=stdout)
 
83
        stderr = tests.StringIOWrapper()
 
84
        stdout = tests.StringIOWrapper()
 
85
        ui_factory = _mod_ui_text.TextUIFactory(stdin=tests.StringIOWrapper(''),
 
86
                                                stderr=stderr,
 
87
                                                stdout=stdout)
159
88
        pb = ui_factory.nested_progress_bar()
160
89
        try:
161
 
            result = pb.note('t')
 
90
            result = self.applyDeprecated(deprecated_in((2, 1, 0)),
 
91
                pb.note,
 
92
                't')
162
93
            self.assertEqual(None, result)
163
94
            self.assertEqual("t\n", stdout.getvalue())
164
95
            # Since there was no update() call, there should be no clear() call
169
100
            pb.finished()
170
101
 
171
102
    def test_progress_note_clears(self):
172
 
        stderr = _TTYStringIO()
173
 
        stdout = _TTYStringIO()
 
103
        stderr = test_progress._TTYStringIO()
 
104
        stdout = test_progress._TTYStringIO()
174
105
        # so that we get a TextProgressBar
175
106
        os.environ['TERM'] = 'xterm'
176
 
        ui_factory = TextUIFactory(
177
 
            stdin=StringIO(''),
 
107
        ui_factory = _mod_ui_text.TextUIFactory(
 
108
            stdin=tests.StringIOWrapper(''),
178
109
            stdout=stdout, stderr=stderr)
179
110
        self.assertIsInstance(ui_factory._progress_view,
180
 
            TextProgressView)
 
111
                              _mod_ui_text.TextProgressView)
181
112
        pb = ui_factory.nested_progress_bar()
182
113
        try:
183
114
            # Create a progress update that isn't throttled
184
115
            pb.update('x', 1, 1)
185
 
            result = pb.note('t')
 
116
            result = self.applyDeprecated(deprecated_in((2, 1, 0)),
 
117
                pb.note, 't')
186
118
            self.assertEqual(None, result)
187
119
            self.assertEqual("t\n", stdout.getvalue())
188
120
            # the exact contents will depend on the terminal width and we don't
192
124
        finally:
193
125
            pb.finished()
194
126
 
195
 
    def test_progress_nested(self):
196
 
        # test factory based nested and popping.
197
 
        ui = TextUIFactory(None, None, None)
198
 
        pb1 = ui.nested_progress_bar()
199
 
        pb2 = ui.nested_progress_bar()
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,))
206
 
        pb2.finished()
207
 
        pb1.finished()
208
 
 
209
127
    def test_text_ui_get_boolean(self):
210
 
        stdin = StringIO("y\n" # True
211
 
                         "n\n" # False
212
 
                         "yes with garbage\nY\n" # True
213
 
                         "not an answer\nno\n" # False
214
 
                         "I'm sure!\nyes\n" # True
215
 
                         "NO\n" # False
216
 
                         "foo\n")
217
 
        stdout = StringIO()
218
 
        stderr = StringIO()
219
 
        factory = TextUIFactory(stdin, stdout, stderr)
 
128
        stdin = tests.StringIOWrapper("y\n" # True
 
129
                                      "n\n" # False
 
130
                                      "yes with garbage\nY\n" # True
 
131
                                      "not an answer\nno\n" # False
 
132
                                      "I'm sure!\nyes\n" # True
 
133
                                      "NO\n" # False
 
134
                                      "foo\n")
 
135
        stdout = tests.StringIOWrapper()
 
136
        stderr = tests.StringIOWrapper()
 
137
        factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
220
138
        self.assertEqual(True, factory.get_boolean(""))
221
139
        self.assertEqual(False, factory.get_boolean(""))
222
140
        self.assertEqual(True, factory.get_boolean(""))
227
145
        # stdin should be empty
228
146
        self.assertEqual('', factory.stdin.readline())
229
147
 
 
148
    def test_text_ui_get_integer(self):
 
149
        stdin = tests.StringIOWrapper(
 
150
            "1\n"
 
151
            "  -2  \n"
 
152
            "hmmm\nwhat else ?\nCome on\nok 42\n4.24\n42\n")
 
153
        stdout = tests.StringIOWrapper()
 
154
        stderr = tests.StringIOWrapper()
 
155
        factory = _mod_ui_text.TextUIFactory(stdin, stdout, stderr)
 
156
        self.assertEqual(1, factory.get_integer(""))
 
157
        self.assertEqual(-2, factory.get_integer(""))
 
158
        self.assertEqual(42, factory.get_integer(""))
 
159
 
230
160
    def test_text_factory_prompt(self):
231
161
        # see <https://launchpad.net/bugs/365891>
232
 
        factory = TextUIFactory(StringIO(), StringIO(), StringIO())
 
162
        StringIO = tests.StringIOWrapper
 
163
        factory = _mod_ui_text.TextUIFactory(StringIO(), StringIO(), StringIO())
233
164
        factory.prompt('foo %2e')
234
165
        self.assertEqual('', factory.stdout.getvalue())
235
166
        self.assertEqual('foo %2e', factory.stderr.getvalue())
236
167
 
237
168
    def test_text_factory_prompts_and_clears(self):
238
169
        # a get_boolean call should clear the pb before prompting
239
 
        out = _TTYStringIO()
 
170
        out = test_progress._TTYStringIO()
240
171
        os.environ['TERM'] = 'xterm'
241
 
        factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
 
172
        factory = _mod_ui_text.TextUIFactory(
 
173
            stdin=tests.StringIOWrapper("yada\ny\n"),
 
174
            stdout=out, stderr=out)
242
175
        pb = factory.nested_progress_bar()
243
176
        pb.show_bar = False
244
177
        pb.show_spinner = False
258
191
        self.assertEqual('', factory.stdin.readline())
259
192
 
260
193
    def test_text_tick_after_update(self):
261
 
        ui_factory = TextUIFactory(stdout=StringIO(), stderr=StringIO())
 
194
        ui_factory = _mod_ui_text.TextUIFactory(stdout=tests.StringIOWrapper(),
 
195
                                                stderr=tests.StringIOWrapper())
262
196
        pb = ui_factory.nested_progress_bar()
263
197
        try:
264
198
            pb.update('task', 0, 3)
269
203
            pb.finished()
270
204
 
271
205
    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()
 
206
        factory = _mod_ui_text.TextUIFactory(None, None, None)
 
207
        factory.stdin = tests.StringIOWrapper("someuser\n\n")
 
208
        factory.stdout = tests.StringIOWrapper()
 
209
        factory.stderr = tests.StringIOWrapper()
276
210
        factory.stdout.encoding = "utf8"
277
211
        # there is no output from the base factory
278
212
        self.assertEqual("someuser",
300
234
        finally:
301
235
            pb.finished()
302
236
 
303
 
 
304
 
class CLIUITests(TestCase):
305
 
 
306
 
    def test_cli_factory_deprecated(self):
307
 
        uif = self.applyDeprecated(deprecated_in((1, 18, 0)),
308
 
            CLIUIFactory,
309
 
            StringIO(), StringIO(), StringIO())
310
 
        self.assertIsInstance(uif, UIFactory)
311
 
 
312
 
 
313
 
class SilentUITests(TestCase):
 
237
    def test_quietness(self):
 
238
        os.environ['BZR_PROGRESS_BAR'] = 'text'
 
239
        ui_factory = _mod_ui_text.TextUIFactory(None,
 
240
            test_progress._TTYStringIO(),
 
241
            test_progress._TTYStringIO())
 
242
        self.assertIsInstance(ui_factory._progress_view,
 
243
            _mod_ui_text.TextProgressView)
 
244
        ui_factory.be_quiet(True)
 
245
        self.assertIsInstance(ui_factory._progress_view,
 
246
            _mod_ui_text.NullProgressView)
 
247
 
 
248
 
 
249
class TestTextUIOutputStream(tests.TestCase):
 
250
    """Tests for output stream that synchronizes with progress bar."""
 
251
 
 
252
    def test_output_clears_terminal(self):
 
253
        stdout = tests.StringIOWrapper()
 
254
        stderr = tests.StringIOWrapper()
 
255
        clear_calls = []
 
256
 
 
257
        uif =  _mod_ui_text.TextUIFactory(None, stdout, stderr)
 
258
        uif.clear_term = lambda: clear_calls.append('clear')
 
259
 
 
260
        stream = _mod_ui_text.TextUIOutputStream(uif, uif.stdout)
 
261
        stream.write("Hello world!\n")
 
262
        stream.write("there's more...\n")
 
263
        stream.writelines(["1\n", "2\n", "3\n"])
 
264
 
 
265
        self.assertEqual(stdout.getvalue(),
 
266
            "Hello world!\n"
 
267
            "there's more...\n"
 
268
            "1\n2\n3\n")
 
269
        self.assertEqual(['clear', 'clear', 'clear'],
 
270
            clear_calls)
 
271
 
 
272
        stream.flush()
 
273
 
 
274
 
 
275
class UITests(tests.TestCase):
 
276
 
 
277
    def test_progress_construction(self):
 
278
        """TextUIFactory constructs the right progress view.
 
279
        """
 
280
        TTYStringIO = test_progress._TTYStringIO
 
281
        FileStringIO = tests.StringIOWrapper
 
282
        for (file_class, term, pb, expected_pb_class) in (
 
283
            # on an xterm, either use them or not as the user requests,
 
284
            # otherwise default on
 
285
            (TTYStringIO, 'xterm', 'none', _mod_ui_text.NullProgressView),
 
286
            (TTYStringIO, 'xterm', 'text', _mod_ui_text.TextProgressView),
 
287
            (TTYStringIO, 'xterm', None, _mod_ui_text.TextProgressView),
 
288
            # on a dumb terminal, again if there's explicit configuration do
 
289
            # it, otherwise default off
 
290
            (TTYStringIO, 'dumb', 'none', _mod_ui_text.NullProgressView),
 
291
            (TTYStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
 
292
            (TTYStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
 
293
            # on a non-tty terminal, it's null regardless of $TERM
 
294
            (FileStringIO, 'xterm', None, _mod_ui_text.NullProgressView),
 
295
            (FileStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
 
296
            # however, it can still be forced on
 
297
            (FileStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
 
298
            ):
 
299
            os.environ['TERM'] = term
 
300
            if pb is None:
 
301
                if 'BZR_PROGRESS_BAR' in os.environ:
 
302
                    del os.environ['BZR_PROGRESS_BAR']
 
303
            else:
 
304
                os.environ['BZR_PROGRESS_BAR'] = pb
 
305
            stdin = file_class('')
 
306
            stderr = file_class()
 
307
            stdout = file_class()
 
308
            uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
 
309
            self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
 
310
                "TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
 
311
            self.assertIsInstance(uif.make_progress_view(),
 
312
                expected_pb_class,
 
313
                "TERM=%s BZR_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
 
314
 
 
315
    def test_text_ui_non_terminal(self):
 
316
        """Even on non-ttys, make_ui_for_terminal gives a text ui."""
 
317
        stdin = test_progress._NonTTYStringIO('')
 
318
        stderr = test_progress._NonTTYStringIO()
 
319
        stdout = test_progress._NonTTYStringIO()
 
320
        for term_type in ['dumb', None, 'xterm']:
 
321
            if term_type is None:
 
322
                del os.environ['TERM']
 
323
            else:
 
324
                os.environ['TERM'] = term_type
 
325
            uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
 
326
            self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
 
327
                'TERM=%r' % (term_type,))
 
328
 
 
329
 
 
330
class SilentUITests(tests.TestCase):
314
331
 
315
332
    def test_silent_factory_get_password(self):
316
333
        # A silent factory that can't do user interaction can't get a
317
334
        # password.  Possibly it should raise a more specific error but it
318
335
        # can't succeed.
319
 
        ui = SilentUIFactory()
320
 
        stdout = StringIO()
 
336
        ui = _mod_ui.SilentUIFactory()
 
337
        stdout = tests.StringIOWrapper()
321
338
        self.assertRaises(
322
339
            NotImplementedError,
323
340
            self.apply_redirected,
326
343
        self.assertEqual('', stdout.getvalue())
327
344
 
328
345
    def test_silent_ui_getbool(self):
329
 
        factory = SilentUIFactory()
330
 
        stdout = StringIO()
 
346
        factory = _mod_ui.SilentUIFactory()
 
347
        stdout = tests.StringIOWrapper()
331
348
        self.assertRaises(
332
349
            NotImplementedError,
333
350
            self.apply_redirected,
334
351
            None, stdout, stdout, factory.get_boolean, "foo")
335
352
 
336
353
 
337
 
class TestUIFactoryTests(TestCase):
 
354
class TestUIFactoryTests(tests.TestCase):
338
355
 
339
356
    def test_test_ui_factory_progress(self):
340
357
        # there's no output; we just want to make sure this doesn't crash -
341
358
        # see https://bugs.edge.launchpad.net/bzr/+bug/408201
342
 
        ui = TestUIFactory()
 
359
        ui = tests.TestUIFactory()
343
360
        pb = ui.nested_progress_bar()
344
361
        pb.update('hello')
345
362
        pb.tick()
346
363
        pb.finished()
347
364
 
348
365
 
349
 
class CannedInputUIFactoryTests(TestCase):
350
 
    
 
366
class CannedInputUIFactoryTests(tests.TestCase):
 
367
 
351
368
    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'),
356
 
            'password')
 
369
        uif = _mod_ui.CannedInputUIFactory([True, 'mbp', 'password', 42])
 
370
        self.assertEqual(True, uif.get_boolean('Extra cheese?'))
 
371
        self.assertEqual('mbp', uif.get_username('Enter your user name'))
 
372
        self.assertEqual('password',
 
373
                         uif.get_password('Password for %(host)s',
 
374
                                          host='example.com'))
 
375
        self.assertEqual(42, uif.get_integer('And all that jazz ?'))
357
376
 
358
377
 
359
378
class TestBoolFromString(tests.TestCase):