summaryrefslogtreecommitdiffstats
path: root/scripts/external_libs/python-daemon-2.0.5/test_version.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/external_libs/python-daemon-2.0.5/test_version.py')
-rw-r--r--scripts/external_libs/python-daemon-2.0.5/test_version.py1373
1 files changed, 1373 insertions, 0 deletions
diff --git a/scripts/external_libs/python-daemon-2.0.5/test_version.py b/scripts/external_libs/python-daemon-2.0.5/test_version.py
new file mode 100644
index 00000000..b52f521d
--- /dev/null
+++ b/scripts/external_libs/python-daemon-2.0.5/test_version.py
@@ -0,0 +1,1373 @@
+# -*- coding: utf-8 -*-
+#
+# test_version.py
+# Part of ‘python-daemon’, an implementation of PEP 3143.
+#
+# Copyright © 2008–2015 Ben Finney <ben+python@benfinney.id.au>
+#
+# This is free software: you may copy, modify, and/or distribute this work
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 3 of that license or any later version.
+# No warranty expressed or implied. See the file ‘LICENSE.GPL-3’ for details.
+
+""" Unit test for ‘version’ packaging module. """
+
+from __future__ import (absolute_import, unicode_literals)
+
+import os
+import os.path
+import io
+import errno
+import functools
+import collections
+import textwrap
+import json
+import tempfile
+import distutils.dist
+import distutils.cmd
+import distutils.errors
+import distutils.fancy_getopt
+try:
+ # Standard library of Python 2.7 and later.
+ from io import StringIO
+except ImportError:
+ # Standard library of Python 2.6 and earlier.
+ from StringIO import StringIO
+
+import mock
+import testtools
+import testscenarios
+import docutils
+import docutils.writers
+import docutils.nodes
+import setuptools
+import setuptools.command
+
+import version
+
+version.ensure_class_bases_begin_with(
+ version.__dict__, str('VersionInfoWriter'), docutils.writers.Writer)
+version.ensure_class_bases_begin_with(
+ version.__dict__, str('VersionInfoTranslator'),
+ docutils.nodes.SparseNodeVisitor)
+
+
+def make_test_classes_for_ensure_class_bases_begin_with():
+ """ Make test classes for use with ‘ensure_class_bases_begin_with’.
+
+ :return: Mapping {`name`: `type`} of the custom types created.
+
+ """
+
+ class quux_metaclass(type):
+ def __new__(metaclass, name, bases, namespace):
+ return super(quux_metaclass, metaclass).__new__(
+ metaclass, name, bases, namespace)
+
+ class Foo(object):
+ __metaclass__ = type
+
+ class Bar(object):
+ pass
+
+ class FooInheritingBar(Bar):
+ __metaclass__ = type
+
+ class FooWithCustomMetaclass(object):
+ __metaclass__ = quux_metaclass
+
+ result = dict(
+ (name, value) for (name, value) in locals().items()
+ if isinstance(value, type))
+
+ return result
+
+class ensure_class_bases_begin_with_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘ensure_class_bases_begin_with’ function. """
+
+ test_classes = make_test_classes_for_ensure_class_bases_begin_with()
+
+ scenarios = [
+ ('simple', {
+ 'test_class': test_classes['Foo'],
+ 'base_class': test_classes['Bar'],
+ }),
+ ('custom metaclass', {
+ 'test_class': test_classes['FooWithCustomMetaclass'],
+ 'base_class': test_classes['Bar'],
+ 'expected_metaclass': test_classes['quux_metaclass'],
+ }),
+ ]
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(ensure_class_bases_begin_with_TestCase, self).setUp()
+
+ self.class_name = self.test_class.__name__
+ self.test_module_namespace = {self.class_name: self.test_class}
+
+ if not hasattr(self, 'expected_metaclass'):
+ self.expected_metaclass = type
+
+ patcher_metaclass = mock.patch.object(
+ self.test_class, '__metaclass__')
+ patcher_metaclass.start()
+ self.addCleanup(patcher_metaclass.stop)
+
+ self.fake_new_class = type(object)
+ self.test_class.__metaclass__.return_value = (
+ self.fake_new_class)
+
+ def test_module_namespace_contains_new_class(self):
+ """ Specified module namespace should have new class. """
+ version.ensure_class_bases_begin_with(
+ self.test_module_namespace, self.class_name, self.base_class)
+ self.assertIn(self.fake_new_class, self.test_module_namespace.values())
+
+ def test_calls_metaclass_with_expected_class_name(self):
+ """ Should call the metaclass with the expected class name. """
+ version.ensure_class_bases_begin_with(
+ self.test_module_namespace, self.class_name, self.base_class)
+ expected_class_name = self.class_name
+ self.test_class.__metaclass__.assert_called_with(
+ expected_class_name, mock.ANY, mock.ANY)
+
+ def test_calls_metaclass_with_expected_bases(self):
+ """ Should call the metaclass with the expected bases. """
+ version.ensure_class_bases_begin_with(
+ self.test_module_namespace, self.class_name, self.base_class)
+ expected_bases = tuple(
+ [self.base_class]
+ + list(self.test_class.__bases__))
+ self.test_class.__metaclass__.assert_called_with(
+ mock.ANY, expected_bases, mock.ANY)
+
+ def test_calls_metaclass_with_expected_namespace(self):
+ """ Should call the metaclass with the expected class namespace. """
+ version.ensure_class_bases_begin_with(
+ self.test_module_namespace, self.class_name, self.base_class)
+ expected_namespace = self.test_class.__dict__.copy()
+ del expected_namespace['__dict__']
+ self.test_class.__metaclass__.assert_called_with(
+ mock.ANY, mock.ANY, expected_namespace)
+
+
+class ensure_class_bases_begin_with_AlreadyHasBase_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘ensure_class_bases_begin_with’ function.
+
+ These test cases test the conditions where the class's base is
+ already the specified base class.
+
+ """
+
+ test_classes = make_test_classes_for_ensure_class_bases_begin_with()
+
+ scenarios = [
+ ('already Bar subclass', {
+ 'test_class': test_classes['FooInheritingBar'],
+ 'base_class': test_classes['Bar'],
+ }),
+ ]
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(
+ ensure_class_bases_begin_with_AlreadyHasBase_TestCase,
+ self).setUp()
+
+ self.class_name = self.test_class.__name__
+ self.test_module_namespace = {self.class_name: self.test_class}
+
+ patcher_metaclass = mock.patch.object(
+ self.test_class, '__metaclass__')
+ patcher_metaclass.start()
+ self.addCleanup(patcher_metaclass.stop)
+
+ def test_metaclass_not_called(self):
+ """ Should not call metaclass to create a new type. """
+ version.ensure_class_bases_begin_with(
+ self.test_module_namespace, self.class_name, self.base_class)
+ self.assertFalse(self.test_class.__metaclass__.called)
+
+
+class VersionInfoWriter_TestCase(testtools.TestCase):
+ """ Test cases for ‘VersionInfoWriter’ class. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(VersionInfoWriter_TestCase, self).setUp()
+
+ self.test_instance = version.VersionInfoWriter()
+
+ def test_declares_version_info_support(self):
+ """ Should declare support for ‘version_info’. """
+ instance = self.test_instance
+ expected_support = "version_info"
+ result = instance.supports(expected_support)
+ self.assertTrue(result)
+
+
+class VersionInfoWriter_translate_TestCase(testtools.TestCase):
+ """ Test cases for ‘VersionInfoWriter.translate’ method. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(VersionInfoWriter_translate_TestCase, self).setUp()
+
+ patcher_translator = mock.patch.object(
+ version, 'VersionInfoTranslator')
+ self.mock_class_translator = patcher_translator.start()
+ self.addCleanup(patcher_translator.stop)
+ self.mock_translator = self.mock_class_translator.return_value
+
+ self.test_instance = version.VersionInfoWriter()
+ patcher_document = mock.patch.object(
+ self.test_instance, 'document')
+ patcher_document.start()
+ self.addCleanup(patcher_document.stop)
+
+ def test_creates_translator_with_document(self):
+ """ Should create a translator with the writer's document. """
+ instance = self.test_instance
+ expected_document = self.test_instance.document
+ instance.translate()
+ self.mock_class_translator.assert_called_with(expected_document)
+
+ def test_calls_document_walkabout_with_translator(self):
+ """ Should call document.walkabout with the translator. """
+ instance = self.test_instance
+ instance.translate()
+ instance.document.walkabout.assert_called_with(self.mock_translator)
+
+ def test_output_from_translator_astext(self):
+ """ Should have output from translator.astext(). """
+ instance = self.test_instance
+ instance.translate()
+ expected_output = self.mock_translator.astext.return_value
+ self.assertEqual(expected_output, instance.output)
+
+
+class ChangeLogEntry_TestCase(testtools.TestCase):
+ """ Test cases for ‘ChangeLogEntry’ class. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(ChangeLogEntry_TestCase, self).setUp()
+
+ self.test_instance = version.ChangeLogEntry()
+
+ def test_instantiate(self):
+ """ New instance of ‘ChangeLogEntry’ should be created. """
+ self.assertIsInstance(
+ self.test_instance, version.ChangeLogEntry)
+
+ def test_minimum_zero_arguments(self):
+ """ Initialiser should not require any arguments. """
+ instance = version.ChangeLogEntry()
+ self.assertIsNot(instance, None)
+
+
+class ChangeLogEntry_release_date_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘ChangeLogEntry.release_date’ attribute. """
+
+ scenarios = [
+ ('default', {
+ 'test_args': {},
+ 'expected_release_date':
+ version.ChangeLogEntry.default_release_date,
+ }),
+ ('unknown token', {
+ 'test_args': {'release_date': "UNKNOWN"},
+ 'expected_release_date': "UNKNOWN",
+ }),
+ ('future token', {
+ 'test_args': {'release_date': "FUTURE"},
+ 'expected_release_date': "FUTURE",
+ }),
+ ('2001-01-01', {
+ 'test_args': {'release_date': "2001-01-01"},
+ 'expected_release_date': "2001-01-01",
+ }),
+ ('bogus', {
+ 'test_args': {'release_date': "b0gUs"},
+ 'expected_error': ValueError,
+ }),
+ ]
+
+ def test_has_expected_release_date(self):
+ """ Should have default `release_date` attribute. """
+ if hasattr(self, 'expected_error'):
+ self.assertRaises(
+ self.expected_error,
+ version.ChangeLogEntry, **self.test_args)
+ else:
+ instance = version.ChangeLogEntry(**self.test_args)
+ self.assertEqual(self.expected_release_date, instance.release_date)
+
+
+class ChangeLogEntry_version_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘ChangeLogEntry.version’ attribute. """
+
+ scenarios = [
+ ('default', {
+ 'test_args': {},
+ 'expected_version':
+ version.ChangeLogEntry.default_version,
+ }),
+ ('unknown token', {
+ 'test_args': {'version': "UNKNOWN"},
+ 'expected_version': "UNKNOWN",
+ }),
+ ('0.0', {
+ 'test_args': {'version': "0.0"},
+ 'expected_version': "0.0",
+ }),
+ ]
+
+ def test_has_expected_version(self):
+ """ Should have default `version` attribute. """
+ instance = version.ChangeLogEntry(**self.test_args)
+ self.assertEqual(self.expected_version, instance.version)
+
+
+class ChangeLogEntry_maintainer_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘ChangeLogEntry.maintainer’ attribute. """
+
+ scenarios = [
+ ('default', {
+ 'test_args': {},
+ 'expected_maintainer': None,
+ }),
+ ('person', {
+ 'test_args': {'maintainer': "Foo Bar <foo.bar@example.org>"},
+ 'expected_maintainer': "Foo Bar <foo.bar@example.org>",
+ }),
+ ('bogus', {
+ 'test_args': {'maintainer': "b0gUs"},
+ 'expected_error': ValueError,
+ }),
+ ]
+
+ def test_has_expected_maintainer(self):
+ """ Should have default `maintainer` attribute. """
+ if hasattr(self, 'expected_error'):
+ self.assertRaises(
+ self.expected_error,
+ version.ChangeLogEntry, **self.test_args)
+ else:
+ instance = version.ChangeLogEntry(**self.test_args)
+ self.assertEqual(self.expected_maintainer, instance.maintainer)
+
+
+class ChangeLogEntry_body_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘ChangeLogEntry.body’ attribute. """
+
+ scenarios = [
+ ('default', {
+ 'test_args': {},
+ 'expected_body': None,
+ }),
+ ('simple', {
+ 'test_args': {'body': "Foo bar baz."},
+ 'expected_body': "Foo bar baz.",
+ }),
+ ]
+
+ def test_has_expected_body(self):
+ """ Should have default `body` attribute. """
+ instance = version.ChangeLogEntry(**self.test_args)
+ self.assertEqual(self.expected_body, instance.body)
+
+
+class ChangeLogEntry_as_version_info_entry_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘ChangeLogEntry.as_version_info_entry’ attribute. """
+
+ scenarios = [
+ ('default', {
+ 'test_args': {},
+ 'expected_result': collections.OrderedDict([
+ ('release_date', version.ChangeLogEntry.default_release_date),
+ ('version', version.ChangeLogEntry.default_version),
+ ('maintainer', None),
+ ('body', None),
+ ]),
+ }),
+ ]
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(ChangeLogEntry_as_version_info_entry_TestCase, self).setUp()
+
+ self.test_instance = version.ChangeLogEntry(**self.test_args)
+
+ def test_returns_result(self):
+ """ Should return expected result. """
+ result = self.test_instance.as_version_info_entry()
+ self.assertEqual(self.expected_result, result)
+
+
+def make_mock_field_node(field_name, field_body):
+ """ Make a mock Docutils field node for tests. """
+
+ mock_field_node = mock.MagicMock(
+ name='field', spec=docutils.nodes.field)
+
+ mock_field_name_node = mock.MagicMock(
+ name='field_name', spec=docutils.nodes.field_name)
+ mock_field_name_node.parent = mock_field_node
+ mock_field_name_node.children = [field_name]
+
+ mock_field_body_node = mock.MagicMock(
+ name='field_body', spec=docutils.nodes.field_body)
+ mock_field_body_node.parent = mock_field_node
+ mock_field_body_node.children = [field_body]
+
+ mock_field_node.children = [mock_field_name_node, mock_field_body_node]
+
+ def fake_func_first_child_matching_class(node_class):
+ result = None
+ node_class_name = node_class.__name__
+ for (index, node) in enumerate(mock_field_node.children):
+ if node._mock_name == node_class_name:
+ result = index
+ break
+ return result
+
+ mock_field_node.first_child_matching_class.side_effect = (
+ fake_func_first_child_matching_class)
+
+ return mock_field_node
+
+
+class JsonEqual(testtools.matchers.Matcher):
+ """ A matcher to compare the value of JSON streams. """
+
+ def __init__(self, expected):
+ self.expected_value = expected
+
+ def match(self, content):
+ """ Assert the JSON `content` matches the `expected_content`. """
+ result = None
+ actual_value = json.loads(content.decode('utf-8'))
+ if actual_value != self.expected_value:
+ result = JsonValueMismatch(self.expected_value, actual_value)
+ return result
+
+
+class JsonValueMismatch(testtools.matchers.Mismatch):
+ """ The specified JSON stream does not evaluate to the expected value. """
+
+ def __init__(self, expected, actual):
+ self.expected_value = expected
+ self.actual_value = actual
+
+ def describe(self):
+ """ Emit a text description of this mismatch. """
+ expected_json_text = json.dumps(self.expected_value, indent=4)
+ actual_json_text = json.dumps(self.actual_value, indent=4)
+ text = (
+ "\n"
+ "reference: {expected}\n"
+ "actual: {actual}\n").format(
+ expected=expected_json_text, actual=actual_json_text)
+ return text
+
+
+class changelog_to_version_info_collection_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘changelog_to_version_info_collection’ function. """
+
+ scenarios = [
+ ('single entry', {
+ 'test_input': textwrap.dedent("""\
+ Version 1.0
+ ===========
+
+ :Released: 2009-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+
+ * Lorem ipsum dolor sit amet.
+ """),
+ 'expected_version_info': [
+ {
+ 'release_date': "2009-01-01",
+ 'version': "1.0",
+ 'maintainer': "Foo Bar <foo.bar@example.org>",
+ 'body': "* Lorem ipsum dolor sit amet.\n",
+ },
+ ],
+ }),
+ ('multiple entries', {
+ 'test_input': textwrap.dedent("""\
+ Version 1.0
+ ===========
+
+ :Released: 2009-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+
+ * Lorem ipsum dolor sit amet.
+
+
+ Version 0.8
+ ===========
+
+ :Released: 2004-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+
+ * Donec venenatis nisl aliquam ipsum.
+
+
+ Version 0.7.2
+ =============
+
+ :Released: 2001-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+
+ * Pellentesque elementum mollis finibus.
+ """),
+ 'expected_version_info': [
+ {
+ 'release_date': "2009-01-01",
+ 'version': "1.0",
+ 'maintainer': "Foo Bar <foo.bar@example.org>",
+ 'body': "* Lorem ipsum dolor sit amet.\n",
+ },
+ {
+ 'release_date': "2004-01-01",
+ 'version': "0.8",
+ 'maintainer': "Foo Bar <foo.bar@example.org>",
+ 'body': "* Donec venenatis nisl aliquam ipsum.\n",
+ },
+ {
+ 'release_date': "2001-01-01",
+ 'version': "0.7.2",
+ 'maintainer': "Foo Bar <foo.bar@example.org>",
+ 'body': "* Pellentesque elementum mollis finibus.\n",
+ },
+ ],
+ }),
+ ('trailing comment', {
+ 'test_input': textwrap.dedent("""\
+ Version NEXT
+ ============
+
+ :Released: FUTURE
+ :Maintainer:
+
+ * Lorem ipsum dolor sit amet.
+
+ ..
+ Vivamus aliquam felis rutrum rutrum dictum.
+ """),
+ 'expected_version_info': [
+ {
+ 'release_date': "FUTURE",
+ 'version': "NEXT",
+ 'maintainer': "",
+ 'body': "* Lorem ipsum dolor sit amet.\n",
+ },
+ ],
+ }),
+ ('inline comment', {
+ 'test_input': textwrap.dedent("""\
+ Version NEXT
+ ============
+
+ :Released: FUTURE
+ :Maintainer:
+
+ ..
+ Vivamus aliquam felis rutrum rutrum dictum.
+
+ * Lorem ipsum dolor sit amet.
+ """),
+ 'expected_version_info': [
+ {
+ 'release_date': "FUTURE",
+ 'version': "NEXT",
+ 'maintainer': "",
+ 'body': "* Lorem ipsum dolor sit amet.\n",
+ },
+ ],
+ }),
+ ('unreleased entry', {
+ 'test_input': textwrap.dedent("""\
+ Version NEXT
+ ============
+
+ :Released: FUTURE
+ :Maintainer:
+
+ * Lorem ipsum dolor sit amet.
+
+
+ Version 0.8
+ ===========
+
+ :Released: 2001-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+
+ * Donec venenatis nisl aliquam ipsum.
+ """),
+ 'expected_version_info': [
+ {
+ 'release_date': "FUTURE",
+ 'version': "NEXT",
+ 'maintainer': "",
+ 'body': "* Lorem ipsum dolor sit amet.\n",
+ },
+ {
+ 'release_date': "2001-01-01",
+ 'version': "0.8",
+ 'maintainer': "Foo Bar <foo.bar@example.org>",
+ 'body': "* Donec venenatis nisl aliquam ipsum.\n",
+ },
+ ],
+ }),
+ ('no section', {
+ 'test_input': textwrap.dedent("""\
+ :Released: 2009-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+
+ * Lorem ipsum dolor sit amet.
+ """),
+ 'expected_error': version.InvalidFormatError,
+ }),
+ ('subsection', {
+ 'test_input': textwrap.dedent("""\
+ Version 1.0
+ ===========
+
+ :Released: 2009-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+
+ * Lorem ipsum dolor sit amet.
+
+ Ut ultricies fermentum quam
+ ---------------------------
+
+ * In commodo magna facilisis in.
+ """),
+ 'expected_error': version.InvalidFormatError,
+ 'subsection': True,
+ }),
+ ('unknown field', {
+ 'test_input': textwrap.dedent("""\
+ Version 1.0
+ ===========
+
+ :Released: 2009-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+ :Favourite: Spam
+
+ * Lorem ipsum dolor sit amet.
+ """),
+ 'expected_error': version.InvalidFormatError,
+ }),
+ ('invalid version word', {
+ 'test_input': textwrap.dedent("""\
+ BoGuS 1.0
+ =========
+
+ :Released: 2009-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+
+ * Lorem ipsum dolor sit amet.
+ """),
+ 'expected_error': version.InvalidFormatError,
+ }),
+ ('invalid section title', {
+ 'test_input': textwrap.dedent("""\
+ Lorem Ipsum 1.0
+ ===============
+
+ :Released: 2009-01-01
+ :Maintainer: Foo Bar <foo.bar@example.org>
+
+ * Lorem ipsum dolor sit amet.
+ """),
+ 'expected_error': version.InvalidFormatError,
+ }),
+ ]
+
+ def test_returns_expected_version_info(self):
+ """ Should return expected version info mapping. """
+ infile = StringIO(self.test_input)
+ if hasattr(self, 'expected_error'):
+ self.assertRaises(
+ self.expected_error,
+ version.changelog_to_version_info_collection, infile)
+ else:
+ result = version.changelog_to_version_info_collection(infile)
+ self.assertThat(result, JsonEqual(self.expected_version_info))
+
+
+try:
+ FileNotFoundError
+ PermissionError
+except NameError:
+ # Python 2 uses OSError.
+ FileNotFoundError = functools.partial(IOError, errno.ENOENT)
+ PermissionError = functools.partial(IOError, errno.EPERM)
+
+fake_version_info = {
+ 'release_date': "2001-01-01", 'version': "2.0",
+ 'maintainer': None, 'body': None,
+ }
+
+@mock.patch.object(
+ version, "get_latest_version", return_value=fake_version_info)
+class generate_version_info_from_changelog_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘generate_version_info_from_changelog’ function. """
+
+ fake_open_side_effects = {
+ 'success': (
+ lambda *args, **kwargs: StringIO()),
+ 'file not found': FileNotFoundError(),
+ 'permission denied': PermissionError(),
+ }
+
+ scenarios = [
+ ('simple', {
+ 'open_scenario': 'success',
+ 'fake_versions_json': json.dumps([fake_version_info]),
+ 'expected_result': fake_version_info,
+ }),
+ ('file not found', {
+ 'open_scenario': 'file not found',
+ 'expected_result': {},
+ }),
+ ('permission denied', {
+ 'open_scenario': 'permission denied',
+ 'expected_result': {},
+ }),
+ ]
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(generate_version_info_from_changelog_TestCase, self).setUp()
+
+ self.fake_changelog_file_path = tempfile.mktemp()
+
+ def fake_open(filespec, *args, **kwargs):
+ if filespec == self.fake_changelog_file_path:
+ side_effect = self.fake_open_side_effects[self.open_scenario]
+ if callable(side_effect):
+ result = side_effect()
+ else:
+ raise side_effect
+ else:
+ result = StringIO()
+ return result
+
+ func_patcher_io_open = mock.patch.object(
+ io, "open")
+ func_patcher_io_open.start()
+ self.addCleanup(func_patcher_io_open.stop)
+ io.open.side_effect = fake_open
+
+ self.file_encoding = "utf-8"
+
+ func_patcher_changelog_to_version_info_collection = mock.patch.object(
+ version, "changelog_to_version_info_collection")
+ func_patcher_changelog_to_version_info_collection.start()
+ self.addCleanup(func_patcher_changelog_to_version_info_collection.stop)
+ if hasattr(self, 'fake_versions_json'):
+ version.changelog_to_version_info_collection.return_value = (
+ self.fake_versions_json.encode(self.file_encoding))
+
+ def test_returns_empty_collection_on_read_error(
+ self,
+ mock_func_get_latest_version):
+ """ Should return empty collection on error reading changelog. """
+ test_error = PermissionError("Not for you")
+ version.changelog_to_version_info_collection.side_effect = test_error
+ result = version.generate_version_info_from_changelog(
+ self.fake_changelog_file_path)
+ expected_result = {}
+ self.assertDictEqual(expected_result, result)
+
+ def test_opens_file_with_expected_encoding(
+ self,
+ mock_func_get_latest_version):
+ """ Should open changelog file in text mode with expected encoding. """
+ result = version.generate_version_info_from_changelog(
+ self.fake_changelog_file_path)
+ expected_file_path = self.fake_changelog_file_path
+ expected_open_mode = 'rt'
+ expected_encoding = self.file_encoding
+ (open_args_positional, open_args_kwargs) = io.open.call_args
+ (open_args_filespec, open_args_mode) = open_args_positional[:2]
+ open_args_encoding = open_args_kwargs['encoding']
+ self.assertEqual(expected_file_path, open_args_filespec)
+ self.assertEqual(expected_open_mode, open_args_mode)
+ self.assertEqual(expected_encoding, open_args_encoding)
+
+ def test_returns_expected_result(
+ self,
+ mock_func_get_latest_version):
+ """ Should return expected result. """
+ result = version.generate_version_info_from_changelog(
+ self.fake_changelog_file_path)
+ self.assertEqual(self.expected_result, result)
+
+
+DefaultNoneDict = functools.partial(collections.defaultdict, lambda: None)
+
+class get_latest_version_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘get_latest_version’ function. """
+
+ scenarios = [
+ ('simple', {
+ 'test_versions': [
+ DefaultNoneDict({'release_date': "LATEST"}),
+ ],
+ 'expected_result': version.ChangeLogEntry.make_ordered_dict(
+ DefaultNoneDict({'release_date': "LATEST"})),
+ }),
+ ('no versions', {
+ 'test_versions': [],
+ 'expected_result': collections.OrderedDict(),
+ }),
+ ('ordered versions', {
+ 'test_versions': [
+ DefaultNoneDict({'release_date': "1"}),
+ DefaultNoneDict({'release_date': "2"}),
+ DefaultNoneDict({'release_date': "LATEST"}),
+ ],
+ 'expected_result': version.ChangeLogEntry.make_ordered_dict(
+ DefaultNoneDict({'release_date': "LATEST"})),
+ }),
+ ('un-ordered versions', {
+ 'test_versions': [
+ DefaultNoneDict({'release_date': "2"}),
+ DefaultNoneDict({'release_date': "LATEST"}),
+ DefaultNoneDict({'release_date': "1"}),
+ ],
+ 'expected_result': version.ChangeLogEntry.make_ordered_dict(
+ DefaultNoneDict({'release_date': "LATEST"})),
+ }),
+ ]
+
+ def test_returns_expected_result(self):
+ """ Should return expected result. """
+ result = version.get_latest_version(self.test_versions)
+ self.assertDictEqual(self.expected_result, result)
+
+
+@mock.patch.object(json, "dumps", side_effect=json.dumps)
+class serialise_version_info_from_mapping_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘get_latest_version’ function. """
+
+ scenarios = [
+ ('simple', {
+ 'test_version_info': {'foo': "spam"},
+ }),
+ ]
+
+ for (name, scenario) in scenarios:
+ scenario['fake_json_dump'] = json.dumps(scenario['test_version_info'])
+ scenario['expected_value'] = scenario['test_version_info']
+
+ def test_passes_specified_object(self, mock_func_json_dumps):
+ """ Should pass the specified object to `json.dumps`. """
+ result = version.serialise_version_info_from_mapping(
+ self.test_version_info)
+ mock_func_json_dumps.assert_called_with(
+ self.test_version_info, indent=mock.ANY)
+
+ def test_returns_expected_result(self, mock_func_json_dumps):
+ """ Should return expected result. """
+ mock_func_json_dumps.return_value = self.fake_json_dump
+ result = version.serialise_version_info_from_mapping(
+ self.test_version_info)
+ value = json.loads(result)
+ self.assertEqual(self.expected_value, value)
+
+
+DistributionMetadata_defaults = {
+ name: None
+ for name in list(collections.OrderedDict.fromkeys(
+ distutils.dist.DistributionMetadata._METHOD_BASENAMES))}
+FakeDistributionMetadata = collections.namedtuple(
+ 'FakeDistributionMetadata', DistributionMetadata_defaults.keys())
+
+Distribution_defaults = {
+ 'metadata': None,
+ 'version': None,
+ 'release_date': None,
+ 'maintainer': None,
+ 'maintainer_email': None,
+ }
+FakeDistribution = collections.namedtuple(
+ 'FakeDistribution', Distribution_defaults.keys())
+
+def make_fake_distribution(
+ fields_override=None, metadata_fields_override=None):
+ metadata_fields = DistributionMetadata_defaults.copy()
+ if metadata_fields_override is not None:
+ metadata_fields.update(metadata_fields_override)
+ metadata = FakeDistributionMetadata(**metadata_fields)
+
+ fields = Distribution_defaults.copy()
+ fields['metadata'] = metadata
+ if fields_override is not None:
+ fields.update(fields_override)
+ distribution = FakeDistribution(**fields)
+
+ return distribution
+
+
+class get_changelog_path_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘get_changelog_path’ function. """
+
+ default_path = "."
+ default_script_filename = "setup.py"
+
+ scenarios = [
+ ('simple', {}),
+ ('unusual script name', {
+ 'script_filename': "lorem_ipsum",
+ }),
+ ('relative script path', {
+ 'script_directory': "dolor/sit/amet",
+ }),
+ ('absolute script path', {
+ 'script_directory': "/dolor/sit/amet",
+ }),
+ ('specify filename', {
+ 'changelog_filename': "adipiscing",
+ }),
+ ]
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(get_changelog_path_TestCase, self).setUp()
+
+ self.test_distribution = mock.MagicMock(distutils.dist.Distribution)
+
+ if not hasattr(self, 'script_directory'):
+ self.script_directory = self.default_path
+ if not hasattr(self, 'script_filename'):
+ self.script_filename = self.default_script_filename
+ self.test_distribution.script_name = os.path.join(
+ self.script_directory, self.script_filename)
+
+ changelog_filename = version.changelog_filename
+ if hasattr(self, 'changelog_filename'):
+ changelog_filename = self.changelog_filename
+
+ self.expected_result = os.path.join(
+ self.script_directory, changelog_filename)
+
+ def test_returns_expected_result(self):
+ """ Should return expected result. """
+ args = {
+ 'distribution': self.test_distribution,
+ }
+ if hasattr(self, 'changelog_filename'):
+ args.update({'filename': self.changelog_filename})
+ result = version.get_changelog_path(**args)
+ self.assertEqual(self.expected_result, result)
+
+
+class WriteVersionInfoCommand_BaseTestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Base class for ‘WriteVersionInfoCommand’ test case classes. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(WriteVersionInfoCommand_BaseTestCase, self).setUp()
+
+ fake_distribution_name = self.getUniqueString()
+
+ self.test_distribution = distutils.dist.Distribution()
+ self.test_distribution.metadata.name = fake_distribution_name
+
+
+class WriteVersionInfoCommand_TestCase(WriteVersionInfoCommand_BaseTestCase):
+ """ Test cases for ‘WriteVersionInfoCommand’ class. """
+
+ def test_subclass_of_distutils_command(self):
+ """ Should be a subclass of ‘distutils.cmd.Command’. """
+ instance = version.WriteVersionInfoCommand(self.test_distribution)
+ self.assertIsInstance(instance, distutils.cmd.Command)
+
+
+class WriteVersionInfoCommand_user_options_TestCase(
+ WriteVersionInfoCommand_BaseTestCase):
+ """ Test cases for ‘WriteVersionInfoCommand.user_options’ attribute. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(WriteVersionInfoCommand_user_options_TestCase, self).setUp()
+
+ self.test_instance = version.WriteVersionInfoCommand(
+ self.test_distribution)
+ self.commandline_parser = distutils.fancy_getopt.FancyGetopt(
+ self.test_instance.user_options)
+
+ def test_parses_correctly_as_fancy_getopt(self):
+ """ Should parse correctly in ‘FancyGetopt’. """
+ self.assertIsInstance(
+ self.commandline_parser, distutils.fancy_getopt.FancyGetopt)
+
+ def test_includes_base_class_user_options(self):
+ """ Should include base class's user_options. """
+ base_command = setuptools.command.egg_info.egg_info
+ expected_user_options = base_command.user_options
+ self.assertThat(
+ set(expected_user_options),
+ IsSubset(set(self.test_instance.user_options)))
+
+ def test_has_option_changelog_path(self):
+ """ Should have a ‘changelog-path’ option. """
+ expected_option_name = "changelog-path="
+ result = self.commandline_parser.has_option(expected_option_name)
+ self.assertTrue(result)
+
+ def test_has_option_outfile_path(self):
+ """ Should have a ‘outfile-path’ option. """
+ expected_option_name = "outfile-path="
+ result = self.commandline_parser.has_option(expected_option_name)
+ self.assertTrue(result)
+
+
+class WriteVersionInfoCommand_initialize_options_TestCase(
+ WriteVersionInfoCommand_BaseTestCase):
+ """ Test cases for ‘WriteVersionInfoCommand.initialize_options’ method. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(
+ WriteVersionInfoCommand_initialize_options_TestCase, self
+ ).setUp()
+
+ patcher_func_egg_info_initialize_options = mock.patch.object(
+ setuptools.command.egg_info.egg_info, "initialize_options")
+ patcher_func_egg_info_initialize_options.start()
+ self.addCleanup(patcher_func_egg_info_initialize_options.stop)
+
+ def test_calls_base_class_method(self):
+ """ Should call base class's ‘initialize_options’ method. """
+ instance = version.WriteVersionInfoCommand(self.test_distribution)
+ base_command_class = setuptools.command.egg_info.egg_info
+ base_command_class.initialize_options.assert_called_with()
+
+ def test_sets_changelog_path_to_none(self):
+ """ Should set ‘changelog_path’ attribute to ``None``. """
+ instance = version.WriteVersionInfoCommand(self.test_distribution)
+ self.assertIs(instance.changelog_path, None)
+
+ def test_sets_outfile_path_to_none(self):
+ """ Should set ‘outfile_path’ attribute to ``None``. """
+ instance = version.WriteVersionInfoCommand(self.test_distribution)
+ self.assertIs(instance.outfile_path, None)
+
+
+class WriteVersionInfoCommand_finalize_options_TestCase(
+ WriteVersionInfoCommand_BaseTestCase):
+ """ Test cases for ‘WriteVersionInfoCommand.finalize_options’ method. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(WriteVersionInfoCommand_finalize_options_TestCase, self).setUp()
+
+ self.test_instance = version.WriteVersionInfoCommand(self.test_distribution)
+
+ patcher_func_egg_info_finalize_options = mock.patch.object(
+ setuptools.command.egg_info.egg_info, "finalize_options")
+ patcher_func_egg_info_finalize_options.start()
+ self.addCleanup(patcher_func_egg_info_finalize_options.stop)
+
+ self.fake_script_dir = self.getUniqueString()
+ self.test_distribution.script_name = os.path.join(
+ self.fake_script_dir, self.getUniqueString())
+
+ self.fake_egg_dir = self.getUniqueString()
+ self.test_instance.egg_info = self.fake_egg_dir
+
+ patcher_func_get_changelog_path = mock.patch.object(
+ version, "get_changelog_path")
+ patcher_func_get_changelog_path.start()
+ self.addCleanup(patcher_func_get_changelog_path.stop)
+
+ self.fake_changelog_path = self.getUniqueString()
+ version.get_changelog_path.return_value = self.fake_changelog_path
+
+ def test_calls_base_class_method(self):
+ """ Should call base class's ‘finalize_options’ method. """
+ base_command_class = setuptools.command.egg_info.egg_info
+ self.test_instance.finalize_options()
+ base_command_class.finalize_options.assert_called_with()
+
+ def test_sets_force_to_none(self):
+ """ Should set ‘force’ attribute to ``None``. """
+ self.test_instance.finalize_options()
+ self.assertIs(self.test_instance.force, None)
+
+ def test_sets_changelog_path_using_get_changelog_path(self):
+ """ Should set ‘changelog_path’ attribute if it was ``None``. """
+ self.test_instance.changelog_path = None
+ self.test_instance.finalize_options()
+ expected_changelog_path = self.fake_changelog_path
+ self.assertEqual(expected_changelog_path, self.test_instance.changelog_path)
+
+ def test_leaves_changelog_path_if_already_set(self):
+ """ Should leave ‘changelog_path’ attribute set. """
+ prior_changelog_path = self.getUniqueString()
+ self.test_instance.changelog_path = prior_changelog_path
+ self.test_instance.finalize_options()
+ expected_changelog_path = prior_changelog_path
+ self.assertEqual(expected_changelog_path, self.test_instance.changelog_path)
+
+ def test_sets_outfile_path_to_default(self):
+ """ Should set ‘outfile_path’ attribute to default value. """
+ fake_version_info_filename = self.getUniqueString()
+ with mock.patch.object(
+ version, "version_info_filename",
+ new=fake_version_info_filename):
+ self.test_instance.finalize_options()
+ expected_outfile_path = os.path.join(
+ self.fake_egg_dir, fake_version_info_filename)
+ self.assertEqual(expected_outfile_path, self.test_instance.outfile_path)
+
+ def test_leaves_outfile_path_if_already_set(self):
+ """ Should leave ‘outfile_path’ attribute set. """
+ prior_outfile_path = self.getUniqueString()
+ self.test_instance.outfile_path = prior_outfile_path
+ self.test_instance.finalize_options()
+ expected_outfile_path = prior_outfile_path
+ self.assertEqual(expected_outfile_path, self.test_instance.outfile_path)
+
+
+class has_changelog_TestCase(
+ testscenarios.WithScenarios, testtools.TestCase):
+ """ Test cases for ‘has_changelog’ function. """
+
+ fake_os_path_exists_side_effects = {
+ 'true': (lambda path: True),
+ 'false': (lambda path: False),
+ }
+
+ scenarios = [
+ ('no changelog path', {
+ 'changelog_path': None,
+ 'expected_result': False,
+ }),
+ ('changelog exists', {
+ 'os_path_exists_scenario': 'true',
+ 'expected_result': True,
+ }),
+ ('changelog not found', {
+ 'os_path_exists_scenario': 'false',
+ 'expected_result': False,
+ }),
+ ]
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(has_changelog_TestCase, self).setUp()
+
+ self.test_distribution = distutils.dist.Distribution()
+ self.test_command = version.EggInfoCommand(
+ self.test_distribution)
+
+ patcher_func_get_changelog_path = mock.patch.object(
+ version, "get_changelog_path")
+ patcher_func_get_changelog_path.start()
+ self.addCleanup(patcher_func_get_changelog_path.stop)
+
+ self.fake_changelog_file_path = self.getUniqueString()
+ if hasattr(self, 'changelog_path'):
+ self.fake_changelog_file_path = self.changelog_path
+ version.get_changelog_path.return_value = self.fake_changelog_file_path
+ self.fake_changelog_file = StringIO()
+
+ def fake_os_path_exists(path):
+ if path == self.fake_changelog_file_path:
+ side_effect = self.fake_os_path_exists_side_effects[
+ self.os_path_exists_scenario]
+ if callable(side_effect):
+ result = side_effect(path)
+ else:
+ raise side_effect
+ else:
+ result = False
+ return result
+
+ func_patcher_os_path_exists = mock.patch.object(
+ os.path, "exists")
+ func_patcher_os_path_exists.start()
+ self.addCleanup(func_patcher_os_path_exists.stop)
+ os.path.exists.side_effect = fake_os_path_exists
+
+ def test_gets_changelog_path_from_distribution(self):
+ """ Should call ‘get_changelog_path’ with distribution. """
+ result = version.has_changelog(self.test_command)
+ version.get_changelog_path.assert_called_with(
+ self.test_distribution)
+
+ def test_returns_expected_result(self):
+ """ Should be a subclass of ‘distutils.cmd.Command’. """
+ result = version.has_changelog(self.test_command)
+ self.assertEqual(self.expected_result, result)
+
+
+@mock.patch.object(version, 'generate_version_info_from_changelog')
+@mock.patch.object(version, 'serialise_version_info_from_mapping')
+@mock.patch.object(version.EggInfoCommand, "write_file")
+class WriteVersionInfoCommand_run_TestCase(
+ WriteVersionInfoCommand_BaseTestCase):
+ """ Test cases for ‘WriteVersionInfoCommand.run’ method. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(WriteVersionInfoCommand_run_TestCase, self).setUp()
+
+ self.test_instance = version.WriteVersionInfoCommand(
+ self.test_distribution)
+
+ self.fake_changelog_path = self.getUniqueString()
+ self.test_instance.changelog_path = self.fake_changelog_path
+
+ self.fake_outfile_path = self.getUniqueString()
+ self.test_instance.outfile_path = self.fake_outfile_path
+
+ def test_returns_none(
+ self,
+ mock_func_egg_info_write_file,
+ mock_func_serialise_version_info,
+ mock_func_generate_version_info):
+ """ Should return ``None``. """
+ result = self.test_instance.run()
+ self.assertIs(result, None)
+
+ def test_generates_version_info_from_changelog(
+ self,
+ mock_func_egg_info_write_file,
+ mock_func_serialise_version_info,
+ mock_func_generate_version_info):
+ """ Should generate version info from specified changelog. """
+ self.test_instance.run()
+ expected_changelog_path = self.test_instance.changelog_path
+ mock_func_generate_version_info.assert_called_with(
+ expected_changelog_path)
+
+ def test_serialises_version_info_from_mapping(
+ self,
+ mock_func_egg_info_write_file,
+ mock_func_serialise_version_info,
+ mock_func_generate_version_info):
+ """ Should serialise version info from specified mapping. """
+ self.test_instance.run()
+ expected_version_info = mock_func_generate_version_info.return_value
+ mock_func_serialise_version_info.assert_called_with(
+ expected_version_info)
+
+ def test_writes_file_using_command_context(
+ self,
+ mock_func_egg_info_write_file,
+ mock_func_serialise_version_info,
+ mock_func_generate_version_info):
+ """ Should write the metadata file using the command context. """
+ self.test_instance.run()
+ expected_content = mock_func_serialise_version_info.return_value
+ mock_func_egg_info_write_file.assert_called_with(
+ "version info", self.fake_outfile_path, expected_content)
+
+
+IsSubset = testtools.matchers.MatchesPredicateWithParams(
+ set.issubset, "{0} should be a subset of {1}")
+
+class EggInfoCommand_TestCase(testtools.TestCase):
+ """ Test cases for ‘EggInfoCommand’ class. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(EggInfoCommand_TestCase, self).setUp()
+
+ self.test_distribution = distutils.dist.Distribution()
+ self.test_instance = version.EggInfoCommand(self.test_distribution)
+
+ def test_subclass_of_setuptools_egg_info(self):
+ """ Should be a subclass of Setuptools ‘egg_info’. """
+ self.assertIsInstance(
+ self.test_instance, setuptools.command.egg_info.egg_info)
+
+ def test_sub_commands_include_base_class_sub_commands(self):
+ """ Should include base class's sub-commands in this sub_commands. """
+ base_command = setuptools.command.egg_info.egg_info
+ expected_sub_commands = base_command.sub_commands
+ self.assertThat(
+ set(expected_sub_commands),
+ IsSubset(set(self.test_instance.sub_commands)))
+
+ def test_sub_commands_includes_write_version_info_command(self):
+ """ Should include sub-command named ‘write_version_info’. """
+ commands_by_name = dict(self.test_instance.sub_commands)
+ expected_predicate = version.has_changelog
+ expected_item = ('write_version_info', expected_predicate)
+ self.assertIn(expected_item, commands_by_name.items())
+
+
+@mock.patch.object(setuptools.command.egg_info.egg_info, "run")
+class EggInfoCommand_run_TestCase(testtools.TestCase):
+ """ Test cases for ‘EggInfoCommand.run’ method. """
+
+ def setUp(self):
+ """ Set up test fixtures. """
+ super(EggInfoCommand_run_TestCase, self).setUp()
+
+ self.test_distribution = distutils.dist.Distribution()
+ self.test_instance = version.EggInfoCommand(self.test_distribution)
+
+ base_command = setuptools.command.egg_info.egg_info
+ patcher_func_egg_info_get_sub_commands = mock.patch.object(
+ base_command, "get_sub_commands")
+ patcher_func_egg_info_get_sub_commands.start()
+ self.addCleanup(patcher_func_egg_info_get_sub_commands.stop)
+
+ patcher_func_egg_info_run_command = mock.patch.object(
+ base_command, "run_command")
+ patcher_func_egg_info_run_command.start()
+ self.addCleanup(patcher_func_egg_info_run_command.stop)
+
+ self.fake_sub_commands = ["spam", "eggs", "beans"]
+ base_command.get_sub_commands.return_value = self.fake_sub_commands
+
+ def test_returns_none(self, mock_func_egg_info_run):
+ """ Should return ``None``. """
+ result = self.test_instance.run()
+ self.assertIs(result, None)
+
+ def test_runs_each_command_in_sub_commands(
+ self, mock_func_egg_info_run):
+ """ Should run each command in ‘self.get_sub_commands()’. """
+ base_command = setuptools.command.egg_info.egg_info
+ self.test_instance.run()
+ expected_calls = [mock.call(name) for name in self.fake_sub_commands]
+ base_command.run_command.assert_has_calls(expected_calls)
+
+ def test_calls_base_class_run(self, mock_func_egg_info_run):
+ """ Should call base class's ‘run’ method. """
+ result = self.test_instance.run()
+ mock_func_egg_info_run.assert_called_with()
+
+
+# Local variables:
+# coding: utf-8
+# mode: python
+# End:
+# vim: fileencoding=utf-8 filetype=python :