added comments about how to enable bison's debug output
[swftools.git] / lib / as3 / runtests.py
1 #!/usr/bin/python
2 #
3 # runtests.py
4 #
5 # Run compiler unit tests
6 #
7 # Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
8 #
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
22
23 import sys
24 import os
25 import time
26 import subprocess
27 import marshal
28 from optparse import OptionParser
29
30 def check(s):
31     row = None
32     ok = 0
33     for line in s.split("\n"):
34         if line.startswith("[") and line.endswith("]"):
35             continue
36         if not line.strip():
37             continue
38         if not line.startswith("ok"):
39             return 0
40         if line.startswith("ok "):
41             if "/" not in line:
42                 return 0
43             i = line.index('/')
44             nr,len = int(line[3:i]),int(line[i+1:])
45             if nr<1 or nr>len:
46                 return 0
47             if not row:
48                 row = [0]*len
49             if row[nr-1]:
50                 return 0
51             row[nr-1] = 1
52         elif line == "ok":
53             ok = 1
54     if ok:
55         return not row
56     if row:
57         return 0 not in row
58     return 0
59
60 def runcmd(cmd,args,wait):
61     #fo = open(tempfile, "wb")
62     fo= os.tmpfile()
63     p = subprocess.Popen([cmd] + args, executable=cmd, stdout=fo, stderr=fo)
64     ret = -1
65     for i in range(wait*10):
66         ret = p.poll()
67         if ret is not None:
68             break
69         time.sleep(0.1)
70     else:
71         os.kill(p.pid, 9)
72         os.system("killall -9 "+cmd)
73   
74     fo.seek(0)
75     output = fo.read()
76     fo.close()
77     return ret,output
78
79 class Cache:
80     def __init__(self, filename):
81         try:
82             self.filename2status = marshal.load(open(filename, "rb"))
83         except IOError:
84             self.filename2status = {}
85
86     def parse_args(self):
87         parser = OptionParser()
88         parser.add_option("-d", "--diff", dest="diff", help="Only run tests that failed the last time",action="store_true")
89         (options, args) = parser.parse_args()
90         self.__dict__.update(options.__dict__)
91
92         self.checknum=-1
93         if len(args):
94             self.checknum = int(args[0])
95
96     @staticmethod
97     def load(filename):
98         return Cache(filename)
99
100     def save(self, filename):
101         fi = open(filename, "wb")
102         marshal.dump(self.filename2status, fi)
103         fi.close()
104
105     def highlight(self, nr, filename):
106         return self.checknum==nr
107
108     def skip_file(self, nr, filename):
109         if self.checknum>=0 and nr!=self.checknum:
110             return 1
111         if self.diff and self.filename2status[filename]=="ok":
112             return 1
113         return 0
114
115     def file_status(self, filename, status):
116         self.filename2status[filename] = status
117
118 class TestBase:
119     def __init__(self, nr, file, run):
120         self.nr = nr
121         self.dorun = run
122         self.file = file
123         self.flash_output = None
124         self.flash_error = None
125         self.compile_output = None
126         self.compile_error = None
127
128     def compile(self):
129         try: os.unlink("abc.swf");
130         except: pass
131         ret,output = runcmd("./parser",[self.file],wait=60)
132         self.compile_error = 0
133         self.compile_output = output
134         if ret:
135             self.compile_error = 1
136             return 0
137         if not os.path.isfile("abc.swf"):
138             self.compile_error = 1
139             return 0
140         return 1
141
142     def run(self):
143         ret,output = runcmd("flashplayer",["abc.swf"],wait=1)
144         os.system("killall flashplayer")
145         self.flash_output = output
146         
147         if not check(self.flash_output):
148             self.flash_error = 1
149             return 0
150         return 1
151
152     def doprint(self):
153         print self.r(str(self.nr),3)," ",
154         if self.compile_error:
155             if self.dorun:
156                 print "err"," - ",
157             else:
158                 print "err","   ",
159         else:
160             print "ok ",
161             if self.dorun:
162                 if not self.flash_error:
163                     print "ok ",
164                 else:
165                     print "err",
166             else:
167                 print "   ",
168         print " ",
169         print self.file
170
171     def doprintlong(self):
172         print self.nr, self.file
173         print "================================"
174         print "compile:", (test.compile_error and "error" or "ok")
175         print test.compile_output
176         if not self.dorun:
177             return
178         print "================================"
179         print "run:", (test.flash_error and "error" or "ok")
180         print test.flash_output
181         print "================================"
182
183     def r(self,s,l):
184         if(len(s)>=l):
185             return s
186         return (" "*(l-len(s))) + s
187     def l(self,s,l):
188         if(len(s)>=l):
189             return s
190         return s + (" "*(l-len(s)))
191
192 class Test(TestBase):
193     def __init__(self, cache, nr, file):
194         TestBase.__init__(self, nr, file, run=1)
195         if self.compile() and self.run():
196             cache.file_status(file, "ok")
197         else:
198             cache.file_status(file, "error")
199
200 class ErrTest(TestBase):
201     def __init__(self, cache, nr, file):
202         TestBase.__init__(self, nr, file, run=0)
203         if self.compile():
204             cache.file_status(file, "error")
205             self.compile_error = True
206         else:
207             cache.file_status(file, "ok")
208             self.compile_error = False
209
210 class Suite:
211     def __init__(self, cache, dir):
212         self.dir = dir
213         self.cache = cache
214         self.errtest = "err" in dir
215     def run(self, nr):
216         print "-"*40,"tests \""+self.dir+"\"","-"*40
217         for file in sorted(os.listdir(self.dir)):
218             if not file.endswith(".as"):
219                 continue
220             nr = nr + 1
221             file = os.path.join(self.dir, file)
222
223             if cache.skip_file(nr, file):
224                 continue
225
226             if self.errtest:
227                 test = ErrTest(cache, nr, file)
228             else:
229                 test = Test(cache, nr, file)
230
231             if not cache.highlight(nr, file):
232                 test.doprint()
233             else:
234                 test.doprintlong()
235         return nr
236
237 cache = Cache.load(".tests.cache")
238 cache.parse_args()
239
240 nr = 0
241 nr = Suite(cache, "err").run(nr)
242 nr = Suite(cache, "ok").run(nr)
243
244 cache.save(".tests.cache")