1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2014 Sven Brauch
# SPDX-License-Identifier: GPL-2.0-or-later
import sys
import subprocess
import io
from PyQt4.QtCore import QProcess, QByteArray
import re
def colorize(s, colnum):
return "\033[9" + str(colnum) + "m" + str(s) + "\033[0m"
def green(s):
return colorize(s, 2)
def red(s):
return colorize(s, 1)
def yellow(s):
return colorize(s, 3)
def blue(s):
return colorize(s, 4)
def pink(s):
return colorize(s, 5)
def cyan(s):
return colorize(s, 6)
def white(s):
return colorize(s, 7)
def indent(s, level = 1):
return '\n'.join([" "*level + line for line in s.splitlines()])
class FailedTest():
def __init__(self, name, reason):
self.filename = '<none>'
self.lineno = '<none>'
self.name = name
self.reason = reason
self.failExpected = False
def __str__(self):
return "%s:%s %s" % (self.filename, self.lineno, self.name)
class TestRunner():
def __init__(self, testfile):
self.testfile = testfile
self.data = ""
self.passed_tests = []
self.failed_tests = []
def writeStdout(self):
data = self.process.readAllStandardOutput().data().decode("utf-8").replace(r'\n', '\n')
if "debug" in sys.argv:
sys.stdout.write(data)
else:
for line in data.split('\n'):
if line[:4] == "PASS" or line[:5] == "FAIL!" or line[:5] == "XFAIL":
sys.stdout.write(".")
sys.stdout.flush()
self.data += data
def writeStderr(self):
data = self.process.readAllStandardError().data().decode("utf-8").replace(r'\n', '\n')
if "debug" in sys.argv:
sys.stdout.write(data)
self.data += data
def doTestrun(self):
data = self.fetchOutputForJob()
last_failed = False
for line in data.split('\n'):
success = re.match(r"PASS\s*:\s*(.*)", line)
if success:
function = success.groups()[0]
self.passed_tests.append(function)
last_failed = False
if last_failed:
getLocation = re.match(r"\s*Loc:\s*\[(.*)\((\d*)\)]", line)
if getLocation:
filename = ".../" + '/'.join(getLocation.groups()[0].split('/')[-2:])
lineno = getLocation.groups()[1]
self.failed_tests[-1].filename = filename
self.failed_tests[-1].lineno = lineno
last_failed = False
fail = re.match(r"FAIL!\s*:\s*(.*)\((.*)\)\s+(.*)", line)
if fail:
function = fail.groups()[0]
args = fail.groups()[1]
function = function + "(" + args + ")"
reason = fail.groups()[2]
self.failed_tests.append(FailedTest(function, reason))
last_failed = True
xfail = re.match(r"XFAIL\s*:\s*(.*)\((.*)\)\s+(.*)", line)
if xfail:
function = xfail.groups()[0]
args = xfail.groups()[1]
function = function + "(" + args + ")"
reason = xfail.groups()[2]
self.failed_tests.append(FailedTest(function, reason))
self.failed_tests[-1].failExpected = True
last_failed = True
fatal_fail = re.match(r"(QFATAL|ASSERT)\s*", line)
if fatal_fail:
print(self.data)
print(red("Fatal error occurred, aborting"))
return
passed, failed = len(self.passed_tests), len(self.failed_tests)
try:
percent = round((float(passed) / (failed+passed)) * 100)
except ZeroDivisionError:
percent = 0
percent = green(percent) if percent == 100 else yellow(percent) if percent > 80 else red(percent)
total = white(passed+failed)
passed, failed = green(passed), red(failed)
print("\n Done. Summary: %s tests reported total, %s passed, %s failed (%s%% passed)." % (total, passed, failed, percent))
print(" Detailed information:\n")
print(white(" ==="), green("Passed tests:"), white("==="))
namespaceFunctionArgs = r"(.*)::(.*)\((.*)\)"
if len(self.passed_tests):
for test in self.passed_tests:
test = re.match(namespaceFunctionArgs, test)
test = test.groups()
test = "[%s] " % test[0] + green(test[1]) + "(" + white(test[2]) + ")"
print(indent(green("✔ ") + test))
if len(self.failed_tests):
print("\n" + white(" ==="), red("Failed tests:"), white("==="))
for test in self.failed_tests:
namespace, function, args = re.match(namespaceFunctionArgs, test.name).groups()
filename = test.filename.split('/')[-1]
path = '/'.join(test.filename.split('/')[:-1]) + "/"
print(indent((yellow("✘ ") if test.failExpected else red("✘ ")) + white(filename) + ":" + blue(test.lineno) +
" "*(5-len(str(lineno))) + red(function) + "(" + yellow(args) + ")"))
if 'noreason' not in sys.argv:
print(indent("Reason of failure:" + blue(" ❮") + white(test.reason) + blue("❯ ")
+ ( "(Failure expected)" if test.failExpected else "" ), 2))
#print "[in %s]" % namespace
def fetchOutputForJob(self):
self.process = QProcess()
self.process.readyReadStandardOutput.connect(self.writeStdout)
self.process.readyReadStandardError.connect(self.writeStderr)
print(" Please wait, running tests", end=' ')
sys.stdout.flush()
self.process.start(self.testfile, ["-maxwarnings", "0"])
self.process.waitForFinished(-1)
return str(self.data)
if __name__ == '__main__':
runner = TestRunner(sys.argv[1])
runner.doTestrun()
|