~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_ui.py

  • Committer: John Arbash Meinel
  • Date: 2009-07-24 18:26:21 UTC
  • mfrom: (4567 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4568.
  • Revision ID: john@arbash-meinel.com-20090724182621-68s2jhoqf3pn72n7
Merge bzr.dev 4567 to resolve NEWS

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
from bzrlib.symbol_versioning import (
32
32
    deprecated_in,
33
33
    )
34
 
from bzrlib.tests.test_progress import _TTYStringIO
 
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
    )
35
50
from bzrlib.ui.text import (
36
51
    NullProgressView,
37
52
    TextProgressView,
41
56
 
42
57
class UITests(tests.TestCase):
43
58
 
44
 
    def test_silent_factory(self):
45
 
        ui = _mod_ui.SilentUIFactory()
46
 
        stdout = StringIO()
47
 
        self.assertEqual(None,
48
 
                         self.apply_redirected(None, stdout, stdout,
49
 
                                               ui.get_password))
50
 
        self.assertEqual('', stdout.getvalue())
51
 
        self.assertEqual(None,
52
 
                         self.apply_redirected(None, stdout, stdout,
53
 
                                               ui.get_password,
54
 
                                               u'Hello\u1234 %(user)s',
55
 
                                               user=u'some\u1234'))
56
 
        self.assertEqual('', stdout.getvalue())
57
 
 
58
59
    def test_text_factory_ascii_password(self):
59
60
        ui = tests.TestUIFactory(stdin='secret\n',
60
61
                                 stdout=tests.StringIOWrapper(),
102
103
    def test_progress_construction(self):
103
104
        """TextUIFactory constructs the right progress view.
104
105
        """
105
 
        os.environ['BZR_PROGRESS_BAR'] = 'none'
106
 
        self.assertIsInstance(TextUIFactory()._progress_view,
107
 
            NullProgressView)
108
 
 
109
 
        os.environ['BZR_PROGRESS_BAR'] = 'text'
110
 
        self.assertIsInstance(TextUIFactory()._progress_view,
111
 
            TextProgressView)
112
 
 
113
 
        os.environ['BZR_PROGRESS_BAR'] = 'text'
114
 
        self.assertIsInstance(TextUIFactory()._progress_view,
115
 
            TextProgressView)
116
 
 
117
 
        del os.environ['BZR_PROGRESS_BAR']
118
 
        self.assertIsInstance(TextUIFactory()._progress_view,
119
 
            TextProgressView)
 
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,))
120
152
 
121
153
    def test_progress_note(self):
122
154
        stderr = StringIO()
137
169
            pb.finished()
138
170
 
139
171
    def test_progress_note_clears(self):
140
 
        stderr = StringIO()
141
 
        stdout = StringIO()
142
 
        # The PQM redirects the output to a file, so it
143
 
        # defaults to creating a Dots progress bar. we
144
 
        # need to force it to believe we are a TTY
 
172
        stderr = _TTYStringIO()
 
173
        stdout = _TTYStringIO()
 
174
        # so that we get a TextProgressBar
 
175
        os.environ['TERM'] = 'xterm'
145
176
        ui_factory = TextUIFactory(
146
177
            stdin=StringIO(''),
147
178
            stdout=stdout, stderr=stderr)
 
179
        self.assertIsInstance(ui_factory._progress_view,
 
180
            TextProgressView)
148
181
        pb = ui_factory.nested_progress_bar()
149
182
        try:
150
183
            # Create a progress update that isn't throttled
173
206
        pb2.finished()
174
207
        pb1.finished()
175
208
 
176
 
    def assert_get_bool_acceptance_of_user_input(self, factory):
177
 
        factory.stdin = StringIO("y\n" # True
178
 
                                 "n\n" # False
179
 
                                 "yes with garbage\nY\n" # True
180
 
                                 "not an answer\nno\n" # False
181
 
                                 "I'm sure!\nyes\n" # True
182
 
                                 "NO\n" # False
183
 
                                 "foo\n")
