~bzr-pqm/bzr/bzr.dev

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# Copyright (C) 2009, 2010, 2011, 2016 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

"""Tests run per UIFactory."""

# Testing UIFactories is a bit interesting because we require they all support a
# common interface, but the way they implement it can vary very widely.  Between
# text, batch-mode, graphical and other potential UIFactories, the requirements
# to set up a factory, to make it respond to requests, and to simulate user
# input can vary a lot.
#
# We want tests that therefore allow for the evaluation of the result to vary
# per implementation, but we want to check that the supported facilities are
# the same across all UIFactorys, unless they're specifically skipped.
#
# Our normal approach is to use test scenarios but that seems to just end up
# creating test-like objects inside the scenario.  Therefore we fall back to
# the older method of putting the common tests in a mixin.
#
# Plugins that add new UIFactorys can create their own subclasses.


from cStringIO import StringIO
import unittest


from bzrlib import (
    tests,
    transport,
    ui,
    )


class UIFactoryTestMixin(object):
    """Common tests for UIFactories.

    These are supposed to be expressed with no assumptions about how the
    UIFactory implements the method, only that it does implement them (or
    fails cleanly), and that the concrete subclass will make arrangements to
    build a factory and to examine its behaviour.

    Note that this is *not* a TestCase, because it can't be directly run, but
    the concrete subclasses should be.
    """

    def test_be_quiet(self):
        self.factory.be_quiet(True)
        self.assertEqual(True, self.factory.is_quiet())
        self.factory.be_quiet(False)
        self.assertEqual(False, self.factory.is_quiet())

    def test_confirm_action(self):
        # confirm_action should be answered by every ui factory; even
        # noninteractive ones should have a reasonable default
        self._load_responses([True])
        result = self.factory.confirm_action(u'Break a lock?',
             'bzr.lock.break.confirm',
            {})
        # will be true either because we read it from the input or because
        # that's the default
        self.assertEqual(result, True)

    def test_note(self):
        self.factory.note("a note to the user")
        self._check_note("a note to the user")

    def test_show_error(self):
        msg = 'an error occurred'
        self.factory.show_error(msg)
        self._check_show_error(msg)

    def test_show_message(self):
        msg = 'a message'
        self.factory.show_message(msg)
        self._check_show_message(msg)

    def test_show_warning(self):
        msg = 'a warning'
        self.factory.show_warning(msg)
        self._check_show_warning(msg)

    def test_make_output_stream(self):
        # All UIs must now be able to at least accept output, even if they
        # just discard it.
        output_stream = self.factory.make_output_stream()
        output_stream.write('hello!')

    def test_transport_activity(self):
        # It doesn't matter what the implementation does, we just want to make
        # sure the interface is there
        t = transport.get_transport_from_url('memory:///')
        self.factory.report_transport_activity(t, 1000, 'write')
        self.factory.report_transport_activity(t, 2000, 'read')
        self.factory.report_transport_activity(t, 4000, None)
        self.factory.log_transport_activity()
        self._check_log_transport_activity_noarg()
        self.factory.log_transport_activity(display=True)
        self._check_log_transport_activity_display()

    def test_no_transport_activity(self):
        # No activity to report
        t = transport.get_transport_from_url('memory:///')
        self.factory.log_transport_activity(display=True)
        self._check_log_transport_activity_display_no_bytes()


