2912be46e7f3c916d3fb58825164fe2c03e6de5a
[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 import select
29 from optparse import OptionParser
30
31 def check(s):
32     row = None
33     ok = 0
34     for line in s.split("\n"):
35         if line.startswith("[") and line.endswith("]"):
36             continue
37         if not line.strip():
38             continue
39         if not line.startswith("ok"):
40             return 0
41         if line.startswith("ok "):
42             if "/" not in line:
43                 return 0
44             i = line.index('/')
45             nr,len = int(line[3:i]),int(line[i+1:])
46             if nr<1 or nr>len:
47                 return 0
48             if not row:
49                 row = [0]*len
50             if row[nr-1]:
51                 return 0
52             row[nr-1] = 1
53         elif line == "ok":
54             ok = 1
55     if ok:
56         return not row
57     if row:
58         return 0 not in row
59     return 0
60
61 def runcmd(cmd,args,wait):
62     #fo = os.tmpfile()
63     fi,fo = os.pipe()
64     fo = os.fdopen(fo, "wb")
65     p = subprocess.Popen([cmd] + args, executable=cmd, stdout=fo, stderr=fo)
66     ret = -1
67     output = ""
68     for i in range(wait*10):
69         if fi in select.select([fi],[],[], 0.01)[0]:
70             output += os.read(fi, 8192)
71             if "[exit]" in output:
72                 break
73         ret = p.poll()
74         if ret is not None:
75             break
76         time.sleep(0.1)
77     else:
78         os.kill(p.pid, 9)
79         os.system("killall -9 %s >/dev/null 2>/dev/null" % cmd)
80     fo.close()
81    
82     if fi in select.select([fi],[],[], 0.01)[0]:
83         output += os.read(fi, 8192)
84
85     os.close(fi)
86     return ret,output
87
88 class Cache:
89     def __init__(self, filename):
90         try:
91             self.filename2status = marshal.load(open(filename, "rb"))
92         except IOError:
93             self.filename2status = {}
94
95     def parse_args(self):
96         parser = OptionParser()
97         parser.add_option("-d", "--diff", dest="diff", help="Only run tests that failed the last time",action="store_true")
98         (options, args) = parser.parse_args()
99         self.__dict__.update(options.__dict__)
100
101         self.checknum=-1
102         if len(args):
103             self.checknum = int(args[0])
104
105     @staticmethod
106     def load(filename):
107         return Cache(filename)
108
109     def save(self, filename):
110         fi = open(filename, "wb")
111         marshal.dump(self.filename2status, fi)
112         fi.close()
113
114     def highlight(self, nr, filename):
115         return self.checknum==nr
116
117     def skip_file(self, nr, filename):
118         if self.checknum>=0 and nr!=self.checknum:
119             return 1
120         if self.diff and self.filename2status[filename]=="ok":
121             return 1
122         return 0
123
124     def file_status(self, filename, status):
125         self.filename2status[filename] = status
126
127 class TestBase:
128     def __init__(self, nr, file, run):
129         self.nr = nr
130         self.dorun = run
131         self.file = file
132         self.flash_output = None
133         self.flash_error = None
134         self.compile_output = None
135         self.compile_error = None
136
137     def compile(self):
138         try: os.unlink("abc.swf");
139         except: pass
140         ret,output = runcmd("./parser",[self.file],wait=1)
141         self.compile_error = 0
142         self.compile_output = output
143         self.exit_status = 0
144         if ret:
145             self.compile_output += "\nExit status %d" % (-ret)
146             self.exit_status = -ret
147             self.compile_error = 1
148             return 0
149         if not os.path.isfile("abc.swf"):
150             self.compile_error = 1
151             return 0
152         return 1
153
154     def run(self):
155         ret,output = runcmd("flashplayer",["abc.swf"],wait=1)
156         os.system("killall flashplayer")
157         self.flash_output = output
158         
159         if not check(self.flash_output):
160             self.flash_error = 1
161             return 0
162         return 1
163
164     def doprint(self):
165         print self.r(str(self.nr),3)," ",
166         if self.compile_error:
167             if self.dorun:
168                 if self.exit_status == 11:
169                     print "crash"," - ",
170                 else:
171                     print "err  "," - ",
172             else:
173                 print "err  ","   ",
174         else:
175             print "ok   ",
176             if self.dorun:
177                 if not self.flash_error:
178                     print "ok ",
179                 else:
180                     print "err",
181             else:
182                 print "   ",
183         print " ",
184         print self.file
185
186     def doprintlong(self):
187         print self.nr, self.file
188         print "================================"
189         print "compile:", (self.compile_error and "error" or "ok")
190         print self.compile_output
191         if not self.dorun:
192             return
193         print "================================"
194         print "run:", (self.flash_error and "error" or "ok")
195         print self.flash_output
196         print "================================"
197
198     def r(self,s,l):
199         if(len(s)>=l):
200             return s
201         return (" "*(l-len(s))) + s
202     def l(self,s,l):
203         if(len(s)>=l):
204             return s
205         return s + (" "*(l-len(s)))
206
207 class Test(TestBase):
208     def __init__(self, cache, nr, file):
209         TestBase.__init__(self, nr, file, run=1)
210         if self.compile() and self.run():
211             cache.file_status(file, "ok")
212         else:
213             cache.file_status(file, "error")
214
215 class ErrTest(TestBase):
216     def __init__(self, cache, nr, file):
217         TestBase.__init__(self, nr, file, run=0)
218         if self.compile():
219             cache.file_status(file, "error")
220             self.compile_error = True
221         else:
222             cache.file_status(file, "ok")
223             self.compile_error = False
224
225 class Suite:
226     def __init__(self, cache, dir):
227         self.dir = dir
228         self.cache = cache
229         self.errtest = "err" in dir
230     def run(self, nr):
231         print "-"*40,"tests \""+self.dir+"\"","-"*40
232         for file in sorted(os.listdir(self.dir)):
233             if not file.endswith(".as"):
234                 continue
235             nr = nr + 1
236             file = os.path.join(self.dir, file)
237
238             if cache.skip_file(nr, file):
239                 continue
240
241             if self.errtest:
242                 test = ErrTest(cache, nr, file)
243             else:
244                 test = Test(cache, nr, file)
245
246             if not cache.highlight(nr, file):
247                 test.doprint()
248             else:
249                 test.doprintlong()
250         return nr
251
252 cache = Cache.load(".tests.cache")
253 cache.parse_args()
254
255 nr = 0
256 #nr = Suite(cache, "err").run(nr)
257 nr = Suite(cache, "ok").run(nr)
258
259 cache.save(".tests.cache")