blob: ad91b94ca3d2ebd59c9661cc65384cb5f1cd3e16 [file] [log] [blame]
Tarek Ziade1231a4e2011-05-19 13:07:25 +02001import os
2import io
3import csv
Tarek Ziade1231a4e2011-05-19 13:07:25 +02004import sys
5import shutil
Tarek Ziade1231a4e2011-05-19 13:07:25 +02006import tempfile
Tarek Ziade1231a4e2011-05-19 13:07:25 +02007from hashlib import md5
Tarek Ziadea17d8882011-05-30 10:57:44 +02008from textwrap import dedent
Tarek Ziade1231a4e2011-05-19 13:07:25 +02009
Tarek Ziadea17d8882011-05-30 10:57:44 +020010from packaging.tests.test_util import GlobTestCaseBase
11from packaging.tests.support import requires_zlib
12
Éric Araujo618b7302011-11-14 19:43:37 +010013import packaging.database
Tarek Ziadea17d8882011-05-30 10:57:44 +020014from packaging.config import get_resources_dests
Tarek Ziade1231a4e2011-05-19 13:07:25 +020015from packaging.errors import PackagingError
16from packaging.metadata import Metadata
Tarek Ziade43f289a2011-05-30 11:07:54 +020017from packaging.tests import unittest, support
Tarek Ziade1231a4e2011-05-19 13:07:25 +020018from packaging.database import (
19 Distribution, EggInfoDistribution, get_distribution, get_distributions,
20 provides_distribution, obsoletes_distribution, get_file_users,
Tarek Ziadea17d8882011-05-30 10:57:44 +020021 enable_cache, disable_cache, distinfo_dirname, _yield_distributions,
22 get_file, get_file_path)
Tarek Ziade1231a4e2011-05-19 13:07:25 +020023
24# TODO Add a test for getting a distribution provided by another distribution
25# TODO Add a test for absolute pathed RECORD items (e.g. /etc/myapp/config.ini)
26# TODO Add tests from the former pep376 project (zipped site-packages, etc.)
27
28
29def get_hexdigest(filename):
30 with open(filename, 'rb') as file:
31 checksum = md5(file.read())
32 return checksum.hexdigest()
33
34
Éric Araujo37ccd6f2011-09-15 18:18:51 +020035def record_pieces(path):
36 path = os.path.join(*path)
37 digest = get_hexdigest(path)
38 size = os.path.getsize(path)
39 return path, digest, size
Tarek Ziade1231a4e2011-05-19 13:07:25 +020040
41
Éric Araujob85b9662011-07-31 20:47:47 +020042class FakeDistsMixin:
43
44 def setUp(self):
45 super(FakeDistsMixin, self).setUp()
46 self.addCleanup(enable_cache)
47 disable_cache()
48
49 # make a copy that we can write into for our fake installed
50 # distributions
51 tmpdir = tempfile.mkdtemp()
52 self.addCleanup(shutil.rmtree, tmpdir)
Éric Araujo229011d2011-09-18 20:11:48 +020053 self.fake_dists_path = os.path.realpath(
54 os.path.join(tmpdir, 'fake_dists'))
Éric Araujob85b9662011-07-31 20:47:47 +020055 fake_dists_src = os.path.abspath(
56 os.path.join(os.path.dirname(__file__), 'fake_dists'))
57 shutil.copytree(fake_dists_src, self.fake_dists_path)
58 # XXX ugly workaround: revert copystat calls done by shutil behind our
59 # back (to avoid getting a read-only copy of a read-only file). we
60 # could pass a custom copy_function to change the mode of files, but
61 # shutil gives no control over the mode of directories :(
Éric Araujo229011d2011-09-18 20:11:48 +020062 # see http://bugs.python.org/issue1666318
Éric Araujob85b9662011-07-31 20:47:47 +020063 for root, dirs, files in os.walk(self.fake_dists_path):
64 os.chmod(root, 0o755)
65 for f in files:
66 os.chmod(os.path.join(root, f), 0o644)
67 for d in dirs:
68 os.chmod(os.path.join(root, d), 0o755)
69
70
71class CommonDistributionTests(FakeDistsMixin):
Tarek Ziade1231a4e2011-05-19 13:07:25 +020072 """Mixin used to test the interface common to both Distribution classes.
73
74 Derived classes define cls, sample_dist, dirs and records. These
75 attributes are used in test methods. See source code for details.
76 """
77
Tarek Ziade1231a4e2011-05-19 13:07:25 +020078 def test_instantiation(self):
79 # check that useful attributes are here
80 name, version, distdir = self.sample_dist
81 here = os.path.abspath(os.path.dirname(__file__))
82 dist_path = os.path.join(here, 'fake_dists', distdir)
83
84 dist = self.dist = self.cls(dist_path)
85 self.assertEqual(dist.path, dist_path)
86 self.assertEqual(dist.name, name)
87 self.assertEqual(dist.metadata['Name'], name)
88 self.assertIsInstance(dist.metadata, Metadata)
89 self.assertEqual(dist.version, version)
90 self.assertEqual(dist.metadata['Version'], version)
91
Ezio Melotticad648c2011-05-19 21:25:10 +030092 @requires_zlib
Tarek Ziade1231a4e2011-05-19 13:07:25 +020093 def test_repr(self):
94 dist = self.cls(self.dirs[0])
95 # just check that the class name is in the repr
96 self.assertIn(self.cls.__name__, repr(dist))
97
Ezio Melotticad648c2011-05-19 21:25:10 +030098 @requires_zlib
Tarek Ziade1231a4e2011-05-19 13:07:25 +020099 def test_comparison(self):
100 # tests for __eq__ and __hash__
101 dist = self.cls(self.dirs[0])
102 dist2 = self.cls(self.dirs[0])
103 dist3 = self.cls(self.dirs[1])
104 self.assertIn(dist, {dist: True})
105 self.assertEqual(dist, dist)
106
107 self.assertIsNot(dist, dist2)
108 self.assertEqual(dist, dist2)
109 self.assertNotEqual(dist, dist3)
110 self.assertNotEqual(dist, ())
111
112 def test_list_installed_files(self):
113 for dir_ in self.dirs:
114 dist = self.cls(dir_)
115 for path, md5_, size in dist.list_installed_files():
116 record_data = self.records[dist.path]
117 self.assertIn(path, record_data)
118 self.assertEqual(md5_, record_data[path][0])
119 self.assertEqual(size, record_data[path][1])
120
121
122class TestDistribution(CommonDistributionTests, unittest.TestCase):
123
124 cls = Distribution
125 sample_dist = 'choxie', '2.0.0.9', 'choxie-2.0.0.9.dist-info'
126
127 def setUp(self):
128 super(TestDistribution, self).setUp()
129 self.dirs = [os.path.join(self.fake_dists_path, f)
130 for f in os.listdir(self.fake_dists_path)
131 if f.endswith('.dist-info')]
132
133 self.records = {}
134 for distinfo_dir in self.dirs:
Éric Araujob85b9662011-07-31 20:47:47 +0200135
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200136 record_file = os.path.join(distinfo_dir, 'RECORD')
137 with open(record_file, 'w') as file:
138 record_writer = csv.writer(
Tarek Ziadebe20be12011-05-21 19:45:48 +0200139 file, delimiter=',', quoting=csv.QUOTE_NONE,
140 lineterminator='\n')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200141
142 dist_location = distinfo_dir.replace('.dist-info', '')
143
144 for path, dirs, files in os.walk(dist_location):
145 for f in files:
Éric Araujo37ccd6f2011-09-15 18:18:51 +0200146 record_writer.writerow(record_pieces((path, f)))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200147 for file in ('INSTALLER', 'METADATA', 'REQUESTED'):
Éric Araujo37ccd6f2011-09-15 18:18:51 +0200148 record_writer.writerow(record_pieces((distinfo_dir, file)))
149 record_writer.writerow([record_file])
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200150
151 with open(record_file) as file:
Tarek Ziadebe20be12011-05-21 19:45:48 +0200152 record_reader = csv.reader(file, lineterminator='\n')
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200153 record_data = {}
154 for row in record_reader:
Tarek Ziadebe20be12011-05-21 19:45:48 +0200155 if row == []:
156 continue
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200157 path, md5_, size = (row[:] +
158 [None for i in range(len(row), 3)])
159 record_data[path] = md5_, size
160 self.records[distinfo_dir] = record_data
161
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200162 def test_instantiation(self):
163 super(TestDistribution, self).test_instantiation()
164 self.assertIsInstance(self.dist.requested, bool)
165
166 def test_uses(self):
167 # Test to determine if a distribution uses a specified file.
168 # Criteria to test against
169 distinfo_name = 'grammar-1.0a4'
170 distinfo_dir = os.path.join(self.fake_dists_path,
171 distinfo_name + '.dist-info')
172 true_path = [self.fake_dists_path, distinfo_name,
173 'grammar', 'utils.py']
Éric Araujo37ccd6f2011-09-15 18:18:51 +0200174 true_path = os.path.join(*true_path)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200175 false_path = [self.fake_dists_path, 'towel_stuff-0.1', 'towel_stuff',
176 '__init__.py']
Éric Araujo37ccd6f2011-09-15 18:18:51 +0200177 false_path = os.path.join(*false_path)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200178
179 # Test if the distribution uses the file in question
180 dist = Distribution(distinfo_dir)
Éric Araujo37ccd6f2011-09-15 18:18:51 +0200181 self.assertTrue(dist.uses(true_path), 'dist %r is supposed to use %r' %
182 (dist, true_path))
183 self.assertFalse(dist.uses(false_path), 'dist %r is not supposed to '
184 'use %r' % (dist, true_path))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200185
186 def test_get_distinfo_file(self):
187 # Test the retrieval of dist-info file objects.
188 distinfo_name = 'choxie-2.0.0.9'
189 other_distinfo_name = 'grammar-1.0a4'
190 distinfo_dir = os.path.join(self.fake_dists_path,
191 distinfo_name + '.dist-info')
192 dist = Distribution(distinfo_dir)
193 # Test for known good file matches
194 distinfo_files = [
195 # Relative paths
196 'INSTALLER', 'METADATA',
197 # Absolute paths
198 os.path.join(distinfo_dir, 'RECORD'),
199 os.path.join(distinfo_dir, 'REQUESTED'),
200 ]
201
202 for distfile in distinfo_files:
203 with dist.get_distinfo_file(distfile) as value:
204 self.assertIsInstance(value, io.TextIOWrapper)
205 # Is it the correct file?
206 self.assertEqual(value.name,
207 os.path.join(distinfo_dir, distfile))
208
209 # Test an absolute path that is part of another distributions dist-info
210 other_distinfo_file = os.path.join(
211 self.fake_dists_path, other_distinfo_name + '.dist-info',
212 'REQUESTED')
213 self.assertRaises(PackagingError, dist.get_distinfo_file,
214 other_distinfo_file)
215 # Test for a file that should not exist
216 self.assertRaises(PackagingError, dist.get_distinfo_file,
217 'MAGICFILE')
218
219 def test_list_distinfo_files(self):
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200220 distinfo_name = 'towel_stuff-0.1'
221 distinfo_dir = os.path.join(self.fake_dists_path,
222 distinfo_name + '.dist-info')
223 dist = Distribution(distinfo_dir)
224 # Test for the iteration of the raw path
Éric Araujo37ccd6f2011-09-15 18:18:51 +0200225 distinfo_files = [os.path.join(distinfo_dir, filename) for filename in
226 os.listdir(distinfo_dir)]
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200227 found = dist.list_distinfo_files()
Éric Araujo37ccd6f2011-09-15 18:18:51 +0200228 self.assertEqual(sorted(found), sorted(distinfo_files))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200229 # Test for the iteration of local absolute paths
Éric Araujo37ccd6f2011-09-15 18:18:51 +0200230 distinfo_files = [os.path.join(sys.prefix, distinfo_dir, path) for
231 path in distinfo_files]
232 found = sorted(dist.list_distinfo_files(local=True))
233 if os.sep != '/':
234 self.assertNotIn('/', found[0])
235 self.assertIn(os.sep, found[0])
236 self.assertEqual(found, sorted(distinfo_files))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200237
238 def test_get_resources_path(self):
239 distinfo_name = 'babar-0.1'
240 distinfo_dir = os.path.join(self.fake_dists_path,
241 distinfo_name + '.dist-info')
242 dist = Distribution(distinfo_dir)
243 resource_path = dist.get_resource_path('babar.png')
244 self.assertEqual(resource_path, 'babar.png')
245 self.assertRaises(KeyError, dist.get_resource_path, 'notexist')
246
247
248class TestEggInfoDistribution(CommonDistributionTests,
249 support.LoggingCatcher,
250 unittest.TestCase):
251
252 cls = EggInfoDistribution
253 sample_dist = 'bacon', '0.1', 'bacon-0.1.egg-info'
254
255 def setUp(self):
256 super(TestEggInfoDistribution, self).setUp()
257
258 self.dirs = [os.path.join(self.fake_dists_path, f)
259 for f in os.listdir(self.fake_dists_path)
260 if f.endswith('.egg') or f.endswith('.egg-info')]
261
262 self.records = {}
263
264 @unittest.skip('not implemented yet')
265 def test_list_installed_files(self):
266 # EggInfoDistribution defines list_installed_files but there is no
267 # test for it yet; someone with setuptools expertise needs to add a
268 # file with the list of installed files for one of the egg fake dists
269 # and write the support code to populate self.records (and then delete
270 # this method)
271 pass
272
273
274class TestDatabase(support.LoggingCatcher,
Éric Araujob85b9662011-07-31 20:47:47 +0200275 FakeDistsMixin,
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200276 unittest.TestCase):
277
278 def setUp(self):
279 super(TestDatabase, self).setUp()
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200280 sys.path.insert(0, self.fake_dists_path)
Éric Araujob85b9662011-07-31 20:47:47 +0200281 self.addCleanup(sys.path.remove, self.fake_dists_path)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200282
Éric Araujo618b7302011-11-14 19:43:37 +0100283 def test_caches(self):
284 # sanity check for internal caches
285 for name in ('_cache_name', '_cache_name_egg',
286 '_cache_path', '_cache_path_egg'):
287 self.assertEqual(getattr(packaging.database, name), {})
288
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200289 def test_distinfo_dirname(self):
290 # Given a name and a version, we expect the distinfo_dirname function
291 # to return a standard distribution information directory name.
292
293 items = [
294 # (name, version, standard_dirname)
295 # Test for a very simple single word name and decimal version
296 # number
297 ('docutils', '0.5', 'docutils-0.5.dist-info'),
298 # Test for another except this time with a '-' in the name, which
299 # needs to be transformed during the name lookup
300 ('python-ldap', '2.5', 'python_ldap-2.5.dist-info'),
301 # Test for both '-' in the name and a funky version number
302 ('python-ldap', '2.5 a---5', 'python_ldap-2.5 a---5.dist-info'),
303 ]
304
305 # Loop through the items to validate the results
306 for name, version, standard_dirname in items:
307 dirname = distinfo_dirname(name, version)
308 self.assertEqual(dirname, standard_dirname)
309
Ezio Melotticad648c2011-05-19 21:25:10 +0300310 @requires_zlib
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200311 def test_get_distributions(self):
312 # Lookup all distributions found in the ``sys.path``.
313 # This test could potentially pick up other installed distributions
314 fake_dists = [('grammar', '1.0a4'), ('choxie', '2.0.0.9'),
315 ('towel-stuff', '0.1'), ('babar', '0.1')]
316 found_dists = []
317
318 # Verify the fake dists have been found.
319 dists = [dist for dist in get_distributions()]
320 for dist in dists:
321 self.assertIsInstance(dist, Distribution)
322 if (dist.name in dict(fake_dists) and
323 dist.path.startswith(self.fake_dists_path)):
Éric Araujobab50cb2011-07-29 02:37:21 +0200324 found_dists.append((dist.name, dist.version))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200325 else:
326 # check that it doesn't find anything more than this
327 self.assertFalse(dist.path.startswith(self.fake_dists_path))
328 # otherwise we don't care what other distributions are found
329
330 # Finally, test that we found all that we were looking for
331 self.assertEqual(sorted(found_dists), sorted(fake_dists))
332
333 # Now, test if the egg-info distributions are found correctly as well
334 fake_dists += [('bacon', '0.1'), ('cheese', '2.0.2'),
335 ('coconuts-aster', '10.3'),
336 ('banana', '0.4'), ('strawberry', '0.6'),
337 ('truffles', '5.0'), ('nut', 'funkyversion')]
338 found_dists = []
339
340 dists = [dist for dist in get_distributions(use_egg_info=True)]
341 for dist in dists:
342 self.assertIsInstance(dist, (Distribution, EggInfoDistribution))
343 if (dist.name in dict(fake_dists) and
344 dist.path.startswith(self.fake_dists_path)):
Éric Araujobab50cb2011-07-29 02:37:21 +0200345 found_dists.append((dist.name, dist.version))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200346 else:
347 self.assertFalse(dist.path.startswith(self.fake_dists_path))
348
349 self.assertEqual(sorted(fake_dists), sorted(found_dists))
350
Ezio Melotticad648c2011-05-19 21:25:10 +0300351 @requires_zlib
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200352 def test_get_distribution(self):
353 # Test for looking up a distribution by name.
354 # Test the lookup of the towel-stuff distribution
355 name = 'towel-stuff' # Note: This is different from the directory name
356
357 # Lookup the distribution
358 dist = get_distribution(name)
359 self.assertIsInstance(dist, Distribution)
360 self.assertEqual(dist.name, name)
361
362 # Verify that an unknown distribution returns None
363 self.assertIsNone(get_distribution('bogus'))
364
365 # Verify partial name matching doesn't work
366 self.assertIsNone(get_distribution('towel'))
367
368 # Verify that it does not find egg-info distributions, when not
369 # instructed to
370 self.assertIsNone(get_distribution('bacon'))
371 self.assertIsNone(get_distribution('cheese'))
372 self.assertIsNone(get_distribution('strawberry'))
373 self.assertIsNone(get_distribution('banana'))
374
375 # Now check that it works well in both situations, when egg-info
376 # is a file and directory respectively.
377 dist = get_distribution('cheese', use_egg_info=True)
378 self.assertIsInstance(dist, EggInfoDistribution)
379 self.assertEqual(dist.name, 'cheese')
380
381 dist = get_distribution('bacon', use_egg_info=True)
382 self.assertIsInstance(dist, EggInfoDistribution)
383 self.assertEqual(dist.name, 'bacon')
384
385 dist = get_distribution('banana', use_egg_info=True)
386 self.assertIsInstance(dist, EggInfoDistribution)
387 self.assertEqual(dist.name, 'banana')
388
389 dist = get_distribution('strawberry', use_egg_info=True)
390 self.assertIsInstance(dist, EggInfoDistribution)
391 self.assertEqual(dist.name, 'strawberry')
392
393 def test_get_file_users(self):
394 # Test the iteration of distributions that use a file.
395 name = 'towel_stuff-0.1'
396 path = os.path.join(self.fake_dists_path, name,
397 'towel_stuff', '__init__.py')
398 for dist in get_file_users(path):
399 self.assertIsInstance(dist, Distribution)
400 self.assertEqual(dist.name, name)
401
Ezio Melotticad648c2011-05-19 21:25:10 +0300402 @requires_zlib
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200403 def test_provides(self):
404 # Test for looking up distributions by what they provide
405 checkLists = lambda x, y: self.assertEqual(sorted(x), sorted(y))
406
407 l = [dist.name for dist in provides_distribution('truffles')]
408 checkLists(l, ['choxie', 'towel-stuff'])
409
410 l = [dist.name for dist in provides_distribution('truffles', '1.0')]
411 checkLists(l, ['choxie'])
412
413 l = [dist.name for dist in provides_distribution('truffles', '1.0',
414 use_egg_info=True)]
415 checkLists(l, ['choxie', 'cheese'])
416
417 l = [dist.name for dist in provides_distribution('truffles', '1.1.2')]
418 checkLists(l, ['towel-stuff'])
419
420 l = [dist.name for dist in provides_distribution('truffles', '1.1')]
421 checkLists(l, ['towel-stuff'])
422
423 l = [dist.name for dist in provides_distribution('truffles',
424 '!=1.1,<=2.0')]
425 checkLists(l, ['choxie'])
426
427 l = [dist.name for dist in provides_distribution('truffles',
428 '!=1.1,<=2.0',
429 use_egg_info=True)]
430 checkLists(l, ['choxie', 'bacon', 'cheese'])
431
432 l = [dist.name for dist in provides_distribution('truffles', '>1.0')]
433 checkLists(l, ['towel-stuff'])
434
435 l = [dist.name for dist in provides_distribution('truffles', '>1.5')]
436 checkLists(l, [])
437
438 l = [dist.name for dist in provides_distribution('truffles', '>1.5',
439 use_egg_info=True)]
440 checkLists(l, ['bacon'])
441
442 l = [dist.name for dist in provides_distribution('truffles', '>=1.0')]
443 checkLists(l, ['choxie', 'towel-stuff'])
444
445 l = [dist.name for dist in provides_distribution('strawberry', '0.6',
446 use_egg_info=True)]
447 checkLists(l, ['coconuts-aster'])
448
449 l = [dist.name for dist in provides_distribution('strawberry', '>=0.5',
450 use_egg_info=True)]
451 checkLists(l, ['coconuts-aster'])
452
453 l = [dist.name for dist in provides_distribution('strawberry', '>0.6',
454 use_egg_info=True)]
455 checkLists(l, [])
456
457 l = [dist.name for dist in provides_distribution('banana', '0.4',
458 use_egg_info=True)]
459 checkLists(l, ['coconuts-aster'])
460
461 l = [dist.name for dist in provides_distribution('banana', '>=0.3',
462 use_egg_info=True)]
463 checkLists(l, ['coconuts-aster'])
464
465 l = [dist.name for dist in provides_distribution('banana', '!=0.4',
466 use_egg_info=True)]
467 checkLists(l, [])
468
Ezio Melotticad648c2011-05-19 21:25:10 +0300469 @requires_zlib
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200470 def test_obsoletes(self):
471 # Test looking for distributions based on what they obsolete
472 checkLists = lambda x, y: self.assertEqual(sorted(x), sorted(y))
473
474 l = [dist.name for dist in obsoletes_distribution('truffles', '1.0')]
475 checkLists(l, [])
476
477 l = [dist.name for dist in obsoletes_distribution('truffles', '1.0',
478 use_egg_info=True)]
479 checkLists(l, ['cheese', 'bacon'])
480
481 l = [dist.name for dist in obsoletes_distribution('truffles', '0.8')]
482 checkLists(l, ['choxie'])
483
484 l = [dist.name for dist in obsoletes_distribution('truffles', '0.8',
485 use_egg_info=True)]
486 checkLists(l, ['choxie', 'cheese'])
487
488 l = [dist.name for dist in obsoletes_distribution('truffles', '0.9.6')]
489 checkLists(l, ['choxie', 'towel-stuff'])
490
491 l = [dist.name for dist in obsoletes_distribution('truffles',
492 '0.5.2.3')]
493 checkLists(l, ['choxie', 'towel-stuff'])
494
495 l = [dist.name for dist in obsoletes_distribution('truffles', '0.2')]
496 checkLists(l, ['towel-stuff'])
497
Ezio Melotticad648c2011-05-19 21:25:10 +0300498 @requires_zlib
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200499 def test_yield_distribution(self):
500 # tests the internal function _yield_distributions
501 checkLists = lambda x, y: self.assertEqual(sorted(x), sorted(y))
502
503 eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'),
504 ('truffles', '5.0'), ('cheese', '2.0.2'),
505 ('coconuts-aster', '10.3'), ('nut', 'funkyversion')]
506 dists = [('choxie', '2.0.0.9'), ('grammar', '1.0a4'),
507 ('towel-stuff', '0.1'), ('babar', '0.1')]
508
Éric Araujo6f677652011-06-16 23:43:15 +0200509 checkLists([], _yield_distributions(False, False, sys.path))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200510
Éric Araujobab50cb2011-07-29 02:37:21 +0200511 found = [(dist.name, dist.version)
Éric Araujo6f677652011-06-16 23:43:15 +0200512 for dist in _yield_distributions(False, True, sys.path)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200513 if dist.path.startswith(self.fake_dists_path)]
514 checkLists(eggs, found)
515
Éric Araujobab50cb2011-07-29 02:37:21 +0200516 found = [(dist.name, dist.version)
Éric Araujo6f677652011-06-16 23:43:15 +0200517 for dist in _yield_distributions(True, False, sys.path)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200518 if dist.path.startswith(self.fake_dists_path)]
519 checkLists(dists, found)
520
Éric Araujobab50cb2011-07-29 02:37:21 +0200521 found = [(dist.name, dist.version)
Éric Araujo6f677652011-06-16 23:43:15 +0200522 for dist in _yield_distributions(True, True, sys.path)
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200523 if dist.path.startswith(self.fake_dists_path)]
524 checkLists(dists + eggs, found)
525
526
Tarek Ziadea17d8882011-05-30 10:57:44 +0200527class DataFilesTestCase(GlobTestCaseBase):
528
529 def assertRulesMatch(self, rules, spec):
530 tempdir = self.build_files_tree(spec)
531 expected = self.clean_tree(spec)
532 result = get_resources_dests(tempdir, rules)
533 self.assertEqual(expected, result)
534
535 def clean_tree(self, spec):
536 files = {}
537 for path, value in spec.items():
538 if value is not None:
539 files[path] = value
540 return files
541
542 def test_simple_glob(self):
543 rules = [('', '*.tpl', '{data}')]
544 spec = {'coucou.tpl': '{data}/coucou.tpl',
545 'Donotwant': None}
546 self.assertRulesMatch(rules, spec)
547
548 def test_multiple_match(self):
549 rules = [('scripts', '*.bin', '{appdata}'),
550 ('scripts', '*', '{appscript}')]
551 spec = {'scripts/script.bin': '{appscript}/script.bin',
552 'Babarlikestrawberry': None}
553 self.assertRulesMatch(rules, spec)
554
555 def test_set_match(self):
556 rules = [('scripts', '*.{bin,sh}', '{appscript}')]
557 spec = {'scripts/script.bin': '{appscript}/script.bin',
558 'scripts/babar.sh': '{appscript}/babar.sh',
559 'Babarlikestrawberry': None}
560 self.assertRulesMatch(rules, spec)
561
562 def test_set_match_multiple(self):
563 rules = [('scripts', 'script{s,}.{bin,sh}', '{appscript}')]
564 spec = {'scripts/scripts.bin': '{appscript}/scripts.bin',
565 'scripts/script.sh': '{appscript}/script.sh',
566 'Babarlikestrawberry': None}
567 self.assertRulesMatch(rules, spec)
568
569 def test_set_match_exclude(self):
570 rules = [('scripts', '*', '{appscript}'),
571 ('', os.path.join('**', '*.sh'), None)]
572 spec = {'scripts/scripts.bin': '{appscript}/scripts.bin',
573 'scripts/script.sh': None,
574 'Babarlikestrawberry': None}
575 self.assertRulesMatch(rules, spec)
576
577 def test_glob_in_base(self):
578 rules = [('scrip*', '*.bin', '{appscript}')]
579 spec = {'scripts/scripts.bin': '{appscript}/scripts.bin',
580 'scripouille/babar.bin': '{appscript}/babar.bin',
581 'scriptortu/lotus.bin': '{appscript}/lotus.bin',
582 'Babarlikestrawberry': None}
583 self.assertRulesMatch(rules, spec)
584
585 def test_recursive_glob(self):
586 rules = [('', os.path.join('**', '*.bin'), '{binary}')]
587 spec = {'binary0.bin': '{binary}/binary0.bin',
588 'scripts/binary1.bin': '{binary}/scripts/binary1.bin',
589 'scripts/bin/binary2.bin': '{binary}/scripts/bin/binary2.bin',
590 'you/kill/pandabear.guy': None}
591 self.assertRulesMatch(rules, spec)
592
593 def test_final_exemple_glob(self):
594 rules = [
595 ('mailman/database/schemas/', '*', '{appdata}/schemas'),
596 ('', os.path.join('**', '*.tpl'), '{appdata}/templates'),
597 ('', os.path.join('developer-docs', '**', '*.txt'), '{doc}'),
598 ('', 'README', '{doc}'),
599 ('mailman/etc/', '*', '{config}'),
Tarek Ziade43f289a2011-05-30 11:07:54 +0200600 ('mailman/foo/', os.path.join('**', 'bar', '*.cfg'),
601 '{config}/baz'),
Tarek Ziadea17d8882011-05-30 10:57:44 +0200602 ('mailman/foo/', os.path.join('**', '*.cfg'), '{config}/hmm'),
603 ('', 'some-new-semantic.sns', '{funky-crazy-category}'),
604 ]
605 spec = {
606 'README': '{doc}/README',
607 'some.tpl': '{appdata}/templates/some.tpl',
608 'some-new-semantic.sns':
609 '{funky-crazy-category}/some-new-semantic.sns',
610 'mailman/database/mailman.db': None,
611 'mailman/database/schemas/blah.schema':
612 '{appdata}/schemas/blah.schema',
613 'mailman/etc/my.cnf': '{config}/my.cnf',
614 'mailman/foo/some/path/bar/my.cfg':
615 '{config}/hmm/some/path/bar/my.cfg',
616 'mailman/foo/some/path/other.cfg':
617 '{config}/hmm/some/path/other.cfg',
618 'developer-docs/index.txt': '{doc}/developer-docs/index.txt',
619 'developer-docs/api/toc.txt': '{doc}/developer-docs/api/toc.txt',
620 }
621 self.maxDiff = None
622 self.assertRulesMatch(rules, spec)
623
624 def test_get_file(self):
625 # Create a fake dist
626 temp_site_packages = tempfile.mkdtemp()
627 self.addCleanup(shutil.rmtree, temp_site_packages)
628
629 dist_name = 'test'
630 dist_info = os.path.join(temp_site_packages, 'test-0.1.dist-info')
631 os.mkdir(dist_info)
632
633 metadata_path = os.path.join(dist_info, 'METADATA')
634 resources_path = os.path.join(dist_info, 'RESOURCES')
635
636 with open(metadata_path, 'w') as fp:
637 fp.write(dedent("""\
638 Metadata-Version: 1.2
639 Name: test
640 Version: 0.1
641 Summary: test
642 Author: me
643 """))
644
645 test_path = 'test.cfg'
646
647 fd, test_resource_path = tempfile.mkstemp()
648 os.close(fd)
649 self.addCleanup(os.remove, test_resource_path)
650
651 with open(test_resource_path, 'w') as fp:
652 fp.write('Config')
653
654 with open(resources_path, 'w') as fp:
655 fp.write('%s,%s' % (test_path, test_resource_path))
656
657 # Add fake site-packages to sys.path to retrieve fake dist
658 self.addCleanup(sys.path.remove, temp_site_packages)
659 sys.path.insert(0, temp_site_packages)
660
661 # Force packaging.database to rescan the sys.path
662 self.addCleanup(enable_cache)
663 disable_cache()
664
665 # Try to retrieve resources paths and files
666 self.assertEqual(get_file_path(dist_name, test_path),
667 test_resource_path)
668 self.assertRaises(KeyError, get_file_path, dist_name, 'i-dont-exist')
669
670 with get_file(dist_name, test_path) as fp:
671 self.assertEqual(fp.read(), 'Config')
672 self.assertRaises(KeyError, get_file, dist_name, 'i-dont-exist')
673
674
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200675def test_suite():
676 suite = unittest.TestSuite()
677 load = unittest.defaultTestLoader.loadTestsFromTestCase
678 suite.addTest(load(TestDistribution))
679 suite.addTest(load(TestEggInfoDistribution))
680 suite.addTest(load(TestDatabase))
Tarek Ziadea17d8882011-05-30 10:57:44 +0200681 suite.addTest(load(DataFilesTestCase))
Tarek Ziade1231a4e2011-05-19 13:07:25 +0200682 return suite
683
684
685if __name__ == "__main__":
686 unittest.main(defaultTest='test_suite')