~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_ui.py

  • Committer: Vincent Ladeuil
  • Date: 2009-06-22 12:52:39 UTC
  • mto: (4471.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4472.
  • Revision ID: v.ladeuil+lp@free.fr-20090622125239-kabo9smxt9c3vnir
Use a consistent scheme for naming pyrex source files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 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
12
12
#
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
16
16
 
17
17
"""Tests for the bzrlib ui
18
18
"""
21
21
from StringIO import StringIO
22
22
import re
23
23
import sys
 
24
import time
24
25
 
25
26
import bzrlib
26
27
import bzrlib.errors as errors
27
 
from bzrlib.progress import (
28
 
    DotsProgressBar,
29
 
    ProgressBarStack,
30
 
    TTYProgressBar,
 
28
from bzrlib.symbol_versioning import (
 
29
    deprecated_in,
31
30
    )
32
31
from bzrlib.tests import (
33
32
    TestCase,
39
38
    CLIUIFactory,
40
39
    SilentUIFactory,
41
40
    )
42
 
from bzrlib.ui.text import TextUIFactory
 
41
from bzrlib.ui.text import (
 
42
    NullProgressView,
 
43
    TextProgressView,
 
44
    TextUIFactory,
 
45
    )
43
46
 
44
47
 
45
48
class UITests(TestCase):
59
62
        self.assertEqual('', stdout.getvalue())
60
63
 
61
64
    def test_text_factory_ascii_password(self):
62
 
        ui = TestUIFactory(stdin='secret\n', stdout=StringIOWrapper())
 
65
        ui = TestUIFactory(stdin='secret\n', stdout=StringIOWrapper(),
 
66
                           stderr=StringIOWrapper())
63
67
        pb = ui.nested_progress_bar()
64
68
        try:
65
69
            self.assertEqual('secret',
66
70
                             self.apply_redirected(ui.stdin, ui.stdout,
67
 
                                                   ui.stdout,
 
71
                                                   ui.stderr,
68
72
                                                   ui.get_password))
69
73
            # ': ' is appended to prompt
70
 
            self.assertEqual(': ', ui.stdout.getvalue())
 
74
            self.assertEqual(': ', ui.stderr.getvalue())
 
75
            self.assertEqual('', ui.stdout.readline())
71
76
            # stdin should be empty
72
77
            self.assertEqual('', ui.stdin.readline())
73
78
        finally:
80
85
        it to utf8 to test that we transport the password correctly.
81
86
        """
82
87
        ui = TestUIFactory(stdin=u'baz\u1234'.encode('utf8'),
83
 
                           stdout=StringIOWrapper())
84
 
        ui.stdin.encoding = 'utf8'
85
 
        ui.stdout.encoding = ui.stdin.encoding
 
88
                           stdout=StringIOWrapper(),
 
89
                           stderr=StringIOWrapper())
 
90
        ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = 'utf8'
86
91
        pb = ui.nested_progress_bar()
87
92
        try:
88
 
            password = self.apply_redirected(ui.stdin, ui.stdout, ui.stdout,
 
93
            password = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
89
94
                                             ui.get_password,
90
95
                                             u'Hello \u1234 %(user)s',
91
96
                                             user=u'some\u1234')
92
97
            # We use StringIO objects, we need to decode them
93
98
            self.assertEqual(u'baz\u1234', password.decode('utf8'))
94
99
            self.assertEqual(u'Hello \u1234 some\u1234: ',
95
 
                             ui.stdout.getvalue().decode('utf8'))
96
 
            # stdin should be empty
 
100
                             ui.stderr.getvalue().decode('utf8'))
 
101
            # stdin and stdout should be empty
97
102
            self.assertEqual('', ui.stdin.readline())
 
103
            self.assertEqual('', ui.stdout.readline())
98
104
        finally:
99
105
            pb.finished()
100
106
 
 
107
    def test_progress_construction(self):
 
108
        """TextUIFactory constructs the right progress view.
 
109
        """
 
110
        os.environ['BZR_PROGRESS_BAR'] = 'none'
 
111
        self.assertIsInstance(TextUIFactory()._progress_view,
 
112
            NullProgressView)
 
113
 
 
114
        os.environ['BZR_PROGRESS_BAR'] = 'text'
 
115
        self.assertIsInstance(TextUIFactory()._progress_view,
 
116
            TextProgressView)
 
117
 
 
118
        os.environ['BZR_PROGRESS_BAR'] = 'text'
 
119
        self.assertIsInstance(TextUIFactory()._progress_view,
 
120
            TextProgressView)
 
121
 
 
122
        del os.environ['BZR_PROGRESS_BAR']
 
123
        self.assertIsInstance(TextUIFactory()._progress_view,
 
124
            TextProgressView)
 
125
 
101
126
    def test_progress_note(self):
102
127
        stderr = StringIO()
103
128
        stdout = StringIO()
104
 
        ui_factory = TextUIFactory(bar_type=TTYProgressBar)
 
129
        ui_factory = TextUIFactory(stdin=StringIO(''),
 
130
            stderr=stderr,
 
131
            stdout=stdout)
105
132
        pb = ui_factory.nested_progress_bar()
106
133
        try:
107
 
            pb.to_messages_file = stdout
108
 
            ui_factory._progress_bar_stack.bottom().to_file = stderr
109
134
            result = pb.note('t')
110
135
            self.assertEqual(None, result)
111
136
            self.assertEqual("t\n", stdout.getvalue())
122
147
        # The PQM redirects the output to a file, so it
123
148
        # defaults to creating a Dots progress bar. we
124
149
        # need to force it to believe we are a TTY
125
 
        ui_factory = TextUIFactory(bar_type=TTYProgressBar)
 
150
        ui_factory = TextUIFactory(
 
151
            stdin=StringIO(''),
 
152
            stdout=stdout, stderr=stderr)
126
153
        pb = ui_factory.nested_progress_bar()
127
154
        try:
128
 
            pb.to_messages_file = stdout
129
 
            ui_factory._progress_bar_stack.bottom().to_file = stderr
130
155
            # Create a progress update that isn't throttled
131
 
            pb.start_time -= 10
132
156
            pb.update('x', 1, 1)
133
157
            result = pb.note('t')
134
158
            self.assertEqual(None, result)
142
166
 
143
167
    def test_progress_nested(self):
144
168
        # test factory based nested and popping.
145
 
        ui = TextUIFactory()
 
169
        ui = TextUIFactory(None, None, None)
146
170
        pb1 = ui.nested_progress_bar()
147
171
        pb2 = ui.nested_progress_bar()
148
 
        self.assertRaises(errors.MissingProgressBarFinish, pb1.finished)
149
 
        pb2.finished()
150
 
        pb1.finished()
151
 
 
152
 
    def test_progress_stack(self):
153
 
        # test the progress bar stack which the default text factory 
154
 
        # uses.
155
 
        stderr = StringIO()
156
 
        stdout = StringIO()
157
 
        # make a stack, which accepts parameters like a pb.
158
 
        stack = ProgressBarStack(to_file=stderr, to_messages_file=stdout)
159
 
        # but is not one
160
 
        self.assertFalse(getattr(stack, 'note', False))
161
 
        pb1 = stack.get_nested()
162
 
        pb2 = stack.get_nested()
163
 
        self.assertRaises(errors.MissingProgressBarFinish, pb1.finished)
164
 
        pb2.finished()
165
 
        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)
171
 
        pb2.finished()
172
 
        pb1.finished()
173
 
 
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()
178
 
        bar.finished()
179
 
        self.assertIsInstance(bar, DotsProgressBar)
180
 
 
181
 
    def test_cli_stdin_is_default_stdin(self):
182
 
        factory = CLIUIFactory()
183
 
        self.assertEqual(sys.stdin, factory.stdin)
 
172
        # You do get a warning if the outermost progress bar wasn't finished
 
173
        # first - it's not clear if this is really useful or if it should just
 
174
        # become orphaned -- mbp 20090120
 
175
        warnings, _ = self.callCatchWarnings(pb1.finished)
 
176
        if len(warnings) != 1:
 
177
            self.fail("unexpected warnings: %r" % (warnings,))
 
178
        pb2.finished()
 
179
        pb1.finished()
184
180
 
185
181
    def assert_get_bool_acceptance_of_user_input(self, factory):
186
182
        factory.stdin = StringIO("y\nyes with garbage\n"
187
183
                                 "yes\nn\nnot an answer\n"
188
184
                                 "no\nfoo\n")
189
185
        factory.stdout = StringIO()
 
186
        factory.stderr = StringIO()
190
187
        # there is no output from the base factory
191
188
        self.assertEqual(True, factory.get_boolean(""))
192
189
        self.assertEqual(True, factory.get_boolean(""))
212
209
        self.assertEqual('', factory.stdin.readline())
213
210
 
214
211
    def test_text_ui_getbool(self):
215
 
        factory = TextUIFactory()
 
212
        factory = TextUIFactory(None, None, None)
216
213
        self.assert_get_bool_acceptance_of_user_input(factory)
217
214
 
 
215
    def test_text_factory_prompt(self):
 
216
        # see <https://launchpad.net/bugs/365891>
 
217
        factory = TextUIFactory(None, StringIO(), StringIO(), StringIO())
 
218
        factory.prompt('foo %2e')
 
219
        self.assertEqual('', factory.stdout.getvalue())
 
220
        self.assertEqual('foo %2e', factory.stderr.getvalue())
 
221
 
218
222
    def test_text_factory_prompts_and_clears(self):
219
223
        # 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)
225
 
        pb.start_time = None
226
 
        self.apply_redirected(factory.stdin, factory.stdout,
227
 
                              factory.stdout, pb.update, "foo", 0, 1)
 
224
        out = _TTYStringIO()
 
225
        factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
 
226
        pb = factory.nested_progress_bar()
 
227
        pb.show_bar = False
 
228
        pb.show_spinner = False
 
229
        pb.show_count = False
 
230
        pb.update("foo", 0, 1)
228
231
        self.assertEqual(True,
229
232
                         self.apply_redirected(None, factory.stdout,
230
233
                                               factory.stdout,
231
234
                                               factory.get_boolean,
232
235
                                               "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())
 
236
        output = out.getvalue()
 
237
        self.assertContainsRe(factory.stdout.getvalue(),
 
238
            "foo *\r\r  *\r*")
 
239
        self.assertContainsRe(factory.stdout.getvalue(),
 
240
            r"what do you want\? \[y/n\]: what do you want\? \[y/n\]: ")
 
241
        # stdin should have been totally consumed
 
242
        self.assertEqual('', factory.stdin.readline())
 
243
 
 
244
    def test_text_tick_after_update(self):
 
245
        ui_factory = TextUIFactory(stdout=StringIO(), stderr=StringIO())
 
246
        pb = ui_factory.nested_progress_bar()
 
247
        try:
 
248
            pb.update('task', 0, 3)
 
249
            # Reset the clock, so that it actually tries to repaint itself
 
250
            ui_factory._progress_view._last_repaint = time.time() - 1.0
 
251
            pb.tick()
 
252
        finally:
 
253
            pb.finished()
 
254
 
 
255
    def test_silent_ui_getusername(self):
 
256
        factory = SilentUIFactory()
 
257
        factory.stdin = StringIO("someuser\n\n")
 
258
        factory.stdout = StringIO()
 
259
        factory.stderr = StringIO()
 
260
        self.assertEquals(None,
 
261
            factory.get_username(u'Hello\u1234 %(host)s', host=u'some\u1234'))
 
262
        self.assertEquals("", factory.stdout.getvalue())
 
263
        self.assertEquals("", factory.stderr.getvalue())
 
264
        self.assertEquals("someuser\n\n", factory.stdin.getvalue())
 
265
 
 
266
    def test_text_ui_getusername(self):
 
267
        factory = TextUIFactory(None, None, None)
 
268
        factory.stdin = StringIO("someuser\n\n")
 
269
        factory.stdout = StringIO()
 
270
        factory.stderr = StringIO()
 
271
        factory.stdout.encoding = "utf8"
 
272
        # there is no output from the base factory
 
273
        self.assertEqual("someuser",
 
274
                         factory.get_username('Hello %(host)s', host='some'))
 
275
        self.assertEquals("Hello some: ", factory.stderr.getvalue())
 
276
        self.assertEquals('', factory.stdout.getvalue())
 
277
        self.assertEqual("", factory.get_username("Gebruiker"))
237
278
        # stdin should be empty
238
279
        self.assertEqual('', factory.stdin.readline())
239
280
 
 
281
    def test_text_ui_getusername_utf8(self):
 
282
        ui = TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
 
283
                           stdout=StringIOWrapper(), stderr=StringIOWrapper())
 
284
        ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = "utf8"
 
285
        pb = ui.nested_progress_bar()
 
286
        try:
 
287
            # there is no output from the base factory
 
288
            username = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
 
289
                ui.get_username, u'Hello\u1234 %(host)s', host=u'some\u1234')
 
290
            self.assertEquals(u"someuser\u1234", username.decode('utf8'))
 
291
            self.assertEquals(u"Hello\u1234 some\u1234: ",
 
292
                              ui.stderr.getvalue().decode("utf8"))
 
293
            self.assertEquals('', ui.stdout.getvalue())
 
294
        finally:
 
295
            pb.finished()
 
296
 
 
297
 
 
298
class TestTextProgressView(TestCase):
 
299
    """Tests for text display of progress bars.
 
300
    """
 
301
    # XXX: These might be a bit easier to write if the rendering and
 
302
    # state-maintaining parts of TextProgressView were more separate, and if
 
303
    # the progress task called back directly to its own view not to the ui
 
304
    # factory. -- mbp 20090312
 
305
    
 
306
    def _make_factory(self):
 
307
        out = StringIO()
 
308
        uif = TextUIFactory(stderr=out)
 
309
        uif._progress_view._width = 80
 
310
        return out, uif
 
311
 
 
312
    def test_render_progress_easy(self):
 
313
        """Just one task and one quarter done"""
 
314
        out, uif = self._make_factory()
 
315
        task = uif.nested_progress_bar()
 
316
        task.update('reticulating splines', 5, 20)
 
317
        self.assertEqual(
 
318
'\r[####/               ] reticulating splines 5/20                               \r'
 
319
            , out.getvalue())
 
320
 
 
321
    def test_render_progress_nested(self):
 
322
        """Tasks proportionally contribute to overall progress"""
 
323
        out, uif = self._make_factory()
 
324
        task = uif.nested_progress_bar()
 
325
        task.update('reticulating splines', 0, 2)
 
326
        task2 = uif.nested_progress_bar()
 
327
        task2.update('stage2', 1, 2)
 
328
        # so we're in the first half of the main task, and half way through
 
329
        # that
 
330
        self.assertEqual(
 
331
r'[####\               ] reticulating splines:stage2 1/2'
 
332
            , uif._progress_view._render_line())
 
333
        # if the nested task is complete, then we're all the way through the
 
334
        # first half of the overall work
 
335
        task2.update('stage2', 2, 2)
 
336
        self.assertEqual(
 
337
r'[#########|          ] reticulating splines:stage2 2/2'
 
338
            , uif._progress_view._render_line())
 
339
 
 
340
    def test_render_progress_sub_nested(self):
 
341
        """Intermediate tasks don't mess up calculation."""
 
342
        out, uif = self._make_factory()
 
343
        task_a = uif.nested_progress_bar()
 
344
        task_a.update('a', 0, 2)
 
345
        task_b = uif.nested_progress_bar()
 
346
        task_b.update('b')
 
347
        task_c = uif.nested_progress_bar()
 
348
        task_c.update('c', 1, 2)
 
349
        # the top-level task is in its first half; the middle one has no
 
350
        # progress indication, just a label; and the bottom one is half done,
 
351
        # so the overall fraction is 1/4
 
352
        self.assertEqual(
 
353
            r'[####|               ] a:b:c 1/2'
 
354
            , uif._progress_view._render_line())
 
355