1import unittest
2
3class DistributionTests(unittest.TestCase):
4
5    def _getTargetClass(self):
6        from pkginfo.distribution import Distribution
7        return Distribution
8
9    def _makeOne(self, metadata_version='1.0'):
10        dist = self._getTargetClass()()
11        if metadata_version is not None:
12            dist.metadata_version = metadata_version
13        return dist
14
15    def test_ctor_defaults(self):
16        sdist = self._makeOne(None)
17        self.assertEqual(sdist.metadata_version, None)
18        # version 1.0
19        self.assertEqual(sdist.name, None)
20        self.assertEqual(sdist.version, None)
21        self.assertEqual(sdist.platforms, ())
22        self.assertEqual(sdist.supported_platforms, ())
23        self.assertEqual(sdist.summary, None)
24        self.assertEqual(sdist.description, None)
25        self.assertEqual(sdist.keywords, None)
26        self.assertEqual(sdist.home_page, None)
27        self.assertEqual(sdist.download_url, None)
28        self.assertEqual(sdist.author, None)
29        self.assertEqual(sdist.author_email, None)
30        self.assertEqual(sdist.license, None)
31        # version 1.1
32        self.assertEqual(sdist.classifiers, ())
33        self.assertEqual(sdist.requires, ())
34        self.assertEqual(sdist.provides, ())
35        self.assertEqual(sdist.obsoletes, ())
36        # version 1.2
37        self.assertEqual(sdist.maintainer, None)
38        self.assertEqual(sdist.maintainer_email, None)
39        self.assertEqual(sdist.requires_python, None)
40        self.assertEqual(sdist.requires_external, ())
41        self.assertEqual(sdist.requires_dist, ())
42        self.assertEqual(sdist.provides_dist, ())
43        self.assertEqual(sdist.obsoletes_dist, ())
44        self.assertEqual(sdist.project_urls, ())
45        # version 2.1
46        self.assertEqual(sdist.provides_extras, ())
47        self.assertEqual(sdist.description_content_type, None)
48        # version 2.2
49        self.assertEqual(sdist.dynamic, ())
50
51    def test_extractMetadata_raises_NotImplementedError(self):
52        # 'extractMetadata' calls 'read', which subclasses must override.
53        dist = self._makeOne(None)
54        self.assertRaises(NotImplementedError, dist.extractMetadata)
55
56    def test_read_raises_NotImplementedError(self):
57        # Subclasses must override 'read'.
58        dist = self._makeOne(None)
59        self.assertRaises(NotImplementedError, dist.read)
60
61    def test_parse_given_unicode(self):
62        from pkginfo._compat import u
63        dist = self._makeOne()
64        dist.parse(u('Metadata-Version: 1.0\nName: lp722928_c3')) # no raise
65
66    def test_parse_Metadata_Version_1_0(self):
67        from pkginfo.distribution import HEADER_ATTRS_1_0
68        dist = self._makeOne(None)
69        dist.parse('Metadata-Version: 1.0')
70        self.assertEqual(dist.metadata_version, '1.0')
71        self.assertEqual(list(dist),
72                         [x[1] for x in HEADER_ATTRS_1_0])
73
74    def test_parse_Metadata_Version_1_1(self):
75        from pkginfo.distribution import HEADER_ATTRS_1_1
76        dist = self._makeOne(None)
77        dist.parse('Metadata-Version: 1.1')
78        self.assertEqual(dist.metadata_version, '1.1')
79        self.assertEqual(list(dist),
80                         [x[1] for x in HEADER_ATTRS_1_1])
81
82    def test_parse_Metadata_Version_1_2(self):
83        from pkginfo.distribution import HEADER_ATTRS_1_2
84        dist = self._makeOne(None)
85        dist.parse('Metadata-Version: 1.2')
86        self.assertEqual(dist.metadata_version, '1.2')
87        self.assertEqual(list(dist),
88                         [x[1] for x in HEADER_ATTRS_1_2])
89
90    def test_parse_Metadata_Version_2_1(self):
91        from pkginfo.distribution import HEADER_ATTRS_2_1
92        dist = self._makeOne(None)
93        dist.parse('Metadata-Version: 2.1')
94        self.assertEqual(dist.metadata_version, '2.1')
95        self.assertEqual(list(dist),
96                         [x[1] for x in HEADER_ATTRS_2_1])
97
98    def test_parse_Metadata_Version_2_2(self):
99        from pkginfo.distribution import HEADER_ATTRS_2_2
100        dist = self._makeOne(None)
101        dist.parse('Metadata-Version: 2.2')
102        self.assertEqual(dist.metadata_version, '2.2')
103        self.assertEqual(list(dist),
104                         [x[1] for x in HEADER_ATTRS_2_2])
105
106    def test_parse_Metadata_Version_unknown(self):
107        dist = self._makeOne(None)
108        dist.parse('Metadata-Version: 1.3')
109        self.assertEqual(dist.metadata_version, '1.3')
110        self.assertEqual(list(dist), [])
111
112    def test_parse_Metadata_Version_override(self):
113        dist = self._makeOne('1.2')
114        dist.parse('Metadata-Version: 1.0')
115        self.assertEqual(dist.metadata_version, '1.2')
116
117    def test_parse_Name(self):
118        dist = self._makeOne()
119        dist.parse('Name: foobar')
120        self.assertEqual(dist.name, 'foobar')
121
122    def test_parse_Version(self):
123        dist = self._makeOne()
124        dist.parse('Version: 2.1.3b5')
125        self.assertEqual(dist.version, '2.1.3b5')
126
127    def test_parse_Platform_single(self):
128        dist = self._makeOne()
129        dist.parse('Platform: Plan9')
130        self.assertEqual(list(dist.platforms), ['Plan9'])
131
132    def test_parse_Platform_multiple(self):
133        dist = self._makeOne()
134        dist.parse('Platform: Plan9\nPlatform: AIX')
135        self.assertEqual(list(dist.platforms), ['Plan9', 'AIX'])
136
137    def test_parse_Supported_Platform_single(self):
138        dist = self._makeOne()
139        dist.parse('Supported-Platform: Plan9')
140        self.assertEqual(list(dist.supported_platforms), ['Plan9'])
141
142    def test_parse_Supported_Platform_multiple(self):
143        dist = self._makeOne()
144        dist.parse('Supported-Platform: i386-win32\n'
145                   'Supported-Platform: RedHat 7.2')
146        self.assertEqual(list(dist.supported_platforms),
147                        ['i386-win32', 'RedHat 7.2'])
148
149    def test_parse_Summary(self):
150        dist = self._makeOne()
151        dist.parse('Summary: Package for foo')
152        self.assertEqual(dist.summary, 'Package for foo')
153
154    def test_parse_Description(self):
155        dist = self._makeOne()
156        dist.parse('Description: This package enables integration with '
157                   'foo servers.')
158        self.assertEqual(dist.description,
159                         'This package enables integration with '
160                         'foo servers.')
161
162    def test_parse_Description_multiline(self):
163        dist = self._makeOne()
164        dist.parse('Description: This package enables integration with\n'
165                   '        foo servers.')
166        self.assertEqual(dist.description,
167                         'This package enables integration with\n'
168                         'foo servers.')
169
170    def test_parse_Description_in_payload(self):
171        dist = self._makeOne()
172        dist.parse('Foo: Bar\n'
173                   '\n'
174                   'This package enables integration with\n'
175                   'foo servers.')
176        self.assertEqual(dist.description,
177                         'This package enables integration with\n'
178                         'foo servers.')
179
180    def test_parse_Keywords(self):
181        dist = self._makeOne()
182        dist.parse('Keywords: bar foo qux')
183        self.assertEqual(dist.keywords, 'bar foo qux')
184
185    def test_parse_Home_page(self):
186        dist = self._makeOne()
187        dist.parse('Home-page: http://example.com/package')
188        self.assertEqual(dist.home_page, 'http://example.com/package')
189
190    def test_parse_Author(self):
191        dist = self._makeOne()
192        dist.parse('Author: J. Phredd Bloggs')
193        self.assertEqual(dist.author, 'J. Phredd Bloggs')
194
195    def test_parse_Author_Email(self):
196        dist = self._makeOne()
197        dist.parse('Author-email: phreddy@example.com')
198        self.assertEqual(dist.author_email, 'phreddy@example.com')
199
200    def test_parse_License(self):
201        dist = self._makeOne()
202        dist.parse('License: Poetic')
203        self.assertEqual(dist.license, 'Poetic')
204
205    # Metadata version 1.1, defined in PEP 314.
206    def test_parse_Classifier_single(self):
207        dist = self._makeOne('1.1')
208        dist.parse('Classifier: Some :: Silly Thing')
209        self.assertEqual(list(dist.classifiers), ['Some :: Silly Thing'])
210
211    def test_parse_Classifier_multiple(self):
212        dist = self._makeOne('1.1')
213        dist.parse('Classifier: Some :: Silly Thing\n'
214                   'Classifier: Or :: Other')
215        self.assertEqual(list(dist.classifiers),
216                         ['Some :: Silly Thing', 'Or :: Other'])
217
218    def test_parse_Download_URL(self):
219        dist = self._makeOne('1.1')
220        dist.parse('Download-URL: '
221                   'http://example.com/package/mypackage-0.1.zip')
222        self.assertEqual(dist.download_url,
223                         'http://example.com/package/mypackage-0.1.zip')
224
225    def test_parse_Requires_single_wo_version(self):
226        dist = self._makeOne('1.1')
227        dist.parse('Requires: SpanishInquisition')
228        self.assertEqual(list(dist.requires), ['SpanishInquisition'])
229
230    def test_parse_Requires_single_w_version(self):
231        dist = self._makeOne('1.1')
232        dist.parse('Requires: SpanishInquisition (>=1.3)')
233        self.assertEqual(list(dist.requires), ['SpanishInquisition (>=1.3)'])
234
235    def test_parse_Requires_multiple(self):
236        dist = self._makeOne('1.1')
237        dist.parse('Requires: SpanishInquisition\n'
238                   'Requires: SillyWalks (1.4)\n'
239                   'Requires: kniggits (>=2.3,<3.0)')
240        self.assertEqual(list(dist.requires),
241                         ['SpanishInquisition',
242                          'SillyWalks (1.4)',
243                          'kniggits (>=2.3,<3.0)',
244                         ])
245
246    def test_parse_Provides_single_wo_version(self):
247        dist = self._makeOne('1.1')
248        dist.parse('Provides: SillyWalks')
249        self.assertEqual(list(dist.provides), ['SillyWalks'])
250
251    def test_parse_Provides_single_w_version(self):
252        dist = self._makeOne('1.1')
253        dist.parse('Provides: SillyWalks (1.4)')
254        self.assertEqual(list(dist.provides), ['SillyWalks (1.4)'])
255
256    def test_parse_Provides_multiple(self):
257        dist = self._makeOne('1.1')
258        dist.parse('Provides: SillyWalks\n'
259                   'Provides: DeadlyJoke (3.1.4)')
260        self.assertEqual(list(dist.provides),
261                         ['SillyWalks',
262                          'DeadlyJoke (3.1.4)',
263                         ])
264
265    def test_parse_Obsoletes_single_no_version(self):
266        dist = self._makeOne('1.1')
267        dist.parse('Obsoletes: SillyWalks')
268        self.assertEqual(list(dist.obsoletes), ['SillyWalks'])
269
270    def test_parse_Obsoletes_single_w_version(self):
271        dist = self._makeOne('1.1')
272        dist.parse('Obsoletes: SillyWalks (<=1.3)')
273        self.assertEqual(list(dist.obsoletes), ['SillyWalks (<=1.3)'])
274
275    def test_parse_Obsoletes_multiple(self):
276        dist = self._makeOne('1.1')
277        dist.parse('Obsoletes: kniggits\n'
278                   'Obsoletes: SillyWalks (<=2.0)')
279        self.assertEqual(list(dist.obsoletes),
280                         ['kniggits',
281                          'SillyWalks (<=2.0)',
282                         ])
283
284
285    # Metadata version 1.2, defined in PEP 345.
286    def test_parse_Maintainer(self):
287        dist = self._makeOne(metadata_version='1.2')
288        dist.parse('Maintainer: J. Phredd Bloggs')
289        self.assertEqual(dist.maintainer, 'J. Phredd Bloggs')
290
291    def test_parse_Maintainer_Email(self):
292        dist = self._makeOne(metadata_version='1.2')
293        dist.parse('Maintainer-email: phreddy@example.com')
294        self.assertEqual(dist.maintainer_email, 'phreddy@example.com')
295
296    def test_parse_Requires_Python_single_spec(self):
297        dist = self._makeOne('1.2')
298        dist.parse('Requires-Python: >2.4')
299        self.assertEqual(dist.requires_python, '>2.4')
300
301    def test_parse_Requires_External_single_wo_version(self):
302        dist = self._makeOne('1.2')
303        dist.parse('Requires-External: libfoo')
304        self.assertEqual(list(dist.requires_external), ['libfoo'])
305
306    def test_parse_Requires_External_single_w_version(self):
307        dist = self._makeOne('1.2')
308        dist.parse('Requires-External: libfoo (>=1.3)')
309        self.assertEqual(list(dist.requires_external), ['libfoo (>=1.3)'])
310
311    def test_parse_Requires_External_multiple(self):
312        dist = self._makeOne('1.2')
313        dist.parse('Requires-External: libfoo\n'
314                   'Requires-External: libbar (1.4)\n'
315                   'Requires-External: libbaz (>=2.3,<3.0)')
316        self.assertEqual(list(dist.requires_external),
317                         ['libfoo',
318                          'libbar (1.4)',
319                          'libbaz (>=2.3,<3.0)',
320                         ])
321
322
323    def test_parse_Requires_Dist_single_wo_version(self):
324        dist = self._makeOne('1.2')
325        dist.parse('Requires-Dist: SpanishInquisition')
326        self.assertEqual(list(dist.requires_dist), ['SpanishInquisition'])
327
328    def test_parse_Requires_Dist_single_w_version(self):
329        dist = self._makeOne('1.2')
330        dist.parse('Requires-Dist: SpanishInquisition (>=1.3)')
331        self.assertEqual(list(dist.requires_dist),
332                         ['SpanishInquisition (>=1.3)'])
333
334    def test_parse_Requires_Dist_single_w_env_marker(self):
335        dist = self._makeOne('1.2')
336        dist.parse("Requires-Dist: SpanishInquisition; "
337                        "python_version == '1.4'")
338        self.assertEqual(list(dist.requires_dist),
339                         ["SpanishInquisition; python_version == '1.4'"])
340
341    def test_parse_Requires_Dist_multiple(self):
342        dist = self._makeOne('1.2')
343        dist.parse("Requires-Dist: SpanishInquisition\n"
344                   "Requires-Dist: SillyWalks; python_version == '1.4'\n"
345                   "Requires-Dist: kniggits (>=2.3,<3.0)")
346        self.assertEqual(list(dist.requires_dist),
347                         ["SpanishInquisition",
348                          "SillyWalks; python_version == '1.4'",
349                          "kniggits (>=2.3,<3.0)",
350                         ])
351
352    def test_parse_Provides_Dist_single_wo_version(self):
353        dist = self._makeOne('1.2')
354        dist.parse('Provides-Dist: SillyWalks')
355        self.assertEqual(list(dist.provides_dist), ['SillyWalks'])
356
357    def test_parse_Provides_Dist_single_w_version(self):
358        dist = self._makeOne('1.2')
359        dist.parse('Provides-Dist: SillyWalks (1.4)')
360        self.assertEqual(list(dist.provides_dist), ['SillyWalks (1.4)'])
361
362    def test_parse_Provides_Dist_single_w_env_marker(self):
363        dist = self._makeOne('1.2')
364        dist.parse("Provides-Dist: SillyWalks; sys.platform == 'os2'")
365        self.assertEqual(list(dist.provides_dist),
366                         ["SillyWalks; sys.platform == 'os2'"])
367
368    def test_parse_Provides_Dist_multiple(self):
369        dist = self._makeOne('1.2')
370        dist.parse("Provides-Dist: SillyWalks\n"
371                   "Provides-Dist: SpanishInquisition; sys.platform == 'os2'\n"
372                   "Provides-Dist: DeadlyJoke (3.1.4)")
373        self.assertEqual(list(dist.provides_dist),
374                         ["SillyWalks",
375                          "SpanishInquisition; sys.platform == 'os2'",
376                          "DeadlyJoke (3.1.4)",
377                         ])
378
379    def test_parse_Obsoletes_Dist_single_no_version(self):
380        dist = self._makeOne('1.2')
381        dist.parse('Obsoletes-Dist: SillyWalks')
382        self.assertEqual(list(dist.obsoletes_dist), ['SillyWalks'])
383
384    def test_parse_Obsoletes_Dist_single_w_version(self):
385        dist = self._makeOne('1.2')
386        dist.parse('Obsoletes-Dist: SillyWalks (<=1.3)')
387        self.assertEqual(list(dist.obsoletes_dist), ['SillyWalks (<=1.3)'])
388
389    def test_parse_Obsoletes_Dist_single_w_env_marker(self):
390        dist = self._makeOne('1.2')
391        dist.parse("Obsoletes-Dist: SillyWalks; sys.platform == 'os2'")
392        self.assertEqual(list(dist.obsoletes_dist),
393                         ["SillyWalks; sys.platform == 'os2'"])
394
395    def test_parse_Obsoletes_Dist_multiple(self):
396        dist = self._makeOne('1.2')
397        dist.parse("Obsoletes-Dist: kniggits\n"
398                   "Obsoletes-Dist: SillyWalks; sys.platform == 'os2'\n"
399                   "Obsoletes-Dist: DeadlyJoke (<=2.0)\n"
400                  )
401        self.assertEqual(list(dist.obsoletes_dist),
402                         ["kniggits",
403                          "SillyWalks; sys.platform == 'os2'",
404                          "DeadlyJoke (<=2.0)",
405                         ])
406
407    def test_parse_Project_URL_single_no_version(self):
408        dist = self._makeOne('1.2')
409        dist.parse('Project-URL: Bug tracker, http://bugs.example.com/grail')
410        self.assertEqual(list(dist.project_urls),
411                         ['Bug tracker, http://bugs.example.com/grail'])
412
413    def test_parse_Project_URL_multiple(self):
414        dist = self._makeOne('1.2')
415        dist.parse('Project-URL: Bug tracker, http://bugs.example.com/grail\n'
416                   'Project-URL: Repository, http://svn.example.com/grail')
417        self.assertEqual(list(dist.project_urls),
418                         ['Bug tracker, http://bugs.example.com/grail',
419                          'Repository, http://svn.example.com/grail',
420                         ])
421
422    # Metadata version 2.1, defined in PEP 566.
423    def test_parse_Provides_Extra_single(self):
424        dist = self._makeOne('2.1')
425        dist.parse('Provides-Extra: pdf')
426        self.assertEqual(list(dist.provides_extras), ['pdf'])
427
428    def test_parse_Provides_Extra_multiple(self):
429        dist = self._makeOne('2.1')
430        dist.parse('Provides-Extra: pdf\n'
431                   'Provides-Extra: tex')
432        self.assertEqual(list(dist.provides_extras), ['pdf', 'tex'])
433
434    def test_parse_Provides_Extra_single(self):
435        dist = self._makeOne('2.1')
436        dist.parse('Description-Content-Type: text/plain')
437        self.assertEqual(dist.description_content_type, 'text/plain')
438
439    # Metadata version 2.2, defined in PEP 643.
440    def test_parse_Dynamic_single(self):
441        dist = self._makeOne('2.2')
442        dist.parse('Dynamic: Platforms')
443        self.assertEqual(list(dist.dynamic), ['Platforms'])
444
445    def test_parse_Dynamic_multiple(self):
446        dist = self._makeOne('2.2')
447        dist.parse('Dynamic: Platforms\n'
448                   'Dynamic: Supported-Platforms')
449        self.assertEqual(list(dist.dynamic),
450                         ['Platforms', 'Supported-Platforms'])
451