184
 
        factory.stdout = StringIO()
185
 
        factory.stderr = StringIO()
186
 
        # there is no output from the base factory
 
209
    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)
187
220
        self.assertEqual(True, factory.get_boolean(""))
188
221
        self.assertEqual(False, factory.get_boolean(""))
189
222
        self.assertEqual(True, factory.get_boolean(""))
194
227
        # stdin should be empty
195
228
        self.assertEqual('', factory.stdin.readline())
196
229
 
197
 
    def test_silent_ui_getbool(self):
198
 
        factory = _mod_ui.SilentUIFactory()
199
 
        self.assert_get_bool_acceptance_of_user_input(factory)
200
 
 
201
 
    def test_silent_factory_prompts_silently(self):
202
 
        factory = _mod_ui.SilentUIFactory()
203
 
        stdout = StringIO()
204
 
        factory.stdin = StringIO("y\n")
205
 
        self.assertEqual(True,
206
 
                         self.apply_redirected(None, stdout, stdout,
207
 
                                               factory.get_boolean, "foo"))
208
 
        self.assertEqual("", stdout.getvalue())
209
 
        # stdin should be empty
210
 
        self.assertEqual('', factory.stdin.readline())
211
 
 
212
 
    def test_text_ui_getbool(self):
213
 
        factory = TextUIFactory(None, None, None)
214
 
        self.assert_get_bool_acceptance_of_user_input(factory)
215
 
 
216
230
    def test_text_factory_prompt(self):
217
231
        # see <https://launchpad.net/bugs/365891>
218
 
        factory = TextUIFactory(None, StringIO(), StringIO(), StringIO())
 
232
        factory = TextUIFactory(StringIO(), StringIO(), StringIO())
219
233
        factory.prompt('foo %2e')
220
234
        self.assertEqual('', factory.stdout.getvalue())
221
235
        self.assertEqual('foo %2e', factory.stderr.getvalue())
223
237
    def test_text_factory_prompts_and_clears(self):
224
238
        # a get_boolean call should clear the pb before prompting
225
239
        out = _TTYStringIO()
226
 
        factory = TextUIFactory(stdin=StringIO("yada\ny\n"),
227
 
                                stdout=out, stderr=out)
 
240
        os.environ['TERM'] = 'xterm'
 
241
        factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
228
242
        pb = factory.nested_progress_bar()
229
243
        pb.show_bar = False
230
244
        pb.show_spinner = False
254
268
        finally:
255
269
            pb.finished()
256
270
 
257
 
    def test_silent_ui_getusername(self):
258
 
        factory = _mod_ui.SilentUIFactory()
259
 
        factory.stdin = StringIO("someuser\n\n")
260
 
        factory.stdout = StringIO()
261
 
        factory.stderr = StringIO()
262
 
        self.assertEquals(None,
263
 
            factory.get_username(u'Hello\u1234 %(host)s', host=u'some\u1234'))
264
 
        self.assertEquals("", factory.stdout.getvalue())
265
 
        self.assertEquals("", factory.stderr.getvalue())
266
 
        self.assertEquals("someuser\n\n", factory.stdin.getvalue())
267
 
 
268
271
    def test_text_ui_getusername(self):
269
272
        factory = TextUIFactory(None, None, None)
270
273
        factory.stdin = StringIO("someuser\n\n")
298
301
            pb.finished()
299
302
 
300
303
 
301
 
class TestTextProgressView(tests.TestCase):
302
 
    """Tests for text display of progress bars.
303
 
    """
304
 
    # XXX: These might be a bit easier to write if the rendering and
305
 
    # state-maintaining parts of TextProgressView were more separate, and if
306
 
    # the progress task called back directly to its own view not to the ui
307
 
    # factory. -- mbp 20090312
 
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):
 
