new memberinfo field subfunctions
[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=60)
141         self.compile_error = 0
142         self.compile_output = output
143         if ret:
144             self.compile_output += "\nExit status %d" % (-ret)
145             self.compile_error = 1
146             return 0
147         if not os.path.isfile("abc.swf"):
148             self.compile_error = 1
149             return 0
150         return 1
151
152     def run(self):
153         ret,output = runcmd("flashplayer",["abc.swf"],wait=1)
154         os.system("killall flashplayer")
155         self.flash_output = output
156         
157         if not check(self.flash_output):
158             self.flash_error = 1
159             return 0
160         return 1
161
162     def doprint(self):
163         print self.r(str(self.nr),3)," ",
164         if self.compile_error:
165             if self.dorun:
166                 print "err"," - ",
167             else:
168                 print "err","   ",
169         else:
170             print "ok ",
171             if self.dorun:
172                 if not self.flash_error:
173                     print "ok ",
174                 else:
175                     print "err",
176             else:
177                 print "   ",
178         print " ",
179         print self.file
180
181     def doprintlong(self):
182         print self.nr, self.file
183         print "================================"
184         print "compile:", (self.compile_error and "error" or "ok")
185         print self.compile_output
186         if not self.dorun:
187             return
188         print "================================"
189         print "run:", (self.flash_error and "error" or "ok")
190         print self.flash_output
191         print "================================"
192
193     def r(self,s,l):
194         if(len(s)>=l):
195             return s
196         return (" "*(l-len(s))) + s
197     def l(self,s,l):
198         if(len(s)>=l):
199             return s
200         return s + (" "*(l-len(s)))
201
202 class Test(TestBase):
203     def __init__(self, cache, nr, file):
204         TestBase.__init__(self, nr, file, run=1)
205         if self.compile() and self.run():
206             cache.file_status(file, "ok")
207         else:
208             cache.file_status(file, "error")
209
210 class ErrTest(TestBase):
211     def __init__(self, cache, nr, file):
212         TestBase.__init__(self, nr, file, run=0)
213         if self.compile():
214             cache.file_status(file, "error")
215             self.compile_error = True
216         else:
217             cache.file_status(file, "ok")
218             self.compile_error = False
219
220 class Suite:
221     def __init__(self, cache, dir):
222         self.dir = dir
223         self.cache = cache
224         self.errtest = "err" in dir
225     def run(self, nr):
226         print "-"*40,"tests \""+self.dir+"\"","-"*40
227         for file in sorted(os.listdir(self.dir)):
228             if not file.endswith(".as"):
229                 continue
230             nr = nr + 1
231             file = os.path.join(self.dir, file)
232
233             if cache.skip_file(nr, file):
234                 continue
235
236             if self.errtest:
237                 test = ErrTest(cache, nr, file)
238             else:
239                 test = Test(cache, nr, file)
240
241             if not cache.highlight(nr, file):
242                 test.doprint()
243             else:
244                 test.doprintlong()
245         return nr
246
247 cache = Cache.load(".tests.cache")
248 cache.parse_args()
249
250 nr = 0
251 nr = Suite(cache, "err").run(nr)
252 nr = Suite(cache, "ok").run(nr)
253
254 cache.save(".tests.cache")