~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_ui.py

(gz) Backslash escape selftest output when printing to non-unicode consoles
 (Martin [gz])

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2008, 2009, 2010 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
 
import re
22
21
import time
23
22
 
 
23
from StringIO import StringIO
 
24
 
 
25
from testtools.matchers import *
 
26
 
24
27
from bzrlib import (
 
28
    config,
25
29
    errors,
 
30
    remote,
 
31
    repository,
26
32
    tests,
27
33
    ui as _mod_ui,
28
34
    )
29
35
from bzrlib.symbol_versioning import (
30
36
    deprecated_in,
31
37
    )
32
 
from bzrlib.tests import test_progress
 
38
from bzrlib.tests import (
 
39
    fixtures,
 
40
    test_progress,
 
41
    )
33
42
from bzrlib.ui import text as _mod_ui_text
 
43
from bzrlib.tests.testui import (
 
44
    ProgressRecordingUIFactory,
 
45
    )
 
46
 
 
47
 
 
48
class TestUIConfiguration(tests.TestCaseWithTransport):
 
49
 
 
50
    def test_output_encoding_configuration(self):
 
51
        enc = fixtures.generate_unicode_encodings().next()
 
52
        config.GlobalConfig().set_user_option('output_encoding',
 
53
            enc)
 
54
        ui = tests.TestUIFactory(stdin=None,
 
55
            stdout=tests.StringIOWrapper(),
 
56
            stderr=tests.StringIOWrapper())
 
57
        output = ui.make_output_stream()
 
58
        self.assertEquals(output.encoding, enc)
34
59
 
35
60
 
36
61
class TestTextUIFactory(tests.TestCase):
37
62
 
 
63
    def make_test_ui_factory(self, stdin_contents):
 
64
        ui = tests.TestUIFactory(stdin=stdin_contents,
 
65
                                 stdout=tests.StringIOWrapper(),
 
66
                                 stderr=tests.StringIOWrapper())
 
67
        return ui
 
68
 
 
69
    def test_text_factory_confirm(self):
 
70
        # turns into reading a regular boolean
 
71
        ui = self.make_test_ui_factory('n\n')
 
72
        self.assertEquals(ui.confirm_action('Should %(thing)s pass?',
 
73
            'bzrlib.tests.test_ui.confirmation',
 
74
            {'thing': 'this'},),
 
75
            False)
 
76
 
38
77
    def test_text_factory_ascii_password(self):
39
 
        ui = tests.TestUIFactory(stdin='secret\n',
40
 
                                 stdout=tests.StringIOWrapper(),
41
 
                                 stderr=tests.StringIOWrapper())
 
78
        ui = self.make_test_ui_factory('secret\n')
42
79
        pb = ui.nested_progress_bar()
43
80
        try:
