/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3948.2.6 by Martin Pool
ProgressBarStack is deprecated
1
# Copyright (C) 2006, 2007, 2009 Canonical Ltd
1551.2.27 by Aaron Bentley
Got propogation under test
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
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
17
import os
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
18
from StringIO import StringIO
19
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
20
from bzrlib import errors
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
21
from bzrlib.progress import (
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
22
        DummyProgress,
23
        ChildProgress,
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
24
        TTYProgressBar,
25
        DotsProgressBar,
26
        ProgressBarStack,
3146.6.1 by Aaron Bentley
InterDifferingSerializer shows a progress bar
27
        InstrumentedProgress,
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
28
        )
1551.2.27 by Aaron Bentley
Got propogation under test
29
from bzrlib.tests import TestCase
3948.2.6 by Martin Pool
ProgressBarStack is deprecated
30
from bzrlib.symbol_versioning import (
31
    deprecated_in,
32
    )
1551.2.27 by Aaron Bentley
Got propogation under test
33
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
34
1551.2.29 by Aaron Bentley
Got stack handling under test
35
class FakeStack:
3006.3.1 by Robert Collins
Minor PEP8 changes.
36
1551.2.29 by Aaron Bentley
Got stack handling under test
37
    def __init__(self, top):
38
        self.__top = top
39
40
    def top(self):
41
        return self.__top
42
3006.3.1 by Robert Collins
Minor PEP8 changes.
43
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
44
class _TTYStringIO(StringIO):
45
    """A helper class which makes a StringIO look like a terminal"""
46
47
    def isatty(self):
48
        return True
49
50
51
class _NonTTYStringIO(StringIO):
52
    """Helper that implements isatty() but returns False"""
53
54
    def isatty(self):
55
        return False
56
57
1551.2.27 by Aaron Bentley
Got propogation under test
58
class TestProgress(TestCase):
3006.3.1 by Robert Collins
Minor PEP8 changes.
59
1551.2.27 by Aaron Bentley
Got propogation under test
60
    def setUp(self):
1551.2.29 by Aaron Bentley
Got stack handling under test
61
        q = DummyProgress()
62
        self.top = ChildProgress(_stack=FakeStack(q))
1551.2.27 by Aaron Bentley
Got propogation under test
63
64
    def test_propogation(self):
65
        self.top.update('foobles', 1, 2)
66
        self.assertEqual(self.top.message, 'foobles')
67
        self.assertEqual(self.top.current, 1)
68
        self.assertEqual(self.top.total, 2)
69
        self.assertEqual(self.top.child_fraction, 0)
1551.2.29 by Aaron Bentley
Got stack handling under test
70
        child = ChildProgress(_stack=FakeStack(self.top))
1551.2.27 by Aaron Bentley
Got propogation under test
71
        child.update('baubles', 2, 4)
72
        self.assertEqual(self.top.message, 'foobles')
73
        self.assertEqual(self.top.current, 1)
74
        self.assertEqual(self.top.total, 2)
75
        self.assertEqual(self.top.child_fraction, 0.5)
1551.2.29 by Aaron Bentley
Got stack handling under test
76
        grandchild = ChildProgress(_stack=FakeStack(child))
1551.2.27 by Aaron Bentley
Got propogation under test
77
        grandchild.update('barbells', 1, 2)
78
        self.assertEqual(self.top.child_fraction, 0.625)
79
        self.assertEqual(child.child_fraction, 0.5)
80
        child.update('baubles', 3, 4)
81
        self.assertEqual(child.child_fraction, 0)
82
        self.assertEqual(self.top.child_fraction, 0.75)
83
        grandchild.update('barbells', 1, 2)
84
        self.assertEqual(self.top.child_fraction, 0.875)
85
        grandchild.update('barbells', 2, 2)
86
        self.assertEqual(self.top.child_fraction, 1)
87
        child.update('baubles', 4, 4)
88
        self.assertEqual(self.top.child_fraction, 1)
89
        #test clamping
90
        grandchild.update('barbells', 2, 2)
91
        self.assertEqual(self.top.child_fraction, 1)
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
92
93
    def test_implementations(self):
94
        for implementation in (TTYProgressBar, DotsProgressBar, 
95
                               DummyProgress):
96
            self.check_parent_handling(implementation)
97
98
    def check_parent_handling(self, parentclass):
99
        top = parentclass(to_file=StringIO())
100
        top.update('foobles', 1, 2)
