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()