44
81
            self.assertEqual('secret',
59
96
        We can't predict what encoding users will have for stdin, so we force
60
97
        it to utf8 to test that we transport the password correctly.
61
98
        """
62
 
        ui = tests.TestUIFactory(stdin=u'baz\u1234'.encode('utf8'),
63
 
                                 stdout=tests.StringIOWrapper(),
64
 
                                 stderr=tests.StringIOWrapper())
 
99
        ui = self.make_test_ui_factory(u'baz\u1234'.encode('utf8'))
65
100
        ui.stderr.encoding = ui.stdout.encoding = ui.stdin.encoding = 'utf8'
66
101
        pb = ui.nested_progress_bar()
67
102
        try:
79
114
        finally:
80
115
            pb.finished()
81
116
 
82
 
    def test_progress_note(self):
83
 
        stderr = tests.StringIOWrapper()
84
 
        stdout = tests.StringIOWrapper()
85
 
        ui_factory = _mod_ui_text.TextUIFactory(stdin=tests.StringIOWrapper(''),
86
 
                                                stderr=stderr,
87
 
                                                stdout=stdout)
88
 
        pb = ui_factory.nested_progress_bar()
89
 
        try:
90
 
            result = self.applyDeprecated(deprecated_in((2, 1, 0)),
91
 
                pb.note,
92
 
                't')
93
 
            self.assertEqual(None, result)
94
 
            self.assertEqual("t\n", stdout.getvalue())
95
 
            # Since there was no update() call, there should be no clear() call
96
 
            self.failIf(re.search(r'^\r {10,}\r$',
97
 
                                  stderr.getvalue()) is not None,
98
 
                        'We cleared the stderr without anything to put there')
99
 
        finally:
100
 
            pb.finished()
101
 
 
102
 
    def test_progress_note_clears(self):
103
 
        stderr = test_progress._TTYStringIO()
104
 
        stdout = test_progress._TTYStringIO()
105
 
        # so that we get a TextProgressBar
106
 
        os.environ['TERM'] = 'xterm'
107
 
        ui_factory = _mod_ui_text.TextUIFactory(
108
 
            stdin=tests.StringIOWrapper(''),
109
 
            stdout=stdout, stderr=stderr)
110
 
        self.assertIsInstance(ui_factory._progress_view,
111
 
                              _mod_ui_text.TextProgressView)
112
 
        pb = ui_factory.nested_progress_bar()
113
 
        try:
114
 
            # Create a progress update that isn't throttled
115
 
            pb.update('x', 1, 1)
116
 
            result = self.applyDeprecated(deprecated_in((2, 1, 0)),
117
 
                pb.note, 't')
118
 
            self.assertEqual(None, result)
119
 
            self.assertEqual("t\n", stdout.getvalue())
120
 
            # the exact contents will depend on the terminal width and we don't
121
 
            # care about that right now - but you're probably running it on at
122
 
            # least a 10-character wide terminal :)
123
 
            self.assertContainsRe(stderr.getvalue(), r'\r {10,}\r$')
124
 
        finally:
125
 
            pb.finished()
126
 
 
127
 
    def test_progress_nested(self):
128
 
        # test factory based nested and popping.
129
 
        ui = _mod_ui_text.TextUIFactory(None, None, None)
130
 
        pb1 = ui.nested_progress_bar()
131
 
        pb2 = ui.nested_progress_bar()
132
 
        # You do get a warning if the outermost progress bar wasn't finished
133
 
        # first - it's not clear if this is really useful or if it should just
134
 
        # become orphaned -- mbp 20090120
135
 
        warnings, _ = self.callCatchWarnings(pb1.finished)
136
 
        if len(warnings) != 1:
137
 
            self.fail("unexpected warnings: %r" % (warnings,))
138
 
        pb2.finished()
139
 
        pb1.finished()
140
 
 
141
117
    def test_text_ui_get_boolean(self):
142
118
        stdin = tests.StringIOWrapper("y\n" # True
143
119
                                      "n\n" # False
186
162
        factory = _mod_ui_text.TextUIFactory(
187
163
            stdin=tests.StringIOWrapper("yada\ny\n"),
188
164
            stdout=out, stderr=out)
 
165
        factory._avail_width = lambda: 79
189
166
        pb = factory.nested_progress_bar()
190
167
        pb.show_bar = False
191
168
        pb.show_spinner = False
197
174
                                               factory.get_boolean,
198
175
                                               "what do you want"))
199
176
        output = out.getvalue()
200
 
        self.assertContainsRe(factory.stdout.getvalue(),
201
 
            "foo *\r\r  *\r*")
202
 
        self.assertContainsRe(factory.stdout.getvalue(),
 
177
        self.assertContainsRe(output,
 
178
            "| foo *\r\r  *\r*")
 
179
        self.assertContainsRe(output,
203
180
            r"what do you want\? \[y/n\]: what do you want\? \[y/n\]: ")
204
181
        # stdin should have been totally consumed
205
182
        self.assertEqual('', factory.stdin.readline())
259
236
        self.assertIsInstance(ui_factory._progress_view,
260
237
            _mod_ui_text.NullProgressView)
261
238
 
 
239
    def test_text_ui_show_user_warning(self):
 
240
        from bzrlib.repofmt.groupcompress_repo import RepositoryFormat2a
 
241
        from bzrlib.repofmt.pack_repo import RepositoryFormatKnitPack5
 
242
        err = StringIO()
 
243
        out = StringIO()
 
244
        ui = tests.TextUIFactory(stdin=None, stdout=out, stderr=err)
 
245
        remote_fmt = remote.RemoteRepositoryFormat()
 
246
        remote_fmt._network_name = RepositoryFormatKnitPack5().network_name()
 
247
        ui.show_user_warning('cross_format_fetch', from_format=RepositoryFormat2a(),
 
248
            to_format=remote_fmt)
 
249
        self.assertEquals('', out.getvalue())
 
250
        self.assertEquals("Doing on-the-fly conversion from RepositoryFormat2a() to "
 
251
            "RemoteRepositoryFormat(_network_name='Bazaar RepositoryFormatKnitPack5 "
 
252
            "(bzr 1.6)\\n').\nThis may take some time. Upgrade the repositories to "
 
253
            "the same format for better performance.\n",
 
254
            err.getvalue())
 
255
        # and now with it suppressed please
 
256
        err = StringIO()
 
257
        out = StringIO()
 
258
        ui = tests.TextUIFactory(stdin=None, stdout=out, stderr=err)
 
259
        ui.suppressed_warnings.add('cross_format_fetch')
 
260
        ui.show_user_warning('cross_format_fetch', from_format=RepositoryFormat2a(),
 
261
            to_format=remote_fmt)
 
262
        self.assertEquals('', out.getvalue())
 
263
        self.assertEquals('', err.getvalue())
 
264
 
262
265
 
263
266
class TestTextUIOutputStream(tests.TestCase):
264
267
    """Tests for output stream that synchronizes with progress bar."""
369
372
 
370
373
    def test_test_ui_factory_progress(self):
371
374
        # there's no output; we just want to make sure this doesn't crash -
372
 
        # see https://bugs.edge.launchpad.net/bzr/+bug/408201
 
375
        # see https://bugs.launchpad.net/bzr/+bug/408201
373
376
        ui = tests.TestUIFactory()
374
377
        pb = ui.nested_progress_bar()
375
378
        pb.update('hello')
443
446
        self.assertIsNone('0', av)
444
447
        self.assertIsNone('on', av)
445
448
        self.assertIsNone('off', av)
 
449
 
 
450
 
 
451
class TestConfirmationUserInterfacePolicy(tests.TestCase):
 
452
 
 
453
    def test_confirm_action_default(self):
 
454
        base_ui = _mod_ui.NoninteractiveUIFactory()
 
455
        for answer in [True, False]:
 
456
            self.assertEquals(
 
457
                _mod_ui.ConfirmationUserInterfacePolicy(base_ui, answer, {})
 
458
                .confirm_action("Do something?",
 
459
                    "bzrlib.tests.do_something", {}),
 
460
                answer)
 
461
 
 
462
    def test_confirm_action_specific(self):
 
463
        base_ui = _mod_ui.NoninteractiveUIFactory()
 
464
        for default_answer in [True, False]:
 
465
            for specific_answer in [True, False]:
 
466
                for conf_id in ['given_id', 'other_id']:
 
467
                    wrapper = _mod_ui.ConfirmationUserInterfacePolicy(
 
468
                        base_ui, default_answer, dict(given_id=specific_answer))
 
469
                    result = wrapper.confirm_action("Do something?", conf_id, {})
 
470
                    if conf_id == 'given_id':
 
471
                        self.assertEquals(result, specific_answer)
 
472
                    else:
 
473
                        self.assertEquals(result, default_answer)
 
474
 
 
475
    def test_repr(self):
 
476
        base_ui = _mod_ui.NoninteractiveUIFactory()
 
477
        wrapper = _mod_ui.ConfirmationUserInterfacePolicy(
 
478
            base_ui, True, dict(a=2))
 
479
        self.assertThat(repr(wrapper),
 
480
            Equals("ConfirmationUserInterfacePolicy("
 
481
                "NoninteractiveUIFactory(), True, {'a': 2})"))
 
482
 
 
483
 
 
484
class TestProgressRecordingUI(tests.TestCase):
 
485
    """Test test-oriented UIFactory that records progress updates"""
 
486
 
 
487
    def test_nested_ignore_depth_beyond_one(self):
 
488
        # we only want to capture the first level out progress, not
 
489
        # want sub-components might do. So we have nested bars ignored.
 
490
        factory = ProgressRecordingUIFactory()
 
491
        pb1 = factory.nested_progress_bar()
 
492
        pb1.update('foo', 0, 1)
 
493
        pb2 = factory.nested_progress_bar()
 
494
        pb2.update('foo', 0, 1)
 
495
        pb2.finished()
 
496
        pb1.finished()
 
497
        self.assertEqual([("update", 0, 1, 'foo')], factory._calls)