314
 
 
315
    def test_silent_factory_get_password(self):
 
316
        # A silent factory that can't do user interaction can't get a
 
317
        # password.  Possibly it should raise a more specific error but it
 
318
        # can't succeed.
 
319
        ui = SilentUIFactory()
 
320
        stdout = StringIO()
 
321
        self.assertRaises(
 
322
            NotImplementedError,
 
323
            self.apply_redirected,
 
324
            None, stdout, stdout, ui.get_password)
 
325
        # and it didn't write anything out either
 
326
        self.assertEqual('', stdout.getvalue())
 
327
 
 
328
    def test_silent_ui_getbool(self):
 
329
        factory = SilentUIFactory()
 
330
        stdout = StringIO()
 
331
        self.assertRaises(
 
332
            NotImplementedError,
 
333
            self.apply_redirected,
 
334
            None, stdout, stdout, factory.get_boolean, "foo")
 
335
 
 
336
 
 
337
class CannedInputUIFactoryTests(TestCase):
308
338
    
309
 
    def _make_factory(self):
310
 
        out = StringIO()
311
 
        uif = TextUIFactory(stderr=out)
312
 
        uif._progress_view._width = 80
313
 
        return out, uif
314
 
 
315
 
    def test_render_progress_easy(self):
316
 
        """Just one task and one quarter done"""
317
 
        out, uif = self._make_factory()
318
 
        task = uif.nested_progress_bar()
319
 
        task.update('reticulating splines', 5, 20)
320
 
        self.assertEqual(
321
 
'\r[####/               ] reticulating splines 5/20                               \r'
322
 
            , out.getvalue())
323
 
 
324
 
    def test_render_progress_nested(self):
325
 
        """Tasks proportionally contribute to overall progress"""
326
 
        out, uif = self._make_factory()
327
 
        task = uif.nested_progress_bar()
328
 
        task.update('reticulating splines', 0, 2)
329
 
        task2 = uif.nested_progress_bar()
330
 
        task2.update('stage2', 1, 2)
331
 
        # so we're in the first half of the main task, and half way through
332
 
        # that
333
 
        self.assertEqual(
334
 
r'[####\               ] reticulating splines:stage2 1/2'
335
 
            , uif._progress_view._render_line())
336
 
        # if the nested task is complete, then we're all the way through the
337
 
        # first half of the overall work
338
 
        task2.update('stage2', 2, 2)
339
 
        self.assertEqual(
340
 
r'[#########|          ] reticulating splines:stage2 2/2'
341
 
            , uif._progress_view._render_line())
342
 
 
343
 
    def test_render_progress_sub_nested(self):
344
 
        """Intermediate tasks don't mess up calculation."""
345
 
        out, uif = self._make_factory()
346
 
        task_a = uif.nested_progress_bar()
347
 
        task_a.update('a', 0, 2)
348
 
        task_b = uif.nested_progress_bar()
349
 
        task_b.update('b')
350
 
        task_c = uif.nested_progress_bar()
351
 
        task_c.update('c', 1, 2)
352
 
        # the top-level task is in its first half; the middle one has no
353
 
        # progress indication, just a label; and the bottom one is half done,
354
 
        # so the overall fraction is 1/4
355
 
        self.assertEqual(
356
 
            r'[####|               ] a:b:c 1/2'
357
 
            , uif._progress_view._render_line())
 
339
    def test_canned_input_get_input(self):
 
340
        uif = CannedInputUIFactory([True, 'mbp', 'password'])
 
341
        self.assertEqual(uif.get_boolean('Extra cheese?'), True)
 
342
        self.assertEqual(uif.get_username('Enter your user name'), 'mbp')
 
343
        self.assertEqual(uif.get_password('Password for %(host)s', host='example.com'),
 
344
            'password')
358
345
 
359
346
 
360
347
class TestBoolFromString(tests.TestCase):