__init__.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. from zope.interface._compat import _should_attempt_c_optimizations
  2. class OptimizationTestMixin:
  3. """Mixin testing that C optimizations are used when appropriate.
  4. """
  5. def _getTargetClass(self):
  6. """Return the implementation in use, without 'Py' or 'Fallback' suffix.
  7. """
  8. raise NotImplementedError
  9. def _getFallbackClass(self):
  10. """Return the fallback Python implementation.
  11. """
  12. # Is there an algorithmic way to do this? The C
  13. # objects all come from the same module so I don't see how we can
  14. # get the Python object from that.
  15. raise NotImplementedError
  16. def _test_optimizations(self):
  17. used = self._getTargetClass()
  18. fallback = self._getFallbackClass()
  19. if _should_attempt_c_optimizations():
  20. self.assertIsNot(used, fallback)
  21. else:
  22. self.assertIs(used, fallback)
  23. class SubclassableMixin:
  24. def _getTargetClass(self):
  25. """Return the implementation in use without 'Py' or 'Fallback' suffix.
  26. """
  27. raise NotImplementedError
  28. def test_can_subclass(self):
  29. klass = self._getTargetClass()
  30. class Derived(klass): # no raise
  31. pass
  32. class MissingSomeAttrs:
  33. """
  34. Helper for tests that raises a specific exception
  35. for attributes that are missing. This is usually not
  36. an AttributeError, and this object is used to test that
  37. those errors are not improperly caught and treated like
  38. an AttributeError.
  39. """
  40. def __init__(self, exc_kind, **other_attrs):
  41. self.__exc_kind = exc_kind
  42. d = object.__getattribute__(self, '__dict__')
  43. d.update(other_attrs)
  44. def __getattribute__(self, name):
  45. # Note that we ignore objects found in the class dictionary.
  46. d = object.__getattribute__(self, '__dict__')
  47. try:
  48. return d[name]
  49. except KeyError:
  50. raise d['_MissingSomeAttrs__exc_kind'](name)
  51. EXCEPTION_CLASSES = (
  52. TypeError,
  53. RuntimeError,
  54. BaseException,
  55. ValueError,
  56. )
  57. @classmethod
  58. def test_raises(cls, unittest, test_func, expected_missing, **other_attrs):
  59. """
  60. Loop through various exceptions, calling *test_func* inside a
  61. ``assertRaises`` block.
  62. :param test_func: A callable of one argument, the instance of this
  63. class.
  64. :param str expected_missing: The attribute that should fail with the
  65. exception. This is used to ensure that we're testing the path we
  66. think we are.
  67. :param other_attrs: Attributes that should be provided on the test
  68. object. Must not contain *expected_missing*.
  69. """
  70. assert isinstance(expected_missing, str)
  71. assert expected_missing not in other_attrs
  72. for exc in cls.EXCEPTION_CLASSES:
  73. ob = cls(exc, **other_attrs)
  74. with unittest.assertRaises(exc) as ex:
  75. test_func(ob)
  76. unittest.assertEqual(ex.exception.args[0], expected_missing)
  77. # Now test that the AttributeError for that expected_missing is *not*
  78. # raised.
  79. ob = cls(AttributeError, **other_attrs)
  80. try:
  81. test_func(ob)
  82. except AttributeError as e:
  83. unittest.assertNotIn(expected_missing, str(e))
  84. except Exception: # pylint:disable=broad-except
  85. pass
  86. # Be sure cleanup functionality is available; classes that use the adapter hook
  87. # need to be sure to subclass ``CleanUp``.
  88. #
  89. # If zope.component is installed and imported when we run our tests
  90. # (import chain:
  91. # zope.testrunner->zope.security->zope.location->zope.component.api)
  92. # it adds an adapter hook that uses its global site manager. That can cause
  93. # leakage from one test to another unless its cleanup hooks are run. The
  94. # symptoms can be odd, especially if one test used C objects and the next used
  95. # the Python implementation. (For example, you can get strange TypeErrors or
  96. # find inexplicable comparisons being done.)
  97. try:
  98. from zope.testing import cleanup
  99. except ImportError:
  100. class CleanUp:
  101. def cleanUp(self):
  102. pass
  103. setUp = tearDown = cleanUp
  104. else:
  105. CleanUp = cleanup.CleanUp