/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_ui.py

  • Committer: Andrew Bennetts
  • Date: 2009-06-15 08:01:21 UTC
  • mto: This revision was merged to the branch mainline in revision 4446.
  • Revision ID: andrew.bennetts@canonical.com-20090615080121-ef0m1mj83qjv6gc6
Fix bug when partial_history == [stop_revision]

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2008, 2009 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for the bzrlib ui
 
18
"""
 
19
 
 
20
import os
 
21
from StringIO import StringIO
 
22
import re
 
23
import sys
 
24
import time
 
25
 
 
26
import bzrlib
 
27
import bzrlib.errors as errors
 
28
from bzrlib.symbol_versioning import (
 
29
    deprecated_in,
 
30
    )
 
31
from bzrlib.tests import (
 
32
    TestCase,
 
33
    TestUIFactory,
 
34
    StringIOWrapper,
 
35
    )
 
36
from bzrlib.tests.test_progress import _TTYStringIO
 
37
from bzrlib.ui import (
 
38
    CLIUIFactory,
 
39
    SilentUIFactory,
 
40
    )
 
41
from bzrlib.ui.text import (
 
42
    TextProgressView,
 
43
    TextUIFactory,
 
44
    )
 
45
 
 
46
 
 
47
class UITests(TestCase):
 
48
 
 
49
    def test_silent_factory(self):
 
50
        ui = SilentUIFactory()
 
51
        stdout = StringIO()
 
52
        self.assertEqual(None,
 
53
                         self.apply_redirected(None, stdout, stdout,
 
54
                                               ui.get_password))
 
55
        self.assertEqual('', stdout.getvalue())
 
56
        self.assertEqual(None,
 
57
                         self.apply_redirected(None, stdout, stdout,
 
58
                                               ui.get_password,
 
59
                                               u'Hello\u1234 %(user)s',
 
60
                                               user=u'some\u1234'))
 
61
        self.assertEqual('', stdout.getvalue())
 
62
 
 
63
    def test_text_factory_ascii_password(self):
 
64
        ui = TestUIFactory(stdin='secret\n', stdout=StringIOWrapper(),
 
65
                           stderr=StringIOWrapper())
 
66
        pb = ui.nested_progress_bar()
 
67
        try:
 
68
            self.assertEqual('secret',
 
69
                             self.apply_redirected(ui.stdin, ui.stdout,
 
70
                                                   ui.stderr,
 
71
                                                   ui.get_password))
 
72
            # ': ' is appended to prompt
 
73
            self.assertEqual(': ', ui.stderr.getvalue())
 
74
            self.assertEqual('', ui.stdout.readline())
 
75
            # stdin should be empty
 
76
            self.assertEqual('', ui.stdin.readline())
 
77
        finally:
 
78
            pb.finished()
 
79
 
 
80
    def test_text_factory_utf8_password(self):
 
81
        """Test an utf8 password.
 
82
 
 
83
        We can't predict what encoding users will have for stdin, so we force
 
84
        it to utf8 to test that we transport the password correctly.
 
