From b8296ac85e510854e7ad57b02ddba25114b92775 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Sat, 17 Mar 2012 14:13:33 +0000 Subject: [PATCH] Split the driver code. --- driver.py => app_driver.py | 190 ++++++++----------------------------- apps/CMakeLists.txt | 2 +- base_driver.py | 171 +++++++++++++++++++++++++++++++++ tool_driver.py | 145 ++++++++++++++++++++++++++++ traces/CMakeLists.txt | 5 +- traces/zlib-no-eof.ref.txt | 1 + 6 files changed, 361 insertions(+), 153 deletions(-) rename driver.py => app_driver.py (75%) create mode 100644 base_driver.py create mode 100755 tool_driver.py diff --git a/driver.py b/app_driver.py similarity index 75% rename from driver.py rename to app_driver.py index d5789e3..a44bade 100755 --- a/driver.py +++ b/app_driver.py @@ -24,10 +24,9 @@ # ##########################################################################/ -'''Main test driver.''' +'''Application test driver.''' -import optparse import os.path import platform import re @@ -43,93 +42,7 @@ except ImportError: from StringIO import StringIO -def _exit(status, code, reason=None): - if reason is None: - reason = '' - else: - reason = ' (%s)' % reason - sys.stdout.write('%s%s\n' % (status, reason)) - sys.exit(code) - -def fail(reason=None): - _exit('FAIL', 1, reason) - -def skip(reason=None): - _exit('SKIP', 0, reason) - -def pass_(reason=None): - _exit('PASS', 0, reason) - - -def popen(command, *args, **kwargs): - if kwargs.get('cwd', None) is not None: - sys.stdout.write('cd %s && ' % kwargs['cwd']) - - try: - env = kwargs.pop('env') - except KeyError: - env = None - else: - names = env.keys() - names.sort() - for name in names: - value = env[name] - if value != os.environ.get(name, None): - sys.stdout.write('%s=%s ' % (name, value)) - env[name] = str(value) - - sys.stdout.write(' '.join(command) + '\n') - sys.stdout.flush() - - return subprocess.Popen(command, *args, env=env, **kwargs) - - -def which(executable): - dirs = os.environ['PATH'].split(os.path.pathsep) - for dir in dirs: - path = os.path.join(dir, executable) - if os.path.exists(path): - return path - return None - - -def _get_bin_path(): - if os.path.exists(options.apitrace): - apitrace_abspath = os.path.abspath(options.apitrace) - else: - apitrace_abspath = which(options.apitrace) - if apitrace_abspath is None: - sys.stderr.write('error: could not determine the absolute path of\n' % options.apitrace) - sys.exit(1) - return os.path.dirname(apitrace_abspath) - - -def _get_build_program(program): - bin_path = _get_bin_path() - if platform.system() == 'Windows': - program += '.exe' - path = os.path.join(bin_path, program) - if not os.path.exists(path): - sys.stderr.write('error: %s does not exist\n' % path) - sys.exit(1) - return path - -def _get_scripts_path(): - bin_path = _get_bin_path() - - try_paths = [ - 'scripts', - '../lib/scripts', - '../lib/apitrace/scripts', - ] - - for try_path in try_paths: - path = os.path.join(bin_path, try_path) - if os.path.exists(path): - return os.path.abspath(path) - - sys.stderr.write('error: could not find scripts directory\n') - sys.exit(1) +from base_driver import * class TraceChecker: @@ -482,7 +395,7 @@ class TestCase: def _retrace(self, args = None, stdout=subprocess.PIPE): retrace = self.api_map[self.api] + 'retrace' - cmd = [_get_build_program(retrace)] + cmd = [get_build_program(retrace)] if self.doubleBuffer: cmd += ['-db'] else: @@ -501,68 +414,45 @@ class TestCase: pass_() -def main(): - global options - - default_apitrace = 'apitrace' - if platform.system() == 'Windows': - default_apitrace += '.exe' - - # Parse command line options - optparser = optparse.OptionParser( - usage='\n\t%prog [options] -- [TRACE|PROGRAM] ...', - version='%%prog') - optparser.add_option( - '-v', '--verbose', - action="store_true", - dest="verbose", default=False, - help="verbose output") - optparser.add_option( - '-a', '--api', metavar='API', - type='string', dest='api', default='gl', - help='api to trace') - optparser.add_option( - '--apitrace', metavar='PROGRAM', - type='string', dest='apitrace', default=default_apitrace, - help='path to apitrace executable') - optparser.add_option( - '-C', '--directory', metavar='PATH', - type='string', dest='cwd', default=None, - help='change to directory') - optparser.add_option( - '-R', '--results', metavar='PATH', - type='string', dest='results', default='.', - help='results directory [default=%default]') - optparser.add_option( - '--ref-dump', metavar='PATH', - type='string', dest='ref_dump', default=None, - help='reference dump') - - (options, args) = optparser.parse_args(sys.argv[1:]) - if not args: - optparser.error('an argument must be specified') - - if not os.path.exists(options.results): - os.makedirs(options.results) - - print _get_scripts_path() - - sys.path.insert(0, _get_scripts_path()) - - test = TestCase() - test.verbose = options.verbose - - if args[0].endswith('.trace'): - test.trace_file = args[0] - else: +class AppMain(Main): + + def createOptParser(self): + optparser = Main.createOptParser(self) + + optparser.add_option( + '-a', '--api', metavar='API', + type='string', dest='api', default='gl', + help='api to trace') + optparser.add_option( + '-R', '--results', metavar='PATH', + type='string', dest='results', default='.', + help='results directory [default=%default]') + optparser.add_option( + '--ref-dump', metavar='PATH', + type='string', dest='ref_dump', default=None, + help='reference dump') + + return optparser + + def main(self): + global options + + (options, args) = self.parseOptions() + + if not os.path.exists(options.results): + os.makedirs(options.results) + + test = TestCase() + test.verbose = options.verbose + test.cmd = args - test.cwd = options.cwd - test.api = options.api - test.ref_dump = options.ref_dump - test.results = options.results + test.cwd = options.cwd + test.api = options.api + test.ref_dump = options.ref_dump + test.results = options.results - test.run() + test.run() if __name__ == '__main__': - main() + AppMain().main() diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 5736c21..1793709 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -13,7 +13,7 @@ function (ADD_APP_TEST) add_test( NAME app_${TEST_NAME} COMMAND - python ${CMAKE_SOURCE_DIR}/driver.py + python ${CMAKE_SOURCE_DIR}/app_driver.py --apitrace ${APITRACE_EXECUTABLE} --api ${api} --ref-dump ${CMAKE_CURRENT_SOURCE_DIR}/${TEST_REF} diff --git a/base_driver.py b/base_driver.py new file mode 100644 index 0000000..51032bd --- /dev/null +++ b/base_driver.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2011-2012 Jose Fonseca +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +##########################################################################/ + +'''Common test driver code.''' + + +import optparse +import os.path +import platform +import subprocess +import sys + + +def _exit(status, code, reason=None): + if reason is None: + reason = '' + else: + reason = ' (%s)' % reason + sys.stdout.write('%s%s\n' % (status, reason)) + sys.exit(code) + +def fail(reason=None): + _exit('FAIL', 1, reason) + +def skip(reason=None): + _exit('SKIP', 0, reason) + +def pass_(reason=None): + _exit('PASS', 0, reason) + + +def popen(command, *args, **kwargs): + if kwargs.get('cwd', None) is not None: + sys.stdout.write('cd %s && ' % kwargs['cwd']) + + try: + env = kwargs.pop('env') + except KeyError: + env = None + else: + names = env.keys() + names.sort() + for name in names: + value = env[name] + if value != os.environ.get(name, None): + sys.stdout.write('%s=%s ' % (name, value)) + env[name] = str(value) + + sys.stdout.write(' '.join(command) + '\n') + sys.stdout.flush() + + return subprocess.Popen(command, *args, env=env, **kwargs) + + +def which(executable): + dirs = os.environ['PATH'].split(os.path.pathsep) + for dir in dirs: + path = os.path.join(dir, executable) + if os.path.exists(path): + return path + return None + + +def get_bin_path(): + if os.path.exists(options.apitrace): + apitrace_abspath = os.path.abspath(options.apitrace) + else: + apitrace_abspath = which(options.apitrace) + if apitrace_abspath is None: + sys.stderr.write('error: could not determine the absolute path of\n' % options.apitrace) + sys.exit(1) + return os.path.dirname(apitrace_abspath) + + +def get_build_program(program): + bin_path = get_bin_path() + if platform.system() == 'Windows': + program += '.exe' + path = os.path.join(bin_path, program) + if not os.path.exists(path): + sys.stderr.write('error: %s does not exist\n' % path) + sys.exit(1) + return path + + +def get_scripts_path(): + bin_path = get_bin_path() + + try_paths = [ + 'scripts', + '../lib/scripts', + '../lib/apitrace/scripts', + ] + + for try_path in try_paths: + path = os.path.join(bin_path, try_path) + if os.path.exists(path): + return os.path.abspath(path) + + sys.stderr.write('error: could not find scripts directory\n') + sys.exit(1) + + +class Main: + global options + + def createOptParser(self): + default_apitrace = 'apitrace' + if platform.system() == 'Windows': + default_apitrace += '.exe' + + # Parse command line options + optparser = optparse.OptionParser( + usage='\n\t%prog [OPTIONS] -- [ARGS] ...', + version='%%prog') + optparser.add_option( + '-v', '--verbose', + action="store_true", + dest="verbose", default=False, + help="verbose output") + optparser.add_option( + '--apitrace', metavar='PROGRAM', + type='string', dest='apitrace', default=default_apitrace, + help='path to apitrace executable') + optparser.add_option( + '-C', '--directory', metavar='PATH', + type='string', dest='cwd', default=None, + help='change to directory') + + return optparser + + def parseOptions(self): + global options + + optparser = self.createOptParser() + (options, args) = optparser.parse_args(sys.argv[1:]) + if not args: + optparser.error('an argument must be specified') + + print get_scripts_path() + + sys.path.insert(0, get_scripts_path()) + + return options, args + + def main(self): + raise NotImplementedError + diff --git a/tool_driver.py b/tool_driver.py new file mode 100755 index 0000000..63c10af --- /dev/null +++ b/tool_driver.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2011 Jose Fonseca +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +##########################################################################/ + +'''Tool test driver.''' + + +import os.path +import subprocess +import sys + + +from base_driver import * + + +class AsciiComparer: + + def __init__(self, srcStream, refFileName, verbose=False): + self.srcStream = srcStream + self.refFileName = refFileName + if refFileName: + self.refStream = open(refFileName, 'rt') + else: + self.refStream = None + + def readLines(self, stream): + lines = [] + for line in stream: + line = line[:-1] + lines.append(line) + return lines + + def compare(self): + refLines = self.readLines(self.refStream) + srcLines = self.readLines(self.srcStream) + + numLines = max(len(refLines), len(srcLines)) + + for lineNo in xrange(numLines): + try: + refLine = refLines[lineNo] + except IndexError: + fail('unexpected junk: %r' % self.srcLines[lineNo]) + + try: + srcLine = srcLines[lineNo] + except IndexError: + fail('unexpected EOF: %r expected' % refLine) + + if refLine != srcLine: + fail('mismatch: expected %r but got %r' % (refLine ,srcLine)) + + + +class TestCase: + + cmd = None + cwd = None + ref_dump = None + + verbose = False + + def __init__(self): + pass + + def runTool(self): + '''Run the application standalone, skipping this test if it fails by + some reason.''' + + if not self.cmd: + return + + if self.ref_dump: + stdout = subprocess.PIPE + else: + stdout = None + + cmd = [options.apitrace] + self.cmd + p = popen(cmd, cwd=self.cwd, stdout=stdout) + + if self.ref_dump: + comparer = AsciiComparer(p.stdout, self.ref_dump, self.verbose) + comparer.compare() + + p.wait() + if p.returncode != 0: + fail('tool returned code %i' % p.returncode) + + def run(self): + self.runTool() + + pass_() + + +class ToolMain(Main): + + def createOptParser(self): + optparser = Main.createOptParser(self) + + optparser.add_option( + '--ref-dump', metavar='PATH', + type='string', dest='ref_dump', default=None, + help='reference dump') + + return optparser + + def main(self): + global options + + (options, args) = self.parseOptions() + + test = TestCase() + test.verbose = options.verbose + + test.cmd = args + test.cwd = options.cwd + test.ref_dump = options.ref_dump + + test.run() + + +if __name__ == '__main__': + ToolMain().main() diff --git a/traces/CMakeLists.txt b/traces/CMakeLists.txt index e25bc9f..ab18a52 100644 --- a/traces/CMakeLists.txt +++ b/traces/CMakeLists.txt @@ -7,9 +7,10 @@ foreach (trace ${traces}) add_test( NAME trace_${trace} COMMAND - python ${CMAKE_SOURCE_DIR}/driver.py + python ${CMAKE_SOURCE_DIR}/tool_driver.py --apitrace ${APITRACE_EXECUTABLE} --ref-dump ${CMAKE_CURRENT_SOURCE_DIR}/${trace}.ref.txt - ${CMAKE_CURRENT_SOURCE_DIR}/${trace}.trace + -- + dump --call-nos=no ${CMAKE_CURRENT_SOURCE_DIR}/${trace}.trace ) endforeach (trace) diff --git a/traces/zlib-no-eof.ref.txt b/traces/zlib-no-eof.ref.txt index a7cf0a9..acd3858 100644 --- a/traces/zlib-no-eof.ref.txt +++ b/traces/zlib-no-eof.ref.txt @@ -24,4 +24,5 @@ glEnd() glFlush() glFlush() glXSwapBuffers(dpy = 0x1da4360, drawable = 69206018) + glXMakeContextCurrent(dpy = 0x1da4360, draw = 69206018, read = 69206018, ctx = 0x1e1cad0) = True -- 2.43.0