2 TestSCons.py: a testing framework for the SCons software construction
5 A TestSCons environment object is created via the usual invocation:
9 TestScons is a subclass of TestCommon, which is in turn is a subclass
10 of TestCmd), and hence has available all of the methods and attributes
11 from those classes, as well as any overridden or additional methods or
12 attributes defined in this subclass.
17 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
29 except AttributeError:
32 for i in xrange(len(lists[0])):
33 result.append(tuple(map(lambda l, i=i: l[i], lists)))
37 from TestCommon import *
38 from TestCommon import __all__
40 # Some tests which verify that SCons has been packaged properly need to
41 # look for specific version file names. Replicating the version number
42 # here provides some independent verification that what we packaged
43 # conforms to what we expect.
45 default_version = '0.98.5'
47 copyright_years = '2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008'
49 # In the checked-in source, the value of SConsVersion in the following
50 # line must remain "__ VERSION __" (without the spaces) so the built
51 # version in build/QMTest/TestSCons.py contains the actual version
52 # string of the packages that have been built.
53 SConsVersion = '__VERSION__'
54 if SConsVersion == '__' + 'VERSION' + '__':
55 SConsVersion = default_version
57 __all__.extend([ 'TestSCons',
78 except AttributeError:
79 # Windows doesn't have a uname() function. We could use something like
80 # sys.platform as a fallback, but that's not really a "machine," so
81 # just leave it as None.
85 machine = machine_map.get(machine, machine)
87 python = python_executable
88 _python_ = '"' + python_executable + '"'
99 """Test whether -lfrtbegin is required. This can probably be done in
100 a more reliable way, but using popen3 is relatively efficient."""
106 stderr = popen2.popen3('gcc -v')[2]
110 for l in stderr.readlines():
111 list = string.split(l)
112 if len(list) > 3 and list[:2] == ['gcc', 'version']:
113 if list[2][:2] in ('3.', '4.'):
114 libs = ['frtbegin'] + libs
119 if sys.platform == 'cygwin':
120 # On Cygwin, os.path.normcase() lies, so just report back the
121 # fact that the underlying Win32 OS is case-insensitive.
122 def case_sensitive_suffixes(s1, s2):
125 def case_sensitive_suffixes(s1, s2):
126 return (os.path.normcase(s1) != os.path.normcase(s2))
129 if sys.platform == 'win32':
130 fortran_lib = gccFortranLibs()
131 elif sys.platform == 'cygwin':
132 fortran_lib = gccFortranLibs()
133 elif string.find(sys.platform, 'irix') != -1:
134 fortran_lib = ['ftn']
136 fortran_lib = gccFortranLibs()
140 file_expr = r"""File "[^"]*", line \d+, in .+
143 # re.escape escapes too much.
145 for c in ['.', '[', ']', '(', ')', '*', '+', '?']: # Not an exhaustive list.
146 str = string.replace(str, c, '\\' + c)
153 except AttributeError:
154 # Pre-1.6 Python has no sys.version_info
155 version_string = string.split(sys.version)[0]
156 version_ints = map(int, string.split(version_string, '.'))
157 sys.version_info = tuple(version_ints + ['final', 0])
159 def python_version_string():
160 return string.split(sys.version)[0]
162 def python_minor_version_string():
163 return sys.version[:3]
165 def unsupported_python_version(version=sys.version_info):
166 return version < (1, 5, 2)
168 def deprecated_python_version(version=sys.version_info):
169 return version < (2, 2, 0)
171 if deprecated_python_version():
173 scons: warning: Support for pre-2.2 Python (%s) is deprecated.
174 If this will cause hardship, contact dev@scons.tigris.org.
177 deprecated_python_expr = re_escape(msg % python_version_string()) + file_expr
180 deprecated_python_expr = ""
184 class TestSCons(TestCommon):
185 """Class for testing SCons.
187 This provides a common place for initializing SCons tests,
188 eliminating the need to begin every test with the same repeated
192 scons_version = SConsVersion
194 def __init__(self, **kw):
195 """Initialize an SCons testing object.
197 If they're not overridden by keyword arguments, this
198 initializes the object with the following default values:
200 program = 'scons' if it exists,
202 interpreter = 'python'
206 The workdir value means that, by default, a temporary workspace
207 directory is created for a TestSCons environment. In addition,
208 this method changes directory (chdir) to the workspace directory,
209 so an explicit "chdir = '.'" on all of the run() method calls
212 self.orig_cwd = os.getcwd()
214 script_dir = os.environ['SCONS_SCRIPT_DIR']
219 if not kw.has_key('program'):
220 kw['program'] = os.environ.get('SCONS')
221 if not kw['program']:
222 if os.path.exists('scons'):
223 kw['program'] = 'scons'
225 kw['program'] = 'scons.py'
226 if not kw.has_key('interpreter') and not os.environ.get('SCONS_EXEC'):
227 kw['interpreter'] = [python, '-tt']
228 if not kw.has_key('match'):
229 kw['match'] = match_exact
230 if not kw.has_key('workdir'):
233 # Term causing test failures due to bogus readline init
234 # control character output on FC8
235 # TERM can cause test failures due to control chars in prompts etc.
236 os.environ['TERM'] = 'dumb'
238 if deprecated_python_version():
239 sconsflags = os.environ.get('SCONSFLAGS')
241 sconsflags = [sconsflags]
244 sconsflags = sconsflags + ['--warn=no-python-version']
245 os.environ['SCONSFLAGS'] = string.join(sconsflags)
247 apply(TestCommon.__init__, [self], kw)
250 if SCons.Node.FS.default_fs is None:
251 SCons.Node.FS.default_fs = SCons.Node.FS.FS()
253 def Environment(self, ENV=None, *args, **kw):
255 Return a construction Environment that optionally overrides
256 the default external environment with the specified ENV.
258 import SCons.Environment
263 return apply(SCons.Environment.Environment, args, kw)
264 except (SCons.Errors.UserError, SCons.Errors.InternalError):
267 def detect(self, var, prog=None, ENV=None, norm=None):
269 Detect a program named 'prog' by first checking the construction
270 variable named 'var' and finally searching the path used by
271 SCons. If either method fails to detect the program, then false
272 is returned, otherwise the full path to prog is returned. If
273 prog is None, then the value of the environment variable will be
276 env = self.Environment(ENV)
277 v = env.subst('$'+var)
284 result = env.WhereIs(prog)
285 if norm and os.sep != '/':
286 result = string.replace(result, os.sep, '/')
289 def detect_tool(self, tool, prog=None, ENV=None):
291 Given a tool (i.e., tool specification that would be passed
292 to the "tools=" parameter of Environment()) and a program that
293 corresponds to that tool, return true if and only if we can find
294 that tool using Environment.Detect().
296 By default, prog is set to the value passed into the tools parameter.
301 env = self.Environment(ENV, tools=[tool])
304 return env.Detect([prog])
306 def where_is(self, prog, path=None):
308 Given a program, search for it in the specified external PATH,
309 or in the actual external PATH is none is specified.
311 import SCons.Environment
312 env = SCons.Environment.Environment()
314 path = os.environ['PATH']
315 return env.WhereIs(prog, path)
317 def wrap_stdout(self, build_str = "", read_str = "", error = 0, cleaning = 0):
318 """Wraps standard output string(s) in the normal
319 "Reading ... done" and "Building ... done" strings
321 cap,lc = [ ('Build','build'),
322 ('Clean','clean') ][cleaning]
324 term = "scons: %sing terminated because of errors.\n" % lc
326 term = "scons: done %sing targets.\n" % lc
327 return "scons: Reading SConscript files ...\n" + \
329 "scons: done reading SConscript files.\n" + \
330 "scons: %sing targets ...\n" % cap + \
334 def up_to_date(self, options = None, arguments = None, read_str = "", **kw):
336 for arg in string.split(arguments):
337 s = s + "scons: `%s' is up to date.\n" % arg
339 arguments = options + " " + arguments
340 kw['arguments'] = arguments
341 stdout = self.wrap_stdout(read_str = read_str, build_str = s)
342 kw['stdout'] = re.escape(stdout)
343 kw['match'] = self.match_re_dotall
344 apply(self.run, [], kw)
346 def not_up_to_date(self, options = None, arguments = None, **kw):
347 """Asserts that none of the targets listed in arguments is
348 up to date, but does not make any assumptions on other targets.
349 This function is most useful in conjunction with the -n option.
352 for arg in string.split(arguments):
353 s = s + "(?!scons: `%s' is up to date.)" % re.escape(arg)
355 arguments = options + " " + arguments
356 s = '('+s+'[^\n]*\n)*'
357 kw['arguments'] = arguments
358 stdout = re.escape(self.wrap_stdout(build_str='ARGUMENTSGOHERE'))
359 kw['stdout'] = string.replace(stdout, 'ARGUMENTSGOHERE', s)
360 kw['match'] = self.match_re_dotall
361 apply(self.run, [], kw)
363 def diff_substr(self, expect, actual, prelen=20, postlen=40):
365 for x, y in zip(expect, actual):
367 return "Actual did not match expect at char %d:\n" \
370 % (i, repr(expect[i-prelen:i+postlen]),
371 repr(actual[i-prelen:i+postlen]))
373 return "Actual matched the expected output???"
375 def python_file_line(self, file, line):
377 Returns a Python error line for output comparisons.
379 The exec of the traceback line gives us the correct format for
380 this version of Python. Before 2.5, this yielded:
382 File "<string>", line 1, ?
384 Python 2.5 changed this to:
386 File "<string>", line 1, <module>
388 We stick the requested file name and line number in the right
389 places, abstracting out the version difference.
391 exec 'import traceback; x = traceback.format_stack()[-1]'
393 x = string.replace(x, '<string>', file)
394 x = string.replace(x, 'line 1,', 'line %s,' % line)
397 def normalize_pdf(self, s):
398 s = re.sub(r'/(Creation|Mod)Date \(D:[^)]*\)',
399 r'/\1Date (D:XXXX)', s)
400 s = re.sub(r'/ID \[<[0-9a-fA-F]*> <[0-9a-fA-F]*>\]',
401 r'/ID [<XXXX> <XXXX>]', s)
402 s = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}',
404 s = re.sub(r'/Length \d+ *\n/Filter /FlateDecode\n',
405 r'/Length XXXX\n/Filter /FlateDecode\n', s)
413 begin_marker = '/FlateDecode\n>>\nstream\n'
414 end_marker = 'endstream\nendobj'
417 b = string.find(s, begin_marker, 0)
419 b = b + len(begin_marker)
420 e = string.find(s, end_marker, b)
421 encoded.append((b, e))
422 b = string.find(s, begin_marker, e + len(end_marker))
428 d = zlib.decompress(s[b:e])
429 d = re.sub(r'%%CreationDate: [^\n]*\n',
430 r'%%CreationDate: 1970 Jan 01 00:00:00\n', d)
431 d = re.sub(r'%DVIPSSource: TeX output \d\d\d\d\.\d\d\.\d\d:\d\d\d\d',
432 r'%DVIPSSource: TeX output 1970.01.01:0000', d)
433 d = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}',
438 s = string.join(r, '')
442 def paths(self,patterns):
452 def java_ENV(self, version=None):
454 Initialize with a default external environment that uses a local
455 Java SDK in preference to whatever's found in the default PATH.
458 return self._java_env[version]['ENV']
459 except AttributeError:
464 import SCons.Environment
465 env = SCons.Environment.Environment()
466 self._java_env[version] = env
471 '/usr/java/jdk%s*/bin' % version,
472 '/usr/lib/jvm/*-%s*/bin' % version,
473 '/usr/local/j2sdk%s*/bin' % version,
475 java_path = self.paths(patterns) + [env['ENV']['PATH']]
478 '/usr/java/latest/bin',
479 '/usr/lib/jvm/*/bin',
480 '/usr/local/j2sdk*/bin',
482 java_path = self.paths(patterns) + [env['ENV']['PATH']]
484 env['ENV']['PATH'] = string.join(java_path, os.pathsep)
487 def java_where_includes(self,version=None):
489 Return java include paths compiling java jni code
495 jni_dirs = ['/usr/lib/jvm/java-*-sun-%s*/include/jni.h'%version,
496 '/usr/java/jdk%s*/include/jni.h'%version,
498 dirs = self.paths(jni_dirs)
501 d=os.path.dirname(self.paths(jni_dirs)[0])
504 if sys.platform == 'win32':
505 result.append(os.path.join(d,'win32'))
506 elif sys.platform == 'linux2':
507 result.append(os.path.join(d,'linux'))
511 def java_where_java_home(self,version=None):
513 jar=self.java_where_jar(version)
514 home=os.path.normpath('%s/..'%jar)
517 def java_where_jar(self, version=None):
518 ENV = self.java_ENV(version)
519 if self.detect_tool('jar', ENV=ENV):
520 where_jar = self.detect('JAR', 'jar', ENV=ENV)
522 where_jar = self.where_is('jar', ENV['PATH'])
524 self.skip_test("Could not find Java jar, skipping test(s).\n")
527 def java_where_java(self, version=None):
529 Return a path to the java executable.
531 ENV = self.java_ENV(version)
532 where_java = self.where_is('java', ENV['PATH'])
534 self.skip_test("Could not find Java java, skipping test(s).\n")
537 def java_where_javac(self, version=None):
539 Return a path to the javac compiler.
541 ENV = self.java_ENV(version)
542 if self.detect_tool('javac'):
543 where_javac = self.detect('JAVAC', 'javac', ENV=ENV)
545 where_javac = self.where_is('javac', ENV['PATH'])
547 self.skip_test("Could not find Java javac, skipping test(s).\n")
548 self.run(program = where_javac,
549 arguments = '-version',
553 if string.find(self.stderr(), 'javac %s' % version) == -1:
554 fmt = "Could not find javac for Java version %s, skipping test(s).\n"
555 self.skip_test(fmt % version)
557 m = re.search(r'javac (\d\.\d)', self.stderr())
562 return where_javac, version
564 def java_where_javah(self, version=None):
565 ENV = self.java_ENV(version)
566 if self.detect_tool('javah'):
567 where_javah = self.detect('JAVAH', 'javah', ENV=ENV)
569 where_javah = self.where_is('javah', ENV['PATH'])
571 self.skip_test("Could not find Java javah, skipping test(s).\n")
574 def java_where_rmic(self, version=None):
575 ENV = self.java_ENV(version)
576 if self.detect_tool('rmic'):
577 where_rmic = self.detect('RMIC', 'rmic', ENV=ENV)
579 where_rmic = self.where_is('rmic', ENV['PATH'])
581 self.skip_test("Could not find Java rmic, skipping non-simulated test(s).\n")
584 def Qt_dummy_installation(self, dir='qt'):
585 # create a dummy qt installation
587 self.subdir( dir, [dir, 'bin'], [dir, 'include'], [dir, 'lib'] )
589 self.write([dir, 'bin', 'mymoc.py'], """\
594 cmd_opts, args = getopt.getopt(sys.argv[1:], 'io:', [])
598 for opt, arg in cmd_opts:
599 if opt == '-o': output = open(arg, 'wb')
600 elif opt == '-i': impl = 1
601 else: opt_string = opt_string + ' ' + opt
603 contents = open(a, 'rb').read()
604 a = string.replace(a, '\\\\', '\\\\\\\\')
605 subst = r'{ my_qt_symbol( "' + a + '\\\\n" ); }'
607 contents = re.sub( r'#include.*', '', contents )
608 output.write(string.replace(contents, 'Q_OBJECT', subst))
613 self.write([dir, 'bin', 'myuic.py'], """\
622 for arg in sys.argv[1:]:
624 output = open(arg, 'wb')
636 source = open(arg, 'rb')
639 output.write( '#include "' + impl + '"\\n' )
640 includes = re.findall('<include.*?>(.*?)</include>', source.read())
641 for incFile in includes:
642 # this is valid for ui.h files, at least
643 if os.path.exists(incFile):
644 output.write('#include "' + incFile + '"\\n')
646 output.write( '#include "my_qobject.h"\\n' + source.read() + " Q_OBJECT \\n" )
651 self.write([dir, 'include', 'my_qobject.h'], r"""
653 void my_qt_symbol(const char *arg);
656 self.write([dir, 'lib', 'my_qobject.cpp'], r"""
657 #include "../include/my_qobject.h"
659 void my_qt_symbol(const char *arg) {
664 self.write([dir, 'lib', 'SConstruct'], r"""
667 if sys.platform == 'win32':
668 env.StaticLibrary( 'myqt', 'my_qobject.cpp' )
670 env.SharedLibrary( 'myqt', 'my_qobject.cpp' )
673 self.run(chdir = self.workpath(dir, 'lib'),
676 match = self.match_re_dotall)
678 self.QT = self.workpath(dir)
680 self.QT_MOC = '%s %s' % (_python_, self.workpath(dir, 'bin', 'mymoc.py'))
681 self.QT_UIC = '%s %s' % (_python_, self.workpath(dir, 'bin', 'myuic.py'))
682 self.QT_LIB_DIR = self.workpath(dir, 'lib')
684 def Qt_create_SConstruct(self, place):
685 if type(place) is type([]):
686 place = apply(test.workpath, place)
687 self.write(place, """\
688 if ARGUMENTS.get('noqtdir', 0): QTDIR=None
690 env = Environment(QTDIR = QTDIR,
694 tools=['default','qt'])
696 if ARGUMENTS.get('variant_dir', 0):
697 if ARGUMENTS.get('chdir', 0):
701 dup=int(ARGUMENTS.get('dup', 1))
703 builddir = 'build_dup0'
707 VariantDir(builddir, '.', duplicate=dup)
709 sconscript = Dir(builddir).File('SConscript')
711 sconscript = File('SConscript')
713 SConscript( sconscript )
714 """ % (self.QT, self.QT_LIB, self.QT_MOC, self.QT_UIC))
716 def msvs_versions(self):
717 if not hasattr(self, '_msvs_versions'):
719 # Determine the SCons version and the versions of the MSVS
720 # environments installed on the test machine.
722 # We do this by executing SCons with an SConstruct file
723 # (piped on stdin) that spits out Python assignments that
724 # we can just exec(). We construct the SCons.__"version"__
725 # string in the input here so that the SCons build itself
726 # doesn't fill it in when packaging SCons.
729 print "self._scons_version =", repr(SCons.__%s__)
731 print "self._msvs_versions =", str(env['MSVS']['VERSIONS'])
734 self.run(arguments = '-n -q -Q -f -', stdin = input)
737 return self._msvs_versions
739 def vcproj_sys_path(self, fname):
742 orig = 'sys.path = [ join(sys'
744 enginepath = repr(os.path.join(self._cwd, '..', 'engine'))
745 replace = 'sys.path = [ %s, join(sys' % enginepath
747 contents = self.read(fname)
748 contents = string.replace(contents, orig, replace)
749 self.write(fname, contents)
751 def msvs_substitute(self, input, msvs_ver,
752 subdir=None, sconscript=None,
753 python=sys.executable,
755 if not hasattr(self, '_msvs_versions'):
759 workpath = self.workpath(subdir)
761 workpath = self.workpath()
763 if sconscript is None:
764 sconscript = self.workpath('SConstruct')
766 if project_guid is None:
767 project_guid = "{E5466E26-0003-F18B-8F8A-BCD76C86388D}"
769 if os.environ.has_key('SCONS_LIB_DIR'):
770 exec_script_main = "from os.path import join; import sys; sys.path = [ r'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % os.environ['SCONS_LIB_DIR']
772 exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-%s'), join(sys.prefix, 'scons-%s'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" % (self._scons_version, self._scons_version)
773 exec_script_main_xml = string.replace(exec_script_main, "'", "'")
775 result = string.replace(input, r'<WORKPATH>', workpath)
776 result = string.replace(result, r'<PYTHON>', python)
777 result = string.replace(result, r'<SCONSCRIPT>', sconscript)
778 result = string.replace(result, r'<SCONS_SCRIPT_MAIN>', exec_script_main)
779 result = string.replace(result, r'<SCONS_SCRIPT_MAIN_XML>', exec_script_main_xml)
780 result = string.replace(result, r'<PROJECT_GUID>', project_guid)
783 def get_msvs_executable(self, version):
784 """Returns a full path to the executable (MSDEV or devenv)
785 for the specified version of Visual Studio.
787 common_msdev98_bin_msdev_com = ['Common', 'MSDev98', 'Bin', 'MSDEV.COM']
788 common7_ide_devenv_com = ['Common7', 'IDE', 'devenv.com']
789 common7_ide_vcexpress_exe = ['Common7', 'IDE', 'VCExpress.exe']
792 common_msdev98_bin_msdev_com,
795 common7_ide_devenv_com,
798 common7_ide_devenv_com,
801 common7_ide_devenv_com,
802 common7_ide_vcexpress_exe,
805 from SCons.Tool.msvs import get_msvs_install_dirs
806 vs_path = get_msvs_install_dirs(version)['VSINSTALLDIR']
807 for sp in sub_paths[version]:
808 p = apply(os.path.join, [vs_path] + sp)
809 if os.path.exists(p):
811 return apply(os.path.join, [vs_path] + sub_paths[version][0])
814 NCR = 0 # non-cached rebuild
815 CR = 1 # cached rebuild (up to date)
816 NCF = 2 # non-cached build failure
817 CF = 3 # cached build failure
819 if sys.platform == 'win32':
820 Configure_lib = 'msvcrt'
824 # to use cygwin compilers on cmd.exe -> uncomment following line
827 def checkLogAndStdout(self, checks, results, cached,
828 logfile, sconf_dir, sconstruct,
829 doCheckLog=1, doCheckStdout=1):
832 def __init__(self, p):
835 def matchPart(log, logfile, lastEnd, NoMatch=NoMatch):
836 m = re.match(log, logfile[lastEnd:])
838 raise NoMatch, lastEnd
839 return m.end() + lastEnd
841 #print len(os.linesep)
844 for i in range(len(ls)):
848 nols = nols + "[^" + ls[i] + "])"
853 logfile = self.read(self.workpath(logfile))
855 string.find( logfile, "scons: warning: The stored build "
856 "information has an unexpected class." ) >= 0):
858 sconf_dir = sconf_dir
859 sconstruct = sconstruct
861 log = r'file\ \S*%s\,line \d+:' % re.escape(sconstruct) + ls
862 if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
863 log = "\t" + re.escape("Configure(confdir = %s)" % sconf_dir) + ls
864 if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
867 for check,result,cache_desc in zip(checks, results, cached):
868 log = re.escape("scons: Configure: " + check) + ls
869 if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
872 for bld_desc in cache_desc: # each TryXXX
873 for ext, flag in bld_desc: # each file in TryBuild
874 file = os.path.join(sconf_dir,"conftest_%d%s" % (cnt, ext))
877 if ext in ['.c', '.cpp']:
878 log=log + re.escape(file + " <-") + ls
879 log=log + r"( \|" + nols + "*" + ls + ")+?"
881 log=log + "(" + nols + "*" + ls +")*?"
886 re.escape("scons: Configure: \"%s\" is up to date."
888 log=log+re.escape("scons: Configure: The original builder "
890 log=log+r"( \|.*"+ls+")+"
892 # non-cached rebuild failure
893 log=log + "(" + nols + "*" + ls + ")*?"
896 # cached rebuild failure
898 re.escape("scons: Configure: Building \"%s\" failed "
899 "in a previous run and all its sources are"
900 " up to date." % file) + ls
901 log=log+re.escape("scons: Configure: The original builder "
903 log=log+r"( \|.*"+ls+")+"
906 result = "(cached) " + result
907 rdstr = rdstr + re.escape(check) + re.escape(result) + "\n"
908 log=log + re.escape("scons: Configure: " + result) + ls + ls
909 if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
911 if doCheckLog: lastEnd = matchPart(ls, logfile, lastEnd)
912 if doCheckLog and lastEnd != len(logfile):
913 raise NoMatch, lastEnd
916 print "Cannot match log file against log regexp."
918 print "------------------------------------------------------"
919 print logfile[m.pos:]
920 print "------------------------------------------------------"
922 print "------------------------------------------------------"
924 print "------------------------------------------------------"
928 exp_stdout = self.wrap_stdout(".*", rdstr)
929 if not self.match_re_dotall(self.stdout(), exp_stdout):
930 print "Unexpected stdout: "
931 print "-----------------------------------------------------"
932 print repr(self.stdout())
933 print "-----------------------------------------------------"
934 print repr(exp_stdout)
935 print "-----------------------------------------------------"
938 def get_python_version(self):
940 Returns the Python version (just so everyone doesn't have to
941 hand-code slicing the right number of characters).
943 # see also sys.prefix documentation
944 return python_minor_version_string()
946 def get_platform_python(self):
948 Returns a path to a Python executable suitable for testing on
951 Mac OS X has no static libpython for SWIG to link against,
952 so we have to link against Apple's framwork version. However,
953 testing must use the executable version that corresponds to the
954 framework we link against, or else we get interpreter errors.
956 if sys.platform == 'darwin':
957 return '/System/Library/Frameworks/Python.framework/Versions/Current/bin/python'
962 def get_quoted_platform_python(self):
964 Returns a quoted path to a Python executable suitable for testing on
967 Mac OS X has no static libpython for SWIG to link against,
968 so we have to link against Apple's framwork version. However,
969 testing must use the executable version that corresponds to the
970 framework we link against, or else we get interpreter errors.
972 if sys.platform == 'darwin':
973 return '"' + self.get_platform_python() + '"'
978 def get_platform_sys_prefix(self):
980 Returns a "sys.prefix" value suitable for linking on this platform.
982 Mac OS X has a built-in Python but no static libpython,
983 so we must link to it using Apple's 'framework' scheme.
985 if sys.platform == 'darwin':
986 fmt = '/System/Library/Frameworks/Python.framework/Versions/%s/'
987 return fmt % self.get_python_version()
991 def get_python_frameworks_flags(self):
993 Returns a FRAMEWORKSFLAGS value for linking with Python.
995 Mac OS X has a built-in Python but no static libpython,
996 so we must link to it using Apple's 'framework' scheme.
998 if sys.platform == 'darwin':
999 return '-framework Python'
1003 def get_python_inc(self):
1005 Returns a path to the Python include directory.
1008 import distutils.sysconfig
1010 return os.path.join(self.get_platform_sys_prefix(),
1012 'python' + self.get_python_version())
1014 return distutils.sysconfig.get_python_inc()
1016 def wait_for(self, fname, timeout=10.0, popen=None):
1018 Waits for the specified file name to exist.
1021 while not os.path.exists(fname):
1022 if timeout and waited >= timeout:
1023 sys.stderr.write('timed out waiting for %s to exist\n' % fname)
1030 waited = waited + 1.0
1032 def get_alt_cpp_suffix(self):
1034 Many CXX tests have this same logic.
1035 They all needed to determine if the current os supports
1036 files with .C and .c as different files or not
1037 in which case they are instructed to use .cpp instead of .C
1039 if not case_sensitive_suffixes('.c','.C'):
1040 alt_cpp_suffix = '.cpp'
1042 alt_cpp_suffix = '.C'
1043 return alt_cpp_suffix
1046 # In some environments, $AR will generate a warning message to stderr
1047 # if the library doesn't previously exist and is being created. One
1048 # way to fix this is to tell AR to be quiet (sometimes the 'c' flag),
1049 # but this is difficult to do in a platform-/implementation-specific
1050 # method. Instead, we will use the following as a stderr match for
1051 # tests that use AR so that we will view zero or more "ar: creating
1052 # <file>" messages to be successful executions of the test (see
1053 # test/AR.py for sample usage).
1055 noisy_ar=r'(ar: creating( archive)? \S+\n?)*'