85
        """
 
86
        ui = TestUIFactory(stdin=u'baz\u1234'.encode('utf8'),
 
87
                           stdout=StringIOWrapper(),
 
88
                           stderr=StringIOWrapper())
 
89
        ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = 'utf8'
 
90
        pb = ui.nested_progress_bar()
 
91
        try:
 
92
            password = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
 
93
                                             ui.get_password,
 
94
                                             u'Hello \u1234 %(user)s',
 
95
                                             user=u'some\u1234')
 
96
            # We use StringIO objects, we need to decode them
 
97
            self.assertEqual(u'baz\u1234', password.decode('utf8'))
 
98
            self.assertEqual(u'Hello \u1234 some\u1234: ',
 
99
                             ui.stderr.getvalue().decode('utf8'))
 
100
            # stdin and stdout should be empty
 
101
            self.assertEqual('', ui.stdin.readline())
 
102
            self.assertEqual('', ui.stdout.readline())
 
103
        finally:
 
104
            pb.finished()
 
105
 
 
106
    def test_progress_note(self):
 
107
        stderr = StringIO()
 
108
        stdout = StringIO()
 
109
        ui_factory = TextUIFactory(stdin=StringIO(''),
 
110
            stderr=stderr,
 
111
            stdout=stdout)
 
112
        pb = ui_factory.nested_progress_bar()
 
113
        try:
 
114
            result = pb.note('t')
 
115
            self.assertEqual(None, result)
 
116
            self.assertEqual("t\n", stdout.getvalue())
 
117
            # Since there was no update() call, there should be no clear() call
 
118
            self.failIf(re.search(r'^\r {10,}\r$',
 
119
                                  stderr.getvalue()) is not None,
 
120
                        'We cleared the stderr without anything to put there')
 
121
        finally:
 
122
            pb.finished()
 
123
 
 
124
    def test_progress_note_clears(self):
 
125
        stderr = StringIO()
 
126
        stdout = StringIO()
 
127
        # The PQM redirects the output to a file, so it
 
128
        # defaults to creating a Dots progress bar. we
 
129
        # need to force it to believe we are a TTY
 
130
        ui_factory = TextUIFactory(
 
131
            stdin=StringIO(''),
 
132
            stdout=stdout, stderr=stderr)
 
133
        pb = ui_factory.nested_progress_bar()
 
134
        try:
 
135
            # Create a progress update that isn't throttled
 
136
            pb.update('x', 1, 1)
 
137
            result = pb.note('t')
 
138
            self.assertEqual(None, result)
 
139
            self.assertEqual("t\n", stdout.getvalue())
 
140
            # the exact contents will depend on the terminal width and we don't
 
141
            # care about that right now - but you're probably running it on at
 
142
            # least a 10-character wide terminal :)
 
143
            self.assertContainsRe(stderr.getvalue(), r'\r {10,}\r$')
 
144
        finally:
 
145
            pb.finished()
 
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
 
 
161
    def assert_get_bool_acceptance_of_user_input(self, factory):
 
162
        factory.stdin = StringIO("y\nyes with garbage\n"
 
163
                                 "yes\nn\nnot an answer\n"
 
164
                                 "no\nfoo\n")
 
165
        factory.stdout = StringIO()
 
166
        factory.stderr = StringIO()
 
167
        # there is no output from the base factory
 
168
        self.assertEqual(True, factory.get_boolean(""))
 
169
        self.assertEqual(True, factory.get_boolean(""))
 
170
        self.assertEqual(False, factory.get_boolean(""))
 
171
        self.assertEqual(False, factory.get_boolean(""))
 
172
        self.assertEqual("foo\n", factory.stdin.read())
 
173
        # stdin should be empty
 
174
        self.assertEqual('', factory.stdin.readline())
 
175
 
 
176
    def test_silent_ui_getbool(self):
 
177
        factory = SilentUIFactory()
 
178
        self.assert_get_bool_acceptance_of_user_input(factory)
 
179
 
 
180
    def test_silent_factory_prompts_silently(self):
 
181
        factory = SilentUIFactory()
 
182
        stdout = StringIO()
 
183
        factory.stdin = StringIO("y\n")
 
184
        self.assertEqual(True,
 
185
                         self.apply_redirected(None, stdout, stdout,
 
186
                                               factory.get_boolean, "foo"))
 
187
        self.assertEqual("", stdout.getvalue())
 
188
        # stdin should be empty
 
189
        self.assertEqual('', factory.stdin.readline())
 
190
 
 
191
    def test_text_ui_getbool(self):
 
192
        factory = TextUIFactory(None, None, None)
 
193
        self.assert_get_bool_acceptance_of_user_input(factory)
 
194
 
 
195
    def test_text_factory_prompt(self):
 
196
        # see <https://launchpad.net/bugs/365891>
 
197
        factory = TextUIFactory(None, StringIO(), StringIO(), StringIO())
 
198
        factory.prompt('foo %2e')
 
199
        self.assertEqual('', factory.stdout.getvalue())
 
200
        self.assertEqual('foo %2e', factory.stderr.getvalue())
 
201
 
 
202
    def test_text_factory_prompts_and_clears(self):
 
203
        # a get_boolean call should clear the pb before prompting
 
204
        out = _TTYStringIO()
 
205
        factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
 
206
        pb = factory.nested_progress_bar()
 
207
        pb.show_bar = False
 
208
        pb.show_spinner = False
 
209
        pb.show_count = False
 
210
        pb.update("foo", 0, 1)
 
211
        self.assertEqual(True,
 
212
                         self.apply_redirected(None, factory.stdout,
 
213
                                               factory.stdout,
 
214
                                               factory.get_boolean,
 
215
                                               "what do you want"))
 
216
        output = out.getvalue()
 
217
        self.assertContainsRe(factory.stdout.getvalue(),
 
218
            "foo *\r\r  *\r*")
 
219
        self.assertContainsRe(factory.stdout.getvalue(),
 
220
            r"what do you want\? \[y/n\]: what do you want\? \[y/n\]: ")
 
221
        # stdin should have been totally consumed
 
222
        self.assertEqual('', factory.stdin.readline())
 
223
 
 
224
    def test_text_tick_after_update(self):
 
225
        ui_factory = TextUIFactory(stdout=StringIO(), stderr=StringIO())
 
226
        pb = ui_factory.nested_progress_bar()
 
227
        try:
 
228
            pb.update('task', 0, 3)
 
229
            # Reset the clock, so that it actually tries to repaint itself
 
230
            ui_factory._progress_view._last_repaint = time.time() - 1.0
 
231
            pb.tick()
 
232
        finally:
 
233
            pb.finished()
 
234
 
 
235
    def test_silent_ui_getusername(self):
 
236
        factory = SilentUIFactory()
 
237
        factory.stdin = StringIO("someuser\n\n")
 
238
        factory.stdout = StringIO()
 
239
        factory.stderr = StringIO()
 
240
        self.assertEquals(None,
 
241
            factory.get_username(u'Hello\u1234 %(host)s', host=u'some\u1234'))
 
242
        self.assertEquals("", factory.stdout.getvalue())
 
243
        self.assertEquals("", factory.stderr.getvalue())
 
244
        self.assertEquals("someuser\n\n", factory.stdin.getvalue())
 
245
 
 
246
    def test_text_ui_getusername(self):
 
247
        factory = TextUIFactory(None, None, None)
 
248
        factory.stdin = StringIO("someuser\n\n")
 
249
        factory.stdout = StringIO()
 
250
        factory.stderr = StringIO()
 
251
        factory.stdout.encoding = "utf8"
 
252
        # there is no output from the base factory
 
253
        self.assertEqual("someuser",
 
254
                         factory.get_username('Hello %(host)s', host='some'))
 
255
        self.assertEquals("Hello some: ", factory.stderr.getvalue())
 
256
        self.assertEquals('', factory.stdout.getvalue())
 
257
        self.assertEqual("", factory.get_username("Gebruiker"))
 
258
        # stdin should be empty
 
259
        self.assertEqual('', factory.stdin.readline())
 
260
 
 
261
    def test_text_ui_getusername_utf8(self):
 
262
        ui = TestUIFactory(stdin=u'someuser\u1234'.encode('utf8'),
 
263
                           stdout=StringIOWrapper(), stderr=StringIOWrapper())
 
264
        ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = "utf8"
 
265
        pb = ui.nested_progress_bar()
 
266
        try:
 
267
            # there is no output from the base factory
 
268
            username = self.apply_redirected(ui.stdin, ui.stdout, ui.stderr,
 
269
                ui.get_username, u'Hello\u1234 %(host)s', host=u'some\u1234')
 
270
            self.assertEquals(u"someuser\u1234", username.decode('utf8'))
 
271
            self.assertEquals(u"Hello\u1234 some\u1234: ",
 
272
                              ui.stderr.getvalue().decode("utf8"))
 
273
            self.assertEquals('', ui.stdout.getvalue())
 
274
        finally:
 
275
            pb.finished()
 
276
 
 
277
 
 
278
class TestTextProgressView(TestCase):
 
279
    """Tests for text display of progress bars.
 
