~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_ui.py

merge merge tweaks from aaron, which includes latest .dev

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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
 
 
25
 
import bzrlib
26
 
import bzrlib.errors as errors
27
 
from bzrlib.progress import (
28
 
    DotsProgressBar,
29
 
    ProgressBarStack,
30
 
    TTYProgressBar,
31
 
    )
32
 
from bzrlib.symbol_versioning import (
33
 
    deprecated_in,
34
 
    )
35
 
from bzrlib.tests import (
36
 
    TestCase,
37
 
    TestUIFactory,
38
 
    StringIOWrapper,
39
 
    )
40
 
from bzrlib.tests.test_progress import _TTYStringIO
41
 
from bzrlib.ui import (
42
 
    CLIUIFactory,
43
 
    SilentUIFactory,
44
 
    )
45
 
from bzrlib.ui.text import TextUIFactory
46
 
 
47
 
 
48
 
class UITests(TestCase):
49
 
 
50
 
    def test_silent_factory(self):
51
 
        ui = SilentUIFactory()
52
 
        stdout = StringIO()
53
 
        self.assertEqual(None,
54
 
                         self.apply_redirected(None, stdout, stdout,
55
 
                                               ui.get_password))
56
 
        self.assertEqual('', stdout.getvalue())
57
 
        self.assertEqual(None,
58
 
                         self.apply_redirected(None, stdout, stdout,
59
 
                                               ui.get_password,
60
 
                                               u'Hello\u1234 %(user)s',
61
 
                                               user=u'some\u1234'))
62
 
        self.assertEqual('', stdout.getvalue())
63
 
 
64
 
    def test_text_factory_ascii_password(self):
65
 
        ui = TestUIFactory(stdin='secret\n', stdout=StringIOWrapper())
66
 
        pb = ui.nested_progress_bar()
67
 
        try:
68
 
            self.assertEqual('secret',
69
 
                             self.apply_redirected(ui.stdin, ui.stdout,
70
 
                                                   ui.stdout,
71
 
                                                   ui.get_password))
72
 
            # ': ' is appended to prompt
73
 
            self.assertEqual(': ', ui.stdout.getvalue())
74
 
            # stdin should be empty
75
 
            self.assertEqual('', ui.stdin.readline())
76
 
        finally:
77
 
            pb.finished()
78
 
 
79
 
    def test_text_factory_utf8_password(self):
80
 
        """Test an utf8 password.
81
 
 
82
 
        We can't predict what encoding users will have for stdin, so we force
83
 
        it to utf8 to test that we transport the password correctly.
84
 
        """
85
 
        ui = TestUIFactory(stdin=u'baz\u1234'.encode('utf8'),
86
 
                           stdout=StringIOWrapper())
87
 
        ui.stdin.encoding = 'utf8'
88
 
        ui.stdout.encoding = ui.stdin.encoding
89
 
        pb = ui.nested_progress_bar()
90
 
        try:
91
 
            password = self.apply_redirected(ui.stdin, ui.stdout, ui.stdout,
92
 
                                             ui.get_password,
93
 
                                             u'Hello \u1234 %(user)s',
94
 
                                             user=u'some\u1234')
95
 
            # We use StringIO objects, we need to decode them
96
 
            self.assertEqual(u'baz\u1234', password.decode('utf8'))
97
 
            self.assertEqual(u'Hello \u1234 some\u1234: ',
98
 
                             ui.stdout.getvalue().decode('utf8'))
99
 
            # stdin should be empty
100
 
            self.assertEqual('', ui.stdin.readline())
101
 
        finally:
102
 
            pb.finished()
103
 
 
104
 
    def test_progress_note(self):
105
 
        stderr = StringIO()
106
 
        stdout = StringIO()
107
 
        ui_factory = TextUIFactory(stdin=StringIO(''),
108
 
            stderr=stderr,
109
 
            stdout=stdout)
110
 
        pb = ui_factory.nested_progress_bar()
111
 
        try:
112
 
            result = pb.note('t')
113
 
            self.assertEqual(None, result)
114
 
            self.assertEqual("t\n", stdout.getvalue())
115
 
            # Since there was no update() call, there should be no clear() call
116
 
            self.failIf(re.search(r'^\r {10,}\r$',
117
 
                                  stderr.getvalue()) is not None,
118
 
                        'We cleared the stderr without anything to put there')
119
 
        finally:
120
 
            pb.finished()
121
 
 
122
 
    def test_progress_note_clears(self):
123
 
        stderr = StringIO()
124
 
        stdout = StringIO()
125
 
        # The PQM redirects the output to a file, so it
126
 
        # defaults to creating a Dots progress bar. we
127
 
        # need to force it to believe we are a TTY
128
 
        ui_factory = TextUIFactory(
129
 
            stdin=StringIO(''),
130
 
            stdout=stdout, stderr=stderr)
131
 
        pb = ui_factory.nested_progress_bar()
132
 
        try:
133
 
            # Create a progress update that isn't throttled
134
 
            pb.update('x', 1, 1)
135
 
            result = pb.note('t')
136
 
            self.assertEqual(None, result)
137
 
            self.assertEqual("t\n", stdout.getvalue())
