/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_ui.py

  • Committer: Jelmer Vernooij
  • Date: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005-2012, 2016 Canonical Ltd
 
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for the breezy ui."""
 
18
 
 
19
import time
 
20
 
 
21
from testtools.matchers import *
 
22
 
 
23
from .. import (
 
24
    config,
 
25
    remote,
 
26
    tests,
 
27
    ui as _mod_ui,
 
28
    )
 
29
from . import (
 
30
    fixtures,
 
31
    ui_testing,
 
32
    )
 
33
from ..ui import text as _mod_ui_text
 
34
from .testui import (
 
35
    ProgressRecordingUIFactory,
 
36
    )
 
37
 
 
38
 
 
39
class TestUIConfiguration(tests.TestCaseInTempDir):
 
40
 
 
41
    def test_output_encoding_configuration(self):
 
42
        enc = next(fixtures.generate_unicode_encodings())
 
43
        config.GlobalStack().set('output_encoding', enc)
 
44
        IO = ui_testing.BytesIOWithEncoding
 
45
        ui = _mod_ui.make_ui_for_terminal(IO(), IO(), IO())
 
46
        output = ui.make_output_stream()
 
47
        self.assertEqual(output.encoding, enc)
 
48
 
 
49
 
 
50
class TestTextUIFactory(tests.TestCase):
 
51
 
 
52
    def test_text_factory_confirm(self):
 
53
        # turns into reading a regular boolean
 
54
        ui = ui_testing.TestUIFactory('n\n')
 
55
        self.assertEqual(ui.confirm_action(u'Should %(thing)s pass?',
 
56
            'breezy.tests.test_ui.confirmation',
 
57
            {'thing': 'this'},),
 
58
            False)
 
59
 
 
60
    def test_text_factory_ascii_password(self):
 
61
        ui = ui_testing.TestUIFactory('secret\n')
 
62
        pb = ui.nested_progress_bar()
 
63
        try:
 
64
            self.assertEqual('secret',
 
65
                             self.apply_redirected(ui.stdin, ui.stdout,
 
66
                                                   ui.stderr,
 
67
                                                   ui.get_password))
 
68
            # ': ' is appended to prompt
 
69
            self.assertEqual(': ', ui.stderr.getvalue())
 
70
            self.assertEqual('', ui.stdout.readline())
 
71
            # stdin should be empty
 
72
            self.assertEqual('', ui.stdin.readline())
 
73
        finally:
 
74
            pb.finished()
 
75
 
 
76
    def test_text_factory_unicode_password(self):
 
77
        """Test a unicode password."""
 
78
        ui = ui_testing.TextUIFactory(u'baz\u1234')
 
79
        password = ui.get_password(u'Hello \u1234 %(user)s', user=u'some\u1234')
 
80
        self.assertEqual(u'baz\u1234', password)
 
81
        self.assertEqual(u'Hello \u1234 some\u1234: ', ui.stderr.getvalue())
 
82
        # stdin and stdout should be empty
 
83
        self.assertEqual('', ui.stdin.readline())
 
84
        self.assertEqual('', ui.stdout.getvalue())
 
85
 
 
86
    def test_text_ui_get_boolean(self):
 
87
        stdin_text = (
 
88
            "y\n" # True
 
89
            "n\n" # False
 
90
            " \n y \n" # True
 
91
            " no \n" # False
 
92
            "yes with garbage\nY\n" # True
 
93
            "not an answer\nno\n" # False
 
94
            "I'm sure!\nyes\n" # True
 
95
            "NO\n" # False
 
96
            "foo\n")
 
97
        factory = ui_testing.TextUIFactory(stdin_text)
 
98
        self.assertEqual(True, factory.get_boolean(u""))
 
99
        self.assertEqual(False, factory.get_boolean(u""))
 
100
        self.assertEqual(True, factory.get_boolean(u""))
 
101
        self.assertEqual(False, factory.get_boolean(u""))
 
102
        self.assertEqual(True, factory.get_boolean(u""))
 
103
        self.assertEqual(False, factory.get_boolean(u""))
 
104
        self.assertEqual(True, factory.get_boolean(u""))
 
105
        self.assertEqual(False, factory.get_boolean(u""))
 
106
        self.assertEqual("foo\n", factory.stdin.read())
 
107
        # stdin should be empty
 
108
        self.assertEqual('', factory.stdin.readline())
 
109
        # return false on EOF
 
110
        self.assertEqual(False, factory.get_boolean(u""))
 
111
 
 
112
    def test_text_ui_choose_bad_parameters(self):
 
113
        factory = ui_testing.TextUIFactory(u"")
 
114
        # invalid default index
 
115
        self.assertRaises(ValueError, factory.choose, u"", u"&Yes\n&No", 3)
 
116
        # duplicated choice
 
117
        self.assertRaises(ValueError, factory.choose, u"", u"&choice\n&ChOiCe")
 
118
        # duplicated shortcut
 
119
        self.assertRaises(ValueError, factory.choose, u"", u"&choice1\nchoi&ce2")
 
120
 
 
121
    def test_text_ui_choose_prompt_explicit(self):
 
122
        # choices with explicit shortcuts
 
123
        factory = ui_testing.TextUIFactory(u"")
 
124
        factory.choose(u"prompt", u"&yes\n&No\nmore &info")
 
125
        self.assertEqual("prompt ([y]es, [N]o, more [i]nfo): \n", factory.stderr.getvalue())
 
126
 
 
127
    def test_text_ui_choose_prompt_automatic(self):
 
128
        # automatic shortcuts
 
129
        factory = ui_testing.TextUIFactory(u"")
 
130
        factory.choose(u"prompt", u"yes\nNo\nmore info")
 
131
        self.assertEqual("prompt ([y]es, [N]o, [m]ore info): \n", factory.stderr.getvalue())
 
132
 
 
133
    def test_text_ui_choose_return_values(self):
 
134
        choose = lambda: factory.choose(u"", u"&Yes\n&No\nMaybe\nmore &info", 3)
 
135
        stdin_text = (
 
136
            "y\n" # 0
 
137
            "n\n" # 1
 
138
            " \n" # default: 3
 
139
            " no \n" # 1
 
140
            "b\na\nd \n" # bad shortcuts, all ignored
 
141
            "yes with garbage\nY\n" # 0
 
142
            "not an answer\nno\n" # 1
 
143
            "info\nmore info\n" # 3
 
144
            "Maybe\n" # 2
 
145
            "foo\n")
 
146
        factory = ui_testing.TextUIFactory(stdin_text)
 
147
        self.assertEqual(0, choose())
 
148
        self.assertEqual(1, choose())
 
149
        self.assertEqual(3, choose())
 
150
        self.assertEqual(1, choose())
 
151
        self.assertEqual(0, choose())
 
152
        self.assertEqual(1, choose())
 
153
        self.assertEqual(3, choose())
 
154
        self.assertEqual(2, choose())
 
155
        self.assertEqual("foo\n", factory.stdin.read())
 
156
        # stdin should be empty
 
157
        self.assertEqual('', factory.stdin.readline())
 
158
        # return None on EOF
 
159
        self.assertEqual(None, choose())
 
160
 
 
161
    def test_text_ui_choose_no_default(self):
 
162
        stdin_text = (
 
163
            " \n" # no default, invalid!
 
164
            " yes \n" # 0
 
165
            "foo\n")
 
166
        factory = ui_testing.TextUIFactory(stdin_text)
 
167
        self.assertEqual(0, factory.choose(u"", u"&Yes\n&No"))
 
168
        self.assertEqual("foo\n", factory.stdin.read())
 
169
 
 
170
    def test_text_ui_get_integer(self):
 
171
        stdin_text = (
 
172
            "1\n"
 
173
            "  -2  \n"
 
174
            "hmmm\nwhat else ?\nCome on\nok 42\n4.24\n42\n")
 
175
        factory = ui_testing.TextUIFactory(stdin_text)
 
176
        self.assertEqual(1, factory.get_integer(u""))
 
177
        self.assertEqual(-2, factory.get_integer(u""))
 
178
        self.assertEqual(42, factory.get_integer(u""))
 
179
 
 
180
    def test_text_factory_prompt(self):
 
181
        # see <https://launchpad.net/bugs/365891>
 
182
        factory = ui_testing.TextUIFactory()
 
183
        factory.prompt(u'foo %2e')
 
184
        self.assertEqual('', factory.stdout.getvalue())
 
185
        self.assertEqual('foo %2e', factory.stderr.getvalue())
 
186
 
 
187
    def test_text_factory_prompts_and_clears(self):
 
188
        # a get_boolean call should clear the pb before prompting
 
189
        out = ui_testing.StringIOAsTTY()
 
190
        self.overrideEnv('TERM', 'xterm')
 
191
        factory = ui_testing.TextUIFactory("yada\ny\n", stdout=out, stderr=out)
 
192
        pb = factory.nested_progress_bar()
 
193
        pb._avail_width = lambda: 79
 
194
        pb.show_bar = False
 
195
        pb.show_spinner = False
 
196
        pb.show_count = False
 
197
        pb.update("foo", 0, 1)
 
198
        self.assertEqual(True,
 
199
                         self.apply_redirected(None, factory.stdout,
 
200
                                               factory.stdout,
 
201
                                               factory.get_boolean,
 
202
                                               u"what do you want"))
 
203
        output = out.getvalue()
 
204
        self.assertContainsRe(output,
 
205
            "| foo *\r\r  *\r*")
 
206
        self.assertContainsString(output,
 
207
            r"what do you want? ([y]es, [n]o): what do you want? ([y]es, [n]o): ")
 
208
        # stdin should have been totally consumed
 
209
        self.assertEqual('', factory.stdin.readline())
 
210
 
 
211
    def test_text_tick_after_update(self):
 
212
        ui_factory = ui_testing.TextUIFactory()
 
213
        pb = ui_factory.nested_progress_bar()
 
214
        try:
 
215
            pb.update('task', 0, 3)
 
216
            # Reset the clock, so that it actually tries to repaint itself
 
217
            ui_factory._progress_view._last_repaint = time.time() - 1.0
 
218
            pb.tick()
 
219
        finally:
 
220
            pb.finished()
 
221
 
 
222
    def test_text_ui_getusername(self):
 
223
        ui = ui_testing.TextUIFactory('someuser\n\n')
 
224
        self.assertEqual('someuser',
 
225
                         ui.get_username(u'Hello %(host)s', host='some'))
 
226
        self.assertEqual('Hello some: ', ui.stderr.getvalue())
 
227
        self.assertEqual('', ui.stdout.getvalue())
 
228
        self.assertEqual('', ui.get_username(u"Gebruiker"))
 
229
        # stdin should be empty
 
230
        self.assertEqual('', ui.stdin.readline())
 
231
 
 
232
    def test_text_ui_getusername_unicode(self):
 
233
        ui = ui_testing.TextUIFactory(u'someuser\u1234')
 
234
        username = ui.get_username(u'Hello %(host)s', host=u'some\u1234')
 
235
        self.assertEqual(u"someuser\u1234", username)
 
236
        self.assertEqual(u"Hello some\u1234: ", ui.stderr.getvalue())
 
237
        self.assertEqual('', ui.stdout.getvalue())
 
238
 
 
239
    def test_quietness(self):
 
240
        self.overrideEnv('BRZ_PROGRESS_BAR', 'text')
 
241
        ui_factory = ui_testing.TextUIFactory(
 
242
            stderr=ui_testing.StringIOAsTTY())
 
243
        self.assertIsInstance(ui_factory._progress_view,
 
244
            _mod_ui_text.TextProgressView)
 
245
        ui_factory.be_quiet(True)
 
246
        self.assertIsInstance(ui_factory._progress_view,
 
247
            _mod_ui_text.NullProgressView)
 
248
 
 
249
    def test_text_ui_show_user_warning(self):
 
250
        from ..repofmt.groupcompress_repo import RepositoryFormat2a
 
251
        from ..repofmt.knitpack_repo import RepositoryFormatKnitPack5
 
252
        ui = ui_testing.TextUIFactory()
 
253
        remote_fmt = remote.RemoteRepositoryFormat()
 
254
        remote_fmt._network_name = RepositoryFormatKnitPack5().network_name()
 
255
        ui.show_user_warning('cross_format_fetch', from_format=RepositoryFormat2a(),
 
256
            to_format=remote_fmt)
 
257
        self.assertEqual('', ui.stdout.getvalue())
 
258
        self.assertEqual("Doing on-the-fly conversion from RepositoryFormat2a() to "
 
259
            "RemoteRepositoryFormat(_network_name='Bazaar RepositoryFormatKnitPack5 "
 
260
            "(bzr 1.6)\\n').\nThis may take some time. Upgrade the repositories to "
 
261
            "the same format for better performance.\n",
 
262
            ui.stderr.getvalue())
 
263
        # and now with it suppressed please
 
264
        ui = ui_testing.TextUIFactory()
 
265
        ui.suppressed_warnings.add('cross_format_fetch')
 
266
        ui.show_user_warning('cross_format_fetch', from_format=RepositoryFormat2a(),
 
267
            to_format=remote_fmt)
 
268
        self.assertEqual('', ui.stdout.getvalue())
 
269
        self.assertEqual('', ui.stderr.getvalue())
 
270
 
 
271
 
 
272
class TestTextUIOutputStream(tests.TestCase):
 
273
    """Tests for output stream that synchronizes with progress bar."""
 
274
 
 
275
    def test_output_clears_terminal(self):
 
276
        clear_calls = []
 
277
 
 
278
        uif =  ui_testing.TextUIFactory()
 
279
        uif.clear_term = lambda: clear_calls.append('clear')
 
280
 
 
281
        stream = _mod_ui_text.TextUIOutputStream(uif, uif.stdout, 'utf-8', 'strict')
 
282
        stream.write(u"Hello world!\n")
 
283
        stream.write(u"there's more...\n")
 
284
        stream.writelines([u"1\n", u"2\n", u"3\n"])
 
285
 
 
286
        self.assertEqual(uif.stdout.getvalue(),
 
287
            u"Hello world!\n"
 
288
            u"there's more...\n"
 
289
            u"1\n2\n3\n")
 
290
        self.assertEqual(['clear', 'clear', 'clear'],
 
291
            clear_calls)
 
292
 
 
293
        stream.flush()
 
294
 
 
295
 
 
296
class UITests(tests.TestCase):
 
297
 
 
298
    def test_progress_construction(self):
 
299
        """TextUIFactory constructs the right progress view.
 
