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.'''
39 def popen(command, *args, **kwargs):
40 if kwargs.get('cwd', None) is not None:
41 sys.stdout.write('cd %s && ' % kwargs['cwd'])
43 for name, value in kwargs['env'].iteritems():
44 if value != os.environ.get(name, None):
45 sys.stdout.write('%s=%s ' % (name, value))
46 sys.stdout.write(' '.join(command) + '\n')
48 return subprocess.Popen(command, *args, **kwargs)
51 def _get_build_path(path):
52 if options.build is not None:
53 path = os.path.abspath(os.path.join(options.build, path))
54 if not os.path.exists(path):
55 sys.stderr.write('error: %s does not exist\n' % path)
66 def __init__(self, name, args, cwd=None, build=None, results = '.'):
71 self.results = results
73 if not os.path.exists(results):
79 p = popen(self.args, cwd=self.cwd)
82 self.skip('application returned code %i' % p.returncode)
85 if self.trace_file is None:
86 self.trace_file = os.path.abspath(os.path.join(self.results, self.name + '.trace'))
87 if os.path.exists(self.trace_file):
88 os.remove(self.trace_file)
90 trace_dir = os.path.dirname(self.trace_file)
91 if not os.path.exists(trace_dir):
92 os.makedirs(trace_dir)
94 env = os.environ.copy()
96 system = platform.system()
97 if system == 'Windows':
99 self.skip('tracing not supported on Windows')
100 wrapper = _get_build_path('wrappers/opengl32.dll')
101 elif system == 'Darwin':
102 wrapper = _get_build_path('wrappers/OpenGL')
103 env['DYLD_LIBRARY_PATH'] = os.path.dirname(wrapper)
105 wrapper = _get_build_path('glxtrace.so')
106 env['LD_PRELOAD'] = wrapper
108 env['TRACE_FILE'] = self.trace_file
109 if self.max_frames is not None:
110 env['TRACE_FRAMES'] = str(self.max_frames)
112 p = popen(self.args, env=env, cwd=self.cwd)
115 if not os.path.exists(self.trace_file):
116 self.fail('no trace file generated\n')
118 call_re = re.compile(r'^([0-9]+) (\w+)\(')
122 cmd = [_get_build_path('tracedump'), '--color=never', self.trace_file]
123 p = popen(cmd, stdout=subprocess.PIPE)
129 if self.ref_dump is not None:
130 ref = open(self.ref_dump, 'rt')
131 ref_line = ref.readline().rstrip()
132 for line in p.stdout:
134 mo = self.call_re.match(line)
137 call_no = int(mo.group(1))
138 function_name = mo.group(2)
139 if function_name == 'glXSwapBuffers':
141 if function_name in ('glFlush', 'glFinish'):
143 src_line = line[mo.start(2):]
145 if src_line == ref_line:
146 sys.stdout.write(src_line + '\n')
147 ref_line = ref.readline().rstrip()
149 if p.returncode != 0:
150 self.fail('tracedump returned code %i' % p.returncode)
152 self.fail('missing call %s' % ref_line)
162 ref_prefix = os.path.abspath(os.path.join(self.results, self.name + '.ref.'))
163 src_prefix = os.path.join(self.results, self.name + '.src.')
164 diff_prefix = os.path.join(self.results, self.name + '.diff.')
167 if not os.path.isfile(trace):
168 sys.stdout.write('SKIP (no trace)\n')
170 args = [_get_build_path('glretrace')]
177 args += ['-s', src_prefix]
179 p = popen(args, stdout=subprocess.PIPE)
180 image_re = re.compile(r'^Wrote (.*\.png)$')
182 for line in p.stdout:
184 mo = image_re.match(line)
187 if image.startswith(src_prefix):
188 image = image[len(src_prefix):]
191 if p.returncode != 0:
192 sys.stdout.write('FAIL (glretrace)\n')
196 ref_image = ref_prefix + image
197 src_image = src_prefix + image
198 diff_image = diff_prefix + image
200 if not os.path.isfile(ref_image):
202 assert os.path.isfile(src_image)
204 comparer = Comparer(ref_image, src_image)
205 match = comparer.ae()
206 sys.stdout.write('%s: %s bits\n' % (image, comparer.precision()))
208 comparer.write_diff(diff_image)
209 #report.add_snapshot(ref_image, src_image, diff_image)
210 sys.stdout.write('FAIL (snapshot)\n')
213 def fail(self, reason=None):
214 self._exit('FAIL', 1, reason)
216 def skip(self, reason=None):
217 self._exit('SKIP', 0, reason)
219 def pass_(self, reason=None):
220 self._exit('PASS', 0, reason)
222 def _exit(self, status, code, reason=None):
226 reason = ' (%s)' % reason
227 sys.stdout.write('%s%s\n' % (status, reason))
235 # Parse command line options
236 optparser = optparse.OptionParser(
237 usage='\n\t%prog [options] -- program [args] ...',
239 optparser.add_option(
240 '-B', '--build', metavar='PATH',
241 type='string', dest='build', default='..',
242 help='path to apitrace build')
243 optparser.add_option(
244 '-C', '--directory', metavar='PATH',
245 type='string', dest='cwd', default=None,
246 help='change to directory')
247 optparser.add_option(
248 '-R', '--results', metavar='PATH',
249 type='string', dest='results', default='.',
250 help='results directory [default=%default]')
251 optparser.add_option(
252 '--ref-dump', metavar='PATH',
253 type='string', dest='ref_dump', default=None,
254 help='reference dump')
256 (options, args) = optparser.parse_args(sys.argv[1:])
258 optparser.error('program must be specified')
261 name = os.path.basename(args[0]),
264 build = options.build,
265 results = options.results,
267 test.ref_dump = options.ref_dump
272 if __name__ == '__main__':