]> git.cworth.org Git - apitrace-tests/blob - driver.py
Test varray variants.
[apitrace-tests] / driver.py
1 #!/usr/bin/env python
2 ##########################################################################
3 #
4 # Copyright 2011 Jose Fonseca
5 # All Rights Reserved.
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 # THE SOFTWARE.
24 #
25 ##########################################################################/
26
27 '''Main test driver.'''
28
29
30 import optparse
31 import os.path
32 import platform
33 import re
34 import shutil
35 import subprocess
36 import sys
37 import time
38
39
40 def popen(command, *args, **kwargs):
41     if kwargs.get('cwd', None) is not None:
42         sys.stdout.write('cd %s && ' % kwargs['cwd'])
43     if 'env' in kwargs:
44         for name, value in kwargs['env'].iteritems():
45             if value != os.environ.get(name, None):
46                 sys.stdout.write('%s=%s ' % (name, value))
47     sys.stdout.write(' '.join(command) + '\n')
48     sys.stdout.flush()
49     return subprocess.Popen(command, *args, **kwargs)
50
51
52 def _get_build_path(path):
53     if options.build is not None:
54         path = os.path.abspath(os.path.join(options.build, path))
55     if not os.path.exists(path):
56         sys.stderr.write('error: %s does not exist\n' % path)
57         sys.exit(1)
58     return path
59
60 def _get_build_program(program):
61     if platform.system() == 'Windows':
62         program += '.exe'
63     return _get_build_path(program)
64
65
66 class TestCase:
67
68     max_frames = None
69
70     trace_file = None
71
72     def __init__(self, name, args, cwd=None, build=None, results = '.'):
73         self.name = name
74         self.args = args
75         self.cwd = cwd
76         self.build = build
77         self.results = results
78
79         if not os.path.exists(results):
80             os.makedirs(results)
81
82     expected_dump = None
83
84     def standalone(self):
85         p = popen(self.args, cwd=self.cwd)
86         p.wait()
87         if p.returncode:
88             self.skip('application returned code %i' % p.returncode)
89
90     def trace(self):
91         if self.trace_file is None:
92             self.trace_file = os.path.abspath(os.path.join(self.results, self.name + '.trace'))
93         if os.path.exists(self.trace_file):
94             os.remove(self.trace_file)
95         else:
96             trace_dir = os.path.dirname(self.trace_file)
97             if not os.path.exists(trace_dir):
98                 os.makedirs(trace_dir)
99
100         cmd = self.args
101         env = os.environ.copy()
102         
103         system = platform.system()
104         local_wrapper = None
105         if system == 'Windows':
106             wrapper = _get_build_path('wrappers/opengl32.dll')
107             local_wrapper = os.path.join(os.path.dirname(self.args[0]), os.path.basename(wrapper))
108             shutil.copy(wrapper, local_wrapper)
109             env['TRACE_FILE'] = self.trace_file
110         else:
111             apitrace = _get_build_program('apitrace')
112             cmd = [
113                 apitrace, 'trace', 
114                 '-o', self.trace_file,
115                 '--'
116             ] + cmd
117         if self.max_frames is not None:
118             env['TRACE_FRAMES'] = str(self.max_frames)
119
120         try:
121             p = popen(cmd, env=env, cwd=self.cwd)
122             p.wait()
123         finally:
124             if local_wrapper is not None:
125                 os.remove(local_wrapper)
126
127         if not os.path.exists(self.trace_file):
128             self.fail('no trace file generated\n')
129     
130     call_re = re.compile(r'^([0-9]+) (\w+)\(')
131
132     def dump(self):
133
134         cmd = [_get_build_program('apitrace'), 'dump', '--color=never', self.trace_file]
135         p = popen(cmd, stdout=subprocess.PIPE)
136
137         swapbuffers = 0
138         flushes = 0
139
140         ref_line = ''
141         src_lines = []
142         if self.ref_dump is not None:
143             ref = open(self.ref_dump, 'rt')
144             ref_line = ref.readline().rstrip()
145         for line in p.stdout:
146             line = line.rstrip()
147             mo = self.call_re.match(line)
148             assert mo
149             if mo:
150                 call_no = int(mo.group(1))
151                 function_name = mo.group(2)
152                 if function_name == 'glXSwapBuffers':
153                     swapbuffers += 1
154                 if function_name in ('glFlush', 'glFinish'):
155                     flushes += 1
156                 src_line = line[mo.start(2):]
157                 if ref_line:
158                     if src_line == ref_line:
159                         sys.stdout.write(src_line + '\n')
160                         ref_line = ref.readline().rstrip()
161                         src_lines = []
162                     else:
163                         src_lines.append(src_line)
164
165         p.wait()
166         if p.returncode != 0:
167             self.fail('`apitrace dump` returned code %i' % p.returncode)
168         if ref_line:
169             if src_lines:
170                 self.fail('missing call `%s` (found `%s`)' % (ref_line, src_lines[0]))
171             else:
172                 self.fail('missing call %s' % ref_line)
173
174     def run(self):
175         self.standalone()
176         self.trace()
177         self.dump()
178
179         self.pass_()
180         return
181
182         ref_prefix = os.path.abspath(os.path.join(self.results, self.name + '.ref.'))
183         src_prefix = os.path.join(self.results, self.name + '.src.')
184         diff_prefix = os.path.join(self.results, self.name + '.diff.')
185
186
187         if not os.path.isfile(trace):
188             sys.stdout.write('SKIP (no trace)\n')
189             return
190         args = [_get_build_path('glretrace')]
191         if swapbuffers:
192             args += ['-db']
193             frames = swapbuffers
194         else:
195             args += ['-sb']
196             frames = flushes
197         args += ['-s', src_prefix]
198         args += [trace]
199         p = popen(args, stdout=subprocess.PIPE)
200         image_re = re.compile(r'^Wrote (.*\.png)$')
201         images = []
202         for line in p.stdout:
203             line = line.rstrip()
204             mo = image_re.match(line)
205             if mo:
206                 image = mo.group(1)
207                 if image.startswith(src_prefix):
208                     image = image[len(src_prefix):]
209                     images.append(image)
210         p.wait()
211         if p.returncode != 0:
212             sys.stdout.write('FAIL (glretrace)\n')
213             return
214
215         for image in images:
216             ref_image = ref_prefix + image
217             src_image = src_prefix + image
218             diff_image = diff_prefix + image
219             
220             if not os.path.isfile(ref_image):
221                 continue
222             assert os.path.isfile(src_image)
223
224             comparer = Comparer(ref_image, src_image)
225             match = comparer.ae()
226             sys.stdout.write('%s: %s bits\n' % (image, comparer.precision()))
227             if not match:
228                 comparer.write_diff(diff_image)
229                 #report.add_snapshot(ref_image, src_image, diff_image)
230                 sys.stdout.write('FAIL (snapshot)\n')
231                 return
232
233     def fail(self, reason=None):
234         self._exit('FAIL', 1, reason)
235
236     def skip(self, reason=None):
237         self._exit('SKIP', 0, reason)
238
239     def pass_(self, reason=None):
240         self._exit('PASS', 0, reason)
241
242     def _exit(self, status, code, reason=None):
243         if reason is None:
244             reason = ''
245         else:
246             reason = ' (%s)' % reason
247         sys.stdout.write('%s%s\n' % (status, reason))
248         sys.exit(code)
249
250
251
252 def main():
253     global options
254
255     # Parse command line options
256     optparser = optparse.OptionParser(
257         usage='\n\t%prog [options] -- program [args] ...',
258         version='%%prog')
259     optparser.add_option(
260         '-B', '--build', metavar='PATH',
261         type='string', dest='build', default='..',
262         help='path to apitrace build')
263     optparser.add_option(
264         '-C', '--directory', metavar='PATH',
265         type='string', dest='cwd', default=None,
266         help='change to directory')
267     optparser.add_option(
268         '-R', '--results', metavar='PATH',
269         type='string', dest='results', default='.',
270         help='results directory [default=%default]')
271     optparser.add_option(
272         '--ref-dump', metavar='PATH',
273         type='string', dest='ref_dump', default=None,
274         help='reference dump')
275
276     (options, args) = optparser.parse_args(sys.argv[1:])
277     if not args:
278         optparser.error('program must be specified')
279
280     test = TestCase(
281         name = os.path.basename(args[0]), 
282         args = args,
283         cwd = options.cwd,
284         build = options.build,
285         results = options.results,
286     )
287     test.ref_dump = options.ref_dump
288
289     test.run()
290
291
292 if __name__ == '__main__':
293     main()