diff options
Diffstat (limited to 'bzrlib/tests/per_uifactory/__init__.py')
-rw-r--r-- | bzrlib/tests/per_uifactory/__init__.py | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/bzrlib/tests/per_uifactory/__init__.py b/bzrlib/tests/per_uifactory/__init__.py new file mode 100644 index 0000000..1a72f6e --- /dev/null +++ b/bzrlib/tests/per_uifactory/__init__.py @@ -0,0 +1,274 @@ +# Copyright (C) 2009, 2010, 2011 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.assertEquals(True, self.factory.is_quiet()) + self.factory.be_quiet(False) + self.assertEquals(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.assertEquals(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.assertEquals("%s\n" % note_text, + self.stdout.getvalue()) + + def _check_show_error(self, msg): + self.assertEquals("bzr: error: %s\n" % msg, + self.stderr.getvalue()) + self.assertEquals("", self.stdout.getvalue()) + + def _check_show_message(self, msg): + self.assertEquals("%s\n" % msg, + self.stdout.getvalue()) + self.assertEquals("", self.stderr.getvalue()) + + def _check_show_warning(self, msg): + self.assertEquals("bzr: warning: %s\n" % msg, + self.stderr.getvalue()) + self.assertEquals("", 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) |