280
    """
 
281
    # XXX: These might be a bit easier to write if the rendering and
 
282
    # state-maintaining parts of TextProgressView were more separate, and if
 
283
    # the progress task called back directly to its own view not to the ui
 
284
    # factory. -- mbp 20090312
 
285
    
 
286
    def _make_factory(self):
 
287
        out = StringIO()
 
288
        uif = TextUIFactory(stderr=out)
 
289
        uif._progress_view._width = 80
 
290
        return out, uif
 
291
 
 
292
    def test_render_progress_easy(self):
 
293
        """Just one task and one quarter done"""
 
294
        out, uif = self._make_factory()
 
295
        task = uif.nested_progress_bar()
 
296
        task.update('reticulating splines', 5, 20)
 
297
        self.assertEqual(
 
298
'\r[####/               ] reticulating splines 5/20                               \r'
 
299
            , out.getvalue())
 
300
 
 
301
    def test_render_progress_nested(self):
 
302
        """Tasks proportionally contribute to overall progress"""
 
303
        out, uif = self._make_factory()
 
304
        task = uif.nested_progress_bar()
 
305
        task.update('reticulating splines', 0, 2)
 
306
        task2 = uif.nested_progress_bar()
 
307
        task2.update('stage2', 1, 2)
 
308
        # so we're in the first half of the main task, and half way through
 
309
        # that
 
310
        self.assertEqual(
 
311
r'[####\               ] reticulating splines:stage2 1/2'
 
312
            , uif._progress_view._render_line())
 
313
        # if the nested task is complete, then we're all the way through the
 
314
        # first half of the overall work
 
315
        task2.update('stage2', 2, 2)
 
316
        self.assertEqual(
 
317
r'[#########|          ] reticulating splines:stage2 2/2'
 
318
            , uif._progress_view._render_line())
 
319
 
 
320
    def test_render_progress_sub_nested(self):
 
321
        """Intermediate tasks don't mess up calculation."""
 
322
        out, uif = self._make_factory()
 
323
        task_a = uif.nested_progress_bar()
 
324
        task_a.update('a', 0, 2)
 
325
        task_b = uif.nested_progress_bar()
 
326
        task_b.update('b')
 
327
        task_c = uif.nested_progress_bar()
 
328
        task_c.update('c', 1, 2)
 
329
        # the top-level task is in its first half; the middle one has no
 
330
        # progress indication, just a label; and the bottom one is half done,
 
331
        # so the overall fraction is 1/4
 
332
        self.assertEqual(
 
333
            r'[####|               ] a:b:c 1/2'
 
334
            , uif._progress_view._render_line())
 
335