class TestTextUIFactory(tests.TestCase, UIFactoryTestMixin):

    def setUp(self):
        super(TestTextUIFactory, self).setUp()
        self.stdin = StringIO()
        self.stdout = StringIO()
        self.stderr = StringIO()
        self.factory = ui.text.TextUIFactory(self.stdin, self.stdout,
            self.stderr)

    def _check_note(self, note_text):
        self.assertEqual("%s\n" % note_text,
            self.stdout.getvalue())

    def _check_show_error(self, msg):
        self.assertEqual("bzr: error: %s\n" % msg,
            self.stderr.getvalue())
        self.assertEqual("", self.stdout.getvalue())

    def _check_show_message(self, msg):
        self.assertEqual("%s\n" % msg,
            self.stdout.getvalue())
        self.assertEqual("", self.stderr.getvalue())

    def _check_show_warning(self, msg):
        self.assertEqual("bzr: warning: %s\n" % msg,
            self.stderr.getvalue())
        self.assertEqual("", self.stdout.getvalue())

    def _check_log_transport_activity_noarg(self):
        self.assertEqual('', self.stdout.getvalue())
        self.assertContainsRe(self.stderr.getvalue(), r'\d+kB\s+\dkB/s |')
        self.assertNotContainsRe(self.stderr.getvalue(), r'Transferred:')

    def _check_log_transport_activity_display(self):
        self.assertEqual('', self.stdout.getvalue())
        # Without a TTY, we shouldn't display anything
        self.assertEqual('', self.stderr.getvalue())

    def _check_log_transport_activity_display_no_bytes(self):
        self.assertEqual('', self.stdout.getvalue())
        # Without a TTY, we shouldn't display anything
        self.assertEqual('', self.stderr.getvalue())

    def _load_responses(self, responses):
        self.factory.stdin.seek(0)
        self.factory.stdin.writelines([(r and "y\n" or "n\n") for r in responses])
        self.factory.stdin.seek(0)


class TestTTYTextUIFactory(TestTextUIFactory):

    def setUp(self):
        super(TestTTYTextUIFactory, self).setUp()

        class TTYStringIO(object):
            """Thunk over to StringIO() for everything but 'isatty'"""

            def __init__(self):
                self.__dict__['_sio'] = StringIO()

            def isatty(self):
                return True

            def __getattr__(self, name):
                return getattr(self._sio, name)

            def __setattr__(self, name, value):
                return setattr(self._sio, name, value)

        # Remove 'TERM' == 'dumb' which causes us to *not* treat output as a
        # real terminal, even though isatty returns True
        self.overrideEnv('TERM', None)
        self.stderr = TTYStringIO()
        self.stdout = TTYStringIO()
        self.factory = ui.text.TextUIFactory(self.stdin, self.stdout,
            self.stderr)

    def _check_log_transport_activity_display(self):
        self.assertEqual('', self.stdout.getvalue())
        # Displaying the result should write to the progress stream using
        # base-10 units (see HACKING.txt).
        self.assertContainsRe(self.stderr.getvalue(),
            r'Transferred: 7kB'
            r' \(\d+\.\dkB/s r:2kB w:1kB u:4kB\)')

    def _check_log_transport_activity_display_no_bytes(self):
        self.assertEqual('', self.stdout.getvalue())
        # Without actual bytes transferred, we should report nothing
        self.assertEqual('', self.stderr.getvalue())


class TestSilentUIFactory(tests.TestCase, UIFactoryTestMixin):
    # discards output, therefore tests for output expect nothing

    def setUp(self):
        super(TestSilentUIFactory, self).setUp()
        self.factory = ui.SilentUIFactory()

    def _check_note(self, note_text):
        # it's just discarded
        pass

    def _check_show_error(self, msg):
        pass

    def _check_show_message(self, msg):
        pass

    def _check_show_warning(self, msg):
        pass

    def _check_log_transport_activity_noarg(self):
        pass

    def _check_log_transport_activity_display(self):
        pass

    def _check_log_transport_activity_display_no_bytes(self):
        pass

    def _load_responses(self, responses):
        pass


class TestCannedInputUIFactory(tests.TestCase, UIFactoryTestMixin):
    # discards output, reads input from variables

    def setUp(self):
        super(TestCannedInputUIFactory, self).setUp()
        self.factory = ui.CannedInputUIFactory([])

    def _check_note(self, note_text):
        pass

    def _check_show_error(self, msg):
        pass

    def _check_show_message(self, msg):
        pass

    def _check_show_warning(self, msg):
        pass

    def _check_log_transport_activity_noarg(self):
        pass

    def _check_log_transport_activity_display(self):
        pass

    def _check_log_transport_activity_display_no_bytes(self):
        pass

    def _load_responses(self, responses):
        self.factory.responses.extend(responses)