138
 
            # the exact contents will depend on the terminal width and we don't
139
 
            # care about that right now - but you're probably running it on at
140
 
            # least a 10-character wide terminal :)
141
 
            self.assertContainsRe(stderr.getvalue(), r'\r {10,}\r$')
142
 
        finally:
143
 
            pb.finished()
144
 
 
145
 
    def test_progress_nested(self):
146
 
        # test factory based nested and popping.
147
 
        ui = TextUIFactory(None, None, None)
148
 
        pb1 = ui.nested_progress_bar()
149
 
        pb2 = ui.nested_progress_bar()
150
 
        # You do get a warning if the outermost progress bar wasn't finished
151
 
        # first - it's not clear if this is really useful or if it should just
152
 
        # become orphaned -- mbp 20090120
153
 
        warnings, _ = self.callCatchWarnings(pb1.finished)
154
 
        if len(warnings) != 1:
155
 
            self.fail("unexpected warnings: %r" % (warnings,))
156
 
        pb2.finished()
157
 
        pb1.finished()
158
 
 
159
 
    def test_progress_stack(self):
160
 
        # test the progress bar stack which the default text factory 
161
 
        # uses.
162
 
        stderr = StringIO()
163
 
        stdout = StringIO()
164
 
        # make a stack, which accepts parameters like a pb.
165
 
        stack = self.applyDeprecated(
166
 
            deprecated_in((1, 12, 0)),
167
 
            ProgressBarStack,
168
 
            to_file=stderr, to_messages_file=stdout)
169
 
        # but is not one
170
 
        self.assertFalse(getattr(stack, 'note', False))
171
 
        pb1 = stack.get_nested()
172
 
        pb2 = stack.get_nested()
173
 
        warnings, _ = self.callCatchWarnings(pb1.finished)
174
 
        self.assertEqual(len(warnings), 1)
175
 
        pb2.finished()
176
 
        pb1.finished()
177
 
        # the text ui factory never actually removes the stack once its setup.
178
 
        # we need to be able to nest again correctly from here.
179
 
        pb1 = stack.get_nested()
180
 
        pb2 = stack.get_nested()
181
 
        warnings, _ = self.callCatchWarnings(pb1.finished)
182
 
        self.assertEqual(len(warnings), 1)
183
 
        pb2.finished()
184
 
        pb1.finished()
185
 
 
186
 
    def assert_get_bool_acceptance_of_user_input(self, factory):
187
 
        factory.stdin = StringIO("y\nyes with garbage\n"
188
 
                                 "yes\nn\nnot an answer\n"
189
 
                                 "no\nfoo\n")
190
 
        factory.stdout = StringIO()
191
 
        # there is no output from the base factory
192
 
        self.assertEqual(True, factory.get_boolean(""))
193
 
        self.assertEqual(True, factory.get_boolean(""))
194
 
        self.assertEqual(False, factory.get_boolean(""))
195
 
        self.assertEqual(False, factory.get_boolean(""))
196
 
        self.assertEqual("foo\n", factory.stdin.read())
197
 
        # stdin should be empty
198
 
        self.assertEqual('', factory.stdin.readline())
199
 
 
200
 
    def test_silent_ui_getbool(self):
201
 
        factory = SilentUIFactory()
202
 
        self.assert_get_bool_acceptance_of_user_input(factory)
203
 
 
204
 
    def test_silent_factory_prompts_silently(self):
205
 
        factory = SilentUIFactory()
206
 
        stdout = StringIO()
207
 
        factory.stdin = StringIO("y\n")
208
 
        self.assertEqual(True,
209
 
                         self.apply_redirected(None, stdout, stdout,
210
 
                                               factory.get_boolean, "foo"))
211
 
        self.assertEqual("", stdout.getvalue())
212
 
        # stdin should be empty
213
 
        self.assertEqual('', factory.stdin.readline())
214
 
 
215
 
    def test_text_ui_getbool(self):
216
 
        factory = TextUIFactory(None, None, None)
217
 
        self.assert_get_bool_acceptance_of_user_input(factory)
218
 
 
219
 
    def test_text_factory_prompts_and_clears(self):
220
 
        # a get_boolean call should clear the pb before prompting
221
 
        out = _TTYStringIO()
222
 
        factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
223
 
        pb = factory.nested_progress_bar()
224
 
        pb.show_bar = False
225
 
        pb.show_spinner = False
226
 
        pb.show_count = False
227
 
        pb.update("foo", 0, 1)
228
 
        self.assertEqual(True,
229
 
                         self.apply_redirected(None, factory.stdout,
230
 
                                               factory.stdout,
231
 
                                               factory.get_boolean,
232
 
                                               "what do you want"))
233
 
        output = out.getvalue()
234
 
        self.assertContainsRe(factory.stdout.getvalue(),
235
 
            "foo *\r\r  *\r*")
236
 
        self.assertContainsRe(factory.stdout.getvalue(),
237
 
            r"what do you want\? \[y/n\]: what do you want\? \[y/n\]: ")
238
 
        # stdin should have been totally consumed
239
 
        self.assertEqual('', factory.stdin.readline())