summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Collins <robertc@robertcollins.net>2010-01-08 21:57:03 +1100
committerRobert Collins <robertc@robertcollins.net>2010-01-08 21:57:03 +1100
commit68cb743c43a74c0473b6f6d0ccf9b77a85bab39b (patch)
tree27fcae5a3f0763ce84157eefecf61ac8d2851e28
parent0d7c3c2904fac03989f3b0c2bd7affcc86a6b9bc (diff)
downloadtestrepository-git-68cb743c43a74c0473b6f6d0ccf9b77a85bab39b.tar.gz
Add ui.output_results().
-rw-r--r--testrepository/tests/test_ui.py10
-rw-r--r--testrepository/tests/ui/test_cli.py28
-rw-r--r--testrepository/ui/__init__.py19
-rw-r--r--testrepository/ui/cli.py33
-rw-r--r--testrepository/ui/model.py3
5 files changed, 93 insertions, 0 deletions
diff --git a/testrepository/tests/test_ui.py b/testrepository/tests/test_ui.py
index 7a243fb..67352ce 100644
--- a/testrepository/tests/test_ui.py
+++ b/testrepository/tests/test_ui.py
@@ -82,6 +82,16 @@ class TestUIContract(ResourcedTestCase):
ui.set_command(cmd)
self.assertRaises(KeyError, ui.iter_streams, 'subunit')
+ def test_output_results(self):
+ # output_results can be called and takes a thing that can be 'run'.
+ ui = self.ui_factory()
+ cmd = commands.Command(ui)
+ ui.set_command(cmd)
+ class Case(ResourcedTestCase):
+ def method(self):
+ pass
+ ui.output_results(Case('method'))
+
def test_output_values(self):
# output_values can be called and takes a list of things to output.
ui = self.ui_factory()
diff --git a/testrepository/tests/ui/test_cli.py b/testrepository/tests/ui/test_cli.py
index 09d0387..031ec53 100644
--- a/testrepository/tests/ui/test_cli.py
+++ b/testrepository/tests/ui/test_cli.py
@@ -14,8 +14,11 @@
"""Tests for UI support logic and the UI contract."""
+import doctest
from cStringIO import StringIO
+from testtools.matchers import DocTestMatches
+
from testrepository import commands
from testrepository.ui import cli
from testrepository.tests import ResourcedTestCase
@@ -51,6 +54,31 @@ class TestCLIUI(ResourcedTestCase):
ui.set_command(cmd)
self.assertEqual('/nowhere/', ui.here)
+ def test_outputs_results_to_stdout(self):
+ stdout = StringIO()
+ stdin = StringIO()
+ stderr = StringIO()
+ ui = cli.UI([], stdin, stdout, stderr)
+ cmd = commands.Command(ui)
+ ui.set_command(cmd)
+ class Case(ResourcedTestCase):
+ def method(self):
+ self.fail('quux')
+ ui.output_results(Case('method'))
+ self.assertThat(stdout.getvalue(),DocTestMatches(
+ """======================================================================
+FAIL: testrepository.tests.ui.test_cli.Case.method
+----------------------------------------------------------------------
+Text attachment: traceback
+------------
+Traceback (most recent call last):
+...
+ File "...test_cli.py", line ..., in method
+ self.fail(\'quux\')
+AssertionError: quux
+------------
+""", doctest.ELLIPSIS))
+
def test_outputs_values_to_stdout(self):
stdout = StringIO()
stdin = StringIO()
diff --git a/testrepository/ui/__init__.py b/testrepository/ui/__init__.py
index 4226b74..74bd349 100644
--- a/testrepository/ui/__init__.py
+++ b/testrepository/ui/__init__.py
@@ -73,6 +73,25 @@ class AbstractUI(object):
"""Helper for iter_streams which subclasses should implement."""
raise NotImplementedError(self._iter_streams)
+ def output_values(self, values):
+ """Show values to the user.
+
+ :param values: An iterable of (label, value).
+ """
+ raise NotImplementedError(self.output_values)
+
+ def output_results(self, suite_or_test):
+ """Show suite_or_test to the user by 'running' it.
+
+ This expects the run to be fast/cheap.
+
+ :param suite_or_test: A suite or test to show to the user. This should
+ obey the 'TestCase' protocol - it should have a method run(result)
+ that causes all the tests contained in the object to be handed to
+ the result object.
+ """
+ raise NotImplementedError(self.output_results)
+
def set_command(self, cmd):
"""Inform the UI what command it is running.
diff --git a/testrepository/ui/cli.py b/testrepository/ui/cli.py
index 2a704d9..d5f630c 100644
--- a/testrepository/ui/cli.py
+++ b/testrepository/ui/cli.py
@@ -17,8 +17,33 @@
from optparse import OptionParser
import os
+import testtools
+
from testrepository import ui
+class CLITestResult(testtools.TestResult):
+ """A TestResult for the CLI."""
+
+ def __init__(self, stream):
+ """Construct a CLITestResult writing to stream."""
+ super(CLITestResult, self).__init__()
+ self.stream = stream
+ self.sep1 = '=' * 70 + '\n'
+ self.sep2 = '-' * 70 + '\n'
+
+ def _show_list(self, label, error_list):
+ for test, output in error_list:
+ self.stream.write(self.sep1)
+ self.stream.write("%s: %s\n" % (label, test.id()))
+ self.stream.write(self.sep2)
+ self.stream.write(output)
+
+ def stopTestRun(self):
+ self._show_list('ERROR', self.errors)
+ self._show_list('FAIL', self.failures)
+ super(CLITestResult, self).stopTestRun()
+
+
class UI(ui.AbstractUI):
"""A command line user interface."""
@@ -44,6 +69,14 @@ class UI(ui.AbstractUI):
outputs.append('%s: %s' % (label, value))
self._stdout.write('%s\n' % ' '.join(outputs))
+ def output_results(self, suite_or_test):
+ result = CLITestResult(self._stdout)
+ result.startTestRun()
+ try:
+ suite_or_test.run(result)
+ finally:
+ result.stopTestRun()
+
def set_command(self, cmd):
ui.AbstractUI.set_command(self, cmd)
parser = OptionParser()
diff --git a/testrepository/ui/model.py b/testrepository/ui/model.py
index a287a1b..dd7d9f6 100644
--- a/testrepository/ui/model.py
+++ b/testrepository/ui/model.py
@@ -56,3 +56,6 @@ class UI(ui.AbstractUI):
def output_values(self, values):
self.outputs.append(('values', values))
+
+ def output_results(self, suite_or_test):
+ self.outputs.append(('results', suite_or_test))