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.1'
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 kw['stdout'] = self.wrap_stdout(read_str = read_str, build_str = s)
342 kw['stdout'] = string.replace(kw['stdout'],'\n','\\n')
343 kw['stdout'] = string.replace(kw['stdout'],'.','\\.')
344 kw['match'] = self.match_re_dotall
345 apply(self.run, [], kw)
347 def not_up_to_date(self, options = None, arguments = None, **kw):
348 """Asserts that none of the targets listed in arguments is
349 up to date, but does not make any assumptions on other targets.
350 This function is most useful in conjunction with the -n option.
353 for arg in string.split(arguments):
354 s = s + "(?!scons: `%s' is up to date.)" % arg
356 arguments = options + " " + arguments
357 kw['arguments'] = arguments
358 kw['stdout'] = self.wrap_stdout(build_str="("+s+"[^\n]*\n)*")
359 kw['stdout'] = string.replace(kw['stdout'],'\n','\\n')
360 kw['stdout'] = string.replace(kw['stdout'],'.','\\.')
361 kw['match'] = self.match_re_dotall
362 apply(self.run, [], kw)
364 def diff_substr(self, expect, actual, prelen=20, postlen=40):
366 for x, y in zip(expect, actual):
368 return "Actual did not match expect at char %d:\n" \
371 % (i, repr(expect[i-prelen:i+postlen]),
372 repr(actual[i-prelen:i+postlen]))
374 return "Actual matched the expected output???"
376 def python_file_line(self, file, line):
378 Returns a Python error line for output comparisons.
380 The exec of the traceback line gives us the correct format for
381 this version of Python. Before 2.5, this yielded:
383 File "<string>", line 1, ?
385 Python 2.5 changed this to:
387 File "<string>", line 1, <module>
389 We stick the requested file name and line number in the right
390 places, abstracting out the version difference.
392 exec 'import traceback; x = traceback.format_stack()[-1]'
394 x = string.replace(x, '<string>', file)
395 x = string.replace(x, 'line 1,', 'line %s,' % line)
398 def normalize_pdf(self, s):
399 s = re.sub(r'/(Creation|Mod)Date \(D:[^)]*\)',
400 r'/\1Date (D:XXXX)', s)
401 s = re.sub(r'/ID \[<[0-9a-fA-F]*> <[0-9a-fA-F]*>\]',
402 r'/ID [<XXXX> <XXXX>]', s)
403 s = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}',
405 s = re.sub(r'/Length \d+ *\n/Filter /FlateDecode\n',
406 r'/Length XXXX\n/Filter /FlateDecode\n', s)
414 begin_marker = '/FlateDecode\n>>\nstream\n'
415 end_marker = 'endstream\nendobj'
418 b = string.find(s, begin_marker, 0)
420 b = b + len(begin_marker)
421 e = string.find(s, end_marker, b)
422 encoded.append((b, e))
423 b = string.find(s, begin_marker, e + len(end_marker))
429 d = zlib.decompress(s[b:e])
430 d = re.sub(r'%%CreationDate: [^\n]*\n',
431 r'%%CreationDate: 1970 Jan 01 00:00:00\n', d)
432 d = re.sub(r'%DVIPSSource: TeX output \d\d\d\d\.\d\d\.\d\d:\d\d\d\d',
433 r'%DVIPSSource: TeX output 1970.01.01:0000', d)
434 d = re.sub(r'/(BaseFont|FontName) /[A-Z]{6}',
439 s = string.join(r, '')
443 def paths(self,patterns):
453 def java_ENV(self, version=None):
455 Initialize with a default external environment that uses a local
456 Java SDK in preference to whatever's found in the default PATH.
459 return self._java_env[version]['ENV']
460 except AttributeError:
465 import SCons.Environment
466 env = SCons.Environment.Environment()
467 self._java_env[version] = env
472 '/usr/java/jdk%s*/bin' % version,
473 '/usr/lib/jvm/*-%s*/bin' % version,
474 '/usr/local/j2sdk%s*/bin' % version,
476 java_path = self.paths(patterns) + [env['ENV']['PATH']]
479 '/usr/java/latest/bin',
480 '/usr/lib/jvm/*/bin',
481 '/usr/local/j2sdk*/bin',
483 java_path = self.paths(patterns) + [env['ENV']['PATH']]
485 env['ENV']['PATH'] = string.join(java_path, os.pathsep)
488 def java_where_includes(self,version=None):
490 Return java include paths compiling java jni code
496 jni_dirs = ['/usr/lib/jvm/java-*-sun-%s*/include/jni.h'%version,
497 '/usr/java/jdk%s*/include/jni.h'%version,
499 dirs = self.paths(jni_dirs)
502 d=os.path.dirname(self.paths(jni_dirs)[0])
505 if sys.platform == 'win32':
506 result.append(os.path.join(d,'win32'))
507 elif sys.platform == 'linux2':
508 result.append(os.path.join(d,'linux'))
512 def java_where_java_home(self,version=None):
514 jar=self.java_where_jar(version)
515 home=os.path.normpath('%s/..'%jar)
518 def java_where_jar(self, version=None):
519 ENV = self.java_ENV(version)
520 if self.detect_tool('jar', ENV=ENV):
521 where_jar = self.detect('JAR', 'jar', ENV=ENV)
523 where_jar = self.where_is('jar', ENV['PATH'])
525 self.skip_test("Could not find Java jar, skipping test(s).\n")
528 def java_where_java(self, version=None):
530 Return a path to the java executable.
532 ENV = self.java_ENV(version)
533 where_java = self.where_is('java', ENV['PATH'])
535 self.skip_test("Could not find Java java, skipping test(s).\n")
538 def java_where_javac(self, version=None):
540 Return a path to the javac compiler.
542 ENV = self.java_ENV(version)
543 if self.detect_tool('javac'):
544 where_javac = self.detect('JAVAC', 'javac', ENV=ENV)
546 where_javac = self.where_is('javac', ENV['PATH'])
548 self.skip_test("Could not find Java javac, skipping test(s).\n")
549 self.run(program = where_javac,
550 arguments = '-version',
554 if string.find(self.stderr(), 'javac %s' % version) == -1:
555 fmt = "Could not find javac for Java version %s, skipping test(s).\n"
556 self.skip_test(fmt % version)
558 m = re.search(r'javac (\d\.\d)', self.stderr())
563 return where_javac, version
565 def java_where_javah(self, version=None):
566 ENV = self.java_ENV(version)
567 if self.detect_tool('javah'):
568 where_javah = self.detect('JAVAH', 'javah', ENV=ENV)
570 where_javah = self.where_is('javah', ENV['PATH'])
572 self.skip_test("Could not find Java javah, skipping test(s).\n")
575 def java_where_rmic(self, version=None):
576 ENV = self.java_ENV(version)
577 if self.detect_tool('rmic'):
578 where_rmic = self.detect('RMIC', 'rmic', ENV=ENV)
580 where_rmic = self.where_is('rmic', ENV['PATH'])
582 self.skip_test("Could not find Java rmic, skipping non-simulated test(s).\n")
585 def Qt_dummy_installation(self, dir='qt'):
586 # create a dummy qt installation
588 self.subdir( dir, [dir, 'bin'], [dir, 'include'], [dir, 'lib'] )
590 self.write([dir, 'bin', 'mymoc.py'], """\
595 cmd_opts, args = getopt.getopt(sys.argv[1:], 'io:', [])
599 for opt, arg in cmd_opts:
600 if opt == '-o': output = open(arg, 'wb')
601 elif opt == '-i': impl = 1
602 else: opt_string = opt_string + ' ' + opt
604 contents = open(a, 'rb').read()
605 a = string.replace(a, '\\\\', '\\\\\\\\')
606 subst = r'{ my_qt_symbol( "' + a + '\\\\n" ); }'
608 contents = re.sub( r'#include.*', '', contents )
609 output.write(string.replace(contents, 'Q_OBJECT', subst))
614 self.write([dir, 'bin', 'myuic.py'], """\
623 for arg in sys.argv[1:]:
625 output = open(arg, 'wb')
637 source = open(arg, 'rb')
640 output.write( '#include "' + impl + '"\\n' )
641 includes = re.findall('<include.*?>(.*?)</include>', source.read())
642 for incFile in includes:
643 # this is valid for ui.h files, at least
644 if os.path.exists(incFile):
645 output.write('#include "' + incFile + '"\\n')
647 output.write( '#include "my_qobject.h"\\n' + source.read() + " Q_OBJECT \\n" )
652 self.write([dir, 'include', 'my_qobject.h'], r"""
654 void my_qt_symbol(const char *arg);
657 self.write([dir, 'lib', 'my_qobject.cpp'], r"""
658 #include "../include/my_qobject.h"
660 void my_qt_symbol(const char *arg) {
665 self.write([dir, 'lib', 'SConstruct'], r"""
668 if sys.platform == 'win32':
669 env.StaticLibrary( 'myqt', 'my_qobject.cpp' )
671 env.SharedLibrary( 'myqt', 'my_qobject.cpp' )
674 self.run(chdir = self.workpath(dir, 'lib'),
677 match = self.match_re_dotall)
679 self.QT = self.workpath(dir)
681 self.QT_MOC = '%s %s' % (_python_, self.workpath(dir, 'bin', 'mymoc.py'))
682 self.QT_UIC = '%s %s' % (_python_, self.workpath(dir, 'bin', 'myuic.py'))
683 self.QT_LIB_DIR = self.workpath(dir, 'lib')
685 def Qt_create_SConstruct(self, place):
686 if type(place) is type([]):
687 place = apply(test.workpath, place)
688 self.write(place, """\
689 if ARGUMENTS.get('noqtdir', 0): QTDIR=None
691 env = Environment(QTDIR = QTDIR,
695 tools=['default','qt'])
697 if ARGUMENTS.get('variant_dir', 0):
698 if ARGUMENTS.get('chdir', 0):
702 dup=int(ARGUMENTS.get('dup', 1))
704 builddir = 'build_dup0'
708 VariantDir(builddir, '.', duplicate=dup)
710 sconscript = Dir(builddir).File('SConscript')
712 sconscript = File('SConscript')
714 SConscript( sconscript )
715 """ % (self.QT, self.QT_LIB, self.QT_MOC, self.QT_UIC))
717 def msvs_versions(self):
718 if not hasattr(self, '_msvs_versions'):
720 # Determine the SCons version and the versions of the MSVS
721 # environments installed on the test machine.
723 # We do this by executing SCons with an SConstruct file
724 # (piped on stdin) that spits out Python assignments that
725 # we can just exec(). We construct the SCons.__"version"__
726 # string in the input here so that the SCons build itself
727 # doesn't fill it in when packaging SCons.
730 print "self._scons_version =", repr(SCons.__%s__)
732 print "self._msvs_versions =", str(env['MSVS']['VERSIONS'])
735 self.run(arguments = '-n -q -Q -f -', stdin = input)
738 return self._msvs_versions
740 def vcproj_sys_path(self, fname):
743 orig = 'sys.path = [ join(sys'
745 enginepath = repr(os.path.join(self._cwd, '..', 'engine'))
746 replace = 'sys.path = [ %s, join(sys' % enginepath
748 contents = self.read(fname)
749 contents = string.replace(contents, orig, replace)
750 self.write(fname, contents)
752 def msvs_substitute(self, input, msvs_ver,
753 subdir=None, sconscript=None,
754 python=sys.executable,
756 if not hasattr(self, '_msvs_versions'):
760 workpath = self.workpath(subdir)
762 workpath = self.workpath()
764 if sconscript is None:
765 sconscript = self.workpath('SConstruct')
767 if project_guid is None:
768 project_guid = "{E5466E26-0003-F18B-8F8A-BCD76C86388D}"
770 if os.environ.has_key('SCONS_LIB_DIR'):
771 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']
773 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)
774 exec_script_main_xml = string.replace(exec_script_main, "'", "'")
776 result = string.replace(input, r'<WORKPATH>', workpath)
777 result = string.replace(result, r'<PYTHON>', python)
778 result = string.replace(result, r'<SCONSCRIPT>', sconscript)
779 result = string.replace(result, r'<SCONS_SCRIPT_MAIN>', exec_script_main)
780 result = string.replace(result, r'<SCONS_SCRIPT_MAIN_XML>', exec_script_main_xml)
781 result = string.replace(result, r'<PROJECT_GUID>', project_guid)
784 def get_msvs_executable(self, version):
785 """Returns a full path to the executable (MSDEV or devenv)
786 for the specified version of Visual Studio.
788 common_msdev98_bin_msdev_com = ['Common', 'MSDev98', 'Bin', 'MSDEV.COM']
789 common7_ide_devenv_com = ['Common7', 'IDE', 'devenv.com']
790 common7_ide_vcexpress_exe = ['Common7', 'IDE', 'VCExpress.exe']
793 common_msdev98_bin_msdev_com,
796 common7_ide_devenv_com,
799 common7_ide_devenv_com,
802 common7_ide_devenv_com,
803 common7_ide_vcexpress_exe,
806 from SCons.Tool.msvs import get_msvs_install_dirs
807 vs_path = get_msvs_install_dirs(version)['VSINSTALLDIR']
808 for sp in sub_paths[version]:
809 p = apply(os.path.join, [vs_path] + sp)
810 if os.path.exists(p):
812 return apply(os.path.join, [vs_path] + sub_paths[version][0])
815 NCR = 0 # non-cached rebuild
816 CR = 1 # cached rebuild (up to date)
817 NCF = 2 # non-cached build failure
818 CF = 3 # cached build failure
820 if sys.platform == 'win32':
821 Configure_lib = 'msvcrt'
825 # to use cygwin compilers on cmd.exe -> uncomment following line
828 def checkLogAndStdout(self, checks, results, cached,
829 logfile, sconf_dir, sconstruct,
830 doCheckLog=1, doCheckStdout=1):
833 def __init__(self, p):
836 def matchPart(log, logfile, lastEnd):
837 m = re.match(log, logfile[lastEnd:])
839 raise NoMatch, lastEnd
840 return m.end() + lastEnd
842 #print len(os.linesep)
845 for i in range(len(ls)):
849 nols = nols + "[^" + ls[i] + "])"
854 logfile = self.read(self.workpath(logfile))
856 string.find( logfile, "scons: warning: The stored build "
857 "information has an unexpected class." ) >= 0):
859 sconf_dir = sconf_dir
860 sconstruct = sconstruct
862 log = r'file\ \S*%s\,line \d+:' % re.escape(sconstruct) + ls
863 if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
864 log = "\t" + re.escape("Configure(confdir = %s)" % sconf_dir) + ls
865 if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
868 for check,result,cache_desc in zip(checks, results, cached):
869 log = re.escape("scons: Configure: " + check) + ls
870 if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
873 for bld_desc in cache_desc: # each TryXXX
874 for ext, flag in bld_desc: # each file in TryBuild
875 file = os.path.join(sconf_dir,"conftest_%d%s" % (cnt, ext))
878 if ext in ['.c', '.cpp']:
879 log=log + re.escape(file + " <-") + ls
880 log=log + r"( \|" + nols + "*" + ls + ")+?"
882 log=log + "(" + nols + "*" + ls +")*?"
887 re.escape("scons: Configure: \"%s\" is up to date."
889 log=log+re.escape("scons: Configure: The original builder "
891 log=log+r"( \|.*"+ls+")+"
893 # non-cached rebuild failure
894 log=log + "(" + nols + "*" + ls + ")*?"
897 # cached rebuild failure
899 re.escape("scons: Configure: Building \"%s\" failed "
900 "in a previous run and all its sources are"
901 " up to date." % file) + ls
902 log=log+re.escape("scons: Configure: The original builder "
904 log=log+r"( \|.*"+ls+")+"
907 result = "(cached) " + result
908 rdstr = rdstr + re.escape(check) + re.escape(result) + "\n"
909 log=log + re.escape("scons: Configure: " + result) + ls + ls
910 if doCheckLog: lastEnd = matchPart(log, logfile, lastEnd)
912 if doCheckLog: lastEnd = matchPart(ls, logfile, lastEnd)
913 if doCheckLog and lastEnd != len(logfile):
914 raise NoMatch, lastEnd
917 print "Cannot match log file against log regexp."
919 print "------------------------------------------------------"
920 print logfile[m.pos:]
921 print "------------------------------------------------------"
923 print "------------------------------------------------------"
925 print "------------------------------------------------------"
929 exp_stdout = self.wrap_stdout(".*", rdstr)
930 if not self.match_re_dotall(self.stdout(), exp_stdout):
931 print "Unexpected stdout: "
932 print "-----------------------------------------------------"
933 print repr(self.stdout())
934 print "-----------------------------------------------------"
935 print repr(exp_stdout)
936 print "-----------------------------------------------------"
939 def get_python_version(self):
941 Returns the Python version (just so everyone doesn't have to
942 hand-code slicing the right number of characters).
944 # see also sys.prefix documentation
945 return python_minor_version_string()
947 def get_platform_python(self):
949 Returns a path to a Python executable suitable for testing on
952 Mac OS X has no static libpython for SWIG to link against,
953 so we have to link against Apple's framwork version. However,
954 testing must use the executable version that corresponds to the
955 framework we link against, or else we get interpreter errors.
957 if sys.platform == 'darwin':
958 return '/System/Library/Frameworks/Python.framework/Versions/Current/bin/python'
963 def get_quoted_platform_python(self):
965 Returns a quoted path to a Python executable suitable for testing on
968 Mac OS X has no static libpython for SWIG to link against,
969 so we have to link against Apple's framwork version. However,
970 testing must use the executable version that corresponds to the
971 framework we link against, or else we get interpreter errors.
973 if sys.platform == 'darwin':
974 return '"' + self.get_platform_python() + '"'
979 def get_platform_sys_prefix(self):
981 Returns a "sys.prefix" value suitable for linking on this platform.
983 Mac OS X has a built-in Python but no static libpython,
984 so we must link to it using Apple's 'framework' scheme.
986 if sys.platform == 'darwin':
987 fmt = '/System/Library/Frameworks/Python.framework/Versions/%s/'
988 return fmt % self.get_python_version()
992 def get_python_frameworks_flags(self):
994 Returns a FRAMEWORKSFLAGS value for linking with Python.
996 Mac OS X has a built-in Python but no static libpython,
997 so we must link to it using Apple's 'framework' scheme.
999 if sys.platform == 'darwin':
1000 return '-framework Python'
1004 def get_python_inc(self):
1006 Returns a path to the Python include directory.
1009 import distutils.sysconfig
1011 return os.path.join(self.get_platform_sys_prefix(),
1013 'python' + self.get_python_version())
1015 return distutils.sysconfig.get_python_inc()
1017 def wait_for(self, fname, timeout=10.0, popen=None):
1019 Waits for the specified file name to exist.
1022 while not os.path.exists(fname):
1023 if timeout and waited >= timeout:
1024 sys.stderr.write('timed out waiting for %s to exist\n' % fname)
1031 waited = waited + 1.0
1033 def get_alt_cpp_suffix(self):
1035 Many CXX tests have this same logic.
1036 They all needed to determine if the current os supports
1037 files with .C and .c as different files or not
1038 in which case they are instructed to use .cpp instead of .C
1040 if not case_sensitive_suffixes('.c','.C'):
1041 alt_cpp_suffix = '.cpp'
1043 alt_cpp_suffix = '.C'
1044 return alt_cpp_suffix
1047 # In some environments, $AR will generate a warning message to stderr
1048 # if the library doesn't previously exist and is being created. One
1049 # way to fix this is to tell AR to be quiet (sometimes the 'c' flag),
1050 # but this is difficult to do in a platform-/implementation-specific
1051 # method. Instead, we will use the following as a stderr match for
1052 # tests that use AR so that we will view zero or more "ar: creating
1053 # <file>" messages to be successful executions of the test (see
1054 # test/AR.py for sample usage).
1056 noisy_ar=r'(ar: creating( archive)? \S+\n?)*'