blob: ffef98bae40db361d1e8088c44a7c7f8a06725f5 [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))
Tarek Ziadé5af55c62009-05-16 16:52:13 +000035 self.logs.append((level, msg, args))
36
37 def get_logs(self, *levels):
38 def _format(msg, args):
39 if len(args) == 0:
40 return msg
41 return msg % args
42 return [_format(msg, args) for level, msg, args
43 in self.logs if level in levels]
44
45 def clear_logs(self):
46 self.logs = []
Fred Drakeb8ab8b62004-06-17 20:14:50 +000047
Éric Araujodef15da2011-08-20 06:27:18 +020048
Fred Drakeb8ab8b62004-06-17 20:14:50 +000049class TempdirManager(object):
50 """Mix-in class that handles temporary directories for test cases.
51
52 This is intended to be used with unittest.TestCase.
53 """
54
55 def setUp(self):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000056 super().setUp()
Fred Drakeb8ab8b62004-06-17 20:14:50 +000057 self.tempdirs = []
58
59 def tearDown(self):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000060 super().tearDown()
Fred Drakeb8ab8b62004-06-17 20:14:50 +000061 while self.tempdirs:
62 d = self.tempdirs.pop()
Tarek Ziadéc1375d52009-02-14 14:35:51 +000063 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
Fred Drakeb8ab8b62004-06-17 20:14:50 +000064
65 def mkdtemp(self):
66 """Create a temporary directory that will be cleaned up.
67
68 Returns the path of the directory.
69 """
70 d = tempfile.mkdtemp()
71 self.tempdirs.append(d)
72 return d
73
Tarek Ziadébaf51802009-03-31 21:37:16 +000074 def write_file(self, path, content='xxx'):
Tarek Ziadé0d0506e2009-02-16 21:49:12 +000075 """Writes a file in the given path.
76
77
78 path can be a string or a sequence.
79 """
80 if isinstance(path, (list, tuple)):
81 path = os.path.join(*path)
82 f = open(path, 'w')
83 try:
84 f.write(content)
85 finally:
86 f.close()
Fred Drakeb8ab8b62004-06-17 20:14:50 +000087
Tarek Ziadébaf51802009-03-31 21:37:16 +000088 def create_dist(self, pkg_name='foo', **kw):
89 """Will generate a test environment.
90
91 This function creates:
92 - a Distribution instance using keywords
93 - a temporary directory with a package structure
94
95 It returns the package directory and the distribution
96 instance.
97 """
98 tmp_dir = self.mkdtemp()
99 pkg_dir = os.path.join(tmp_dir, pkg_name)
100 os.mkdir(pkg_dir)
101 dist = Distribution(attrs=kw)
102
103 return pkg_dir, dist
104
Éric Araujodef15da2011-08-20 06:27:18 +0200105
Fred Drakeb8ab8b62004-06-17 20:14:50 +0000106class DummyCommand:
107 """Class to store options for retrieval via set_undefined_options()."""
108
109 def __init__(self, **kwargs):
110 for kw, val in kwargs.items():
111 setattr(self, kw, val)
112
113 def ensure_finalized(self):
114 pass
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000115
Éric Araujodef15da2011-08-20 06:27:18 +0200116
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000117class EnvironGuard(object):
118
119 def setUp(self):
120 super(EnvironGuard, self).setUp()
Tarek Ziadé430fb632009-10-18 11:34:51 +0000121 self.old_environ = deepcopy(os.environ)
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000122
123 def tearDown(self):
Tarek Ziadé430fb632009-10-18 11:34:51 +0000124 for key, value in self.old_environ.items():
125 if os.environ.get(key) != value:
126 os.environ[key] = value
127
128 for key in tuple(os.environ.keys()):
129 if key not in self.old_environ:
130 del os.environ[key]
131
Tarek Ziadé29bbb962009-05-10 12:02:35 +0000132 super(EnvironGuard, self).tearDown()
Éric Araujodef15da2011-08-20 06:27:18 +0200133
134
135def copy_xxmodule_c(directory):
136 """Helper for tests that need the xxmodule.c source file.
137
138 Example use:
139
Éric Araujoe1e13312011-08-20 07:25:39 +0200140 def test_compile(self):
141 copy_xxmodule_c(self.tmpdir)
Éric Araujo52b201f2011-08-21 12:53:37 +0200142 self.assertIn('xxmodule.c', os.listdir(self.tmpdir))
Éric Araujodef15da2011-08-20 06:27:18 +0200143
144 If the source file can be found, it will be copied to *directory*. If not,
145 the test will be skipped. Errors during copy are not caught.
146 """
147 filename = _get_xxmodule_path()
148 if filename is None:
149 raise unittest.SkipTest('cannot find xxmodule.c (test must run in '
150 'the python build dir)')
151 shutil.copy(filename, directory)
152
153
154def _get_xxmodule_path():
155 srcdir = sysconfig.get_config_var('srcdir')
156 candidates = [
157 # use installed copy if available
158 os.path.join(os.path.dirname(__file__), 'xxmodule.c'),
159 # otherwise try using copy from build directory
160 os.path.join(srcdir, 'Modules', 'xxmodule.c'),
161 # srcdir mysteriously can be $srcdir/Lib/distutils/tests when
162 # this file is run from its parent directory, so walk up the
163 # tree to find the real srcdir
164 os.path.join(srcdir, '..', '..', '..', 'Modules', 'xxmodule.c'),
165 ]
166 for path in candidates:
167 if os.path.exists(path):
168 return path
Éric Araujo6e3ad872011-08-21 17:02:07 +0200169
170
171def fixup_build_ext(cmd):
172 """Function needed to make build_ext tests pass on shared builds.
173
174 When Python was build with --enable-shared, -L. is not good enough to find
175 the libpython<blah>.so. This is because regrtest runs it under a tempdir,
176 not in the top level where the .so lives. By the time we've gotten here,
177 Python's already been chdir'd to the tempdir. This function work arounds
178 that. Example use:
179
180 cmd = build_ext(dist)
181 support.fixup_build_ext(cmd)
182 cmd.ensure_finalized()
183 """
184 # To further add to the fun, we can't just add library_dirs to the
185 # Extension() instance because that doesn't get plumbed through to the
186 # final compiler command.
187 if (sysconfig.get_config_var('Py_ENABLE_SHARED') and
188 not sys.platform.startswith('win')):
189 runshared = sysconfig.get_config_var('RUNSHARED')
190 if runshared is None:
191 cmd.library_dirs = ['.']
192 else:
193 name, equals, value = runshared.partition('=')
194 cmd.library_dirs = value.split(os.pathsep)