coffeetest.py
4.92 KB
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
import os, os.path, subprocess, re
def walk (root='libs/js') :
for dirpath, dirnames, filenames in os.walk(root) :
for name in filenames :
if name.endswith('.coffee') and not name.startswith(".") :
yield os.path.relpath(os.path.join(dirpath, name), root)
class Test (object) :
def __init__ (self, path, lineno, src, out) :
self.path = path
self.lineno = lineno
self.src = src
self.out = out
@classmethod
def require (cls, root, path) :
base = os.path.splitext(path)[0]
name = os.path.basename(base)
full = os.path.join(".", root, base)
return cls(path, 0, "%s = require %r" % (name, full), [])
@classmethod
def bunch (cls, root, path, bunch) :
return [cls.require(root, path)] + bunch
def codegen (self, out) :
out.write("console.log '+++ %s:%s +++'\n" % (self.path, self.lineno))
out.write(self.src + "\n")
out.write("console.log '--- %s:%s ---'\n" % (self.path, self.lineno))
if self.lineno > 0 :
return "%s:%s" % (self.path, self.lineno)
def _fail (self, out) :
print("\n#### %s:%s" % (self.path, self.lineno))
print("%s" % self.src)
print("## expected:")
print("\n".join(self.out))
print("## obtained:")
print("\n".join(out))
def check (self, out) :
if self.src.startswith and out and out[-1] == "undefined" :
del out[-1]
if out and out[0].startswith("[stdin]:") :
self._fail(out)
return False
elif any("..." in s for s in self.out) :
o = re.sub(r"\s", "", "".join(out))
e = re.sub(r"\s", "", "".join(self.out))
e = re.escape(e).replace(r"\.\.\.", ".*?")
if re.match("^%s$" % e, o) :
return True
else :
self._fail(out)
return False
elif not self.out or out == self.out :
return True
else :
self._fail(out)
return False
def extract (root, path) :
bunch = []
src = delim = None
out = []
for num, line in enumerate(open(os.path.join(root, path))) :
stripped = line.strip()
if stripped == delim :
if src is not None :
bunch.append(Test(path, *src, out))
out, src = [], None
if bunch :
yield Test.bunch(root, path, bunch)
delim = None
bunch = []
elif stripped in ("'''", '"""') :
delim = stripped
elif delim and stripped.startswith("coffee>") :
if src is not None :
bunch.append(Test(path, *src, out))
out, src = [], None
src = (num + 1, stripped[7:].strip())
elif delim :
out.append(stripped)
if bunch :
yield Test.bunch(root, path, bunch)
def codegen (tests, path) :
d = {}
with open(path, "w") as out :
for t in tests :
key = t.codegen(out)
if key :
d[key] = t
return d
def run (src) :
try :
out = subprocess.check_output(["coffee", "-i"],
stdin=open(src),
stderr=subprocess.STDOUT)
out = out.decode().splitlines()
except subprocess.CalledProcessError as err :
out = err.output.decode().splitlines()
for line in out :
while line.startswith("coffee> ") :
line = line[8:]
if line.strip() :
yield line.rstrip()
def check_output (out, tests) :
passed = failed = 0
tid = None
tout = []
skip = False
for line in out :
if skip :
skip = False
elif line.startswith("+++") :
tid = line.split()[1]
tout = []
skip = True
elif line.startswith("---") :
skip = True
assert line.split()[1] == tid
if tid not in tests :
continue
t = tests[tid]
if t.check(tout) :
passed += 1
else :
failed += 1
else :
tout.append(line)
return passed, failed
if __name__ == "__main__" :
root = "libs/js"
passed, failed = 0, 0
nl = False
for path in walk(root) :
base = os.path.basename(os.path.splitext(path)[0])
for num, tests in enumerate(extract(root, path)) :
if nl :
print()
nl = False
print("+ %s: %s tests" % (os.path.join(root, path), len(tests) - 1))
src = ",test-%s-%04u.coffee" % (base, num)
tests = codegen(tests, src)
out = run(src)
p, f = check_output(out, tests)
passed += p
failed += f
nl = f > 0
os.unlink(src)
if failed :
print()
print("= %s tests failed (out of %s)" % (failed, failed+passed))