From 937c6ffa48527d5898fa9fab3ca97010aca0d1a1 Mon Sep 17 00:00:00 2001 From: Michał Górny Date: Sat, 10 Aug 2013 01:00:48 +0200 Subject: Add a wiki output backend. --- pmstestsuite/output/__init__.py | 3 +- pmstestsuite/output/wiki.py | 187 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 pmstestsuite/output/wiki.py diff --git a/pmstestsuite/output/__init__.py b/pmstestsuite/output/__init__.py index fcfd27e..7736b45 100644 --- a/pmstestsuite/output/__init__.py +++ b/pmstestsuite/output/__init__.py @@ -90,5 +90,6 @@ def get_output_modules(): from pmstestsuite.output.cli import CLIOutput from pmstestsuite.output.html import HTMLOutput + from pmstestsuite.output.wiki import WikiOutput - return (CLIOutput, HTMLOutput) + return (CLIOutput, HTMLOutput, WikiOutput) diff --git a/pmstestsuite/output/wiki.py b/pmstestsuite/output/wiki.py new file mode 100644 index 0000000..23b7178 --- /dev/null +++ b/pmstestsuite/output/wiki.py @@ -0,0 +1,187 @@ +# vim:fileencoding=utf-8 +# (c) 2011 Michał Górny +# Released under the terms of the 2-clause BSD license. + +from collections import defaultdict +from gentoopm.util import ABCObject +from abc import abstractmethod + +from . import OutputModule + +class WikiOutput(OutputModule): + """ Gentoo Wiki markup output module. """ + + name = 'wiki' + + def __init__(self, path = None): + if path is None: + path = 'pms-test-suite-output.txt' + self._path = path + + def __call__(self, allresults, verbose = False): + mypms = [] + + def _results_by_test(allresults): + ret = defaultdict(lambda: defaultdict(lambda: None)) + for pm, results in allresults.items(): + mypms.append(pm) + for t, r in results.items(): + ret[t][pm] = r + return ret + + def _results_by_class(reorderedresults): + ret = defaultdict(dict) + for t, r in reorderedresults.items(): + ret[t.short_name][t] = r + for cl in sorted(ret): + yield cl, ret[cl] + + def _sorted_pms(pms): + for pm in sorted(pms, key = lambda pm: mypms.index(pm)): + yield (pm, pms[pm]) + + class HTMLElem(ABCObject): + @abstractmethod + def set_rowspan(self, rowspan): + pass + + @abstractmethod + def __str__(self): + pass + + class TD(HTMLElem): + _elem = '|' + + def __init__(self, text, colspan = 1): + self._attrs = [] + self._text = text + self._colspan = colspan + if colspan != 1: + self._attrs.append('colspan="%d"' % colspan) + + def set_rowspan(self, rowspan): + if rowspan != 1: + self._attrs.append('rowspan="%d"' % rowspan) + + def __str__(self): + out = self._text + if self._attrs: + out = '%s | %s' % (' '.join(self._attrs), out) + return '| %s\n' % out + + class TH(TD): + _elem = '!' + + class ValCell(TD): + _color_class = '' + + def __init__(self, text): + text = '%s' % text + TD.__init__(self, text) + if self._color_class: + self._attrs.append('style="%s"' % self._color_class) + + style_good = 'background: #88e888;' + style_bad = 'background: #e88888;' + style_unk_good = 'color: #008800;' + style_unk_bad = 'color: #880000;' + + class ColorValCell(ValCell): + def __init__(self, text, a): + if a.undefined: + self._color_class = style_unk_good if a else style_unk_bad + else: + self._color_class = style_good if a else style_bad + ValCell.__init__(self, text) + + class BoolCell(ValCell): + def __init__(self, r): + if not r.undefined: + self._color_class = style_good if r else style_bad + ValCell.__init__(self, 'OK' if r else 'FAIL') + else: # undefined result + self._color_class = style_unk_good if r else style_unk_bad + ValCell.__init__(self, 'n/a (but OK)' if r \ + else 'n/a (but FAIL)') + + class UnknownValCell(ValCell): + def __init__(self): + ValCell.__init__(self, '?') + + class NoCell(HTMLElem): + def __init__(self): + pass + + def set_rowspan(self, rowspan): + pass + + def __str__(self): + return '' + + ret = True + results = _results_by_test(allresults) + table = defaultdict(lambda: defaultdict(lambda: None)) + + table[0][0] = TH('Test name') + table[0][1] = TH('EAPI') + table[0][2] = TH('Assertion', colspan = 2) + table[0][4] = TH('Expected') + for i, pm in enumerate(mypms): + table[0][5 + i*2] = TH('%s %s' % (pm.name, pm.version), colspan = 2) + table[0][6 + i*2] = NoCell() + table[1][5 + i*2] = TH('Actual') + table[1][6 + i*2] = TH('Result') + maxcol = 7 + i*2 + + row = 2 + for cl, tests in _results_by_class(results): + table[row][0] = cl + for t in sorted(tests, key = lambda t: t.eapi): + table[row][1] = t.eapi + test_asserts = [] + col = 5 + for pm, r in _sorted_pms(tests[t]): + table[row][col+1] = BoolCell(r) + for ai, a in enumerate(r.assertions): + if a.name not in test_asserts: + test_asserts.append(a.name) + crow = row + test_asserts.index(a.name) + if a.prefix is not None: + if ai == 0 or table[crow-1][2] != a.prefix: + table[crow][2] = a.prefix + table[crow][3] = a.unprefixed_name + else: + table[crow][2] = TD(a.name, colspan = 2) + table[crow][3] = NoCell() + table[crow][4] = ValCell(a.expected) + for c in range(5, maxcol, 2): + table[crow][c] = UnknownValCell() + else: + crow = row + test_asserts.index(a.name) + + table[crow][col] = ColorValCell(a.actual, a) + col += 2 + row += len(test_asserts) + + f = open(self._path, 'w') + f.write('{| class="wikitable"\n') + for y in range(0, row): + f.write('|-\n') + for x in range(0, maxcol): + cell = table[y][x] + if cell is not None: + rowspan = 1 + for y2 in range(y + 1, row): + if table[y2][x] is None: + rowspan += 1 + else: + break + + if not isinstance(cell, HTMLElem): + cell = TD(cell) + cell.set_rowspan(rowspan) + f.write(str(cell)) + f.write('|}\n') + f.close() + + return ret -- cgit v1.2.3-65-gdbad