File: runtest.py

package info (click to toggle)
kdevelop-python 24.12.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 12,640 kB
  • sloc: python: 183,048; cpp: 18,798; xml: 140; sh: 14; makefile: 9
file content (166 lines) | stat: -rwxr-xr-x 6,168 bytes parent folder | download | duplicates (2)
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()