Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: Tools/Scripts/webkitpy/test/printer.py

Issue 654063002: Switch webkitpy to use the typ test framework (delete webkitpy.test). (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fix typo for bot_test_expectations Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Tools/Scripts/webkitpy/test/main_unittest.py ('k') | Tools/Scripts/webkitpy/test/runner.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright (C) 2012 Google, Inc.
2 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
6 # are met:
7 # 1. Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # 2. Redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution.
12 #
13 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
17 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24 import StringIO
25 import logging
26
27 from webkitpy.common.system import outputcapture
28 from webkitpy.common.system.systemhost import SystemHost
29 from webkitpy.layout_tests.views.metered_stream import MeteredStream
30
31 _log = logging.getLogger(__name__)
32
33
34 class Printer(object):
35 def __init__(self, stream, options=None):
36 self.stream = stream
37 self.meter = None
38 self.options = options
39 self.num_tests = 0
40 self.num_completed = 0
41 self.num_errors = 0
42 self.num_failures = 0
43 self.running_tests = []
44 self.completed_tests = []
45 if options:
46 self.configure(options)
47
48 def configure(self, options):
49 self.options = options
50
51 if options.timing:
52 # --timing implies --verbose
53 options.verbose = max(options.verbose, 1)
54
55 log_level = logging.INFO
56 if options.quiet:
57 log_level = logging.WARNING
58 elif options.verbose >= 2:
59 log_level = logging.DEBUG
60
61 self.meter = MeteredStream(self.stream, (options.verbose >= 2),
62 number_of_columns=SystemHost().platform.terminal_width())
63
64 handler = logging.StreamHandler(self.stream)
65 # We constrain the level on the handler rather than on the root
66 # logger itself. This is probably better because the handler is
67 # configured and known only to this module, whereas the root logger
68 # is an object shared (and potentially modified) by many modules.
69 # Modifying the handler, then, is less intrusive and less likely to
70 # interfere with modifications made by other modules (e.g. in unit
71 # tests).
72 handler.name = __name__
73 handler.setLevel(log_level)
74 formatter = logging.Formatter("%(message)s")
75 handler.setFormatter(formatter)
76
77 logger = logging.getLogger()
78 logger.addHandler(handler)
79 logger.setLevel(logging.NOTSET)
80
81 # Filter out most webkitpy messages.
82 #
83 # Messages can be selectively re-enabled for this script by updating
84 # this method accordingly.
85 def filter_records(record):
86 """Filter out non-third-party webkitpy messages."""
87 # FIXME: Figure out a way not to use strings here, for example by
88 # using syntax like webkitpy.test.__name__. We want to be
89 # sure not to import any non-Python 2.4 code, though, until
90 # after the version-checking code has executed.
91 if (record.name.startswith("webkitpy.test")):
92 return True
93 if record.name.startswith("webkitpy"):
94 return False
95 return True
96
97 testing_filter = logging.Filter()
98 testing_filter.filter = filter_records
99
100 # Display a message so developers are not mystified as to why
101 # logging does not work in the unit tests.
102 _log.info("Suppressing most webkitpy logging while running unit tests.")
103 handler.addFilter(testing_filter)
104
105 if self.options.pass_through:
106 outputcapture.OutputCapture.stream_wrapper = _CaptureAndPassThroughS tream
107
108 def write_update(self, msg):
109 self.meter.write_update(msg)
110
111 def print_started_test(self, source, test_name):
112 self.running_tests.append(test_name)
113 if len(self.running_tests) > 1:
114 suffix = ' (+%d)' % (len(self.running_tests) - 1)
115 else:
116 suffix = ''
117
118 if self.options.verbose:
119 write = self.meter.write_update
120 else:
121 write = self.meter.write_throttled_update
122
123 write(self._test_line(self.running_tests[0], suffix))
124
125 def print_finished_test(self, source, test_name, test_time, failures, errors ):
126 write = self.meter.writeln
127 if failures:
128 lines = failures[0].splitlines() + ['']
129 suffix = ' failed:'
130 self.num_failures += 1
131 elif errors:
132 lines = errors[0].splitlines() + ['']
133 suffix = ' erred:'
134 self.num_errors += 1
135 else:
136 suffix = ' passed'
137 lines = []
138 if self.options.verbose:
139 write = self.meter.writeln
140 else:
141 write = self.meter.write_throttled_update
142 if self.options.timing:
143 suffix += ' %.4fs' % test_time
144
145 self.num_completed += 1
146
147 if test_name == self.running_tests[0]:
148 self.completed_tests.insert(0, [test_name, suffix, lines])
149 else:
150 self.completed_tests.append([test_name, suffix, lines])
151 self.running_tests.remove(test_name)
152
153 for test_name, msg, lines in self.completed_tests:
154 if lines:
155 self.meter.writeln(self._test_line(test_name, msg))
156 for line in lines:
157 self.meter.writeln(' ' + line)
158 else:
159 write(self._test_line(test_name, msg))
160 self.completed_tests = []
161
162 def _test_line(self, test_name, suffix):
163 format_string = '[%d/%d] %s%s'
164 status_line = format_string % (self.num_completed, self.num_tests, test_ name, suffix)
165 if len(status_line) > self.meter.number_of_columns():
166 overflow_columns = len(status_line) - self.meter.number_of_columns()
167 ellipsis = '...'
168 if len(test_name) < overflow_columns + len(ellipsis) + 3:
169 # We don't have enough space even if we elide, just show the tes t method name.
170 test_name = test_name.split('.')[-1]
171 else:
172 new_length = len(test_name) - overflow_columns - len(ellipsis)
173 prefix = int(new_length / 2)
174 test_name = test_name[:prefix] + ellipsis + test_name[-(new_leng th - prefix):]
175 return format_string % (self.num_completed, self.num_tests, test_name, s uffix)
176
177 def print_result(self, run_time):
178 write = self.meter.writeln
179 write('Ran %d test%s in %.3fs' % (self.num_completed, self.num_completed != 1 and "s" or "", run_time))
180 if self.num_failures or self.num_errors:
181 write('FAILED (failures=%d, errors=%d)\n' % (self.num_failures, self .num_errors))
182 else:
183 write('\nOK\n')
184
185
186 class _CaptureAndPassThroughStream(object):
187 def __init__(self, stream):
188 self._buffer = StringIO.StringIO()
189 self._stream = stream
190
191 def write(self, msg):
192 self._stream.write(msg)
193
194 # Note that we don't want to capture any output generated by the debugge r
195 # because that could cause the results of capture_output() to be invalid .
196 if not self._message_is_from_pdb():
197 self._buffer.write(msg)
198
199 def _message_is_from_pdb(self):
200 # We will assume that if the pdb module is in the stack then the output
201 # is being generated by the python debugger (or the user calling somethi ng
202 # from inside the debugger).
203 import inspect
204 import pdb
205 stack = inspect.stack()
206 return any(frame[1] == pdb.__file__.replace('.pyc', '.py') for frame in stack)
207
208 def flush(self):
209 self._stream.flush()
210
211 def getvalue(self):
212 return self._buffer.getvalue()
OLDNEW
« no previous file with comments | « Tools/Scripts/webkitpy/test/main_unittest.py ('k') | Tools/Scripts/webkitpy/test/runner.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698