1551.2.29 by Aaron Bentley
Got stack handling under test
101
        child = ChildProgress(_stack=FakeStack(top))
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
102
        child.update('baubles', 4, 4)
103
        top.update('lala', 2, 2)
104
        child.update('baubles', 4, 4)
1551.2.29 by Aaron Bentley
Got stack handling under test
105
106
    def test_stacking(self):
107
        self.check_stack(TTYProgressBar, ChildProgress)
108
        self.check_stack(DotsProgressBar, ChildProgress)
109
        self.check_stack(DummyProgress, DummyProgress)
110
111
    def check_stack(self, parent_class, child_class):
3948.2.6 by Martin Pool
ProgressBarStack is deprecated
112
        stack = self.applyDeprecated(
113
            deprecated_in((1, 12, 0)),
114
            ProgressBarStack,
115
            klass=parent_class, to_file=StringIO())
1551.2.29 by Aaron Bentley
Got stack handling under test
116
        parent = stack.get_nested()
117
        try:
118
            self.assertIs(parent.__class__, parent_class)
119
            child = stack.get_nested()
120
            try:
121
                self.assertIs(child.__class__, child_class)
122
            finally:
123
                child.finished()
124
        finally:
125
            parent.finished()
1793.1.1 by Aaron Bentley
Hide TTYProgressBars unless they last more than 1 second
126
127
    def test_throttling(self):
128
        pb = InstrumentedProgress(to_file=StringIO())
129
        # instantaneous updates should be squelched
130
        pb.update('me', 1, 1)
131
        self.assertTrue(pb.always_throttled)
132
        pb = InstrumentedProgress(to_file=StringIO())
133
        # It's like an instant sleep(1)!
134
        pb.start_time -= 1
135
        # Updates after a second should not be squelched
136
        pb.update('me', 1, 1)
137
        self.assertFalse(pb.always_throttled)
1843.3.1 by John Arbash Meinel
Don't clear anything if nothing has been written.
138
139
    def test_clear(self):
140
        sio = StringIO()
141
        pb = TTYProgressBar(to_file=sio, show_eta=False)
142
        pb.width = 20 # Just make it easier to test
143
        # This should not output anything
144
        pb.clear()
145
        # These two should not be displayed because
146
        # of throttling
147
        pb.update('foo', 1, 3)
148
        pb.update('bar', 2, 3)
149
        # So pb.clear() has nothing to do
150
        pb.clear()
151
152
        # Make sure the next update isn't throttled
153
        pb.start_time -= 1
154
        pb.update('baz', 3, 3)
155
        pb.clear()
156
157
        self.assertEqual('\r[=========] baz 3/3'
158
                         '\r                   \r',
159
                         sio.getvalue())
1843.3.3 by John Arbash Meinel
Don't let the last_updates list grow without bound.
160
161
    def test_no_eta(self):
162
        # An old version of the progress bar would
163
        # store every update if show_eta was false
164
        # because the eta routine was where it was
165
        # cleaned out
166
        pb = InstrumentedProgress(to_file=StringIO(), show_eta=False)
167
        # Just make sure this first few are throttled
168
        pb.start_time += 5
169
170
        # These messages are throttled, and don't contribute
171
        for count in xrange(100):
172
            pb.update('x', count, 300)
173
        self.assertEqual(0, len(pb.last_updates))
174
175
        # Unthrottle by time
176
        pb.start_time -= 10
177
178
        # These happen too fast, so only one gets through
179
        for count in xrange(100):
180
            pb.update('x', count+100, 200)
181
        self.assertEqual(1, len(pb.last_updates))
182
183
        pb.MIN_PAUSE = 0.0
184
185
        # But all of these go through, don't let the
186
        # last_update list grow without bound
187
        for count in xrange(100):
188
            pb.update('x', count+100, 200)
189
190
        self.assertEqual(pb._max_last_updates, len(pb.last_updates))
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
191
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
192
193
class TestProgressTypes(TestCase):
194
    """Test that the right ProgressBar gets instantiated at the right time."""
195
196
    def get_nested(self, outf, term, env_progress=None):
197
        """Setup so that ProgressBar thinks we are in the supplied terminal."""
198
        orig_term = os.environ.get('TERM')
199
        orig_progress = os.environ.get('BZR_PROGRESS_BAR')
200
        os.environ['TERM'] = term
201
        if env_progress is not None:
202
            os.environ['BZR_PROGRESS_BAR'] = env_progress
203
        elif orig_progress is not None:
204
            del os.environ['BZR_PROGRESS_BAR']
205
206
        def reset():
207
            if orig_term is None:
