blob: 51a05e8abaf427fb6be9cd6163e2a6fd76b3a6c9 [file] [log] [blame]
import sys
def create_display(opts, tests, total_tests, workers):
if opts.quiet:
return NopDisplay()
num_tests = len(tests)
of_total = (' of %d' % total_tests) if (num_tests != total_tests) else ''
header = '-- Testing: %d%s tests, %d workers --' % (
num_tests, of_total, workers)
progress_bar = None
if opts.succinct and opts.useProgressBar:
import lit.ProgressBar
try:
tc = lit.ProgressBar.TerminalController()
progress_bar = lit.ProgressBar.ProgressBar(tc, header)
header = None
except ValueError:
progress_bar = lit.ProgressBar.SimpleProgressBar('Testing: ')
return Display(opts, tests, header, progress_bar)
class ProgressPredictor(object):
def __init__(self, tests):
self.completed = 0
self.time_elapsed = 0.0
self.predictable_tests_remaining = 0
self.predictable_time_remaining = 0.0
self.unpredictable_tests_remaining = 0
for test in tests:
if test.previous_elapsed:
self.predictable_tests_remaining += 1
self.predictable_time_remaining += test.previous_elapsed
else:
self.unpredictable_tests_remaining += 1
def update(self, test):
self.completed += 1
self.time_elapsed += test.result.elapsed
if test.previous_elapsed:
self.predictable_tests_remaining -= 1
self.predictable_time_remaining -= test.previous_elapsed
else:
self.unpredictable_tests_remaining -= 1
# NOTE: median would be more precise, but might be too slow.
average_test_time = (self.time_elapsed + self.predictable_time_remaining) / \
(self.completed + self.predictable_tests_remaining)
unpredictable_time_remaining = average_test_time * \
self.unpredictable_tests_remaining
total_time_remaining = self.predictable_time_remaining + unpredictable_time_remaining
total_time = self.time_elapsed + total_time_remaining
if total_time > 0:
return self.time_elapsed / total_time
return 0
class NopDisplay(object):
def print_header(self): pass
def update(self, test): pass
def clear(self, interrupted): pass
class Display(object):
def __init__(self, opts, tests, header, progress_bar):
self.opts = opts
self.num_tests = len(tests)
self.header = header
self.progress_predictor = ProgressPredictor(
tests) if progress_bar else None
self.progress_bar = progress_bar
self.completed = 0
def print_header(self):
if self.header:
print(self.header)
if self.progress_bar:
self.progress_bar.update(0.0, '')
def update(self, test):
self.completed += 1
show_result = test.isFailure() or \
self.opts.showAllOutput or \
(not self.opts.quiet and not self.opts.succinct)
if show_result:
if self.progress_bar:
self.progress_bar.clear(interrupted=False)
self.print_result(test)
if self.progress_bar:
if test.isFailure():
self.progress_bar.barColor = 'RED'
percent = self.progress_predictor.update(test)
self.progress_bar.update(percent, test.getFullName())
def clear(self, interrupted):
if self.progress_bar:
self.progress_bar.clear(interrupted)
def print_result(self, test):
# Show the test result line.
test_name = test.getFullName()
print('%s: %s (%d of %d)' % (test.result.code.name, test_name,
self.completed, self.num_tests))
# Show the test failure output, if requested.
if (test.isFailure() and self.opts.showOutput) or \
self.opts.showAllOutput:
if test.isFailure():
print("%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(),
'*'*20))
out = test.result.output
# Encode/decode so that, when using Python 3.6.5 in Windows 10,
# print(out) doesn't raise UnicodeEncodeError if out contains
# special characters. However, Python 2 might try to decode
# as part of the encode call if out is already encoded, so skip
# encoding if it raises UnicodeDecodeError.
if sys.stdout.encoding:
try:
out = out.encode(encoding=sys.stdout.encoding,
errors="replace")
except UnicodeDecodeError:
pass
# Python 2 can raise UnicodeDecodeError here too in cases
# where the stdout encoding is ASCII. Ignore decode errors
# in this case.
out = out.decode(encoding=sys.stdout.encoding, errors="ignore")
print(out)
print("*" * 20)
# Report test metrics, if present.
if test.result.metrics:
print("%s TEST '%s' RESULTS %s" % ('*'*10, test.getFullName(),
'*'*10))
items = sorted(test.result.metrics.items())
for metric_name, value in items:
print('%s: %s ' % (metric_name, value.format()))
print("*" * 10)
# Report micro-tests, if present
if test.result.microResults:
items = sorted(test.result.microResults.items())
for micro_test_name, micro_test in items:
print("%s MICRO-TEST: %s" %
('*'*3, micro_test_name))
if micro_test.metrics:
sorted_metrics = sorted(micro_test.metrics.items())
for metric_name, value in sorted_metrics:
print(' %s: %s ' % (metric_name, value.format()))
# Ensure the output is flushed.
sys.stdout.flush()