2 ##########################################################################
4 # Copyright 2011 Jose Fonseca
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:
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
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
25 ##########################################################################/
27 '''Main test driver.'''
40 def popen(command, *args, **kwargs):
41 if kwargs.get('cwd', None) is not None:
42 sys.stdout.write('cd %s && ' % kwargs['cwd'])
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')
49 return subprocess.Popen(command, *args, **kwargs)
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)
60 def _get_build_program(program):
61 if platform.system() == 'Windows':
63 return _get_build_path(program)
81 p = popen(self.cmd, cwd=self.cwd)
84 self.skip('application returned code %i' % p.returncode)
97 if self.trace_file is None:
98 name = os.path.basename(self.cmd[0])
99 self.trace_file = os.path.abspath(os.path.join(self.results, name + '.trace'))
100 if os.path.exists(self.trace_file):
101 os.remove(self.trace_file)
103 trace_dir = os.path.dirname(self.trace_file)
104 if not os.path.exists(trace_dir):
105 os.makedirs(trace_dir)
108 env = os.environ.copy()
110 system = platform.system()
112 if system == 'Windows':
113 wrapper = _get_build_path('wrappers/opengl32.dll')
114 local_wrapper = os.path.join(os.path.dirname(self.cmd[0]), os.path.basename(wrapper))
115 shutil.copy(wrapper, local_wrapper)
116 env['TRACE_FILE'] = self.trace_file
118 apitrace = _get_build_program('apitrace')
121 '--api', self.api_map[self.api],
122 '--output', self.trace_file,
125 if self.max_frames is not None:
126 env['TRACE_FRAMES'] = str(self.max_frames)
129 p = popen(cmd, env=env, cwd=self.cwd)
132 if local_wrapper is not None:
133 os.remove(local_wrapper)
135 if not os.path.exists(self.trace_file):
136 self.fail('no trace file generated\n')
138 call_re = re.compile(r'^([0-9]+) (\w+)\(')
142 cmd = [_get_build_program('apitrace'), 'dump', '--color=never', self.trace_file]
143 p = popen(cmd, stdout=subprocess.PIPE)
150 if self.ref_dump is not None:
151 ref = open(self.ref_dump, 'rt')
152 ref_line = ref.readline().rstrip()
153 for line in p.stdout:
155 sys.stdout.write(line + '\n')
156 mo = self.call_re.match(line)
158 call_no = int(mo.group(1))
159 function_name = mo.group(2)
160 if function_name == 'glXSwapBuffers':
162 if function_name in ('glFlush', 'glFinish'):
164 src_line = line[mo.start(2):]
168 if src_line == ref_line:
169 sys.stdout.write(src_line + '\n')
170 ref_line = ref.readline().rstrip()
173 src_lines.append(src_line)
176 if p.returncode != 0:
177 self.fail('`apitrace dump` returned code %i' % p.returncode)
180 self.fail('missing call `%s` (found `%s`)' % (ref_line, src_lines[0]))
182 self.fail('missing call %s' % ref_line)
185 retrace = self.api_map[self.api] + 'retrace'
186 args = [_get_build_path(retrace)]
187 args += [self.trace_file]
188 p = popen(args, stdout=subprocess.PIPE)
190 if p.returncode != 0:
191 self.fail('`%s` returned code %i' % (retrace, p.returncode))
202 ref_prefix = os.path.abspath(os.path.join(self.results, self.name + '.ref.'))
203 src_prefix = os.path.join(self.results, self.name + '.src.')
204 diff_prefix = os.path.join(self.results, self.name + '.diff.')
207 if not os.path.isfile(trace):
208 sys.stdout.write('SKIP (no trace)\n')
211 retrace = self.api_map[self.api] + 'retrace'
212 args = [_get_build_path(retrace)]
219 args += ['-s', src_prefix]
221 p = popen(args, stdout=subprocess.PIPE)
222 image_re = re.compile(r'^Wrote (.*\.png)$')
224 for line in p.stdout:
226 mo = image_re.match(line)
229 if image.startswith(src_prefix):
230 image = image[len(src_prefix):]
233 if p.returncode != 0:
234 sys.stdout.write('FAIL (glretrace)\n')
238 ref_image = ref_prefix + image
239 src_image = src_prefix + image
240 diff_image = diff_prefix + image
242 if not os.path.isfile(ref_image):
244 assert os.path.isfile(src_image)
246 comparer = Comparer(ref_image, src_image)
247 match = comparer.ae()
248 sys.stdout.write('%s: %s bits\n' % (image, comparer.precision()))
250 comparer.write_diff(diff_image)
251 #report.add_snapshot(ref_image, src_image, diff_image)
252 sys.stdout.write('FAIL (snapshot)\n')
255 def fail(self, reason=None):
256 self._exit('FAIL', 1, reason)
258 def skip(self, reason=None):
259 self._exit('SKIP', 0, reason)
261 def pass_(self, reason=None):
262 self._exit('PASS', 0, reason)
264 def _exit(self, status, code, reason=None):
268 reason = ' (%s)' % reason
269 sys.stdout.write('%s%s\n' % (status, reason))
277 # Parse command line options
278 optparser = optparse.OptionParser(
279 usage='\n\t%prog [options] -- [TRACE|PROGRAM] ...',
281 optparser.add_option(
282 '-a', '--api', metavar='API',
283 type='string', dest='api', default='gl',
285 optparser.add_option(
286 '-B', '--build', metavar='PATH',
287 type='string', dest='build', default='..',
288 help='path to apitrace build')
289 optparser.add_option(
290 '-C', '--directory', metavar='PATH',
291 type='string', dest='cwd', default=None,
292 help='change to directory')
293 optparser.add_option(
294 '-R', '--results', metavar='PATH',
295 type='string', dest='results', default='.',
296 help='results directory [default=%default]')
297 optparser.add_option(
298 '--ref-dump', metavar='PATH',
299 type='string', dest='ref_dump', default=None,
300 help='reference dump')
302 (options, args) = optparser.parse_args(sys.argv[1:])
304 optparser.error('an argument must be specified')
306 if not os.path.exists(options.results):
307 os.makedirs(options.results)
311 if args[0].endswith('.trace'):
312 test.trace_file = args[0]
315 test.cwd = options.cwd
316 test.api = options.api
317 test.ref_dump = options.ref_dump
318 test.results = options.results
323 if __name__ == '__main__':