208
                del os.environ['TERM']
209
            else:
210
                os.environ['TERM'] = orig_term
211
            # We may have never created BZR_PROGRESS_BAR
212
            # So we can't just delete like we can 'TERM' (which is always set)
213
            if orig_progress is None:
214
                if 'BZR_PROGRESS_BAR' in os.environ:
215
                    del os.environ['BZR_PROGRESS_BAR']
216
            else:
217
                os.environ['BZR_PROGRESS_BAR'] = orig_progress
218
219
        self.addCleanup(reset)
220
3948.2.6 by Martin Pool
ProgressBarStack is deprecated
221
        stack = self.applyDeprecated(
222
            deprecated_in((1, 12, 0)),
223
            ProgressBarStack,
224
            to_file=outf)
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
225
        pb = stack.get_nested()
226
        pb.start_time -= 1 # Make sure it is ready to write
227
        pb.width = 20 # And it is of reasonable size
228
        return pb
229
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
230
    def test_tty_progress(self):
231
        # Make sure the ProgressBarStack thinks it is
232
        # writing out to a terminal, and thus uses a TTYProgressBar
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
233
        out = _TTYStringIO()
234
        pb = self.get_nested(out, 'xterm')
235
        self.assertIsInstance(pb, TTYProgressBar)
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
236
        try:
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
237
            pb.update('foo', 1, 2)
238
            pb.update('bar', 2, 2)
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
239
        finally:
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
240
            pb.finished()
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
241
242
        self.assertEqual('\r/ [====   ] foo 1/2'
243
                         '\r- [=======] bar 2/2'
244
                         '\r                   \r',
245
                         out.getvalue())
246
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
247
    def test_noninteractive_progress(self):
248
        out = _NonTTYStringIO()
249
        pb = self.get_nested(out, 'xterm')
250
        self.assertIsInstance(pb, DummyProgress)
251
        try:
252
            pb.update('foo', 1, 2)
253
            pb.update('bar', 2, 2)
254
        finally:
255
            pb.finished()
256
        self.assertEqual('', out.getvalue())
257
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
258
    def test_dots_progress(self):
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
259
        # make sure we get the right progress bar when not on a terminal
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
260
        out = _NonTTYStringIO()
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
261
        pb = self.get_nested(out, 'xterm', 'dots')
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
262
        self.assertIsInstance(pb, DotsProgressBar)
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
263
        try:
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
264
            pb.update('foo', 1, 2)
265
            pb.update('bar', 2, 2)
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
266
        finally:
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
267
            pb.finished()
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
268
        self.assertEqual('foo: .'
269
                         '\nbar: .'
270
                         '\n',
271
                         out.getvalue())
272
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
273
    def test_no_isatty_progress(self):
274
        # Make sure ProgressBarStack handles a plain StringIO()
275
        import cStringIO
276
        out = cStringIO.StringIO()
277
        pb = self.get_nested(out, 'xterm')
278
        pb.finished()
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
279
        self.assertIsInstance(pb, DummyProgress)
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
280
1843.3.5 by John Arbash Meinel
Add tests to assert we fall back to DotsProgressBar when appropriate.
281
    def test_dumb_progress(self):
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
282
        # using a terminal that can't do cursor movement
1843.3.6 by John Arbash Meinel
Cleanup tests by using a helper
283
        out = _TTYStringIO()
284
        pb = self.get_nested(out, 'dumb')
285
        pb.finished()
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
286
        self.assertIsInstance(pb, DummyProgress)
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
287
288
    def test_progress_env_tty(self):
289
        # The environ variable BZR_PROGRESS_BAR controls what type of
290
        # progress bar we will get, even if it wouldn't usually be that type
291
        import cStringIO
292
293
        # Usually, this would be a DotsProgressBar
294
        out = cStringIO.StringIO()
295
        pb = self.get_nested(out, 'dumb', 'tty')
296
        pb.finished()
297
        # Even though we are not a tty, the env_var will override
298
        self.assertIsInstance(pb, TTYProgressBar)
299
300
    def test_progress_env_none(self):
301
        # Even though we are in a valid tty, no progress
302
        out = _TTYStringIO()
303
        pb = self.get_nested(out, 'xterm', 'none')
304
        pb.finished()
305
        self.assertIsInstance(pb, DummyProgress)
306
307
    def test_progress_env_invalid(self):
308
        out = _TTYStringIO()
309
        self.assertRaises(errors.InvalidProgressBarType, self.get_nested,
310
            out, 'xterm', 'nonexistant')