From 44c1397fdff1c7efd36a953218f8717b6d765d8b Mon Sep 17 00:00:00 2001 From: Michal Sojka Date: Fri, 5 Dec 2014 23:27:51 +0100 Subject: [PATCH] Update wvtool --- tests/wvtool | 161 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 111 insertions(+), 50 deletions(-) diff --git a/tests/wvtool b/tests/wvtool index e3f0abe..fe9098b 100755 --- a/tests/wvtool +++ b/tests/wvtool @@ -7,12 +7,15 @@ provides some other useful features. Namely: - Summary mode (--summary) - Test results aligned to the same column -- FIXME: No "progress" reporting - TODO: Conversion to HTML - TODO: Variable timeout - TODO: Checking of expected number of tests + +Newest version can be found at https://github.com/wentasah/wvtest. """ +version = "v0-6-gca4c750" + import argparse import subprocess as sp import re @@ -25,13 +28,14 @@ import math re_prefix = '' class Term: - reset = '\033[0m' - bold = '\033[01m' - disable = '\033[02m' - underline = '\033[04m' - reverse = '\033[07m' - strikethrough = '\033[09m' - invisible = '\033[08m' + class attr: + reset = '\033[0m' + bold = '\033[01m' + disable = '\033[02m' + underline = '\033[04m' + reverse = '\033[07m' + strikethrough = '\033[09m' + invisible = '\033[08m' class fg: black = '\033[30m' red = '\033[31m' @@ -58,40 +62,68 @@ class Term: cyan = '\033[46m' lightgrey = '\033[47m' - def __init__(self, use_colors): - def clear_colors(obj): - for key in dir(obj): + progress_chars = '|/-\\' + + def __init__(self): + if os.environ['TERM'] == 'dumb': + self.output = None + else: + try: + self.output = open('/dev/tty', 'w') + except IOError: + self.output = None + + if not self.output: + self._clear_colors() + + self.width = self._get_width() + self._enabled = True + + def _raw_write(self, string): + '''Write raw data if output is enabled.''' + if self._enabled and self.output: + try: + self.output.write(string) + self.output.flush() + except IOError: + self._enabled = False + + def _get_width(self): + try: + import fcntl, termios, struct, os + s = struct.pack('HHHH', 0, 0, 0, 0) + x = fcntl.ioctl(self.output.fileno(), termios.TIOCGWINSZ, s) + return struct.unpack('HHHH', x)[1] + except: + return int(getattr(os.environ, 'COLUMNS', 80)) + + def _clear_colors(self): + '''Sets all color and attribute memebers to empty strings''' + for cls in ('attr', 'fg', 'bg'): + c = getattr(self, cls) + for key in dir(c): if key[0] == '_': continue - if key in ('fg', 'bg'): - clear_colors(getattr(obj, key)) - continue - setattr(obj, key, '') - - if not use_colors: - clear_colors(self) - - if use_colors: - def ioctl_GWINSZ(fd): - try: - import fcntl, termios, struct, os - cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) - except: - return - return cr - cr = ioctl_GWINSZ(1) - if not cr: - try: - fd = os.open(os.ctermid(), os.O_RDONLY) - cr = ioctl_GWINSZ(fd) - os.close(fd) - except: - pass - self.width = cr[1] - else: - self.width = int(getattr(os.environ, 'COLUMNS', 80)) + setattr(c, key, '') + + def set_progress_msg(self, msg): + self._progress_msg = msg + self._progress_idx = 0 + self.update_progress_msg() + + def update_progress_msg(self): + self._progress_idx += 1 + if self._progress_idx >= len(self.progress_chars): + self._progress_idx = 0 + if self.output: + self._raw_write(self._progress_msg[:self.width - 3] + " " + self.progress_chars[self._progress_idx] + "\r") + + def clear_progress_msg(self): + if self.output: + self._raw_write(' '*(len(self._progress_msg[:self.width - 3]) + 2) + "\r") -term = Term(sys.stdout.isatty() and os.environ['TERM'] != 'dumb') + +term = Term() class WvLine: def __init__(self, match): @@ -121,7 +153,7 @@ class WvTestingLine(WvLine): def __str__(self): return '{self.prefix}! Testing "{self.what}" in {self.where}:'.format(self=self) def print(self): - print(term.bold + str(self) + term.reset) + print(term.attr.bold + str(self) + term.attr.reset) def asWvCheckLine(self, result): return WvCheckLine('{self.where} {self.what}'.format(self=self), result) @@ -139,7 +171,8 @@ class WvCheckLine(WvLine): raise TypeError("WvCheckLine.__init__() takes at most 2 positional arguments") def __str__(self): - return '{self.prefix}! {self.text} {self.result}'.format(self=self) + # Result == None when printing progress message + return '{self.prefix}! {self.text} {result}'.format(self=self, result=(self.result or '')) def is_success(self): return self.result == 'ok' @@ -150,7 +183,7 @@ class WvCheckLine(WvLine): color = term.fg.lightgreen else: color = term.fg.lightred - result = term.bold + color + self.result + term.reset + result = term.attr.bold + color + self.result + term.attr.reset lines = math.ceil(len(text) / term.width) if len(text) % term.width > term.width - 10: @@ -188,6 +221,7 @@ class WvTestLog(list): self.currentTestFailedCount = 0 self.verbosity = verbosity + self.show_progress = False def setImplicitTestTitle (self, testing): """If the test does not supply its own title as a first line of test @@ -208,27 +242,39 @@ class WvTestLog(list): else: if self.verbosity <= self.Verbosity.NORMAL: self.currentTest.asWvCheckLine('ok').print() + sys.stdout.flush() self.clear() - def _newTest(self, testing): + def clear(self): + del self[:] + + def _newTest(self, testing : WvTestingLine): if self.currentTest: self._finishCurrentTest() if testing != None: self.testCount += 1 + if self.show_progress and self.verbosity < self.Verbosity.VERBOSE: + term.set_progress_msg(str(testing.asWvCheckLine(None))) self.currentTest = testing self.currentTestFailedCount = 0 - def _newCheck(self, check): + def _newCheck(self, check : WvCheckLine): self.checkCount += 1 if not check.is_success(): self.checkFailedCount += 1 self.currentTestFailedCount += 1 - def append(self, logEntry): - if self.implicitTestTitle and type(logEntry) != WvTestingLine: - self._newTest(self.implicitTestTitle) - super().append(self.implicitTestTitle) - self.implicitTestTitle = None + def append(self, logEntry : WvLine): + if self.implicitTestTitle: + if str(logEntry) == '': + pass + elif type(logEntry) != WvTestingLine: + self._newTest(self.implicitTestTitle) + super().append(self.implicitTestTitle) + self.implicitTestTitle = None + else: + self.implicitTestTitle = None + if type(logEntry) == WvTestingLine: self._newTest(logEntry) @@ -238,8 +284,13 @@ class WvTestLog(list): list.append(self, logEntry) if self.verbosity == self.Verbosity.VERBOSE: + if self.show_progress: + term.clear_progress_msg() self.print() self.clear() + else: + if self.show_progress: + term.update_progress_msg() def addLine(self, line): line = line.rstrip() @@ -265,6 +316,7 @@ class WvTestLog(list): return self.testFailedCount == 0 def _run(command, log): + log.show_progress = True timeout = 100 def kill_child(sig = None, frame = None): @@ -337,6 +389,7 @@ parser.add_argument('-s', '--summary', dest='verbosity', action='store_const', const=WvTestLog.Verbosity.SUMMARY, help='''Hide output of all tests. Print just one line for each "Testing" section and report "ok" or "FAILURE" of it.''') +parser.add_argument('--version', action='version', version='%(prog)s '+version) subparsers = parser.add_subparsers(help='sub-command help') @@ -348,7 +401,7 @@ parser_runall = subparsers.add_parser('runall', help='Run multiple scripts/binar parser_runall.set_defaults(func=do_runall) parser_runall.add_argument('commands', nargs='+', help='Scripts/binaries to run') -parser_format = subparsers.add_parser('format', help='Reformat/highlight/summarize WvTest protcol output') +parser_format = subparsers.add_parser('format', help='Reformat/highlight/summarize WvTest protocol output') parser_format.set_defaults(func=do_format) parser_format.add_argument('infiles', nargs='*', help='Files with wvtest output') @@ -357,7 +410,15 @@ parser_format.add_argument('infiles', nargs='*', help='Files with wvtest output' args = parser.parse_args() +if not 'func' in args: + parser.print_help() + sys.exit(1) + log = WvTestLog(args.verbosity) args.func(args, log) log.done() sys.exit(0 if log.is_success() else 1) + +# Local Variables: +# compile-command: "make wvtool" +# End: -- 2.39.2