1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 Tests for parts of our release automation system.
11 from distutils.core import Distribution
13 from twisted.trial.unittest import TestCase
15 from twisted.python import dist
16 from twisted.python.dist import get_setup_args, ConditionalExtension
17 from twisted.python.filepath import FilePath
20 class SetupTest(TestCase):
22 Tests for L{get_setup_args}.
24 def test_conditionalExtensions(self):
26 Passing C{conditionalExtensions} as a list of L{ConditionalExtension}
27 objects to get_setup_args inserts a custom build_ext into the result
28 which knows how to check whether they should be built.
30 good_ext = ConditionalExtension("whatever", ["whatever.c"],
31 condition=lambda b: True)
32 bad_ext = ConditionalExtension("whatever", ["whatever.c"],
33 condition=lambda b: False)
34 args = get_setup_args(conditionalExtensions=[good_ext, bad_ext])
35 # ext_modules should be set even though it's not used. See comment
37 self.assertEqual(args["ext_modules"], [good_ext, bad_ext])
38 cmdclass = args["cmdclass"]
39 build_ext = cmdclass["build_ext"]
40 builder = build_ext(Distribution())
41 builder.prepare_extensions()
42 self.assertEqual(builder.extensions, [good_ext])
45 def test_win32Definition(self):
47 When building on Windows NT, the WIN32 macro will be defined as 1.
49 ext = ConditionalExtension("whatever", ["whatever.c"],
50 define_macros=[("whatever", 2)])
51 args = get_setup_args(conditionalExtensions=[ext])
52 builder = args["cmdclass"]["build_ext"](Distribution())
53 self.patch(os, "name", "nt")
54 builder.prepare_extensions()
55 self.assertEqual(ext.define_macros, [("whatever", 2), ("WIN32", 1)])
59 class GetVersionTest(TestCase):
61 Tests for L{dist.getVersion}.
65 self.dirname = self.mktemp()
66 os.mkdir(self.dirname)
68 def test_getVersionCore(self):
70 Test that getting the version of core reads from the
71 [base]/_version.py file.
73 f = open(os.path.join(self.dirname, "_version.py"), "w")
75 from twisted.python import versions
76 version = versions.Version("twisted", 0, 1, 2)
79 self.assertEqual(dist.getVersion("core", base=self.dirname), "0.1.2")
81 def test_getVersionOther(self):
83 Test that getting the version of a non-core project reads from
84 the [base]/[projname]/_version.py file.
86 os.mkdir(os.path.join(self.dirname, "blat"))
87 f = open(os.path.join(self.dirname, "blat", "_version.py"), "w")
89 from twisted.python import versions
90 version = versions.Version("twisted.blat", 9, 8, 10)
93 self.assertEqual(dist.getVersion("blat", base=self.dirname), "9.8.10")
96 class GetScriptsTest(TestCase):
98 Tests for L{dist.getScripts} which returns the scripts which should be
99 included in the distribution of a project.
102 def test_scriptsInSVN(self):
104 getScripts should return the scripts associated with a project
105 in the context of Twisted SVN.
107 basedir = self.mktemp()
109 os.mkdir(os.path.join(basedir, 'bin'))
110 os.mkdir(os.path.join(basedir, 'bin', 'proj'))
111 f = open(os.path.join(basedir, 'bin', 'proj', 'exy'), 'w')
114 scripts = dist.getScripts('proj', basedir=basedir)
115 self.assertEqual(len(scripts), 1)
116 self.assertEqual(os.path.basename(scripts[0]), 'exy')
119 def test_excludedPreamble(self):
121 L{dist.getScripts} includes neither C{"_preamble.py"} nor
124 basedir = FilePath(self.mktemp())
125 bin = basedir.child('bin')
127 bin.child('_preamble.py').setContent('some preamble code\n')
128 bin.child('_preamble.pyc').setContent('some preamble byte code\n')
129 bin.child('program').setContent('good program code\n')
130 scripts = dist.getScripts("", basedir=basedir.path)
131 self.assertEqual(scripts, [bin.child('program').path])
134 def test_scriptsInRelease(self):
136 getScripts should return the scripts associated with a project
137 in the context of a released subproject tarball.
139 basedir = self.mktemp()
141 os.mkdir(os.path.join(basedir, 'bin'))
142 f = open(os.path.join(basedir, 'bin', 'exy'), 'w')
145 scripts = dist.getScripts('proj', basedir=basedir)
146 self.assertEqual(len(scripts), 1)
147 self.assertEqual(os.path.basename(scripts[0]), 'exy')
150 def test_noScriptsInSVN(self):
152 When calling getScripts for a project which doesn't actually
153 have any scripts, in the context of an SVN checkout, an
154 empty list should be returned.
156 basedir = self.mktemp()
158 os.mkdir(os.path.join(basedir, 'bin'))
159 os.mkdir(os.path.join(basedir, 'bin', 'otherproj'))
160 scripts = dist.getScripts('noscripts', basedir=basedir)
161 self.assertEqual(scripts, [])
164 def test_getScriptsTopLevel(self):
166 Passing the empty string to getScripts returns scripts that are (only)
167 in the top level bin directory.
169 basedir = FilePath(self.mktemp())
170 basedir.createDirectory()
171 bindir = basedir.child("bin")
172 bindir.createDirectory()
173 included = bindir.child("included")
174 included.setContent("yay included")
175 subdir = bindir.child("subdir")
176 subdir.createDirectory()
177 subdir.child("not-included").setContent("not included")
179 scripts = dist.getScripts("", basedir=basedir.path)
180 self.assertEqual(scripts, [included.path])
183 def test_noScriptsInSubproject(self):
185 When calling getScripts for a project which doesn't actually
186 have any scripts in the context of that project's individual
187 project structure, an empty list should be returned.
189 basedir = self.mktemp()
191 scripts = dist.getScripts('noscripts', basedir=basedir)
192 self.assertEqual(scripts, [])
196 class FakeModule(object):
198 A fake module, suitable for dependency injection in testing.
200 def __init__(self, attrs):
202 Initializes a fake module.
204 @param attrs: The attrs that will be accessible on the module.
205 @type attrs: C{dict} of C{str} (Python names) to objects
209 def __getattr__(self, name):
211 Gets an attribute of this fake module from its attrs.
213 @raise AttributeError: When the requested attribute is missing.
216 return self._attrs[name]
218 raise AttributeError()
222 fakeCPythonPlatform = FakeModule({"python_implementation": lambda: "CPython"})
223 fakeOtherPlatform = FakeModule({"python_implementation": lambda: "lvhpy"})
224 emptyPlatform = FakeModule({})
228 class WithPlatformTests(TestCase):
230 Tests for L{_checkCPython} when used with a (fake) recent C{platform}
233 def test_cpython(self):
235 L{_checkCPython} returns C{True} when C{platform.python_implementation}
236 says we're running on CPython.
238 self.assertTrue(dist._checkCPython(platform=fakeCPythonPlatform))
241 def test_other(self):
243 L{_checkCPython} returns C{False} when C{platform.python_implementation}
244 says we're not running on CPython.
246 self.assertFalse(dist._checkCPython(platform=fakeOtherPlatform))
250 fakeCPythonSys = FakeModule({"subversion": ("CPython", None, None)})
251 fakeOtherSys = FakeModule({"subversion": ("lvhpy", None, None)})
254 def _checkCPythonWithEmptyPlatform(sys):
256 A partially applied L{_checkCPython} that uses an empty C{platform}
257 module (otherwise the code this test case is supposed to test won't
260 return dist._checkCPython(platform=emptyPlatform, sys=sys)
264 class WithSubversionTest(TestCase):
266 Tests for L{_checkCPython} when used with a (fake) recent (2.5+)
267 C{sys.subversion}. This is effectively only relevant for 2.5, since 2.6 and
268 beyond have L{platform.python_implementation}, which is tried first.
270 def test_cpython(self):
272 L{_checkCPython} returns C{True} when C{platform.python_implementation}
273 is unavailable and C{sys.subversion} says we're running on CPython.
275 isCPython = _checkCPythonWithEmptyPlatform(fakeCPythonSys)
276 self.assertTrue(isCPython)
279 def test_other(self):
281 L{_checkCPython} returns C{False} when C{platform.python_implementation}
282 is unavailable and C{sys.subversion} says we're not running on CPython.
284 isCPython = _checkCPythonWithEmptyPlatform(fakeOtherSys)
285 self.assertFalse(isCPython)
289 oldCPythonSys = FakeModule({"modules": {}})
290 oldPypySys = FakeModule({"modules": {"__pypy__": None}})
293 class OldPythonsFallbackTest(TestCase):
295 Tests for L{_checkCPython} when used on a Python 2.4-like platform, when
296 neither C{platform.python_implementation} nor C{sys.subversion} is
299 def test_cpython(self):
301 L{_checkCPython} returns C{True} when both
302 C{platform.python_implementation} and C{sys.subversion} are unavailable
303 and there is no C{__pypy__} module in C{sys.modules}.
305 isCPython = _checkCPythonWithEmptyPlatform(oldCPythonSys)
306 self.assertTrue(isCPython)
311 L{_checkCPython} returns C{False} when both
312 C{platform.python_implementation} and C{sys.subversion} are unavailable
313 and there is a C{__pypy__} module in C{sys.modules}.
315 isCPython = _checkCPythonWithEmptyPlatform(oldPypySys)
316 self.assertFalse(isCPython)