-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplunit.py
executable file
·198 lines (159 loc) · 5.84 KB
/
plunit.py
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/usr/bin/python3
# Name: Extract PLUnit results
# By Robbert Gurdeep Singh
##########################################################################
"""
PLUnit tests
Splits up the testfile ending in ".unit.pl" in separate tests and reports
the output for each group.
See:
http://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/plunit.html%27)
"""
import fileinput
import re
from prologGeneral import checkErrors, swipl
from util import CondFormatString
plUnitInfo = {
"nl": CondFormatString(
lambda **d: d["failed"] > 0,
"**PLUnit** voerde **{numtests} testen** uit, **{failed}** faalden. Een test kan meerdere `assert`s bevatten.",
"Alle **PLUnit** testen slaagden."),
"en": CondFormatString(
lambda **d: d["failed"] > 0,
"**PLUnit** ran **{numtests} tests**, **{failed}** of them failed.",
"All **PLUnit** tests passed.")}
plBeginTest = re.compile(r":- +begin_tests\(([^,]*)(,.*)?\)")
plEndTest = re.compile(r":- +end_tests\((.*)\)")
plComment = re.compile(r"%!(.*)")
class PLUnit(object):
"""Executes PLUnit code"""
def __init__(self, config, filename, tabname="QuickCheck"):
self.config = config
self.filename = filename
self.testfile = filename + "-slice.pl"
self.lang = config["natural_language"]
self.tabname = tabname
self.result = None
def getResult(self):
if self.result is None:
self.result = self._doTest()
return self.result
def getAnnotations(self):
return None
def getSummary(self):
res = self.getResult()
if res["badgeCount"] == 0:
return "correct"
else:
return "PLUnit: {} issues".format(res["badgeCount"])
def _doTest(self):
""" Splits up the testfile in smaller parts and execute each of them.
The file needs to be split up in order to have results of tests that occur
after a non-terminating one
We create a file
:- style_check(-singleton). % <- these errors are reported by FormCheck
:- style_check(-discontiguous). % <- also reported by FormCheck
:- consult(STUDENT_SOURCE_FILE).
LINES OF ONE plUnit test in the file
Run it and accumulate the results
"""
lines = []
initlines = [
':- style_check(-singleton).\n',
':- style_check(-discontiguous).\n',
'\n',
':- consult("{}").\n'.format(self.config["source"])
]
testname = None
comments = []
contexts = []
numBad = 0
numTests = 0
# Go over the file,
# At :-end_tests the test is executed
for l in fileinput.input(self.filename):
isStart = plBeginTest.match(l)
isEnd = plEndTest.match(l)
isComment = plComment.match(l)
if isStart: # Start of a new test
testname = isStart.group(1)
initlines += [l for l in lines if l.strip()]
lines = [l]
comments = []
elif isEnd: # End of a new test -> Join lines + run
lines.append(l)
# Create test file
with open(self.testfile, 'w') as out:
out.writelines(initlines)
out.writelines(lines)
ctx = self.doRun(self.testfile, testname, comments, lines)
contexts.append(ctx)
numTests += 1
numBad += int(not ctx["accepted"])
testname = None
lines = []
elif isComment:
comments.append(isComment.group(1))
lines.append(l)
else:
lines.append(l)
return {
"accepted": numBad == 0,
"badgeCount": numBad,
"description": self.tabname,
"messages": [{
"format": "markdown",
"description": plUnitInfo[self.lang].format(
numtests=numTests,
failed=numBad)
}],
"groups": contexts
}
def doRun(self, filename, testname, comments, code):
def oh(stdout, stderr, testname, scriptfile, config, timeout):
"""Output handler"""
failedTests = []
if timeout:
failedTests.append({
"accepted": False,
"description": "Timeout " + testname,
"messages": [{
"format": "code",
"description": "The test timed out (5s)!\n\nstdOut:\n" + ("".join(stdout))
}]
})
failedTests += checkErrors(stderr, testname)
failedTests += checkErrors(stdout, testname)
return failedTests
failedTests = swipl(
scriptfile=filename,
testname=testname,
goal="run_tests",
outputHandler=oh,
timeout=5,
config=self.config
)
messages = [{"format": "plain", "description": c} for c in comments]
messages.append({
"format": "prolog",
"description": "".join(code[1:-1])
})
if failedTests:
context = {
"accepted": False,
"description": {
"format": "plain",
"description": testname + ": Failed"
},
"messages": messages,
"groups": failedTests}
else:
context = {
"accepted": True,
"description": {
"format": "plain",
"description": testname + ": Passed"},
"messages": messages,
"groups": [{"accepted": True, "description": "Ok"}]
}
return context