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