blob: 7385c6bbf67171c55c428ff46abfbd0277c74e94 [file] [log] [blame]
Fred Drakeb8ab8b62004-06-17 20:14:50 +00001"""Support code for distutils test cases."""
Tarek Ziadéc1375d52009-02-14 14:35:51 +00002import os
Éric Araujo6e3ad872011-08-21 17:02:07 +02003import sys
Fred Drakeb8ab8b62004-06-17 20:14:50 +00004import shutil
5import tempfile
Éric Araujodef15da2011-08-20 06:27:18 +02006import unittest
7import sysconfig
Tarek Ziadé430fb632009-10-18 11:34:51 +00008from copy import deepcopy
Fred Drakeb8ab8b62004-06-17 20:14:50 +00009
Fred Drakeedcac8f2004-08-03 18:53:07 +000010from distutils import log
Tarek Ziadé31d46072009-09-21 13:55:19 +000011from distutils.log import DEBUG, INFO, WARN, ERROR, FATAL
Tarek Ziadébaf51802009-03-31 21:37:16 +000012from distutils.core import Distribution
Fred Drakeedcac8f2004-08-03 18:53:07 +000013
Éric Araujodef15da2011-08-20 06:27:18 +020014
Fred Drakeedcac8f2004-08-03 18:53:07 +000015class LoggingSilencer(object):
16
17 def setUp(self):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000018 super().setUp()
Fred Drakeedcac8f2004-08-03 18:53:07 +000019 self.threshold = log.set_threshold(log.FATAL)
Tarek Ziadé5af55c62009-05-16 16:52:13 +000020 # catching warnings
21 # when log will be replaced by logging
22 # we won't need such monkey-patch anymore
23 self._old_log = log.Log._log
24 log.Log._log = self._log
25 self.logs = []
Fred Drakeedcac8f2004-08-03 18:53:07 +000026
27 def tearDown(self):
28 log.set_threshold(self.threshold)
Tarek Ziadé5af55c62009-05-16 16:52:13 +000029 log.Log._log = self._old_log
Guido van Rossumcd16bf62007-06-13 18:07:49 +000030 super().tearDown()
Fred Drakeedcac8f2004-08-03 18:53:07 +000031
Tarek Ziadé5af55c62009-05-16 16:52:13 +000032 def _log(self, level, msg, args):
Tarek Ziadé31d46072009-09-21 13:55:19 +000033 if level not in (DEBUG, INFO, WARN, ERROR, FATAL):
34 raise ValueError('%s wrong log level' % str(level))
Antoine Pitrou716b7222013-12-21 22:57:56 +010035 if not isinstance(msg, str):
36 raise TypeError("msg should be str, not '%.200s'"
37 % (type(msg).__name__))
Tarek Ziadé5af55c62009-05-16 16:52:13 +000038 self.logs.append((level, msg, args))
39
40 def get_logs(self, *levels):
41 def _format(msg, args):
Tarek Ziadé5af55c62009-05-16 16:52:13 +000042 return msg % args
Antoine Pitrou716b7222013-12-21 22:57:56 +010043 return [msg % args for level, msg, args
Tarek Ziadé5af55c62009-05-16 16:52:13 +000044 in self.logs if level in levels]
45
46 def clear_logs(self):
47 self.logs = []
Fred Drakeb8ab8b62004-06-17 20:14:50 +000048
Éric Araujodef15da2011-08-20 06:27:18 +020049
Fred Drakeb8ab8b62004-06-17 20:14:50 +000050class TempdirManager(object):
51 """Mix-in class that handles temporary directories for test cases.
52
53 This is intended to be used with unittest.TestCase.
54 """
55
56 def setUp(self):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000057 super().setUp()
Antoine Pitrou4fc80b62011-08-25 18:32:02 +020058 self.old_cwd = os.getcwd()
Fred Drakeb8ab8b62004-06-17 20:14:50 +000059 self.tempdirs = []
60
61 def tearDown(self):
Antoine Pitrou4fc80b62011-08-25 18:32:02 +020062 # Restore working dir, for Solaris and derivatives, where rmdir()
63 # on the current directory fails.
64 os.chdir(self.old_cwd)
Guido van Rossumcd16bf62007-06-13 18:07:49 +000065 super().tearDown()
Fred Drakeb8ab8b62004-06-17 20:14:50 +000066 while self.tempdirs:
67 d = self.tempdirs.pop()
Tarek Ziadéc1375d52009-02-14 14:35:51 +000068 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
Fred Drakeb8ab8b62004-06-17 20:14:50 +000069
70 def mkdtemp(self):
71 """Create a temporary directory that will be cleaned up.
72
73 Returns the path of the directory.
74 """
75 d = tempfile.mkdtemp()
76 self.tempdirs.append(d)
77 return d
78
Tarek Ziadébaf51802009-03-31 21:37:16 +000079 def write_file(self, path, content='xxx'):
Tarek Ziadé0d0506e2009-02-16 21:49:12 +000080 """Writes a file in the given path.
81
82
83 path can be a string or a sequence.
84 """
85 if isinstance(path, (list, tuple)):
86 path = os.path.join(*path)
87 f = open(path, 'w')
88 try:
89 f.write(content)
90 finally:
91 f.close()
Fred Drakeb8ab8b62004-06-17 20:14:50 +000092
Tarek Ziadébaf51802009-03-31 21:37:16 +000093 def create_dist(self, pkg_name='foo', **kw):
94 """Will generate a test environment.
95
96 This function creates:
97 - a Distribution instance using keywords
98 - a temporary directory with a package structure
99
100 It returns the package directory and the distribution
101 instance.
102 """
103 tmp_dir = self.mkdtemp()
104 pkg_dir = os.path.join(tmp_dir, pkg_name)
105 os.mkdir(pkg_dir)
106 dist = Distribution(attrs=kw)
107
108 return pkg_dir, dist
109
Éric Araujodef15da2011-08-20 06:27:18 +0200110
Fred Drakeb8ab8b62004-06-17 20:14:50 +0000111class DummyCommand:
112 """Class to store options for retrieval via set_undefined_options()."""
113
114 def __init__(self, **kwargs):
115 for kw, val in kwargs.items():
116 setattr(self, kw, val)
117
118 def ensure_finalized(self):
119 pass
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000120
Éric Araujodef15da2011-08-20 06:27:18 +0200121
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000122class EnvironGuard(object):
123
124 def setUp(self):
125 super(EnvironGuard, self).setUp()
Tarek Ziadé430fb632009-10-18 11:34:51 +0000126 self.old_environ = deepcopy(os.environ)
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000127
128 def tearDown(self):
Tarek Ziadé430fb632009-10-18 11:34:51 +0000129 for key, value in self.old_environ.items():
130 if os.environ.get(key) != value:
131 os.environ[key] = value
132
133 for key in tuple(os.environ.keys()):
134 if key not in self.old_environ:
135 del os.environ[key]
136
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000137 super(EnvironGuard, self).tearDown()
Éric Araujodef15da2011-08-20 06:27:18 +0200138
139
140def copy_xxmodule_c(directory):
141 """Helper for tests that need the xxmodule.c source file.
142
143 Example use:
144
Éric Araujoe1e13312011-08-20 07:25:39 +0200145 def test_compile(self):
146 copy_xxmodule_c(self.tmpdir)
Éric Araujo52b201f2011-08-21 12:53:37 +0200147 self.assertIn('xxmodule.c', os.listdir(self.tmpdir))
Éric Araujodef15da2011-08-20 06:27:18 +0200148
149 If the source file can be found, it will be copied to *directory*. If not,
150 the test will be skipped. Errors during copy are not caught.
151 """
152 filename = _get_xxmodule_path()
153 if filename is None:
154 raise unittest.SkipTest('cannot find xxmodule.c (test must run in '
155 'the python build dir)')
156 shutil.copy(filename, directory)
157
158
159def _get_xxmodule_path():
160 srcdir = sysconfig.get_config_var('srcdir')
161 candidates = [
162 # use installed copy if available
163 os.path.join(os.path.dirname(__file__), 'xxmodule.c'),
164 # otherwise try using copy from build directory
165 os.path.join(srcdir, 'Modules', 'xxmodule.c'),
166 # srcdir mysteriously can be $srcdir/Lib/distutils/tests when
167 # this file is run from its parent directory, so walk up the
168 # tree to find the real srcdir
169 os.path.join(srcdir, '..', '..', '..', 'Modules', 'xxmodule.c'),
170 ]
171 for path in candidates:
172 if os.path.exists(path):
173 return path
Éric Araujo6e3ad872011-08-21 17:02:07 +0200174
175
176def fixup_build_ext(cmd):
Éric Araujo175eb992011-08-24 01:29:10 +0200177 """Function needed to make build_ext tests pass.
Éric Araujo6e3ad872011-08-21 17:02:07 +0200178
Éric Araujo024de542011-09-01 23:37:56 +0200179 When Python was built with --enable-shared on Unix, -L. is not enough to
180 find libpython<blah>.so, because regrtest runs in a tempdir, not in the
181 source directory where the .so lives.
Éric Araujo175eb992011-08-24 01:29:10 +0200182
183 When Python was built with in debug mode on Windows, build_ext commands
184 need their debug attribute set, and it is not done automatically for
185 some reason.
186
187 This function handles both of these things. Example use:
Éric Araujo6e3ad872011-08-21 17:02:07 +0200188
189 cmd = build_ext(dist)
190 support.fixup_build_ext(cmd)
191 cmd.ensure_finalized()
Ned Deilycf550dc2012-02-03 02:42:16 +0100192
193 Unlike most other Unix platforms, Mac OS X embeds absolute paths
194 to shared libraries into executables, so the fixup is not needed there.
Éric Araujo6e3ad872011-08-21 17:02:07 +0200195 """
Éric Araujo175eb992011-08-24 01:29:10 +0200196 if os.name == 'nt':
197 cmd.debug = sys.executable.endswith('_d.exe')
198 elif sysconfig.get_config_var('Py_ENABLE_SHARED'):
199 # To further add to the shared builds fun on Unix, we can't just add
200 # library_dirs to the Extension() instance because that doesn't get
201 # plumbed through to the final compiler command.
Éric Araujo6e3ad872011-08-21 17:02:07 +0200202 runshared = sysconfig.get_config_var('RUNSHARED')
203 if runshared is None:
204 cmd.library_dirs = ['.']
205 else:
Ned Deilycf550dc2012-02-03 02:42:16 +0100206 if sys.platform == 'darwin':
207 cmd.library_dirs = []
208 else:
209 name, equals, value = runshared.partition('=')
doko@ubuntu.come5de66e2014-05-07 12:57:44 +0200210 cmd.library_dirs = [d for d in value.split(os.pathsep) if d]