/brz/remove-bazaar

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