300
        """
 
301
        FileStringIO = ui_testing.StringIOWithEncoding
 
302
        TTYStringIO = ui_testing.StringIOAsTTY
 
303
        for (file_class, term, pb, expected_pb_class) in (
 
304
            # on an xterm, either use them or not as the user requests,
 
305
            # otherwise default on
 
306
            (TTYStringIO, 'xterm', 'none', _mod_ui_text.NullProgressView),
 
307
            (TTYStringIO, 'xterm', 'text', _mod_ui_text.TextProgressView),
 
308
            (TTYStringIO, 'xterm', None, _mod_ui_text.TextProgressView),
 
309
            # on a dumb terminal, again if there's explicit configuration do
 
310
            # it, otherwise default off
 
311
            (TTYStringIO, 'dumb', 'none', _mod_ui_text.NullProgressView),
 
312
            (TTYStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
 
313
            (TTYStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
 
314
            # on a non-tty terminal, it's null regardless of $TERM
 
315
            (FileStringIO, 'xterm', None, _mod_ui_text.NullProgressView),
 
316
            (FileStringIO, 'dumb', None, _mod_ui_text.NullProgressView),
 
317
            # however, it can still be forced on
 
318
            (FileStringIO, 'dumb', 'text', _mod_ui_text.TextProgressView),
 
319
            ):
 
320
            self.overrideEnv('TERM', term)
 
321
            self.overrideEnv('BRZ_PROGRESS_BAR', pb)
 
322
            stdin = file_class(u'')
 
323
            stderr = file_class()
 
324
            stdout = file_class()
 
325
            uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
 
326
            self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
 
327
                "TERM=%s BRZ_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
 
328
            self.assertIsInstance(uif.make_progress_view(),
 
329
                expected_pb_class,
 
330
                "TERM=%s BRZ_PROGRESS_BAR=%s uif=%r" % (term, pb, uif,))
 
331
 
 
332
    def test_text_ui_non_terminal(self):
 
333
        """Even on non-ttys, make_ui_for_terminal gives a text ui."""
 
334
        stdin = stderr = stdout = ui_testing.StringIOWithEncoding()
 
335
        for term_type in ['dumb', None, 'xterm']:
 
336
            self.overrideEnv('TERM', term_type)
 
337
            uif = _mod_ui.make_ui_for_terminal(stdin, stdout, stderr)
 
338
            self.assertIsInstance(uif, _mod_ui_text.TextUIFactory,
 
339
                'TERM=%r' % (term_type,))
 
340
 
 
341
 
 
342
class SilentUITests(tests.TestCase):
 
343
 
 
344
    def test_silent_factory_get_password(self):
 
345
        # A silent factory that can't do user interaction can't get a
 
346
        # password.  Possibly it should raise a more specific error but it
 
347
        # can't succeed.
 
348
        ui = _mod_ui.SilentUIFactory()
 
349
        stdout = ui_testing.StringIOWithEncoding()
 
350
        self.assertRaises(
 
351
            NotImplementedError,
 
352
            self.apply_redirected,
 
353
            None, stdout, stdout, ui.get_password)
 
354
        # and it didn't write anything out either
 
355
        self.assertEqual('', stdout.getvalue())
 
356
 
 
357
    def test_silent_ui_getbool(self):
 
358
        factory = _mod_ui.SilentUIFactory()
 
359
        stdout = ui_testing.StringIOWithEncoding()
 
360
        self.assertRaises(
 
361
            NotImplementedError,
 
362
            self.apply_redirected,
 
363
            None, stdout, stdout, factory.get_boolean, u"foo")
 
364
 
 
365
 
 
366
class TestUIFactoryTests(tests.TestCase):
 
367
 
 
368
    def test_test_ui_factory_progress(self):
 
369
        # there's no output; we just want to make sure this doesn't crash -
 
370
        # see https://bugs.launchpad.net/bzr/+bug/408201
 
371
        ui = ui_testing.TestUIFactory()
 
372
        pb = ui.nested_progress_bar()
 
373
        pb.update('hello')
 
374
        pb.tick()
 
375
        pb.finished()
 
376
 
 
377
 
 
378
class CannedInputUIFactoryTests(tests.TestCase):
 
379
 
 
380
    def test_canned_input_get_input(self):
 
381
        uif = _mod_ui.CannedInputUIFactory([True, 'mbp', 'password', 42])
 
382
        self.assertEqual(True, uif.get_boolean(u'Extra cheese?'))
 
383
        self.assertEqual('mbp', uif.get_username(u'Enter your user name'))
 
384
        self.assertEqual('password',
 
385
                         uif.get_password(u'Password for %(host)s',
 
386
                                          host='example.com'))
 
387
        self.assertEqual(42, uif.get_integer(u'And all that jazz ?'))
 
388
 
 
389
 
 
390
class TestBoolFromString(tests.TestCase):
 
391
 
 
392
    def assertIsTrue(self, s, accepted_values=None):
 
393
        res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
 
394
        self.assertEqual(True, res)
 
395
 
 
396
    def assertIsFalse(self, s, accepted_values=None):
 
397
        res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
 
398
        self.assertEqual(False, res)
 
399
 
 
400
    def assertIsNone(self, s, accepted_values=None):
 
401
        res = _mod_ui.bool_from_string(s, accepted_values=accepted_values)
 
402
        self.assertIs(None, res)
 
403
 
 
404
    def test_know_valid_values(self):
 
405
        self.assertIsTrue('true')
 
406
        self.assertIsFalse('false')
 
407
        self.assertIsTrue('1')
 
408
        self.assertIsFalse('0')
 
409
        self.assertIsTrue('on')
 
410
        self.assertIsFalse('off')
 
411
        self.assertIsTrue('yes')
 
412
        self.assertIsFalse('no')
 
413
        self.assertIsTrue('y')
 
414
        self.assertIsFalse('n')
 
415
        # Also try some case variations
 
416
        self.assertIsTrue('True')
 
417
        self.assertIsFalse('False')
 
418
        self.assertIsTrue('On')
 
419
        self.assertIsFalse('Off')
 
420
        self.assertIsTrue('ON')
 
421
        self.assertIsFalse('OFF')
 
422
        self.assertIsTrue('oN')
 
423
        self.assertIsFalse('oFf')
 
424
 
 
425
    def test_invalid_values(self):
 
426
        self.assertIsNone(None)
 
427
        self.assertIsNone('doubt')
 
428
        self.assertIsNone('frue')
 
429
        self.assertIsNone('talse')
 
430
        self.assertIsNone('42')
 
431
 
 
432
    def test_provided_values(self):
 
433
        av = dict(y=True, n=False, yes=True, no=False)
 
434
        self.assertIsTrue('y', av)
 
435
        self.assertIsTrue('Y', av)
 
436
        self.assertIsTrue('Yes', av)
 
437
        self.assertIsFalse('n', av)
 
438
        self.assertIsFalse('N', av)
 
439
        self.assertIsFalse('No', av)
 
440
        self.assertIsNone('1', av)
 
441
        self.assertIsNone('0', av)
 
442
        self.assertIsNone('on', av)
 
443
        self.assertIsNone('off', av)
 
444
 
 
445
 
 
446
class TestConfirmationUserInterfacePolicy(tests.TestCase):
 
447
 
 
448
    def test_confirm_action_default(self):
 
449
        base_ui = _mod_ui.NoninteractiveUIFactory()
 
450
        for answer in [True, False]:
 
451
            self.assertEqual(
 
452
                _mod_ui.ConfirmationUserInterfacePolicy(base_ui, answer, {})
 
453
                .confirm_action("Do something?",
 
454
                    "breezy.tests.do_something", {}),
 
455
                answer)
 
456
 
 
457
    def test_confirm_action_specific(self):
 
458
        base_ui = _mod_ui.NoninteractiveUIFactory()
 
459
        for default_answer in [True, False]:
 
460
            for specific_answer in [True, False]:
 
461
                for conf_id in ['given_id', 'other_id']:
 
462
                    wrapper = _mod_ui.ConfirmationUserInterfacePolicy(
 
463
                        base_ui, default_answer, dict(given_id=specific_answer))
 
464
                    result = wrapper.confirm_action("Do something?", conf_id, {})
 
465
                    if conf_id == 'given_id':
 
466
                        self.assertEqual(result, specific_answer)
 
467
                    else:
 
468
                        self.assertEqual(result, default_answer)
 
469
 
 
470
    def test_repr(self):
 
471
        base_ui = _mod_ui.NoninteractiveUIFactory()
 
472
        wrapper = _mod_ui.ConfirmationUserInterfacePolicy(
 
473
            base_ui, True, dict(a=2))
 
474
        self.assertThat(repr(wrapper),
 
475
            Equals("ConfirmationUserInterfacePolicy("
 
476
                "NoninteractiveUIFactory(), True, {'a': 2})"))
 
477
 
 
478
 
 
479
class TestProgressRecordingUI(tests.TestCase):
 
480
    """Test test-oriented UIFactory that records progress updates"""
 
481
 
 
482
    def test_nested_ignore_depth_beyond_one(self):
 
483
        # we only want to capture the first level out progress, not
 
484
        # want sub-components might do. So we have nested bars ignored.
 
485
        factory = ProgressRecordingUIFactory()
 
486
        pb1 = factory.nested_progress_bar()
 
487
        pb1.update('foo', 0, 1)
 
488
        pb2 = factory.nested_progress_bar()
 
489
        pb2.update('foo', 0, 1)
 
490
        pb2.finished()
 
491
        pb1.finished()
 
492
        self.assertEqual([("update", 0, 1, 'foo')], factory._calls)