33
|
1 # -*- coding: utf-8 -*-
|
|
2 #
|
|
3 # test_version.py
|
|
4 # Part of ‘python-daemon’, an implementation of PEP 3143.
|
|
5 #
|
|
6 # Copyright © 2008–2015 Ben Finney <ben+python@benfinney.id.au>
|
|
7 #
|
|
8 # This is free software: you may copy, modify, and/or distribute this work
|
|
9 # under the terms of the GNU General Public License as published by the
|
|
10 # Free Software Foundation; version 3 of that license or any later version.
|
|
11 # No warranty expressed or implied. See the file ‘LICENSE.GPL-3’ for details.
|
|
12
|
|
13 """ Unit test for ‘version’ packaging module. """
|
|
14
|
|
15 from __future__ import (absolute_import, unicode_literals)
|
|
16
|
|
17 import os
|
|
18 import os.path
|
|
19 import io
|
|
20 import errno
|
|
21 import functools
|
|
22 import collections
|
|
23 import textwrap
|
|
24 import json
|
|
25 import tempfile
|
|
26 import distutils.dist
|
|
27 import distutils.cmd
|
|
28 import distutils.errors
|
|
29 import distutils.fancy_getopt
|
|
30 try:
|
|
31 # Standard library of Python 2.7 and later.
|
|
32 from io import StringIO
|
|
33 except ImportError:
|
|
34 # Standard library of Python 2.6 and earlier.
|
|
35 from StringIO import StringIO
|
|
36
|
|
37 import mock
|
|
38 import testtools
|
|
39 import testscenarios
|
|
40 import docutils
|
|
41 import docutils.writers
|
|
42 import docutils.nodes
|
|
43 import setuptools
|
|
44 import setuptools.command
|
|
45
|
|
46 import version
|
|
47
|
|
48 version.ensure_class_bases_begin_with(
|
|
49 version.__dict__, str('VersionInfoWriter'), docutils.writers.Writer)
|
|
50 version.ensure_class_bases_begin_with(
|
|
51 version.__dict__, str('VersionInfoTranslator'),
|
|
52 docutils.nodes.SparseNodeVisitor)
|
|
53
|
|
54
|
|
55 def make_test_classes_for_ensure_class_bases_begin_with():
|
|
56 """ Make test classes for use with ‘ensure_class_bases_begin_with’.
|
|
57
|
|
58 :return: Mapping {`name`: `type`} of the custom types created.
|
|
59
|
|
60 """
|
|
61
|
|
62 class quux_metaclass(type):
|
|
63 def __new__(metaclass, name, bases, namespace):
|
|
64 return super(quux_metaclass, metaclass).__new__(
|
|
65 metaclass, name, bases, namespace)
|
|
66
|
|
67 class Foo(object):
|
|
68 __metaclass__ = type
|
|
69
|
|
70 class Bar(object):
|
|
71 pass
|
|
72
|
|
73 class FooInheritingBar(Bar):
|
|
74 __metaclass__ = type
|
|
75
|
|
76 class FooWithCustomMetaclass(object):
|
|
77 __metaclass__ = quux_metaclass
|
|
78
|
|
79 result = dict(
|
|
80 (name, value) for (name, value) in locals().items()
|
|
81 if isinstance(value, type))
|
|
82
|
|
83 return result
|
|
84
|
|
85 class ensure_class_bases_begin_with_TestCase(
|
|
86 testscenarios.WithScenarios, testtools.TestCase):
|
|
87 """ Test cases for ‘ensure_class_bases_begin_with’ function. """
|
|
88
|
|
89 test_classes = make_test_classes_for_ensure_class_bases_begin_with()
|
|
90
|
|
91 scenarios = [
|
|
92 ('simple', {
|
|
93 'test_class': test_classes['Foo'],
|
|
94 'base_class': test_classes['Bar'],
|
|
95 }),
|
|
96 ('custom metaclass', {
|
|
97 'test_class': test_classes['FooWithCustomMetaclass'],
|
|
98 'base_class': test_classes['Bar'],
|
|
99 'expected_metaclass': test_classes['quux_metaclass'],
|
|
100 }),
|
|
101 ]
|
|
102
|
|
103 def setUp(self):
|
|
104 """ Set up test fixtures. """
|
|
105 super(ensure_class_bases_begin_with_TestCase, self).setUp()
|
|
106
|
|
107 self.class_name = self.test_class.__name__
|
|
108 self.test_module_namespace = {self.class_name: self.test_class}
|
|
109
|
|
110 if not hasattr(self, 'expected_metaclass'):
|
|
111 self.expected_metaclass = type
|
|
112
|
|
113 patcher_metaclass = mock.patch.object(
|
|
114 self.test_class, '__metaclass__')
|
|
115 patcher_metaclass.start()
|
|
116 self.addCleanup(patcher_metaclass.stop)
|
|
117
|
|
118 self.fake_new_class = type(object)
|
|
119 self.test_class.__metaclass__.return_value = (
|
|
120 self.fake_new_class)
|
|
121
|
|
122 def test_module_namespace_contains_new_class(self):
|
|
123 """ Specified module namespace should have new class. """
|
|
124 version.ensure_class_bases_begin_with(
|
|
125 self.test_module_namespace, self.class_name, self.base_class)
|
|
126 self.assertIn(self.fake_new_class, self.test_module_namespace.values())
|
|
127
|
|
128 def test_calls_metaclass_with_expected_class_name(self):
|
|
129 """ Should call the metaclass with the expected class name. """
|
|
130 version.ensure_class_bases_begin_with(
|
|
131 self.test_module_namespace, self.class_name, self.base_class)
|
|
132 expected_class_name = self.class_name
|
|
133 self.test_class.__metaclass__.assert_called_with(
|
|
134 expected_class_name, mock.ANY, mock.ANY)
|
|
135
|
|
136 def test_calls_metaclass_with_expected_bases(self):
|
|
137 """ Should call the metaclass with the expected bases. """
|
|
138 version.ensure_class_bases_begin_with(
|
|
139 self.test_module_namespace, self.class_name, self.base_class)
|
|
140 expected_bases = tuple(
|
|
141 [self.base_class]
|
|
142 + list(self.test_class.__bases__))
|
|
143 self.test_class.__metaclass__.assert_called_with(
|
|
144 mock.ANY, expected_bases, mock.ANY)
|
|
145
|
|
146 def test_calls_metaclass_with_expected_namespace(self):
|
|
147 """ Should call the metaclass with the expected class namespace. """
|
|
148 version.ensure_class_bases_begin_with(
|
|
149 self.test_module_namespace, self.class_name, self.base_class)
|
|
150 expected_namespace = self.test_class.__dict__.copy()
|
|
151 del expected_namespace['__dict__']
|
|
152 self.test_class.__metaclass__.assert_called_with(
|
|
153 mock.ANY, mock.ANY, expected_namespace)
|
|
154
|
|
155
|
|
156 class ensure_class_bases_begin_with_AlreadyHasBase_TestCase(
|
|
157 testscenarios.WithScenarios, testtools.TestCase):
|
|
158 """ Test cases for ‘ensure_class_bases_begin_with’ function.
|
|
159
|
|
160 These test cases test the conditions where the class's base is
|
|
161 already the specified base class.
|
|
162
|
|
163 """
|
|
164
|
|
165 test_classes = make_test_classes_for_ensure_class_bases_begin_with()
|
|
166
|
|
167 scenarios = [
|
|
168 ('already Bar subclass', {
|
|
169 'test_class': test_classes['FooInheritingBar'],
|
|
170 'base_class': test_classes['Bar'],
|
|
171 }),
|
|
172 ]
|
|
173
|
|
174 def setUp(self):
|
|
175 """ Set up test fixtures. """
|
|
176 super(
|
|
177 ensure_class_bases_begin_with_AlreadyHasBase_TestCase,
|
|
178 self).setUp()
|
|
179
|
|
180 self.class_name = self.test_class.__name__
|
|
181 self.test_module_namespace = {self.class_name: self.test_class}
|
|
182
|
|
183 patcher_metaclass = mock.patch.object(
|
|
184 self.test_class, '__metaclass__')
|
|
185 patcher_metaclass.start()
|
|
186 self.addCleanup(patcher_metaclass.stop)
|
|
187
|
|
188 def test_metaclass_not_called(self):
|
|
189 """ Should not call metaclass to create a new type. """
|
|
190 version.ensure_class_bases_begin_with(
|
|
191 self.test_module_namespace, self.class_name, self.base_class)
|
|
192 self.assertFalse(self.test_class.__metaclass__.called)
|
|
193
|
|
194
|
|
195 class VersionInfoWriter_TestCase(testtools.TestCase):
|
|
196 """ Test cases for ‘VersionInfoWriter’ class. """
|
|
197
|
|
198 def setUp(self):
|
|
199 """ Set up test fixtures. """
|
|
200 super(VersionInfoWriter_TestCase, self).setUp()
|
|
201
|
|
202 self.test_instance = version.VersionInfoWriter()
|
|
203
|
|
204 def test_declares_version_info_support(self):
|
|
205 """ Should declare support for ‘version_info’. """
|
|
206 instance = self.test_instance
|
|
207 expected_support = "version_info"
|
|
208 result = instance.supports(expected_support)
|
|
209 self.assertTrue(result)
|
|
210
|
|
211
|
|
212 class VersionInfoWriter_translate_TestCase(testtools.TestCase):
|
|
213 """ Test cases for ‘VersionInfoWriter.translate’ method. """
|
|
214
|
|
215 def setUp(self):
|
|
216 """ Set up test fixtures. """
|
|
217 super(VersionInfoWriter_translate_TestCase, self).setUp()
|
|
218
|
|
219 patcher_translator = mock.patch.object(
|
|
220 version, 'VersionInfoTranslator')
|
|
221 self.mock_class_translator = patcher_translator.start()
|
|
222 self.addCleanup(patcher_translator.stop)
|
|
223 self.mock_translator = self.mock_class_translator.return_value
|
|
224
|
|
225 self.test_instance = version.VersionInfoWriter()
|
|
226 patcher_document = mock.patch.object(
|
|
227 self.test_instance, 'document')
|
|
228 patcher_document.start()
|
|
229 self.addCleanup(patcher_document.stop)
|
|
230
|
|
231 def test_creates_translator_with_document(self):
|
|
232 """ Should create a translator with the writer's document. """
|
|
233 instance = self.test_instance
|
|
234 expected_document = self.test_instance.document
|
|
235 instance.translate()
|
|
236 self.mock_class_translator.assert_called_with(expected_document)
|
|
237
|
|
238 def test_calls_document_walkabout_with_translator(self):
|
|
239 """ Should call document.walkabout with the translator. """
|
|
240 instance = self.test_instance
|
|
241 instance.translate()
|
|
242 instance.document.walkabout.assert_called_with(self.mock_translator)
|
|
243
|
|
244 def test_output_from_translator_astext(self):
|
|
245 """ Should have output from translator.astext(). """
|
|
246 instance = self.test_instance
|
|
247 instance.translate()
|
|
248 expected_output = self.mock_translator.astext.return_value
|
|
249 self.assertEqual(expected_output, instance.output)
|
|
250
|
|
251
|
|
252 class ChangeLogEntry_TestCase(testtools.TestCase):
|
|
253 """ Test cases for ‘ChangeLogEntry’ class. """
|
|
254
|
|
255 def setUp(self):
|
|
256 """ Set up test fixtures. """
|
|
257 super(ChangeLogEntry_TestCase, self).setUp()
|
|
258
|
|
259 self.test_instance = version.ChangeLogEntry()
|
|
260
|
|
261 def test_instantiate(self):
|
|
262 """ New instance of ‘ChangeLogEntry’ should be created. """
|
|
263 self.assertIsInstance(
|
|
264 self.test_instance, version.ChangeLogEntry)
|
|
265
|
|
266 def test_minimum_zero_arguments(self):
|
|
267 """ Initialiser should not require any arguments. """
|
|
268 instance = version.ChangeLogEntry()
|
|
269 self.assertIsNot(instance, None)
|
|
270
|
|
271
|
|
272 class ChangeLogEntry_release_date_TestCase(
|
|
273 testscenarios.WithScenarios, testtools.TestCase):
|
|
274 """ Test cases for ‘ChangeLogEntry.release_date’ attribute. """
|
|
275
|
|
276 scenarios = [
|
|
277 ('default', {
|
|
278 'test_args': {},
|
|
279 'expected_release_date':
|
|
280 version.ChangeLogEntry.default_release_date,
|
|
281 }),
|
|
282 ('unknown token', {
|
|
283 'test_args': {'release_date': "UNKNOWN"},
|
|
284 'expected_release_date': "UNKNOWN",
|
|
285 }),
|
|
286 ('future token', {
|
|
287 'test_args': {'release_date': "FUTURE"},
|
|
288 'expected_release_date': "FUTURE",
|
|
289 }),
|
|
290 ('2001-01-01', {
|
|
291 'test_args': {'release_date': "2001-01-01"},
|
|
292 'expected_release_date': "2001-01-01",
|
|
293 }),
|
|
294 ('bogus', {
|
|
295 'test_args': {'release_date': "b0gUs"},
|
|
296 'expected_error': ValueError,
|
|
297 }),
|
|
298 ]
|
|
299
|
|
300 def test_has_expected_release_date(self):
|
|
301 """ Should have default `release_date` attribute. """
|
|
302 if hasattr(self, 'expected_error'):
|
|
303 self.assertRaises(
|
|
304 self.expected_error,
|
|
305 version.ChangeLogEntry, **self.test_args)
|
|
306 else:
|
|
307 instance = version.ChangeLogEntry(**self.test_args)
|
|
308 self.assertEqual(self.expected_release_date, instance.release_date)
|
|
309
|
|
310
|
|
311 class ChangeLogEntry_version_TestCase(
|
|
312 testscenarios.WithScenarios, testtools.TestCase):
|
|
313 """ Test cases for ‘ChangeLogEntry.version’ attribute. """
|
|
314
|
|
315 scenarios = [
|
|
316 ('default', {
|
|
317 'test_args': {},
|
|
318 'expected_version':
|
|
319 version.ChangeLogEntry.default_version,
|
|
320 }),
|
|
321 ('unknown token', {
|
|
322 'test_args': {'version': "UNKNOWN"},
|
|
323 'expected_version': "UNKNOWN",
|
|
324 }),
|
|
325 ('0.0', {
|
|
326 'test_args': {'version': "0.0"},
|
|
327 'expected_version': "0.0",
|
|
328 }),
|
|
329 ]
|
|
330
|
|
331 def test_has_expected_version(self):
|
|
332 """ Should have default `version` attribute. """
|
|
333 instance = version.ChangeLogEntry(**self.test_args)
|
|
334 self.assertEqual(self.expected_version, instance.version)
|
|
335
|
|
336
|
|
337 class ChangeLogEntry_maintainer_TestCase(
|
|
338 testscenarios.WithScenarios, testtools.TestCase):
|
|
339 """ Test cases for ‘ChangeLogEntry.maintainer’ attribute. """
|
|
340
|
|
341 scenarios = [
|
|
342 ('default', {
|
|
343 'test_args': {},
|
|
344 'expected_maintainer': None,
|
|
345 }),
|
|
346 ('person', {
|
|
347 'test_args': {'maintainer': "Foo Bar <foo.bar@example.org>"},
|
|
348 'expected_maintainer': "Foo Bar <foo.bar@example.org>",
|
|
349 }),
|
|
350 ('bogus', {
|
|
351 'test_args': {'maintainer': "b0gUs"},
|
|
352 'expected_error': ValueError,
|
|
353 }),
|
|
354 ]
|
|
355
|
|
356 def test_has_expected_maintainer(self):
|
|
357 """ Should have default `maintainer` attribute. """
|
|
358 if hasattr(self, 'expected_error'):
|
|
359 self.assertRaises(
|
|
360 self.expected_error,
|
|
361 version.ChangeLogEntry, **self.test_args)
|
|
362 else:
|
|
363 instance = version.ChangeLogEntry(**self.test_args)
|
|
364 self.assertEqual(self.expected_maintainer, instance.maintainer)
|
|
365
|
|
366
|
|
367 class ChangeLogEntry_body_TestCase(
|
|
368 testscenarios.WithScenarios, testtools.TestCase):
|
|
369 """ Test cases for ‘ChangeLogEntry.body’ attribute. """
|
|
370
|
|
371 scenarios = [
|
|
372 ('default', {
|
|
373 'test_args': {},
|
|
374 'expected_body': None,
|
|
375 }),
|
|
376 ('simple', {
|
|
377 'test_args': {'body': "Foo bar baz."},
|
|
378 'expected_body': "Foo bar baz.",
|
|
379 }),
|
|
380 ]
|
|
381
|
|
382 def test_has_expected_body(self):
|
|
383 """ Should have default `body` attribute. """
|
|
384 instance = version.ChangeLogEntry(**self.test_args)
|
|
385 self.assertEqual(self.expected_body, instance.body)
|
|
386
|
|
387
|
|
388 class ChangeLogEntry_as_version_info_entry_TestCase(
|
|
389 testscenarios.WithScenarios, testtools.TestCase):
|
|
390 """ Test cases for ‘ChangeLogEntry.as_version_info_entry’ attribute. """
|
|
391
|
|
392 scenarios = [
|
|
393 ('default', {
|
|
394 'test_args': {},
|
|
395 'expected_result': collections.OrderedDict([
|
|
396 ('release_date', version.ChangeLogEntry.default_release_date),
|
|
397 ('version', version.ChangeLogEntry.default_version),
|
|
398 ('maintainer', None),
|
|
399 ('body', None),
|
|
400 ]),
|
|
401 }),
|
|
402 ]
|
|
403
|
|
404 def setUp(self):
|
|
405 """ Set up test fixtures. """
|
|
406 super(ChangeLogEntry_as_version_info_entry_TestCase, self).setUp()
|
|
407
|
|
408 self.test_instance = version.ChangeLogEntry(**self.test_args)
|
|
409
|
|
410 def test_returns_result(self):
|
|
411 """ Should return expected result. """
|
|
412 result = self.test_instance.as_version_info_entry()
|
|
413 self.assertEqual(self.expected_result, result)
|
|
414
|
|
415
|
|
416 def make_mock_field_node(field_name, field_body):
|
|
417 """ Make a mock Docutils field node for tests. """
|
|
418
|
|
419 mock_field_node = mock.MagicMock(
|
|
420 name='field', spec=docutils.nodes.field)
|
|
421
|
|
422 mock_field_name_node = mock.MagicMock(
|
|
423 name='field_name', spec=docutils.nodes.field_name)
|
|
424 mock_field_name_node.parent = mock_field_node
|
|
425 mock_field_name_node.children = [field_name]
|
|
426
|
|
427 mock_field_body_node = mock.MagicMock(
|
|
428 name='field_body', spec=docutils.nodes.field_body)
|
|
429 mock_field_body_node.parent = mock_field_node
|
|
430 mock_field_body_node.children = [field_body]
|
|
431
|
|
432 mock_field_node.children = [mock_field_name_node, mock_field_body_node]
|
|
433
|
|
434 def fake_func_first_child_matching_class(node_class):
|
|
435 result = None
|
|
436 node_class_name = node_class.__name__
|
|
437 for (index, node) in enumerate(mock_field_node.children):
|
|
438 if node._mock_name == node_class_name:
|
|
439 result = index
|
|
440 break
|
|
441 return result
|
|
442
|
|
443 mock_field_node.first_child_matching_class.side_effect = (
|
|
444 fake_func_first_child_matching_class)
|
|
445
|
|
446 return mock_field_node
|
|
447
|
|
448
|
|
449 class JsonEqual(testtools.matchers.Matcher):
|
|
450 """ A matcher to compare the value of JSON streams. """
|
|
451
|
|
452 def __init__(self, expected):
|
|
453 self.expected_value = expected
|
|
454
|
|
455 def match(self, content):
|
|
456 """ Assert the JSON `content` matches the `expected_content`. """
|
|
457 result = None
|
|
458 actual_value = json.loads(content.decode('utf-8'))
|
|
459 if actual_value != self.expected_value:
|
|
460 result = JsonValueMismatch(self.expected_value, actual_value)
|
|
461 return result
|
|
462
|
|
463
|
|
464 class JsonValueMismatch(testtools.matchers.Mismatch):
|
|
465 """ The specified JSON stream does not evaluate to the expected value. """
|
|
466
|
|
467 def __init__(self, expected, actual):
|
|
468 self.expected_value = expected
|
|
469 self.actual_value = actual
|
|
470
|
|
471 def describe(self):
|
|
472 """ Emit a text description of this mismatch. """
|
|
473 expected_json_text = json.dumps(self.expected_value, indent=4)
|
|
474 actual_json_text = json.dumps(self.actual_value, indent=4)
|
|
475 text = (
|
|
476 "\n"
|
|
477 "reference: {expected}\n"
|
|
478 "actual: {actual}\n").format(
|
|
479 expected=expected_json_text, actual=actual_json_text)
|
|
480 return text
|
|
481
|
|
482
|
|
483 class changelog_to_version_info_collection_TestCase(
|
|
484 testscenarios.WithScenarios, testtools.TestCase):
|
|
485 """ Test cases for ‘changelog_to_version_info_collection’ function. """
|
|
486
|
|
487 scenarios = [
|
|
488 ('single entry', {
|
|
489 'test_input': textwrap.dedent("""\
|
|
490 Version 1.0
|
|
491 ===========
|
|
492
|
|
493 :Released: 2009-01-01
|
|
494 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
495
|
|
496 * Lorem ipsum dolor sit amet.
|
|
497 """),
|
|
498 'expected_version_info': [
|
|
499 {
|
|
500 'release_date': "2009-01-01",
|
|
501 'version': "1.0",
|
|
502 'maintainer': "Foo Bar <foo.bar@example.org>",
|
|
503 'body': "* Lorem ipsum dolor sit amet.\n",
|
|
504 },
|
|
505 ],
|
|
506 }),
|
|
507 ('multiple entries', {
|
|
508 'test_input': textwrap.dedent("""\
|
|
509 Version 1.0
|
|
510 ===========
|
|
511
|
|
512 :Released: 2009-01-01
|
|
513 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
514
|
|
515 * Lorem ipsum dolor sit amet.
|
|
516
|
|
517
|
|
518 Version 0.8
|
|
519 ===========
|
|
520
|
|
521 :Released: 2004-01-01
|
|
522 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
523
|
|
524 * Donec venenatis nisl aliquam ipsum.
|
|
525
|
|
526
|
|
527 Version 0.7.2
|
|
528 =============
|
|
529
|
|
530 :Released: 2001-01-01
|
|
531 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
532
|
|
533 * Pellentesque elementum mollis finibus.
|
|
534 """),
|
|
535 'expected_version_info': [
|
|
536 {
|
|
537 'release_date': "2009-01-01",
|
|
538 'version': "1.0",
|
|
539 'maintainer': "Foo Bar <foo.bar@example.org>",
|
|
540 'body': "* Lorem ipsum dolor sit amet.\n",
|
|
541 },
|
|
542 {
|
|
543 'release_date': "2004-01-01",
|
|
544 'version': "0.8",
|
|
545 'maintainer': "Foo Bar <foo.bar@example.org>",
|
|
546 'body': "* Donec venenatis nisl aliquam ipsum.\n",
|
|
547 },
|
|
548 {
|
|
549 'release_date': "2001-01-01",
|
|
550 'version': "0.7.2",
|
|
551 'maintainer': "Foo Bar <foo.bar@example.org>",
|
|
552 'body': "* Pellentesque elementum mollis finibus.\n",
|
|
553 },
|
|
554 ],
|
|
555 }),
|
|
556 ('trailing comment', {
|
|
557 'test_input': textwrap.dedent("""\
|
|
558 Version NEXT
|
|
559 ============
|
|
560
|
|
561 :Released: FUTURE
|
|
562 :Maintainer:
|
|
563
|
|
564 * Lorem ipsum dolor sit amet.
|
|
565
|
|
566 ..
|
|
567 Vivamus aliquam felis rutrum rutrum dictum.
|
|
568 """),
|
|
569 'expected_version_info': [
|
|
570 {
|
|
571 'release_date': "FUTURE",
|
|
572 'version': "NEXT",
|
|
573 'maintainer': "",
|
|
574 'body': "* Lorem ipsum dolor sit amet.\n",
|
|
575 },
|
|
576 ],
|
|
577 }),
|
|
578 ('inline comment', {
|
|
579 'test_input': textwrap.dedent("""\
|
|
580 Version NEXT
|
|
581 ============
|
|
582
|
|
583 :Released: FUTURE
|
|
584 :Maintainer:
|
|
585
|
|
586 ..
|
|
587 Vivamus aliquam felis rutrum rutrum dictum.
|
|
588
|
|
589 * Lorem ipsum dolor sit amet.
|
|
590 """),
|
|
591 'expected_version_info': [
|
|
592 {
|
|
593 'release_date': "FUTURE",
|
|
594 'version': "NEXT",
|
|
595 'maintainer': "",
|
|
596 'body': "* Lorem ipsum dolor sit amet.\n",
|
|
597 },
|
|
598 ],
|
|
599 }),
|
|
600 ('unreleased entry', {
|
|
601 'test_input': textwrap.dedent("""\
|
|
602 Version NEXT
|
|
603 ============
|
|
604
|
|
605 :Released: FUTURE
|
|
606 :Maintainer:
|
|
607
|
|
608 * Lorem ipsum dolor sit amet.
|
|
609
|
|
610
|
|
611 Version 0.8
|
|
612 ===========
|
|
613
|
|
614 :Released: 2001-01-01
|
|
615 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
616
|
|
617 * Donec venenatis nisl aliquam ipsum.
|
|
618 """),
|
|
619 'expected_version_info': [
|
|
620 {
|
|
621 'release_date': "FUTURE",
|
|
622 'version': "NEXT",
|
|
623 'maintainer': "",
|
|
624 'body': "* Lorem ipsum dolor sit amet.\n",
|
|
625 },
|
|
626 {
|
|
627 'release_date': "2001-01-01",
|
|
628 'version': "0.8",
|
|
629 'maintainer': "Foo Bar <foo.bar@example.org>",
|
|
630 'body': "* Donec venenatis nisl aliquam ipsum.\n",
|
|
631 },
|
|
632 ],
|
|
633 }),
|
|
634 ('no section', {
|
|
635 'test_input': textwrap.dedent("""\
|
|
636 :Released: 2009-01-01
|
|
637 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
638
|
|
639 * Lorem ipsum dolor sit amet.
|
|
640 """),
|
|
641 'expected_error': version.InvalidFormatError,
|
|
642 }),
|
|
643 ('subsection', {
|
|
644 'test_input': textwrap.dedent("""\
|
|
645 Version 1.0
|
|
646 ===========
|
|
647
|
|
648 :Released: 2009-01-01
|
|
649 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
650
|
|
651 * Lorem ipsum dolor sit amet.
|
|
652
|
|
653 Ut ultricies fermentum quam
|
|
654 ---------------------------
|
|
655
|
|
656 * In commodo magna facilisis in.
|
|
657 """),
|
|
658 'expected_error': version.InvalidFormatError,
|
|
659 'subsection': True,
|
|
660 }),
|
|
661 ('unknown field', {
|
|
662 'test_input': textwrap.dedent("""\
|
|
663 Version 1.0
|
|
664 ===========
|
|
665
|
|
666 :Released: 2009-01-01
|
|
667 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
668 :Favourite: Spam
|
|
669
|
|
670 * Lorem ipsum dolor sit amet.
|
|
671 """),
|
|
672 'expected_error': version.InvalidFormatError,
|
|
673 }),
|
|
674 ('invalid version word', {
|
|
675 'test_input': textwrap.dedent("""\
|
|
676 BoGuS 1.0
|
|
677 =========
|
|
678
|
|
679 :Released: 2009-01-01
|
|
680 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
681
|
|
682 * Lorem ipsum dolor sit amet.
|
|
683 """),
|
|
684 'expected_error': version.InvalidFormatError,
|
|
685 }),
|
|
686 ('invalid section title', {
|
|
687 'test_input': textwrap.dedent("""\
|
|
688 Lorem Ipsum 1.0
|
|
689 ===============
|
|
690
|
|
691 :Released: 2009-01-01
|
|
692 :Maintainer: Foo Bar <foo.bar@example.org>
|
|
693
|
|
694 * Lorem ipsum dolor sit amet.
|
|
695 """),
|
|
696 'expected_error': version.InvalidFormatError,
|
|
697 }),
|
|
698 ]
|
|
699
|
|
700 def test_returns_expected_version_info(self):
|
|
701 """ Should return expected version info mapping. """
|
|
702 infile = StringIO(self.test_input)
|
|
703 if hasattr(self, 'expected_error'):
|
|
704 self.assertRaises(
|
|
705 self.expected_error,
|
|
706 version.changelog_to_version_info_collection, infile)
|
|
707 else:
|
|
708 result = version.changelog_to_version_info_collection(infile)
|
|
709 self.assertThat(result, JsonEqual(self.expected_version_info))
|
|
710
|
|
711
|
|
712 try:
|
|
713 FileNotFoundError
|
|
714 PermissionError
|
|
715 except NameError:
|
|
716 # Python 2 uses OSError.
|
|
717 FileNotFoundError = functools.partial(IOError, errno.ENOENT)
|
|
718 PermissionError = functools.partial(IOError, errno.EPERM)
|
|
719
|
|
720 fake_version_info = {
|
|
721 'release_date': "2001-01-01", 'version': "2.0",
|
|
722 'maintainer': None, 'body': None,
|
|
723 }
|
|
724
|
|
725 @mock.patch.object(
|
|
726 version, "get_latest_version", return_value=fake_version_info)
|
|
727 class generate_version_info_from_changelog_TestCase(
|
|
728 testscenarios.WithScenarios, testtools.TestCase):
|
|
729 """ Test cases for ‘generate_version_info_from_changelog’ function. """
|
|
730
|
|
731 fake_open_side_effects = {
|
|
732 'success': (
|
|
733 lambda *args, **kwargs: StringIO()),
|
|
734 'file not found': FileNotFoundError(),
|
|
735 'permission denied': PermissionError(),
|
|
736 }
|
|
737
|
|
738 scenarios = [
|
|
739 ('simple', {
|
|
740 'open_scenario': 'success',
|
|
741 'fake_versions_json': json.dumps([fake_version_info]),
|
|
742 'expected_result': fake_version_info,
|
|
743 }),
|
|
744 ('file not found', {
|
|
745 'open_scenario': 'file not found',
|
|
746 'expected_result': {},
|
|
747 }),
|
|
748 ('permission denied', {
|
|
749 'open_scenario': 'permission denied',
|
|
750 'expected_result': {},
|
|
751 }),
|
|
752 ]
|
|
753
|
|
754 def setUp(self):
|
|
755 """ Set up test fixtures. """
|
|
756 super(generate_version_info_from_changelog_TestCase, self).setUp()
|
|
757
|
|
758 self.fake_changelog_file_path = tempfile.mktemp()
|
|
759
|
|
760 def fake_open(filespec, *args, **kwargs):
|
|
761 if filespec == self.fake_changelog_file_path:
|
|
762 side_effect = self.fake_open_side_effects[self.open_scenario]
|
|
763 if callable(side_effect):
|
|
764 result = side_effect()
|
|
765 else:
|
|
766 raise side_effect
|
|
767 else:
|
|
768 result = StringIO()
|
|
769 return result
|
|
770
|
|
771 func_patcher_io_open = mock.patch.object(
|
|
772 io, "open")
|
|
773 func_patcher_io_open.start()
|
|
774 self.addCleanup(func_patcher_io_open.stop)
|
|
775 io.open.side_effect = fake_open
|
|
776
|
|
777 self.file_encoding = "utf-8"
|
|
778
|
|
779 func_patcher_changelog_to_version_info_collection = mock.patch.object(
|
|
780 version, "changelog_to_version_info_collection")
|
|
781 func_patcher_changelog_to_version_info_collection.start()
|
|
782 self.addCleanup(func_patcher_changelog_to_version_info_collection.stop)
|
|
783 if hasattr(self, 'fake_versions_json'):
|
|
784 version.changelog_to_version_info_collection.return_value = (
|
|
785 self.fake_versions_json.encode(self.file_encoding))
|
|
786
|
|
787 def test_returns_empty_collection_on_read_error(
|
|
788 self,
|
|
789 mock_func_get_latest_version):
|
|
790 """ Should return empty collection on error reading changelog. """
|
|
791 test_error = PermissionError("Not for you")
|
|
792 version.changelog_to_version_info_collection.side_effect = test_error
|
|
793 result = version.generate_version_info_from_changelog(
|
|
794 self.fake_changelog_file_path)
|
|
795 expected_result = {}
|
|
796 self.assertDictEqual(expected_result, result)
|
|
797
|
|
798 def test_opens_file_with_expected_encoding(
|
|
799 self,
|
|
800 mock_func_get_latest_version):
|
|
801 """ Should open changelog file in text mode with expected encoding. """
|
|
802 result = version.generate_version_info_from_changelog(
|
|
803 self.fake_changelog_file_path)
|
|
804 expected_file_path = self.fake_changelog_file_path
|
|
805 expected_open_mode = 'rt'
|
|
806 expected_encoding = self.file_encoding
|
|
807 (open_args_positional, open_args_kwargs) = io.open.call_args
|
|
808 (open_args_filespec, open_args_mode) = open_args_positional[:2]
|
|
809 open_args_encoding = open_args_kwargs['encoding']
|
|
810 self.assertEqual(expected_file_path, open_args_filespec)
|
|
811 self.assertEqual(expected_open_mode, open_args_mode)
|
|
812 self.assertEqual(expected_encoding, open_args_encoding)
|
|
813
|
|
814 def test_returns_expected_result(
|
|
815 self,
|
|
816 mock_func_get_latest_version):
|
|
817 """ Should return expected result. """
|
|
818 result = version.generate_version_info_from_changelog(
|
|
819 self.fake_changelog_file_path)
|
|
820 self.assertEqual(self.expected_result, result)
|
|
821
|
|
822
|
|
823 DefaultNoneDict = functools.partial(collections.defaultdict, lambda: None)
|
|
824
|
|
825 class get_latest_version_TestCase(
|
|
826 testscenarios.WithScenarios, testtools.TestCase):
|
|
827 """ Test cases for ‘get_latest_version’ function. """
|
|
828
|
|
829 scenarios = [
|
|
830 ('simple', {
|
|
831 'test_versions': [
|
|
832 DefaultNoneDict({'release_date': "LATEST"}),
|
|
833 ],
|
|
834 'expected_result': version.ChangeLogEntry.make_ordered_dict(
|
|
835 DefaultNoneDict({'release_date': "LATEST"})),
|
|
836 }),
|
|
837 ('no versions', {
|
|
838 'test_versions': [],
|
|
839 'expected_result': collections.OrderedDict(),
|
|
840 }),
|
|
841 ('ordered versions', {
|
|
842 'test_versions': [
|
|
843 DefaultNoneDict({'release_date': "1"}),
|
|
844 DefaultNoneDict({'release_date': "2"}),
|
|
845 DefaultNoneDict({'release_date': "LATEST"}),
|
|
846 ],
|
|
847 'expected_result': version.ChangeLogEntry.make_ordered_dict(
|
|
848 DefaultNoneDict({'release_date': "LATEST"})),
|
|
849 }),
|
|
850 ('un-ordered versions', {
|
|
851 'test_versions': [
|
|
852 DefaultNoneDict({'release_date': "2"}),
|
|
853 DefaultNoneDict({'release_date': "LATEST"}),
|
|
854 DefaultNoneDict({'release_date': "1"}),
|
|
855 ],
|
|
856 'expected_result': version.ChangeLogEntry.make_ordered_dict(
|
|
857 DefaultNoneDict({'release_date': "LATEST"})),
|
|
858 }),
|
|
859 ]
|
|
860
|
|
861 def test_returns_expected_result(self):
|
|
862 """ Should return expected result. """
|
|
863 result = version.get_latest_version(self.test_versions)
|
|
864 self.assertDictEqual(self.expected_result, result)
|
|
865
|
|
866
|
|
867 @mock.patch.object(json, "dumps", side_effect=json.dumps)
|
|
868 class serialise_version_info_from_mapping_TestCase(
|
|
869 testscenarios.WithScenarios, testtools.TestCase):
|
|
870 """ Test cases for ‘get_latest_version’ function. """
|
|
871
|
|
872 scenarios = [
|
|
873 ('simple', {
|
|
874 'test_version_info': {'foo': "spam"},
|
|
875 }),
|
|
876 ]
|
|
877
|
|
878 for (name, scenario) in scenarios:
|
|
879 scenario['fake_json_dump'] = json.dumps(scenario['test_version_info'])
|
|
880 scenario['expected_value'] = scenario['test_version_info']
|
|
881
|
|
882 def test_passes_specified_object(self, mock_func_json_dumps):
|
|
883 """ Should pass the specified object to `json.dumps`. """
|
|
884 result = version.serialise_version_info_from_mapping(
|
|
885 self.test_version_info)
|
|
886 mock_func_json_dumps.assert_called_with(
|
|
887 self.test_version_info, indent=mock.ANY)
|
|
888
|
|
889 def test_returns_expected_result(self, mock_func_json_dumps):
|
|
890 """ Should return expected result. """
|
|
891 mock_func_json_dumps.return_value = self.fake_json_dump
|
|
892 result = version.serialise_version_info_from_mapping(
|
|
893 self.test_version_info)
|
|
894 value = json.loads(result)
|
|
895 self.assertEqual(self.expected_value, value)
|
|
896
|
|
897
|
|
898 DistributionMetadata_defaults = {
|
|
899 name: None
|
|
900 for name in list(collections.OrderedDict.fromkeys(
|
|
901 distutils.dist.DistributionMetadata._METHOD_BASENAMES))}
|
|
902 FakeDistributionMetadata = collections.namedtuple(
|
|
903 'FakeDistributionMetadata', DistributionMetadata_defaults.keys())
|
|
904
|
|
905 Distribution_defaults = {
|
|
906 'metadata': None,
|
|
907 'version': None,
|
|
908 'release_date': None,
|
|
909 'maintainer': None,
|
|
910 'maintainer_email': None,
|
|
911 }
|
|
912 FakeDistribution = collections.namedtuple(
|
|
913 'FakeDistribution', Distribution_defaults.keys())
|
|
914
|
|
915 def make_fake_distribution(
|
|
916 fields_override=None, metadata_fields_override=None):
|
|
917 metadata_fields = DistributionMetadata_defaults.copy()
|
|
918 if metadata_fields_override is not None:
|
|
919 metadata_fields.update(metadata_fields_override)
|
|
920 metadata = FakeDistributionMetadata(**metadata_fields)
|
|
921
|
|
922 fields = Distribution_defaults.copy()
|
|
923 fields['metadata'] = metadata
|
|
924 if fields_override is not None:
|
|
925 fields.update(fields_override)
|
|
926 distribution = FakeDistribution(**fields)
|
|
927
|
|
928 return distribution
|
|
929
|
|
930
|
|
931 class get_changelog_path_TestCase(
|
|
932 testscenarios.WithScenarios, testtools.TestCase):
|
|
933 """ Test cases for ‘get_changelog_path’ function. """
|
|
934
|
|
935 default_path = "."
|
|
936 default_script_filename = "setup.py"
|
|
937
|
|
938 scenarios = [
|
|
939 ('simple', {}),
|
|
940 ('unusual script name', {
|
|
941 'script_filename': "lorem_ipsum",
|
|
942 }),
|
|
943 ('relative script path', {
|
|
944 'script_directory': "dolor/sit/amet",
|
|
945 }),
|
|
946 ('absolute script path', {
|
|
947 'script_directory': "/dolor/sit/amet",
|
|
948 }),
|
|
949 ('specify filename', {
|
|
950 'changelog_filename': "adipiscing",
|
|
951 }),
|
|
952 ]
|
|
953
|
|
954 def setUp(self):
|
|
955 """ Set up test fixtures. """
|
|
956 super(get_changelog_path_TestCase, self).setUp()
|
|
957
|
|
958 self.test_distribution = mock.MagicMock(distutils.dist.Distribution)
|
|
959
|
|
960 if not hasattr(self, 'script_directory'):
|
|
961 self.script_directory = self.default_path
|
|
962 if not hasattr(self, 'script_filename'):
|
|
963 self.script_filename = self.default_script_filename
|
|
964 self.test_distribution.script_name = os.path.join(
|
|
965 self.script_directory, self.script_filename)
|
|
966
|
|
967 changelog_filename = version.changelog_filename
|
|
968 if hasattr(self, 'changelog_filename'):
|
|
969 changelog_filename = self.changelog_filename
|
|
970
|
|
971 self.expected_result = os.path.join(
|
|
972 self.script_directory, changelog_filename)
|
|
973
|
|
974 def test_returns_expected_result(self):
|
|
975 """ Should return expected result. """
|
|
976 args = {
|
|
977 'distribution': self.test_distribution,
|
|
978 }
|
|
979 if hasattr(self, 'changelog_filename'):
|
|
980 args.update({'filename': self.changelog_filename})
|
|
981 result = version.get_changelog_path(**args)
|
|
982 self.assertEqual(self.expected_result, result)
|
|
983
|
|
984
|
|
985 class WriteVersionInfoCommand_BaseTestCase(
|
|
986 testscenarios.WithScenarios, testtools.TestCase):
|
|
987 """ Base class for ‘WriteVersionInfoCommand’ test case classes. """
|
|
988
|
|
989 def setUp(self):
|
|
990 """ Set up test fixtures. """
|
|
991 super(WriteVersionInfoCommand_BaseTestCase, self).setUp()
|
|
992
|
|
993 fake_distribution_name = self.getUniqueString()
|
|
994
|
|
995 self.test_distribution = distutils.dist.Distribution()
|
|
996 self.test_distribution.metadata.name = fake_distribution_name
|
|
997
|
|
998
|
|
999 class WriteVersionInfoCommand_TestCase(WriteVersionInfoCommand_BaseTestCase):
|
|
1000 """ Test cases for ‘WriteVersionInfoCommand’ class. """
|
|
1001
|
|
1002 def test_subclass_of_distutils_command(self):
|
|
1003 """ Should be a subclass of ‘distutils.cmd.Command’. """
|
|
1004 instance = version.WriteVersionInfoCommand(self.test_distribution)
|
|
1005 self.assertIsInstance(instance, distutils.cmd.Command)
|
|
1006
|
|
1007
|
|
1008 class WriteVersionInfoCommand_user_options_TestCase(
|
|
1009 WriteVersionInfoCommand_BaseTestCase):
|
|
1010 """ Test cases for ‘WriteVersionInfoCommand.user_options’ attribute. """
|
|
1011
|
|
1012 def setUp(self):
|
|
1013 """ Set up test fixtures. """
|
|
1014 super(WriteVersionInfoCommand_user_options_TestCase, self).setUp()
|
|
1015
|
|
1016 self.test_instance = version.WriteVersionInfoCommand(
|
|
1017 self.test_distribution)
|
|
1018 self.commandline_parser = distutils.fancy_getopt.FancyGetopt(
|
|
1019 self.test_instance.user_options)
|
|
1020
|
|
1021 def test_parses_correctly_as_fancy_getopt(self):
|
|
1022 """ Should parse correctly in ‘FancyGetopt’. """
|
|
1023 self.assertIsInstance(
|
|
1024 self.commandline_parser, distutils.fancy_getopt.FancyGetopt)
|
|
1025
|
|
1026 def test_includes_base_class_user_options(self):
|
|
1027 """ Should include base class's user_options. """
|
|
1028 base_command = setuptools.command.egg_info.egg_info
|
|
1029 expected_user_options = base_command.user_options
|
|
1030 self.assertThat(
|
|
1031 set(expected_user_options),
|
|
1032 IsSubset(set(self.test_instance.user_options)))
|
|
1033
|
|
1034 def test_has_option_changelog_path(self):
|
|
1035 """ Should have a ‘changelog-path’ option. """
|
|
1036 expected_option_name = "changelog-path="
|
|
1037 result = self.commandline_parser.has_option(expected_option_name)
|
|
1038 self.assertTrue(result)
|
|
1039
|
|
1040 def test_has_option_outfile_path(self):
|
|
1041 """ Should have a ‘outfile-path’ option. """
|
|
1042 expected_option_name = "outfile-path="
|
|
1043 result = self.commandline_parser.has_option(expected_option_name)
|
|
1044 self.assertTrue(result)
|
|
1045
|
|
1046
|
|
1047 class WriteVersionInfoCommand_initialize_options_TestCase(
|
|
1048 WriteVersionInfoCommand_BaseTestCase):
|
|
1049 """ Test cases for ‘WriteVersionInfoCommand.initialize_options’ method. """
|
|
1050
|
|
1051 def setUp(self):
|
|
1052 """ Set up test fixtures. """
|
|
1053 super(
|
|
1054 WriteVersionInfoCommand_initialize_options_TestCase, self
|
|
1055 ).setUp()
|
|
1056
|
|
1057 patcher_func_egg_info_initialize_options = mock.patch.object(
|
|
1058 setuptools.command.egg_info.egg_info, "initialize_options")
|
|
1059 patcher_func_egg_info_initialize_options.start()
|
|
1060 self.addCleanup(patcher_func_egg_info_initialize_options.stop)
|
|
1061
|
|
1062 def test_calls_base_class_method(self):
|
|
1063 """ Should call base class's ‘initialize_options’ method. """
|
|
1064 instance = version.WriteVersionInfoCommand(self.test_distribution)
|
|
1065 base_command_class = setuptools.command.egg_info.egg_info
|
|
1066 base_command_class.initialize_options.assert_called_with()
|
|
1067
|
|
1068 def test_sets_changelog_path_to_none(self):
|
|
1069 """ Should set ‘changelog_path’ attribute to ``None``. """
|
|
1070 instance = version.WriteVersionInfoCommand(self.test_distribution)
|
|
1071 self.assertIs(instance.changelog_path, None)
|
|
1072
|
|
1073 def test_sets_outfile_path_to_none(self):
|
|
1074 """ Should set ‘outfile_path’ attribute to ``None``. """
|
|
1075 instance = version.WriteVersionInfoCommand(self.test_distribution)
|
|
1076 self.assertIs(instance.outfile_path, None)
|
|
1077
|
|
1078
|
|
1079 class WriteVersionInfoCommand_finalize_options_TestCase(
|
|
1080 WriteVersionInfoCommand_BaseTestCase):
|
|
1081 """ Test cases for ‘WriteVersionInfoCommand.finalize_options’ method. """
|
|
1082
|
|
1083 def setUp(self):
|
|
1084 """ Set up test fixtures. """
|
|
1085 super(WriteVersionInfoCommand_finalize_options_TestCase, self).setUp()
|
|
1086
|
|
1087 self.test_instance = version.WriteVersionInfoCommand(self.test_distribution)
|
|
1088
|
|
1089 patcher_func_egg_info_finalize_options = mock.patch.object(
|
|
1090 setuptools.command.egg_info.egg_info, "finalize_options")
|
|
1091 patcher_func_egg_info_finalize_options.start()
|
|
1092 self.addCleanup(patcher_func_egg_info_finalize_options.stop)
|
|
1093
|
|
1094 self.fake_script_dir = self.getUniqueString()
|
|
1095 self.test_distribution.script_name = os.path.join(
|
|
1096 self.fake_script_dir, self.getUniqueString())
|
|
1097
|
|
1098 self.fake_egg_dir = self.getUniqueString()
|
|
1099 self.test_instance.egg_info = self.fake_egg_dir
|
|
1100
|
|
1101 patcher_func_get_changelog_path = mock.patch.object(
|
|
1102 version, "get_changelog_path")
|
|
1103 patcher_func_get_changelog_path.start()
|
|
1104 self.addCleanup(patcher_func_get_changelog_path.stop)
|
|
1105
|
|
1106 self.fake_changelog_path = self.getUniqueString()
|
|
1107 version.get_changelog_path.return_value = self.fake_changelog_path
|
|
1108
|
|
1109 def test_calls_base_class_method(self):
|
|
1110 """ Should call base class's ‘finalize_options’ method. """
|
|
1111 base_command_class = setuptools.command.egg_info.egg_info
|
|
1112 self.test_instance.finalize_options()
|
|
1113 base_command_class.finalize_options.assert_called_with()
|
|
1114
|
|
1115 def test_sets_force_to_none(self):
|
|
1116 """ Should set ‘force’ attribute to ``None``. """
|
|
1117 self.test_instance.finalize_options()
|
|
1118 self.assertIs(self.test_instance.force, None)
|
|
1119
|
|
1120 def test_sets_changelog_path_using_get_changelog_path(self):
|
|
1121 """ Should set ‘changelog_path’ attribute if it was ``None``. """
|
|
1122 self.test_instance.changelog_path = None
|
|
1123 self.test_instance.finalize_options()
|
|
1124 expected_changelog_path = self.fake_changelog_path
|
|
1125 self.assertEqual(expected_changelog_path, self.test_instance.changelog_path)
|
|
1126
|
|
1127 def test_leaves_changelog_path_if_already_set(self):
|
|
1128 """ Should leave ‘changelog_path’ attribute set. """
|
|
1129 prior_changelog_path = self.getUniqueString()
|
|
1130 self.test_instance.changelog_path = prior_changelog_path
|
|
1131 self.test_instance.finalize_options()
|
|
1132 expected_changelog_path = prior_changelog_path
|
|
1133 self.assertEqual(expected_changelog_path, self.test_instance.changelog_path)
|
|
1134
|
|
1135 def test_sets_outfile_path_to_default(self):
|
|
1136 """ Should set ‘outfile_path’ attribute to default value. """
|
|
1137 fake_version_info_filename = self.getUniqueString()
|
|
1138 with mock.patch.object(
|
|
1139 version, "version_info_filename",
|
|
1140 new=fake_version_info_filename):
|
|
1141 self.test_instance.finalize_options()
|
|
1142 expected_outfile_path = os.path.join(
|
|
1143 self.fake_egg_dir, fake_version_info_filename)
|
|
1144 self.assertEqual(expected_outfile_path, self.test_instance.outfile_path)
|
|
1145
|
|
1146 def test_leaves_outfile_path_if_already_set(self):
|
|
1147 """ Should leave ‘outfile_path’ attribute set. """
|
|
1148 prior_outfile_path = self.getUniqueString()
|
|
1149 self.test_instance.outfile_path = prior_outfile_path
|
|
1150 self.test_instance.finalize_options()
|
|
1151 expected_outfile_path = prior_outfile_path
|
|
1152 self.assertEqual(expected_outfile_path, self.test_instance.outfile_path)
|
|
1153
|
|
1154
|
|
1155 class has_changelog_TestCase(
|
|
1156 testscenarios.WithScenarios, testtools.TestCase):
|
|
1157 """ Test cases for ‘has_changelog’ function. """
|
|
1158
|
|
1159 fake_os_path_exists_side_effects = {
|
|
1160 'true': (lambda path: True),
|
|
1161 'false': (lambda path: False),
|
|
1162 }
|
|
1163
|
|
1164 scenarios = [
|
|
1165 ('no changelog path', {
|
|
1166 'changelog_path': None,
|
|
1167 'expected_result': False,
|
|
1168 }),
|
|
1169 ('changelog exists', {
|
|
1170 'os_path_exists_scenario': 'true',
|
|
1171 'expected_result': True,
|
|
1172 }),
|
|
1173 ('changelog not found', {
|
|
1174 'os_path_exists_scenario': 'false',
|
|
1175 'expected_result': False,
|
|
1176 }),
|
|
1177 ]
|
|
1178
|
|
1179 def setUp(self):
|
|
1180 """ Set up test fixtures. """
|
|
1181 super(has_changelog_TestCase, self).setUp()
|
|
1182
|
|
1183 self.test_distribution = distutils.dist.Distribution()
|
|
1184 self.test_command = version.EggInfoCommand(
|
|
1185 self.test_distribution)
|
|
1186
|
|
1187 patcher_func_get_changelog_path = mock.patch.object(
|
|
1188 version, "get_changelog_path")
|
|
1189 patcher_func_get_changelog_path.start()
|
|
1190 self.addCleanup(patcher_func_get_changelog_path.stop)
|
|
1191
|
|
1192 self.fake_changelog_file_path = self.getUniqueString()
|
|
1193 if hasattr(self, 'changelog_path'):
|
|
1194 self.fake_changelog_file_path = self.changelog_path
|
|
1195 version.get_changelog_path.return_value = self.fake_changelog_file_path
|
|
1196 self.fake_changelog_file = StringIO()
|
|
1197
|
|
1198 def fake_os_path_exists(path):
|
|
1199 if path == self.fake_changelog_file_path:
|
|
1200 side_effect = self.fake_os_path_exists_side_effects[
|
|
1201 self.os_path_exists_scenario]
|
|
1202 if callable(side_effect):
|
|
1203 result = side_effect(path)
|
|
1204 else:
|
|
1205 raise side_effect
|
|
1206 else:
|
|
1207 result = False
|
|
1208 return result
|
|
1209
|
|
1210 func_patcher_os_path_exists = mock.patch.object(
|
|
1211 os.path, "exists")
|
|
1212 func_patcher_os_path_exists.start()
|
|
1213 self.addCleanup(func_patcher_os_path_exists.stop)
|
|
1214 os.path.exists.side_effect = fake_os_path_exists
|
|
1215
|
|
1216 def test_gets_changelog_path_from_distribution(self):
|
|
1217 """ Should call ‘get_changelog_path’ with distribution. """
|
|
1218 result = version.has_changelog(self.test_command)
|
|
1219 version.get_changelog_path.assert_called_with(
|
|
1220 self.test_distribution)
|
|
1221
|
|
1222 def test_returns_expected_result(self):
|
|
1223 """ Should be a subclass of ‘distutils.cmd.Command’. """
|
|
1224 result = version.has_changelog(self.test_command)
|
|
1225 self.assertEqual(self.expected_result, result)
|
|
1226
|
|
1227
|
|
1228 @mock.patch.object(version, 'generate_version_info_from_changelog')
|
|
1229 @mock.patch.object(version, 'serialise_version_info_from_mapping')
|
|
1230 @mock.patch.object(version.EggInfoCommand, "write_file")
|
|
1231 class WriteVersionInfoCommand_run_TestCase(
|
|
1232 WriteVersionInfoCommand_BaseTestCase):
|
|
1233 """ Test cases for ‘WriteVersionInfoCommand.run’ method. """
|
|
1234
|
|
1235 def setUp(self):
|
|
1236 """ Set up test fixtures. """
|
|
1237 super(WriteVersionInfoCommand_run_TestCase, self).setUp()
|
|
1238
|
|
1239 self.test_instance = version.WriteVersionInfoCommand(
|
|
1240 self.test_distribution)
|
|
1241
|
|
1242 self.fake_changelog_path = self.getUniqueString()
|
|
1243 self.test_instance.changelog_path = self.fake_changelog_path
|
|
1244
|
|
1245 self.fake_outfile_path = self.getUniqueString()
|
|
1246 self.test_instance.outfile_path = self.fake_outfile_path
|
|
1247
|
|
1248 def test_returns_none(
|
|
1249 self,
|
|
1250 mock_func_egg_info_write_file,
|
|
1251 mock_func_serialise_version_info,
|
|
1252 mock_func_generate_version_info):
|
|
1253 """ Should return ``None``. """
|
|
1254 result = self.test_instance.run()
|
|
1255 self.assertIs(result, None)
|
|
1256
|
|
1257 def test_generates_version_info_from_changelog(
|
|
1258 self,
|
|
1259 mock_func_egg_info_write_file,
|
|
1260 mock_func_serialise_version_info,
|
|
1261 mock_func_generate_version_info):
|
|
1262 """ Should generate version info from specified changelog. """
|
|
1263 self.test_instance.run()
|
|
1264 expected_changelog_path = self.test_instance.changelog_path
|
|
1265 mock_func_generate_version_info.assert_called_with(
|
|
1266 expected_changelog_path)
|
|
1267
|
|
1268 def test_serialises_version_info_from_mapping(
|
|
1269 self,
|
|
1270 mock_func_egg_info_write_file,
|
|
1271 mock_func_serialise_version_info,
|
|
1272 mock_func_generate_version_info):
|
|
1273 """ Should serialise version info from specified mapping. """
|
|
1274 self.test_instance.run()
|
|
1275 expected_version_info = mock_func_generate_version_info.return_value
|
|
1276 mock_func_serialise_version_info.assert_called_with(
|
|
1277 expected_version_info)
|
|
1278
|
|
1279 def test_writes_file_using_command_context(
|
|
1280 self,
|
|
1281 mock_func_egg_info_write_file,
|
|
1282 mock_func_serialise_version_info,
|
|
1283 mock_func_generate_version_info):
|
|
1284 """ Should write the metadata file using the command context. """
|
|
1285 self.test_instance.run()
|
|
1286 expected_content = mock_func_serialise_version_info.return_value
|
|
1287 mock_func_egg_info_write_file.assert_called_with(
|
|
1288 "version info", self.fake_outfile_path, expected_content)
|
|
1289
|
|
1290
|
|
1291 IsSubset = testtools.matchers.MatchesPredicateWithParams(
|
|
1292 set.issubset, "{0} should be a subset of {1}")
|
|
1293
|
|
1294 class EggInfoCommand_TestCase(testtools.TestCase):
|
|
1295 """ Test cases for ‘EggInfoCommand’ class. """
|
|
1296
|
|
1297 def setUp(self):
|
|
1298 """ Set up test fixtures. """
|
|
1299 super(EggInfoCommand_TestCase, self).setUp()
|
|
1300
|
|
1301 self.test_distribution = distutils.dist.Distribution()
|
|
1302 self.test_instance = version.EggInfoCommand(self.test_distribution)
|
|
1303
|
|
1304 def test_subclass_of_setuptools_egg_info(self):
|
|
1305 """ Should be a subclass of Setuptools ‘egg_info’. """
|
|
1306 self.assertIsInstance(
|
|
1307 self.test_instance, setuptools.command.egg_info.egg_info)
|
|
1308
|
|
1309 def test_sub_commands_include_base_class_sub_commands(self):
|
|
1310 """ Should include base class's sub-commands in this sub_commands. """
|
|
1311 base_command = setuptools.command.egg_info.egg_info
|
|
1312 expected_sub_commands = base_command.sub_commands
|
|
1313 self.assertThat(
|
|
1314 set(expected_sub_commands),
|
|
1315 IsSubset(set(self.test_instance.sub_commands)))
|
|
1316
|
|
1317 def test_sub_commands_includes_write_version_info_command(self):
|
|
1318 """ Should include sub-command named ‘write_version_info’. """
|
|
1319 commands_by_name = dict(self.test_instance.sub_commands)
|
|
1320 expected_predicate = version.has_changelog
|
|
1321 expected_item = ('write_version_info', expected_predicate)
|
|
1322 self.assertIn(expected_item, commands_by_name.items())
|
|
1323
|
|
1324
|
|
1325 @mock.patch.object(setuptools.command.egg_info.egg_info, "run")
|
|
1326 class EggInfoCommand_run_TestCase(testtools.TestCase):
|
|
1327 """ Test cases for ‘EggInfoCommand.run’ method. """
|
|
1328
|
|
1329 def setUp(self):
|
|
1330 """ Set up test fixtures. """
|
|
1331 super(EggInfoCommand_run_TestCase, self).setUp()
|
|
1332
|
|
1333 self.test_distribution = distutils.dist.Distribution()
|
|
1334 self.test_instance = version.EggInfoCommand(self.test_distribution)
|
|
1335
|
|
1336 base_command = setuptools.command.egg_info.egg_info
|
|
1337 patcher_func_egg_info_get_sub_commands = mock.patch.object(
|
|
1338 base_command, "get_sub_commands")
|
|
1339 patcher_func_egg_info_get_sub_commands.start()
|
|
1340 self.addCleanup(patcher_func_egg_info_get_sub_commands.stop)
|
|
1341
|
|
1342 patcher_func_egg_info_run_command = mock.patch.object(
|
|
1343 base_command, "run_command")
|
|
1344 patcher_func_egg_info_run_command.start()
|
|
1345 self.addCleanup(patcher_func_egg_info_run_command.stop)
|
|
1346
|
|
1347 self.fake_sub_commands = ["spam", "eggs", "beans"]
|
|
1348 base_command.get_sub_commands.return_value = self.fake_sub_commands
|
|
1349
|
|
1350 def test_returns_none(self, mock_func_egg_info_run):
|
|
1351 """ Should return ``None``. """
|
|
1352 result = self.test_instance.run()
|
|
1353 self.assertIs(result, None)
|
|
1354
|
|
1355 def test_runs_each_command_in_sub_commands(
|
|
1356 self, mock_func_egg_info_run):
|
|
1357 """ Should run each command in ‘self.get_sub_commands()’. """
|
|
1358 base_command = setuptools.command.egg_info.egg_info
|
|
1359 self.test_instance.run()
|
|
1360 expected_calls = [mock.call(name) for name in self.fake_sub_commands]
|
|
1361 base_command.run_command.assert_has_calls(expected_calls)
|
|
1362
|
|
1363 def test_calls_base_class_run(self, mock_func_egg_info_run):
|
|
1364 """ Should call base class's ‘run’ method. """
|
|
1365 result = self.test_instance.run()
|
|
1366 mock_func_egg_info_run.assert_called_with()
|
|
1367
|
|
1368
|
|
1369 # Local variables:
|
|
1370 # coding: utf-8
|
|
1371 # mode: python
|
|
1372 # End:
|
|
1373 # vim: fileencoding=utf-8 filetype=python :
|